From bc676b11ca1bb9d08a4c37bcb744d7a94b125d5d Mon Sep 17 00:00:00 2001 From: Quentin Brosse Date: Fri, 3 Apr 2020 14:48:12 +0200 Subject: [PATCH 1/6] feat(core): rework init command --- internal/core/result.go | 4 ++- internal/namespaces/account/custom.go | 4 +-- .../namespaces/autocomplete/autocomplete.go | 21 +++++++---- internal/namespaces/init/init.go | 35 +++++++++++-------- 4 files changed, 40 insertions(+), 24 deletions(-) diff --git a/internal/core/result.go b/internal/core/result.go index 81982eb8fa..87f4dc4b6d 100644 --- a/internal/core/result.go +++ b/internal/core/result.go @@ -11,6 +11,7 @@ import ( type SuccessResult struct { Message string + Details string } func (s *SuccessResult) MarshalHuman() (string, error) { @@ -19,12 +20,13 @@ func (s *SuccessResult) MarshalHuman() (string, error) { message += "." } message = strcase.TitleFirstWord(message) - return "✅ " + terminal.Style(message, color.FgGreen), nil + return "✅ " + terminal.Style(message, color.FgGreen) + "\n" + s.Details, nil } func (s *SuccessResult) MarshalJSON() ([]byte, error) { type tmpRes struct { Message string `json:"message"` + Details string `json:"details"` } return json.Marshal(&tmpRes{Message: s.getMessage()}) } diff --git a/internal/namespaces/account/custom.go b/internal/namespaces/account/custom.go index d5900b1809..4a63922e03 100644 --- a/internal/namespaces/account/custom.go +++ b/internal/namespaces/account/custom.go @@ -48,7 +48,7 @@ func initCommand() *core.Command { func InitRun(ctx context.Context, argsI interface{}) (i interface{}, e error) { // Explanation - _, _ = interactive.Println("An SSH key is required if you want to connect to a server. More info at https://www.scaleway.com/en/docs/configure-new-ssh-key/") + _, _ = interactive.Println("An SSH key is required if you want to connect to a server. More info at https://www.scaleway.com/en/docs/configure-new-ssh-key") // Get default SSH key locally relativePath := path.Join(".ssh", "id_rsa.pub") @@ -86,7 +86,7 @@ func InitRun(ctx context.Context, argsI interface{}) (i interface{}, e error) { // Ask user addSSHKey, err := interactive.PromptBoolWithConfig(&interactive.PromptBoolConfig{ - Prompt: "We found an SSH key in " + shortenedFilename + ". Do you want to add it to your Scaleway account ?", + Prompt: "We found an SSH key in " + shortenedFilename + ". Do you want to add it to your Scaleway account?", DefaultValue: true, }) if err != nil { diff --git a/internal/namespaces/autocomplete/autocomplete.go b/internal/namespaces/autocomplete/autocomplete.go index f595a24cf5..07c358a349 100644 --- a/internal/namespaces/autocomplete/autocomplete.go +++ b/internal/namespaces/autocomplete/autocomplete.go @@ -121,8 +121,8 @@ type InstallArgs struct { func autocompleteInstallCommand() *core.Command { return &core.Command{ - Short: `Install autocompletion script`, - Long: `Install autocompletion script for a given shell and OS.`, + Short: `Install autocomplete script`, + Long: `Install autocomplete script for a given shell and OS.`, Namespace: "autocomplete", Resource: "install", NoClient: true, @@ -138,7 +138,7 @@ func autocompleteInstallCommand() *core.Command { func InstallCommandRun(ctx context.Context, argsI interface{}) (i interface{}, e error) { // Warning - _, _ = interactive.Println("To enable autocomplete, scw needs to update your shell configuration") + _, _ = interactive.Println("To enable autocomplete, scw needs to update your shell configuration.") // If `shell=` is empty, ask for a value for `shell=`. shellArg := argsI.(*InstallArgs).Shell @@ -185,16 +185,23 @@ func InstallCommandRun(ctx context.Context, argsI interface{}) (i interface{}, e return nil, err } if strings.Contains(string(shellConfigurationFileContent), script.CompleteScript) { + _, _ = interactive.Println() _, _ = interactive.Println("Autocomplete looks already installed. If it does not work properly, try to open a new shell.") return "", nil } + // Autocomplete script content + autoCompleteScript := "\n# Scaleway CLI autocomplete initialization.\n" + script.CompleteScript + // Warning - _, _ = interactive.Println("To enable autocompletion we need to append to " + shellConfigurationFilePath + " the following lines:\n\t# Scaleway CLI autocomplete initialization.\n\t" + script.CompleteScript) + interactive.Println() + _, _ = interactive.PrintlnWithoutIndent("To enable autocomplete we need to append to " + shellConfigurationFilePath + " the following lines:") + interactive.Println(strings.ReplaceAll(autoCompleteScript, "\n", "\n\t")) // Early exit if user disagrees + interactive.Println() continueInstallation, err := interactive.PromptBoolWithConfig(&interactive.PromptBoolConfig{ - Prompt: fmt.Sprintf("Do you want to proceed with theses changes ?"), + Prompt: fmt.Sprintf("Do you want to proceed with these changes?"), DefaultValue: true, }) if err != nil { @@ -205,14 +212,14 @@ func InstallCommandRun(ctx context.Context, argsI interface{}) (i interface{}, e } // Append to file - _, err = f.Write([]byte("\n# Scaleway CLI autocomplete initialization.\n" + script.CompleteScript + "\n")) + _, err = f.Write([]byte(autoCompleteScript + "\n")) if err != nil { return nil, err } // Ack return &core.SuccessResult{ - Message: fmt.Sprintf("Autocomplete function for %v installed successfully.\nUpdated %v.", shellName, shellConfigurationFilePath), + Message: fmt.Sprintf("Autocomplete has been successfully installed for your %v shell.\nUpdated %v.", shellName, shellConfigurationFilePath), }, nil } diff --git a/internal/namespaces/init/init.go b/internal/namespaces/init/init.go index ded047a78e..cad095ec1a 100644 --- a/internal/namespaces/init/init.go +++ b/internal/namespaces/init/init.go @@ -137,25 +137,31 @@ func initCommand() *core.Command { ` + terminal.Style(fmt.Sprint(config), color.Faint) + ` `) overrideConfig, err := interactive.PromptBoolWithConfig(&interactive.PromptBoolConfig{ - Prompt: "Do you want to override current config?", + Prompt: "Do you want to override the current config?", DefaultValue: true, }) if err != nil { return err } if !overrideConfig { - return fmt.Errorf("initialization cancelled") + return fmt.Errorf("initialization canceled") } } - // Manually prompt for missing args + // Manually prompt for missing args: + + // Credentials if args.SecretKey == "" { - args.SecretKey, err = promptSecretKey() + interactive.Println() + args.SecretKey, err = promptCredentials() if err != nil { return err } } + + // Zone if args.Zone == "" { + interactive.Println() zone, err := interactive.PromptStringWithConfig(&interactive.PromptStringConfig{ Prompt: "Select a zone", DefaultValueDoc: "fr-par-1", @@ -199,7 +205,7 @@ func initCommand() *core.Command { _, _ = interactive.Println() _, _ = interactive.PrintlnWithoutIndent(` To improve this tool we rely on diagnostic and usage data. - Sending such data is optional and can be disable at any time by running "scw config set send_telemetry false" + Sending such data is optional and can be disabled at any time by running "scw config set send_telemetry false". `) sendTelemetry, err := interactive.PromptBoolWithConfig(&interactive.PromptBoolConfig{ @@ -217,7 +223,7 @@ func initCommand() *core.Command { if args.InstallAutocomplete == nil { _, _ = interactive.Println() _, _ = interactive.PrintlnWithoutIndent(` - To fully enjoy Scaleway CLI we recommend you to install autocomplete support in your shell. + To fully enjoy Scaleway CLI we recommend you install autocomplete support in your shell. `) installAutocomplete, err := interactive.PromptBoolWithConfig(&interactive.PromptBoolConfig{ @@ -277,36 +283,37 @@ func initCommand() *core.Command { return nil, err } - successMessage := "Initialization completed with success" + successDetails := "" // Install autocomplete if *args.InstallAutocomplete { _, _ = interactive.Println() _, err := autocomplete.InstallCommandRun(ctx, &autocomplete.InstallArgs{}) if err != nil { - successMessage += "\n except for autocomplete: " + err.Error() + successDetails += "\n Except for autocomplete: " + err.Error() } } // Init SSH Key if *args.WithSSHKey { _, _ = interactive.Println() - result, err := accountcommands.InitRun(ctx, nil) + _, err := accountcommands.InitRun(ctx, nil) if err != nil { - successMessage += "\n except for ssh-key: " + err.Error() + successDetails += "\n Except for ssh-key: " + err.Error() } - _, _ = interactive.Println(result) - _, _ = interactive.Println() } + _, _ = interactive.Println() + return &core.SuccessResult{ - Message: successMessage, + Message: "Initialization completed with success", + Details: successDetails, }, nil }, } } -func promptSecretKey() (string, error) { +func promptCredentials() (string, error) { UUIDOrEmail, err := interactive.Readline(&interactive.ReadlineConfig{ PromptFunc: func(value string) string { secretKey, email := "secret-key", "email" From f2eaa3fa7c97e1c7c774f7d92ece601def3fe4b7 Mon Sep 17 00:00:00 2001 From: Quentin Brosse Date: Fri, 3 Apr 2020 15:08:51 +0200 Subject: [PATCH 2/6] fix tests --- ...st-all-usage-autocomplete-install-usage.stderr.golden | 2 +- cmd/scw/testdata/test-main-usage-usage.stderr.golden | 2 +- internal/core/result.go | 9 ++++++++- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/cmd/scw/testdata/test-all-usage-autocomplete-install-usage.stderr.golden b/cmd/scw/testdata/test-all-usage-autocomplete-install-usage.stderr.golden index 50383cfbe8..5e8dd3fa59 100644 --- a/cmd/scw/testdata/test-all-usage-autocomplete-install-usage.stderr.golden +++ b/cmd/scw/testdata/test-all-usage-autocomplete-install-usage.stderr.golden @@ -1,4 +1,4 @@ -Install autocompletion script for a given shell and OS. +Install autocomplete script for a given shell and OS. USAGE: scw autocomplete install [arg=value ...] diff --git a/cmd/scw/testdata/test-main-usage-usage.stderr.golden b/cmd/scw/testdata/test-main-usage-usage.stderr.golden index 1edf651557..2e928af8bd 100644 --- a/cmd/scw/testdata/test-main-usage-usage.stderr.golden +++ b/cmd/scw/testdata/test-main-usage-usage.stderr.golden @@ -9,7 +9,7 @@ AVAILABLE COMMANDS: init Initialize the config config Config file management account Manage SSH key - autocomplete Install autocompletion script + autocomplete Install autocomplete script version Display cli version help Help about any command diff --git a/internal/core/result.go b/internal/core/result.go index 87f4dc4b6d..5942f6cbd3 100644 --- a/internal/core/result.go +++ b/internal/core/result.go @@ -19,8 +19,15 @@ func (s *SuccessResult) MarshalHuman() (string, error) { if !strings.HasSuffix(message, ".") { message += "." } + message = strcase.TitleFirstWord(message) - return "✅ " + terminal.Style(message, color.FgGreen) + "\n" + s.Details, nil + message = "✅ " + terminal.Style(message, color.FgGreen) + + if s.Details != "" { + message += s.Details + } + + return message, nil } func (s *SuccessResult) MarshalJSON() ([]byte, error) { From 0bcc920f021c0200babf5eec284be705ceafcdea Mon Sep 17 00:00:00 2001 From: Quentin Brosse Date: Fri, 3 Apr 2020 15:10:06 +0200 Subject: [PATCH 3/6] fix lint --- internal/namespaces/autocomplete/autocomplete.go | 6 +++--- internal/namespaces/init/init.go | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/internal/namespaces/autocomplete/autocomplete.go b/internal/namespaces/autocomplete/autocomplete.go index 07c358a349..ba0b124c21 100644 --- a/internal/namespaces/autocomplete/autocomplete.go +++ b/internal/namespaces/autocomplete/autocomplete.go @@ -194,12 +194,12 @@ func InstallCommandRun(ctx context.Context, argsI interface{}) (i interface{}, e autoCompleteScript := "\n# Scaleway CLI autocomplete initialization.\n" + script.CompleteScript // Warning - interactive.Println() + _, _ = interactive.Println() _, _ = interactive.PrintlnWithoutIndent("To enable autocomplete we need to append to " + shellConfigurationFilePath + " the following lines:") - interactive.Println(strings.ReplaceAll(autoCompleteScript, "\n", "\n\t")) + _, _ = interactive.Println(strings.ReplaceAll(autoCompleteScript, "\n", "\n\t")) // Early exit if user disagrees - interactive.Println() + _, _ = interactive.Println() continueInstallation, err := interactive.PromptBoolWithConfig(&interactive.PromptBoolConfig{ Prompt: fmt.Sprintf("Do you want to proceed with these changes?"), DefaultValue: true, diff --git a/internal/namespaces/init/init.go b/internal/namespaces/init/init.go index cad095ec1a..afdd7575be 100644 --- a/internal/namespaces/init/init.go +++ b/internal/namespaces/init/init.go @@ -152,7 +152,7 @@ func initCommand() *core.Command { // Credentials if args.SecretKey == "" { - interactive.Println() + _, _ = interactive.Println() args.SecretKey, err = promptCredentials() if err != nil { return err @@ -161,7 +161,7 @@ func initCommand() *core.Command { // Zone if args.Zone == "" { - interactive.Println() + _, _ = interactive.Println() zone, err := interactive.PromptStringWithConfig(&interactive.PromptStringConfig{ Prompt: "Select a zone", DefaultValueDoc: "fr-par-1", From a2a218e4330a0cf8a73977f30cb4f0e1080fcd1c Mon Sep 17 00:00:00 2001 From: Quentin Brosse Date: Fri, 3 Apr 2020 16:10:23 +0200 Subject: [PATCH 4/6] print ssh key explaination only if user need it --- internal/namespaces/account/custom.go | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/internal/namespaces/account/custom.go b/internal/namespaces/account/custom.go index 4a63922e03..da188fa667 100644 --- a/internal/namespaces/account/custom.go +++ b/internal/namespaces/account/custom.go @@ -47,10 +47,7 @@ func initCommand() *core.Command { } func InitRun(ctx context.Context, argsI interface{}) (i interface{}, e error) { - // Explanation - _, _ = interactive.Println("An SSH key is required if you want to connect to a server. More info at https://www.scaleway.com/en/docs/configure-new-ssh-key") - - // Get default SSH key locally + // Get default local SSH key relativePath := path.Join(".ssh", "id_rsa.pub") filename := path.Join(core.ExtractEnv(ctx, "HOME"), relativePath) shortenedFilename := "~/" + relativePath @@ -70,7 +67,6 @@ func InitRun(ctx context.Context, argsI interface{}) (i interface{}, e error) { if err != nil { return nil, err } - api := account.NewAPI(client) listSSHKeysResponse, err := api.ListSSHKeys(&account.ListSSHKeysRequest{}, scw.WithAllPages()) if err != nil { @@ -85,6 +81,7 @@ func InitRun(ctx context.Context, argsI interface{}) (i interface{}, e error) { } // Ask user + _, _ = interactive.Println("An SSH key is required if you want to connect to a server. More info at https://www.scaleway.com/en/docs/configure-new-ssh-key") addSSHKey, err := interactive.PromptBoolWithConfig(&interactive.PromptBoolConfig{ Prompt: "We found an SSH key in " + shortenedFilename + ". Do you want to add it to your Scaleway account?", DefaultValue: true, From b08f093ed2423f6982c0a8370d421779d2dbf942 Mon Sep 17 00:00:00 2001 From: Quentin Brosse Date: Fri, 3 Apr 2020 16:20:59 +0200 Subject: [PATCH 5/6] already present is not an error anymore --- internal/namespaces/account/custom.go | 3 ++- internal/namespaces/account/error.go | 12 +++--------- internal/namespaces/init/init.go | 4 ++-- 3 files changed, 7 insertions(+), 12 deletions(-) diff --git a/internal/namespaces/account/custom.go b/internal/namespaces/account/custom.go index da188fa667..0ceca8da1c 100644 --- a/internal/namespaces/account/custom.go +++ b/internal/namespaces/account/custom.go @@ -76,7 +76,8 @@ func InitRun(ctx context.Context, argsI interface{}) (i interface{}, e error) { // Early exit if the SSH key is present locally and on Scaleway for _, SSHKey := range listSSHKeysResponse.SSHKeys { if strings.TrimSpace(SSHKey.PublicKey) == strings.TrimSpace(string(localSSHKeyContent)) { - return nil, sshKeyAlreadyPresent(shortenedFilename) + _, _ = interactive.Println("Look like your local SSH key " + shortenedFilename + " is already present on your Scaleway account.") + return nil, nil } } diff --git a/internal/namespaces/account/error.go b/internal/namespaces/account/error.go index 5641753b18..b3a9e624c8 100644 --- a/internal/namespaces/account/error.go +++ b/internal/namespaces/account/error.go @@ -9,19 +9,13 @@ import ( func installationCanceled(addKeyInstructions string) *core.CliError { return &core.CliError{ Err: fmt.Errorf("installation of SSH key canceled"), - Hint: "Add it later using " + addKeyInstructions, + Hint: "You can add it later using " + addKeyInstructions, } } func sshKeyNotFound(filename string, addKeyInstructions string) *core.CliError { return &core.CliError{ - Err: fmt.Errorf("could not find an ssh key at " + filename), - Hint: "Add one later using " + addKeyInstructions, - } -} - -func sshKeyAlreadyPresent(shortenedFilename string) *core.CliError { - return &core.CliError{ - Err: fmt.Errorf("key " + shortenedFilename + " is already present on your scaleway account"), + Err: fmt.Errorf("could not find an SSH key at " + filename), + Hint: "You can add one later using " + addKeyInstructions, } } diff --git a/internal/namespaces/init/init.go b/internal/namespaces/init/init.go index afdd7575be..0256554424 100644 --- a/internal/namespaces/init/init.go +++ b/internal/namespaces/init/init.go @@ -97,7 +97,7 @@ func initCommand() *core.Command { }, { Name: "with-ssh-key", - Short: "Whether the ssh key for managing instances should be uploaded automatically", + Short: "Whether the SSH key for managing instances should be uploaded automatically", Default: core.DefaultValueSetter("true"), }, { @@ -299,7 +299,7 @@ func initCommand() *core.Command { _, _ = interactive.Println() _, err := accountcommands.InitRun(ctx, nil) if err != nil { - successDetails += "\n Except for ssh-key: " + err.Error() + successDetails += "\n Except for SSH key: " + err.Error() } } From 66bffd818c67731ef8c29b8eb7813336747cb88a Mon Sep 17 00:00:00 2001 From: Quentin Brosse Date: Fri, 3 Apr 2020 17:43:09 +0200 Subject: [PATCH 6/6] address comments --- internal/core/result.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/internal/core/result.go b/internal/core/result.go index 5942f6cbd3..54d817e7c5 100644 --- a/internal/core/result.go +++ b/internal/core/result.go @@ -35,7 +35,10 @@ func (s *SuccessResult) MarshalJSON() ([]byte, error) { Message string `json:"message"` Details string `json:"details"` } - return json.Marshal(&tmpRes{Message: s.getMessage()}) + return json.Marshal(&tmpRes{ + Message: s.getMessage(), + Details: s.Details, + }) } func (s *SuccessResult) getMessage() string {