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

Refactor string flags on apps and apis [CLI-70] #146

Merged
merged 5 commits into from
Mar 13, 2021
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
58 changes: 28 additions & 30 deletions internal/cli/apis.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,28 @@ import (

const (
apiID = "id"
apiName = "name"
apiIdentifier = "identifier"
apiScopes = "scopes"
)

var (
apiName = Flag{
Name: "Name",
LongForm: "name",
ShortForm: "n",
DefaultValue: "",
Help: "Name of the API.",
IsRequired: true,
}
apiIdentifier = Flag{
Name: "Identifier",
LongForm: "identifier",
ShortForm: "i",
DefaultValue: "",
Help: "Identifier of the API. Cannot be changed once set.",
IsRequired: true,
}
)

func apisCmd(cli *cli) *cobra.Command {
cmd := &cobra.Command{
Use: "apis",
Expand Down Expand Up @@ -147,26 +164,12 @@ auth0 apis create --name myapi --identifier http://my-api
prepareInteractivity(cmd)
},
RunE: func(cmd *cobra.Command, args []string) error {
if shouldPrompt(cmd, apiName) {
input := prompt.TextInput(
apiName, "Name:",
"Name of the API. You can change the name later in the API settings.",
true)

if err := prompt.AskOne(input, &flags); err != nil {
return fmt.Errorf("An unexpected error occurred: %w", err)
}
if err := apiName.Ask(cmd, &flags.Name); err != nil {
return err
}

if shouldPrompt(cmd, apiIdentifier) {
input := prompt.TextInput(
apiIdentifier, "Identifier:",
"Identifier of the API. Cannot be changed once set.",
true)

if err := prompt.AskOne(input, &flags); err != nil {
return fmt.Errorf("An unexpected error occurred: %w", err)
}
if err := apiIdentifier.Ask(cmd, &flags.Identifier); err != nil {
return err
}

if shouldPrompt(cmd, apiScopes) {
Expand Down Expand Up @@ -199,10 +202,9 @@ auth0 apis create --name myapi --identifier http://my-api
},
}

cmd.Flags().StringVarP(&flags.Name, apiName, "n", "", "Name of the API.")
cmd.Flags().StringVarP(&flags.Identifier, apiIdentifier, "i", "", "Identifier of the API.")
apiName.RegisterString(cmd, &flags.Name)
apiIdentifier.RegisterString(cmd, &flags.Identifier)
cmd.Flags().StringVarP(&flags.Scopes, apiScopes, "s", "", "Space-separated list of scopes.")
mustRequireFlags(cmd, apiName, apiIdentifier)

return cmd
}
Expand Down Expand Up @@ -240,12 +242,8 @@ auth0 apis update <id> --name myapi
inputs.ID = args[0]
}

if shouldPromptWhenFlagless(cmd, apiName) {
input := prompt.TextInput(apiName, "Name:", "Name of the API.", true)

if err := prompt.AskOne(input, &inputs); err != nil {
return fmt.Errorf("An unexpected error occurred: %w", err)
}
if err := apiName.AskU(cmd, &inputs.Name); err != nil {
return err
}

if shouldPromptWhenFlagless(cmd, apiScopes) {
Expand Down Expand Up @@ -289,7 +287,7 @@ auth0 apis update <id> --name myapi
},
}

cmd.Flags().StringVarP(&inputs.Name, apiName, "n", "", "Name of the API.")
apiName.RegisterStringU(cmd, &inputs.Name)
cmd.Flags().StringVarP(&inputs.Scopes, apiScopes, "s", "", "Space-separated list of scopes.")
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Scopes will be tackled on a future PR, as it needs to be changed from string flag to string slice flag, for consistency with other slice inputs


return cmd
Expand Down
82 changes: 44 additions & 38 deletions internal/cli/apps.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,35 @@ import (
)

const (
appID = "id"
appName = "name"
appType = "type"
appDescription = "description"
appID = "id"
appType = "type"
)

var (
appName = Flag{
Name: "Name",
LongForm: "name",
ShortForm: "n",
DefaultValue: "",
Help: "Name of the application.",
IsRequired: true,
}
appDescription = Flag{
Name: "Description",
LongForm: "description",
ShortForm: "d",
DefaultValue: "",
Help: "Description of the application. Max character count is 140.",
IsRequired: false,
}
appAuthMethod = Flag{
Name: "Auth Method",
LongForm: "auth-method",
ShortForm: "a",
DefaultValue: "",
Help: "Defines the requested authentication method for the token endpoint. Possible values are 'None' (public application without a client secret), 'Post' (application uses HTTP POST parameters) or 'Basic' (application uses HTTP Basic).",
IsRequired: false,
}
)

func appsCmd(cli *cli) *cobra.Command {
Expand Down Expand Up @@ -188,15 +213,8 @@ auth0 apps create --name myapp --type [native|spa|regular|m2m]
prepareInteractivity(cmd)
},
RunE: func(cmd *cobra.Command, args []string) error {
if shouldPrompt(cmd, appName) {
input := prompt.TextInput(
appName, "Name:",
"Name of the application. You can change the name later in the application settings.",
true)

if err := prompt.AskOne(input, &flags); err != nil {
return fmt.Errorf("An unexpected error occurred: %w", err)
}
if err := appName.Ask(cmd, &flags.Name); err != nil {
return err
}

if shouldPrompt(cmd, appType) {
Expand All @@ -215,12 +233,8 @@ auth0 apps create --name myapp --type [native|spa|regular|m2m]
}
}

if shouldPrompt(cmd, appDescription) {
input := prompt.TextInput(appDescription, "Description:", "Description of the application.", false)

if err := prompt.AskOne(input, &flags); err != nil {
return fmt.Errorf("An unexpected error occurred: %w", err)
}
if err := appDescription.Ask(cmd, &flags.Description); err != nil {
return err
}

a := &management.Client{
Expand Down Expand Up @@ -257,20 +271,20 @@ auth0 apps create --name myapp --type [native|spa|regular|m2m]
},
}

cmd.Flags().StringVarP(&flags.Name, "name", "n", "", "Name of the application.")
appName.RegisterString(cmd, &flags.Name)
cmd.Flags().StringVarP(&flags.Type, "type", "t", "", "Type of application:\n"+
"- native: mobile, desktop, CLI and smart device apps running natively.\n"+
"- spa (single page application): a JavaScript front-end app that uses an API.\n"+
"- regular: Traditional web app using redirects.\n"+
"- m2m (machine to machine): CLIs, daemons or services running on your backend.")
cmd.Flags().StringVarP(&flags.Description, "description", "d", "", "Description of the application. Max character count is 140.")
appDescription.RegisterString(cmd, &flags.Description)
cmd.Flags().StringSliceVarP(&flags.Callbacks, "callbacks", "c", nil, "After the user authenticates we will only call back to any of these URLs. You can specify multiple valid URLs by comma-separating them (typically to handle different environments like QA or testing). Make sure to specify the protocol (https://) otherwise the callback may fail in some cases. With the exception of custom URI schemes for native apps, all callbacks should use protocol https://.")
cmd.Flags().StringSliceVarP(&flags.AllowedOrigins, "origins", "o", nil, "Comma-separated list of URLs allowed to make requests from JavaScript to Auth0 API (typically used with CORS). By default, all your callback URLs will be allowed. This field allows you to enter other origins if necessary. You can also use wildcards at the subdomain level (e.g., https://*.contoso.com). Query strings and hash information are not taken into account when validating these URLs.")
cmd.Flags().StringSliceVarP(&flags.AllowedWebOrigins, "web-origins", "w", nil, "Comma-separated list of allowed origins for use with Cross-Origin Authentication, Device Flow, and web message response mode.")
cmd.Flags().StringSliceVarP(&flags.AllowedLogoutURLs, "logout-urls", "l", nil, "Comma-separated list of URLs that are valid to redirect to after logout from Auth0. Wildcards are allowed for subdomains.")
cmd.Flags().StringVarP(&flags.AuthMethod, "auth-method", "a", "", "Defines the requested authentication method for the token endpoint. Possible values are 'None' (public application without a client secret), 'Post' (application uses HTTP POST parameters) or 'Basic' (application uses HTTP Basic).")
appAuthMethod.RegisterString(cmd, &flags.AuthMethod)
cmd.Flags().StringSliceVarP(&flags.Grants, "grants", "g", nil, "List of grant types supported for this application. Can include code, implicit, refresh-token, credentials, password, password-realm, mfa-oob, mfa-otp, mfa-recovery-code, and device-code.")
mustRequireFlags(cmd, appName, appType)
mustRequireFlags(cmd, appType)

return cmd
}
Expand Down Expand Up @@ -316,12 +330,8 @@ auth0 apps update <id> --name myapp --type [native|spa|regular|m2m]
inputs.ID = args[0]
}

if shouldPromptWhenFlagless(cmd, appName) {
input := prompt.TextInput(appName, "Name:", "Name of the application", true)

if err := prompt.AskOne(input, &inputs); err != nil {
return fmt.Errorf("An unexpected error occurred: %w", err)
}
if err := appName.AskU(cmd, &inputs.Name); err != nil {
return err
}

if shouldPromptWhenFlagless(cmd, appType) {
Expand All @@ -340,12 +350,8 @@ auth0 apps update <id> --name myapp --type [native|spa|regular|m2m]
}
}

if shouldPromptWhenFlagless(cmd, appDescription) {
input := prompt.TextInput(appDescription, "Description:", "Description of the application.", false)

if err := prompt.AskOne(input, &inputs); err != nil {
return fmt.Errorf("An unexpected error occurred: %w", err)
}
if err := appDescription.AskU(cmd, &inputs.Description); err != nil {
return err
}

if shouldPromptWhenFlagless(cmd, "CallbacksString") {
Expand Down Expand Up @@ -437,18 +443,18 @@ auth0 apps update <id> --name myapp --type [native|spa|regular|m2m]
},
}

cmd.Flags().StringVarP(&inputs.Name, "name", "n", "", "Name of the application.")
appName.RegisterStringU(cmd, &inputs.Name)
cmd.Flags().StringVarP(&inputs.Type, "type", "t", "", "Type of application:\n"+
"- native: mobile, desktop, CLI and smart device apps running natively.\n"+
"- spa (single page application): a JavaScript front-end app that uses an API.\n"+
"- regular: Traditional web app using redirects.\n"+
"- m2m (machine to machine): CLIs, daemons or services running on your backend.")
cmd.Flags().StringVarP(&inputs.Description, "description", "d", "", "Description of the application. Max character count is 140.")
appDescription.RegisterStringU(cmd, &inputs.Description)
cmd.Flags().StringSliceVarP(&inputs.Callbacks, "callbacks", "c", nil, "After the user authenticates we will only call back to any of these URLs. You can specify multiple valid URLs by comma-separating them (typically to handle different environments like QA or testing). Make sure to specify the protocol (https://) otherwise the callback may fail in some cases. With the exception of custom URI schemes for native apps, all callbacks should use protocol https://.")
cmd.Flags().StringSliceVarP(&inputs.AllowedOrigins, "origins", "o", nil, "Comma-separated list of URLs allowed to make requests from JavaScript to Auth0 API (typically used with CORS). By default, all your callback URLs will be allowed. This field allows you to enter other origins if necessary. You can also use wildcards at the subdomain level (e.g., https://*.contoso.com). Query strings and hash information are not taken into account when validating these URLs.")
cmd.Flags().StringSliceVarP(&inputs.AllowedWebOrigins, "web-origins", "w", nil, "Comma-separated list of allowed origins for use with Cross-Origin Authentication, Device Flow, and web message response mode.")
cmd.Flags().StringSliceVarP(&inputs.AllowedLogoutURLs, "logout-urls", "l", nil, "Comma-separated list of URLs that are valid to redirect to after logout from Auth0. Wildcards are allowed for subdomains.")
cmd.Flags().StringVarP(&inputs.AuthMethod, "auth-method", "a", "", "Defines the requested authentication method for the token endpoint. Possible values are 'None' (public application without a client secret), 'Post' (application uses HTTP POST parameters) or 'Basic' (application uses HTTP Basic).")
appAuthMethod.RegisterStringU(cmd, &inputs.AuthMethod)
cmd.Flags().StringSliceVarP(&inputs.Grants, "grants", "g", nil, "List of grant types supported for this application. Can include code, implicit, refresh-token, credentials, password, password-realm, mfa-oob, mfa-otp, mfa-recovery-code, and device-code.")

return cmd
Expand Down
69 changes: 69 additions & 0 deletions internal/cli/flags.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package cli

import (
"fmt"

"github.com/auth0/auth0-cli/internal/prompt"
"github.com/spf13/cobra"
)

type Flag struct {
Name string
LongForm string
ShortForm string
DefaultValue string
Help string
IsRequired bool
}

func (f *Flag) Ask(cmd *cobra.Command, value interface{}) error {
return ask(cmd, f, value, false)
}

func (f *Flag) AskU(cmd *cobra.Command, value interface{}) error {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does U stand for?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It stands for "Update"

return ask(cmd, f, value, true)
}

func (f *Flag) RegisterString(cmd *cobra.Command, value *string) {
registerString(cmd, f, value, false)
}

func (f *Flag) RegisterStringU(cmd *cobra.Command, value *string) {
registerString(cmd, f, value, true)
}

func ask(cmd *cobra.Command, f *Flag, value interface{}, isUpdate bool) error {
var shouldAsk bool

if isUpdate {
shouldAsk = shouldPromptWhenFlagless(cmd, f.LongForm)
} else {
shouldAsk = shouldPrompt(cmd, f.LongForm)
}

if shouldAsk {
input := prompt.TextInput("", fmt.Sprintf("%s:", f.Name), f.Help, f.IsRequired)

if err := prompt.AskOne(input, value); err != nil {
return fmt.Errorf("An unexpected error occurred: %w", err)
}
}

return nil
}

func registerString(cmd *cobra.Command, f *Flag, value *string, isUpdate bool) {
cmd.Flags().StringVarP(value, f.LongForm, f.ShortForm, f.DefaultValue, f.Help)

if err := markFlagRequired(cmd, f, isUpdate); err != nil {
panic(fmt.Errorf("An unexpected error occurred: %w", err)) // TODO: Handle
}
}

func markFlagRequired(cmd *cobra.Command, f *Flag, isUpdate bool) error {
if f.IsRequired && !isUpdate {
return cmd.MarkFlagRequired(f.LongForm)
}

return nil
}