Skip to content

Commit

Permalink
Merge pull request #58 from auth0/feature/interactive-prompts
Browse files Browse the repository at this point in the history
  • Loading branch information
Widcket authored Jan 27, 2021
2 parents 98fa733 + 53e7a1d commit 6559495
Show file tree
Hide file tree
Showing 4 changed files with 158 additions and 68 deletions.
72 changes: 55 additions & 17 deletions internal/cli/apis.go
Original file line number Diff line number Diff line change
@@ -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"
Expand Down Expand Up @@ -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{
Expand All @@ -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 {
Expand All @@ -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")

Expand All @@ -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{
Expand All @@ -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 {
Expand All @@ -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")

Expand All @@ -132,21 +166,24 @@ 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{
Use: "delete",
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)
})
Expand All @@ -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")

Expand Down
10 changes: 10 additions & 0 deletions internal/cli/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
115 changes: 68 additions & 47 deletions internal/cli/rules.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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{
Expand All @@ -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 {
Expand All @@ -177,72 +197,72 @@ 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{
Use: "delete",
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")
}
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)
})
Expand All @@ -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
}
Expand Down
29 changes: 25 additions & 4 deletions internal/prompt/prompt.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}

Expand All @@ -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
}

Expand Down

0 comments on commit 6559495

Please sign in to comment.