Repository: scaleway/scaleway-cli (go)

Issue:
scw init does not automatically retrieve organization ID
<!--- Please keep this note for the community --->

### Community Note

* Please vote on this issue by adding a 👍 [reaction](https://blog.github.com/2016-03-10-add-reactions-to-pull-requests-issues-and-comments/) to the original issue to help the community and maintainers prioritize this request
* Please do not leave "+1" or other comments that do not add relevant new information or questions, they generate extra noise for issue followers and do not help prioritize the request
* If you are interested in working on this issue or have submitted a pull request, please leave a comment

<!--- Thank you for keeping this note for the community --->

## Command attempted

```
scw init
```

### Expected Behavior

Does not ask for organization ID, retrieve it automatically.

### Actual Behavior

Retrieve it automatically.

## More info

Should rely on `/tokens/<secret_key>`.


Pull request description:
fix(init): rely on token organization
### Community Note

* Please vote on this pull request by adding a 👍 [reaction](https://blog.github.com/2016-03-10-add-reactions-to-pull-requests-issues-and-comments/) to the original pull request comment to help the community and maintainers prioritize this request.
* Please do not leave "+1" or other comments that do not add relevant new information or questions, they generate extra noise for pull request followers and do not help prioritize the request

<!--- Thank you for keeping this note for the community --->

<!--- If your PR fully resolves and should automatically close the linked issue, use Closes. Otherwise, use Relates --->
Closes #1141 

Release note for [CHANGELOG](https://github.com/scaleway/scaleway-cli/blob/v2/CHANGELOG.md):
<!--
If the change is not user facing, just write "NONE" in the release-note block below.
-->

```release-note
fix(init): rely on token organization
```


Patch:
diff --git a/internal/account/account.go b/internal/account/account.go
index cef743ff..769b01d5 100644
--- a/internal/account/account.go
+++ b/internal/account/account.go
@@ -11,10 +11,12 @@ import (
 
 // Token represents a Token
 type Token struct {
-	UserID    string `json:"user_id"`
-	AccessKey string `json:"access_key"`
-	SecretKey string `json:"secret_key"`
-	ID        string `json:"id"`
+	ID             string `json:"id"`
+	UserID         string `json:"user_id"`
+	AccessKey      string `json:"access_key"`
+	SecretKey      string `json:"secret_key"`
+	OrganizationID string `json:"organization_id"`
+	ProjectID      string `json:"project_id"`
 }
 
 type LoginResponse struct {
@@ -31,14 +33,6 @@ type LoginRequest struct {
 	Expires        bool   `json:"expires"`
 }
 
-type organizationsResponse struct {
-	Organizations []organization `json:"organizations"`
-}
-
-type organization struct {
-	ID string `json:"id"`
-}
-
 var (
 	accountURL = "https://account.scaleway.com"
 )
@@ -79,66 +73,27 @@ func Login(ctx context.Context, req *LoginRequest) (*LoginResponse, error) {
 	return loginResponse, err
 }
 
-func GetAccessKey(ctx context.Context, secretKey string) (string, error) {
+func GetAPIKey(ctx context.Context, secretKey string) (*Token, error) {
 	resp, err := extractHTTPClient(ctx).Get(accountURL + "/tokens/" + secretKey)
 	if err != nil {
-		return "", err
+		return nil, err
 	}
 	defer resp.Body.Close()
 
 	if resp.StatusCode != http.StatusOK {
-		return "", fmt.Errorf("could not get token")
+		return nil, fmt.Errorf("could not get token")
 	}
 
 	token := &LoginResponse{}
 	b, err := ioutil.ReadAll(resp.Body)
-	if err != nil {
-		return "", err
-	}
-
-	err = json.Unmarshal(b, token)
-	if err != nil {
-		return "", err
-	}
-
-	return token.Token.AccessKey, err
-}
-
-func getOrganizations(ctx context.Context, secretKey string) ([]organization, error) {
-	req, err := http.NewRequest("GET", accountURL+"/organizations", nil)
 	if err != nil {
 		return nil, err
 	}
-	req.Header.Add("X-Auth-Token", secretKey)
-	resp, err := extractHTTPClient(ctx).Do(req)
-	if err != nil {
-		return nil, err
-	}
-	defer resp.Body.Close()
 
-	if resp.StatusCode != http.StatusOK {
-		return nil, fmt.Errorf("could not get organizations from %s", accountURL)
-	}
-	body, err := ioutil.ReadAll(resp.Body)
-	if err != nil {
-		return nil, err
-	}
-	organizationsResponse := &organizationsResponse{}
-	err = json.Unmarshal(body, organizationsResponse)
+	err = json.Unmarshal(b, token)
 	if err != nil {
 		return nil, err
 	}
-	return organizationsResponse.Organizations, nil
-}
 
-func GetOrganizationsIds(ctx context.Context, secretKey string) ([]string, error) {
-	organizations, err := getOrganizations(ctx, secretKey)
-	if err != nil {
-		return nil, err
-	}
-	ids := []string(nil)
-	for _, organization := range organizations {
-		ids = append(ids, organization.ID)
-	}
-	return ids, nil
+	return token.Token, err
 }
diff --git a/internal/namespaces/init/init.go b/internal/namespaces/init/init.go
index cbc0ea4b..e9e41999 100644
--- a/internal/namespaces/init/init.go
+++ b/internal/namespaces/init/init.go
@@ -63,7 +63,6 @@ type initArgs struct {
 	SecretKey           string
 	Region              scw.Region
 	Zone                scw.Zone
-	OrganizationID      string
 	SendTelemetry       *bool
 	WithSSHKey          *bool
 	InstallAutocomplete *bool
@@ -100,19 +99,8 @@ func initCommand() *core.Command {
 				Name:  "remove-v1-config",
 				Short: "Whether to remove the v1 configuration file if it exists",
 			},
-
-			// `organization-id` is not required before  `PreValidateFunc()`, but is required after `PreValidateFunc()`.
-			// See workflow in cobra_utils.go/cobraRun().
-			// It is not required in the command line: the user is not obliged to type it.
-			// But it is required to make the request: this is why we use `ValidateOrganizationIDRequired().
-			// If `organization-id` is not typed by the user, we set it in `PreValidateFunc()`.
-			{
-				Name:         "organization-id",
-				Short:        "Organization ID to use. If none is passed will use default organization ID from the config",
-				ValidateFunc: core.ValidateOrganizationIDRequired(),
-			},
 			core.RegionArgSpec(scw.RegionFrPar, scw.RegionNlAms),
-			core.ZoneArgSpec(),
+			core.ZoneArgSpec(scw.ZoneFrPar1, scw.ZoneFrPar2, scw.ZoneNlAms1),
 		},
 		SeeAlsos: []*core.SeeAlso{
 			{
@@ -195,15 +183,6 @@ func initCommand() *core.Command {
 				}
 			}
 
-			// Set OrganizationID if not done previously
-			// As OrganizationID depends on args.SecretKey, we can't use a DefaultFunc or ArgPromptFunc.
-			if args.OrganizationID == "" {
-				args.OrganizationID, err = getOrganizationID(ctx, args.SecretKey)
-				if err != nil {
-					return err
-				}
-			}
-
 			// Ask for send usage permission
 			if args.SendTelemetry == nil {
 				_, _ = interactive.Println()
@@ -281,21 +260,22 @@ func initCommand() *core.Command {
 			}
 
 			// Get access key
-			accessKey, err := account.GetAccessKey(ctx, args.SecretKey)
+			apiKey, err := account.GetAPIKey(ctx, args.SecretKey)
 			if err != nil {
 				return "", &core.CliError{
 					Err:     err,
-					Details: "Failed to retrieve Access Key for the given Secret Key.",
+					Details: "Failed to retrieve Access Key from the given Secret Key.",
 				}
 			}
 
 			profile := &scw.Profile{
-				AccessKey:             &accessKey,
+				AccessKey:             &apiKey.AccessKey,
 				SecretKey:             &args.SecretKey,
 				DefaultZone:           scw.StringPtr(args.Zone.String()),
 				DefaultRegion:         scw.StringPtr(args.Region.String()),
-				DefaultOrganizationID: &args.OrganizationID,
+				DefaultOrganizationID: &apiKey.OrganizationID, // An api key is always bound to an organization.
 			}
+
 			// Save the profile as default or as a named profile
 			profileName := core.ExtractProfileName(ctx)
 			_, err = config.GetProfile(profileName)
@@ -438,38 +418,6 @@ func promptCredentials(ctx context.Context) (string, error) {
 	}
 }
 
-// getOrganizationId handles prompting for the argument organization-id
-// If we have only 1 id : we use it, and don't prompt
-// If we have more than 1 id, we prompt, with id[0] as default value.
-func getOrganizationID(ctx context.Context, secretKey string) (string, error) {
-	IDs, err := account.GetOrganizationsIds(ctx, secretKey)
-	if err != nil {
-		logger.Warningf("%v", err)
-		return promptOrganizationID(ctx, IDs)
-	}
-	if len(IDs) != 1 {
-		return promptOrganizationID(ctx, IDs)
-	}
-	return IDs[0], nil
-}
-
-func promptOrganizationID(ctx context.Context, IDs []string) (string, error) {
-	config := &interactive.PromptStringConfig{
-		Prompt:       "Enter your Organization ID",
-		ValidateFunc: interactive.ValidateOrganizationID(),
-		Ctx:          ctx,
-	}
-	if len(IDs) > 0 {
-		config.DefaultValue = IDs[0]
-		config.DefaultValueDoc = IDs[0]
-	}
-	ID, err := interactive.PromptStringWithConfig(config)
-	if err != nil {
-		return "", err
-	}
-	return ID, nil
-}
-
 const logo = `
   @@@@@@@@@@@@@@@.
 @@@@@@@@@@@@@@@@@@@@        __          __  _


Test patch:
diff --git a/internal/namespaces/init/custom_init_autocomplete_test.go b/internal/namespaces/init/custom_init_autocomplete_test.go
index 5439bcad..f99d30c3 100644
--- a/internal/namespaces/init/custom_init_autocomplete_test.go
+++ b/internal/namespaces/init/custom_init_autocomplete_test.go
@@ -15,7 +15,6 @@ import (
 func baseBeforeFunc() core.BeforeFunc {
 	return func(ctx *core.BeforeFuncCtx) error {
 		ctx.Meta["SecretKey"], _ = ctx.Client.GetSecretKey()
-		ctx.Meta["OrganizationID"], _ = ctx.Client.GetDefaultOrganizationID()
 		return nil
 	}
 }
@@ -29,7 +28,6 @@ const (
 func Test_InitAutocomplete(t *testing.T) {
 	defaultSettings := map[string]string{
 		"secret-key":       "{{ .SecretKey }}",
-		"organization-id":  "{{ .OrganizationID }}",
 		"send-telemetry":   "false",
 		"remove-v1-config": "false",
 		"with-ssh-key":     "false",
diff --git a/internal/namespaces/init/custom_init_ssh_test.go b/internal/namespaces/init/custom_init_ssh_test.go
index 53a31bd0..aae2c4af 100644
--- a/internal/namespaces/init/custom_init_ssh_test.go
+++ b/internal/namespaces/init/custom_init_ssh_test.go
@@ -70,7 +70,6 @@ func addSSHKeyToAccount(metaKey string, name string, key string) core.BeforeFunc
 func Test_InitSSH(t *testing.T) {
 	defaultSettings := map[string]string{
 		"secret-key":           "{{ .SecretKey }}",
-		"organization-id":      "{{ .OrganizationID }}",
 		"send-telemetry":       "false",
 		"remove-v1-config":     "false",
 		"install-autocomplete": "false",
diff --git a/internal/namespaces/init/init_test.go b/internal/namespaces/init/init_test.go
index a314d251..09230332 100644
--- a/internal/namespaces/init/init_test.go
+++ b/internal/namespaces/init/init_test.go
@@ -38,7 +38,6 @@ func beforeFuncSaveConfig(config *scw.Config) core.BeforeFunc {
 func TestInit(t *testing.T) {
 	defaultArgs := map[string]string{
 		"secret-key":           "{{ .SecretKey }}",
-		"organization-id":      "{{ .OrganizationID }}",
 		"send-telemetry":       "true",
 		"install-autocomplete": "false",
 		"remove-v1-config":     "false",
@@ -142,9 +141,7 @@ func TestInit(t *testing.T) {
 				core.TestCheckGolden(),
 				checkConfig(func(t *testing.T, ctx *core.CheckFuncCtx, config *scw.Config) {
 					secretKey, _ := ctx.Client.GetSecretKey()
-					organizationID, _ := ctx.Client.GetDefaultOrganizationID()
 					assert.Equal(t, secretKey, *config.SecretKey)
-					assert.Equal(t, organizationID, *config.DefaultOrganizationID)
 				}),
 			),
 			TmpHomeDir: true,