diff --git a/internal/cli/arguments.go b/internal/cli/arguments.go index be5d59cb9..072d4fe4f 100644 --- a/internal/cli/arguments.go +++ b/internal/cli/arguments.go @@ -66,7 +66,7 @@ func selectArgument(cmd *cobra.Command, a *Argument, value interface{}, options func askArgument(cmd *cobra.Command, i commandInput, value interface{}) error { if canPrompt(cmd) { - return ask(cmd, i, value, nil, true) + return ask(cmd, i, value, nil, false) } return fmt.Errorf("Missing a required argument: %s", i.GetName()) diff --git a/internal/cli/cli.go b/internal/cli/cli.go index 9cf7221ea..b258b9e2b 100644 --- a/internal/cli/cli.go +++ b/internal/cli/cli.go @@ -40,10 +40,15 @@ type config struct { // tenant is the cli's concept of an auth0 tenant. The fields are tailor fit // specifically for interacting with the management API. type tenant struct { - Name string `json:"name"` - Domain string `json:"domain"` - AccessToken string `json:"access_token,omitempty"` - ExpiresAt time.Time `json:"expires_at"` + Name string `json:"name"` + Domain string `json:"domain"` + AccessToken string `json:"access_token,omitempty"` + ExpiresAt time.Time `json:"expires_at"` + Apps map[string]app `json:"apps,omitempty"` +} + +type app struct { + FirstRuns map[string]bool `json:"first_runs"` } var errUnauthenticated = errors.New("Not yet configured. Try `auth0 login`.") @@ -224,7 +229,7 @@ func (c *cli) addTenant(ten tenant) error { c.config.Tenants[ten.Name] = ten if err := c.persistConfig(); err != nil { - return fmt.Errorf("persisting config: %w", err) + return fmt.Errorf("unexpected error persisting config: %w", err) } return nil @@ -271,6 +276,52 @@ func (c *cli) removeTenant(ten string) error { return nil } +func (c *cli) isFirstCommandRun(clientID string, command string) (bool, error) { + tenant, err := c.getTenant() + + if err != nil { + return false, err + } + + if a, found := tenant.Apps[clientID]; found { + if a.FirstRuns[command] { + return false, nil + } + } + + return true, nil +} + +func (c *cli) setFirstCommandRun(clientID string, command string) error { + tenant, err := c.getTenant() + + if err != nil { + return err + } + + if a, found := tenant.Apps[clientID]; found { + if a.FirstRuns == nil { + a.FirstRuns = map[string]bool{} + } + a.FirstRuns[command] = true + tenant.Apps[clientID] = a + } else { + tenant.Apps[clientID] = app{ + FirstRuns: map[string]bool{ + command: true, + }, + } + } + + c.config.Tenants[tenant.Name] = tenant + + if err := c.persistConfig(); err != nil { + return fmt.Errorf("Unexpected error persisting config: %w", err) + } + + return nil +} + func (c *cli) persistConfig() error { dir := filepath.Dir(c.path) if _, err := os.Stat(dir); os.IsNotExist(err) { diff --git a/internal/cli/test.go b/internal/cli/test.go index 5f9e8cee9..1a1676b94 100644 --- a/internal/cli/test.go +++ b/internal/cli/test.go @@ -65,7 +65,9 @@ If --client-id is not provided, the default client "CLI Login Testing" will be u auth0 test login --client-id auth0 test login -c --connection `, RunE: func(cmd *cobra.Command, args []string) error { + const commandKey = "test_login" var userInfo *authutil.UserInfo + tenant, err := cli.getTenant() if err != nil { return err @@ -116,6 +118,21 @@ auth0 test login -c --connection `, fmt.Fprint(cli.renderer.MessageWriter, "\n") cli.renderer.TryLogin(userInfo, tokenResponse) + + isFirstRun, err := cli.isFirstCommandRun(inputs.ClientID, commandKey) + if err != nil { + return err + } + + if isFirstRun { + cli.renderer.Infof("%s Login flow is working! Next, try downloading and running a Quickstart: 'auth0 quickstarts download %s'", + ansi.Faint("Hint:"), inputs.ClientID) + + if err := cli.setFirstCommandRun(inputs.ClientID, commandKey); err != nil { + return err + } + } + return nil }, }