diff --git a/internal/cli/apis.go b/internal/cli/apis.go index e7198a9bc..eeeda6430 100644 --- a/internal/cli/apis.go +++ b/internal/cli/apis.go @@ -1,6 +1,7 @@ package cli import ( + "github.com/AlecAivazis/survey/v2" "github.com/auth0/auth0-cli/internal/ansi" "github.com/auth0/auth0-cli/internal/prompt" "github.com/spf13/cobra" @@ -55,8 +56,8 @@ Lists your existing APIs. To create one try: func createApiCmd(cli *cli) *cobra.Command { var flags struct { - name string - identifier string + Name string + Identifier string } cmd := &cobra.Command{ @@ -66,10 +67,31 @@ func createApiCmd(cli *cli) *cobra.Command { auth0 apis create --name myapi --identifier http://my-api `, + PreRun: func(cmd *cobra.Command, args []string) { + checkFlags(cmd) + }, RunE: func(cmd *cobra.Command, args []string) error { + if !hasFlags(cmd) { + name := prompt.TextInput( + "name", "Name:", + "Name of the API. You can change the API name later in the API settings.", + "", + true) + + identifier := prompt.TextInput( + "identifier", "Identifier:", + "Identifier of the API. Cannot be changed once set.", + "", + true) + + if err := prompt.Ask([]*survey.Question {name, identifier}, &flags); err != nil { + return err + } + } + api := &management.ResourceServer{ - Name: &flags.name, - Identifier: &flags.identifier, + Name: &flags.Name, + Identifier: &flags.Identifier, } err := ansi.Spinner("Creating API", func() error { @@ -85,8 +107,8 @@ auth0 apis create --name myapi --identifier http://my-api }, } - cmd.Flags().StringVarP(&flags.name, "name", "n", "", "Name of the API.") - cmd.Flags().StringVarP(&flags.identifier, "identifier", "i", "", "Identifier of the API.") + cmd.Flags().StringVarP(&flags.Name, "name", "n", "", "Name of the API.") + cmd.Flags().StringVarP(&flags.Identifier, "identifier", "i", "", "Identifier of the API.") mustRequireFlags(cmd, "name", "identifier") @@ -95,8 +117,8 @@ auth0 apis create --name myapi --identifier http://my-api func updateApiCmd(cli *cli) *cobra.Command { var flags struct { - id string - name string + ID string + Name string } cmd := &cobra.Command{ @@ -106,11 +128,23 @@ func updateApiCmd(cli *cli) *cobra.Command { auth0 apis update --id id --name myapi `, + PreRun: func(cmd *cobra.Command, args []string) { + checkFlags(cmd) + }, RunE: func(cmd *cobra.Command, args []string) error { - api := &management.ResourceServer{Name: &flags.name} + if !hasFlags(cmd) { + id := prompt.TextInput("id", "Id:", "Id of the API.", "", true) + name := prompt.TextInput("name", "Name:", "Name of the API.", "", true) + + if err := prompt.Ask([]*survey.Question {id, name}, &flags); err != nil { + return err + } + } + + api := &management.ResourceServer{Name: &flags.Name} err := ansi.Spinner("Updating API", func() error { - return cli.api.ResourceServer.Update(flags.id, api) + return cli.api.ResourceServer.Update(flags.ID, api) }) if err != nil { @@ -122,8 +156,8 @@ auth0 apis update --id id --name myapi }, } - cmd.Flags().StringVarP(&flags.id, "id", "i", "", "ID of the API.") - cmd.Flags().StringVarP(&flags.name, "name", "n", "", "Name of the API.") + cmd.Flags().StringVarP(&flags.ID, "id", "i", "", "ID of the API.") + cmd.Flags().StringVarP(&flags.Name, "name", "n", "", "Name of the API.") mustRequireFlags(cmd, "id", "name") @@ -132,7 +166,8 @@ auth0 apis update --id id --name myapi func deleteApiCmd(cli *cli) *cobra.Command { var flags struct { - id string + id string + force bool } cmd := &cobra.Command{ @@ -140,13 +175,15 @@ func deleteApiCmd(cli *cli) *cobra.Command { Short: "Delete an API", Long: `Deletes an API: -auth0 apis delete --id id +auth0 apis delete --id id --force `, RunE: func(cmd *cobra.Command, args []string) error { - if confirmed := prompt.Confirm("Are you sure you want to proceed?"); !confirmed { - return nil + if !flags.force { + if confirmed := prompt.Confirm("Are you sure you want to proceed?"); !confirmed { + return nil + } } - + err := ansi.Spinner("Deleting API", func() error { return cli.api.ResourceServer.Delete(flags.id) }) @@ -160,6 +197,7 @@ auth0 apis delete --id id } cmd.Flags().StringVarP(&flags.id, "id", "i", "", "ID of the API.") + cmd.Flags().BoolVarP(&flags.force, "force", "f", false, "Do not ask for confirmation.") mustRequireFlags(cmd, "id") diff --git a/internal/cli/cli.go b/internal/cli/cli.go index 53d1167ce..335f60301 100644 --- a/internal/cli/cli.go +++ b/internal/cli/cli.go @@ -221,6 +221,16 @@ func (c *cli) initContext() (err error) { return nil } +func hasFlags(cmd *cobra.Command) bool { + return cmd.Flags().NFlag() > 0 +} + +func checkFlags(cmd *cobra.Command) { + if (!hasFlags(cmd)) { + cmd.ResetFlags() + } +} + func mustRequireFlags(cmd *cobra.Command, flags ...string) { for _, f := range flags { if err := cmd.MarkFlagRequired(f); err != nil { diff --git a/internal/cli/rules.go b/internal/cli/rules.go index 2ea65709d..b16054dca 100644 --- a/internal/cli/rules.go +++ b/internal/cli/rules.go @@ -4,6 +4,7 @@ import ( "fmt" "regexp" + "github.com/AlecAivazis/survey/v2" "github.com/auth0/auth0-cli/internal/ansi" "github.com/auth0/auth0-cli/internal/auth0" "github.com/auth0/auth0-cli/internal/prompt" @@ -148,10 +149,10 @@ func disableRuleCmd(cli *cli) *cobra.Command { func createRulesCmd(cli *cli) *cobra.Command { var flags struct { - name string - script string - order int - enabled bool + Name string + Script string + Order int + Enabled bool } cmd := &cobra.Command{ @@ -161,12 +162,31 @@ func createRulesCmd(cli *cli) *cobra.Command { auth0 rules create --name "My Rule" --script "function (user, context, callback) { console.log( 'Hello, world!' ); return callback(null, user, context); }" `, + PreRun: func(cmd *cobra.Command, args []string) { + checkFlags(cmd) + }, RunE: func(cmd *cobra.Command, args []string) error { + if !hasFlags(cmd) { + name := prompt.TextInput( + "name", "Name:", + "Name of the rule. You can change the rule name later in the rule settings.", + "", + true) + + script := prompt.TextInput("script", "Script:", "Script of the rule.", "", true) + order := prompt.TextInput("order", "Order:", "Order of the rule.", "0", false) + enabled := prompt.BoolInput("enabled", "Enabled:", "Enable the rule.", false) + + if err := prompt.Ask([]*survey.Question {name, script, order, enabled}, &flags); err != nil { + return err + } + } + r := &management.Rule{ - Name: &flags.name, - Script: &flags.script, - Order: &flags.order, - Enabled: &flags.enabled, + Name: &flags.Name, + Script: &flags.Script, + Order: &flags.Order, + Enabled: &flags.Enabled, } err := ansi.Spinner("Creating rule", func() error { @@ -177,24 +197,24 @@ func createRulesCmd(cli *cli) *cobra.Command { return err } - cli.renderer.Infof("Your rule `%s` was successfully created.", flags.name) + cli.renderer.Infof("Your rule `%s` was successfully created.", flags.Name) return nil }, } - cmd.Flags().StringVarP(&flags.name, "name", "n", "", "Name of this rule (required)") - cmd.Flags().StringVarP(&flags.script, "script", "s", "", "Code to be executed when this rule runs (required)") - cmd.Flags().IntVarP(&flags.order, "order", "o", 0, "Order that this rule should execute in relative to other rules. Lower-valued rules execute first.") - cmd.Flags().BoolVarP(&flags.enabled, "enabled", "e", false, "Whether the rule is enabled (true), or disabled (false).") + cmd.Flags().StringVarP(&flags.Name, "name", "n", "", "Name of this rule (required)") + cmd.Flags().StringVarP(&flags.Script, "script", "s", "", "Code to be executed when this rule runs (required)") + cmd.Flags().IntVarP(&flags.Order, "order", "o", 0, "Order that this rule should execute in relative to other rules. Lower-valued rules execute first.") + cmd.Flags().BoolVarP(&flags.Enabled, "enabled", "e", false, "Whether the rule is enabled (true), or disabled (false).") mustRequireFlags(cmd, "name", "script") return cmd } func deleteRulesCmd(cli *cli) *cobra.Command { var flags struct { - id string - name string - confirm bool + id string + name string + force bool } cmd := &cobra.Command{ @@ -202,7 +222,7 @@ func deleteRulesCmd(cli *cli) *cobra.Command { Short: "Delete a rule", Long: `Delete a rule: - auth0 rules delete --id "12345"`, + auth0 rules delete --id "12345" --force`, PreRunE: func(cmd *cobra.Command, args []string) error { if flags.id != "" && flags.name != "" { return fmt.Errorf("TMI! 🤯 use either --name or --id") @@ -210,39 +230,39 @@ func deleteRulesCmd(cli *cli) *cobra.Command { return nil }, RunE: func(cmd *cobra.Command, args []string) error { - var r *management.Rule - ruleIDPattern := "^rul_[A-Za-z0-9]{16}$" - re := regexp.MustCompile(ruleIDPattern) - - if flags.id != "" { - if !re.Match([]byte(flags.id)) { - return fmt.Errorf("Rule with id %q does not match pattern %s", flags.id, ruleIDPattern) - } - - rule, err := cli.api.Rule.Read(flags.id) - if err != nil { - return err - } - r = rule - } else { - data, err := getRules(cli) - if err != nil { - return err - } - if rule := findRuleByName(flags.name, data.Rules); rule != nil { - r = rule - } else { - return fmt.Errorf("No rule found with name: %q", flags.name) - } - } - - if !cli.force { - // TODO: Should add validation of rule + if !flags.force { if confirmed := prompt.Confirm("Are you sure you want to proceed?"); !confirmed { return nil } } + // TODO: Should add validation of rule + var r *management.Rule + ruleIDPattern := "^rul_[A-Za-z0-9]{16}$" + re := regexp.MustCompile(ruleIDPattern) + + if flags.id != "" { + if !re.Match([]byte(flags.id)) { + return fmt.Errorf("Rule with id %q does not match pattern %s", flags.id, ruleIDPattern) + } + + rule, err := cli.api.Rule.Read(flags.id) + if err != nil { + return err + } + r = rule + } else { + data, err := getRules(cli) + if err != nil { + return err + } + if rule := findRuleByName(flags.name, data.Rules); rule != nil { + r = rule + } else { + return fmt.Errorf("No rule found with name: %q", flags.name) + } + } + err := ansi.Spinner("Deleting rule", func() error { return cli.api.Rule.Delete(*r.ID) }) @@ -255,8 +275,9 @@ func deleteRulesCmd(cli *cli) *cobra.Command { }, } - cmd.Flags().StringVar(&flags.id, "id", "", "ID of the rule to delete") - cmd.Flags().StringVar(&flags.name, "name", "", "Name of the rule to delete") + cmd.Flags().StringVarP(&flags.id, "id", "i", "", "ID of the rule to delete (required)") + cmd.Flags().StringVarP(&flags.name, "name", "n", "", "Name of the rule to delete") + cmd.Flags().BoolVarP(&flags.force, "force", "f", false, "Do not ask for confirmation.") return cmd } diff --git a/internal/prompt/prompt.go b/internal/prompt/prompt.go index 796538390..aa2b34311 100644 --- a/internal/prompt/prompt.go +++ b/internal/prompt/prompt.go @@ -8,14 +8,35 @@ import ( var stdErrWriter = survey.WithStdio(os.Stdin, os.Stderr, os.Stderr) +var icons = survey.WithIcons(func(icons *survey.IconSet) { + icons.Question.Text = "" +}) + func Ask(inputs []*survey.Question, response interface{}) error { - return survey.Ask(inputs, response, stdErrWriter) + return survey.Ask(inputs, response, stdErrWriter, icons) +} + +func AskOne(prompt survey.Prompt, response interface{}) error { + return survey.AskOne(prompt, response, stdErrWriter, icons) +} + +func TextInput(name string, message string, help string, value string, required bool) *survey.Question { + input := &survey.Question{ + Name: name, + Prompt: &survey.Input{Message: message, Help: help, Default: value}, + } + + if required { + input.Validate = survey.Required + } + + return input } -func TextInput(name string, message string, required bool) *survey.Question { +func BoolInput(name string, message string, help string, required bool) *survey.Question { input := &survey.Question{ Name: name, - Prompt: &survey.Input{Message: message}, + Prompt: &survey.Confirm{Message: message, Help: help}, Transform: survey.Title, } @@ -32,7 +53,7 @@ func Confirm(message string) bool { Message: message, } - if err := survey.AskOne(prompt, &result, stdErrWriter); err != nil { + if err := AskOne(prompt, &result); err != nil { return false }