From 29efee90fb70cb7738b011298dd3a9ff9a2f5100 Mon Sep 17 00:00:00 2001 From: Quentin Brosse Date: Fri, 3 Apr 2020 18:11:00 +0200 Subject: [PATCH] feat(core): rework init command (#835) --- ...e-autocomplete-install-usage.stderr.golden | 2 +- .../test-main-usage-usage.stderr.golden | 2 +- internal/core/result.go | 16 +++++++- internal/namespaces/account/custom.go | 12 +++--- internal/namespaces/account/error.go | 12 ++---- .../namespaces/autocomplete/autocomplete.go | 21 +++++++---- internal/namespaces/init/init.go | 37 +++++++++++-------- 7 files changed, 60 insertions(+), 42 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 81982eb8fa..54d817e7c5 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) { @@ -18,15 +19,26 @@ func (s *SuccessResult) MarshalHuman() (string, error) { if !strings.HasSuffix(message, ".") { message += "." } + message = strcase.TitleFirstWord(message) - return "✅ " + terminal.Style(message, color.FgGreen), nil + message = "✅ " + terminal.Style(message, color.FgGreen) + + if s.Details != "" { + message += s.Details + } + + return message, 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()}) + return json.Marshal(&tmpRes{ + Message: s.getMessage(), + Details: s.Details, + }) } func (s *SuccessResult) getMessage() string { diff --git a/internal/namespaces/account/custom.go b/internal/namespaces/account/custom.go index d5900b1809..0ceca8da1c 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 { @@ -80,13 +76,15 @@ 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 } } // 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 ?", + 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/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/autocomplete/autocomplete.go b/internal/namespaces/autocomplete/autocomplete.go index f595a24cf5..ba0b124c21 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 2e03a48b40..f52377fdc6 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"), }, { @@ -133,25 +133,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", @@ -195,7 +201,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{ @@ -213,7 +219,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{ @@ -273,36 +279,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"