Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(core): rework init command #835

Merged
merged 6 commits into from
Apr 3, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -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 ...]
Expand Down
2 changes: 1 addition & 1 deletion cmd/scw/testdata/test-main-usage-usage.stderr.golden
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
16 changes: 14 additions & 2 deletions internal/core/result.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,22 +11,34 @@ import (

type SuccessResult struct {
Message string
Details string
}

func (s *SuccessResult) MarshalHuman() (string, error) {
message := s.getMessage()
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 {
Expand Down
12 changes: 5 additions & 7 deletions internal/namespaces/account/custom.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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 {
Expand All @@ -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 {
Expand Down
12 changes: 3 additions & 9 deletions internal/namespaces/account/error.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}
}
21 changes: 14 additions & 7 deletions internal/namespaces/autocomplete/autocomplete.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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
Expand Down Expand Up @@ -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 {
Expand All @@ -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
}

Expand Down
37 changes: 22 additions & 15 deletions internal/namespaces/init/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"),
},
{
Expand Down Expand Up @@ -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",
Expand Down Expand Up @@ -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{
Expand All @@ -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{
Expand Down Expand Up @@ -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"
Expand Down