diff --git a/cmd/cmdtest.go b/cmd/cmdtest.go index a3999f9b..20fea899 100644 --- a/cmd/cmdtest.go +++ b/cmd/cmdtest.go @@ -2,6 +2,7 @@ package cmd import ( "bytes" + "fmt" "io" "os" "testing" @@ -69,3 +70,10 @@ func SetupTestEnvVars(_ *testing.T) func(t *testing.T) { os.Unsetenv("LD_BASE_URI") } } + +func ExtraErrorHelp(cmdName string, cmdAction string) string { + out := ".\n\nUse `ldcli config --set access-token ` to configure the value to persist across CLI commands." + out += fmt.Sprintf("\n\nSee `ldcli %s %s --help` for supported flags and usage.", cmdName, cmdAction) + + return out +} diff --git a/cmd/environments/get_test.go b/cmd/environments/get_test.go index 9dba82ac..b7645465 100644 --- a/cmd/environments/get_test.go +++ b/cmd/environments/get_test.go @@ -99,7 +99,7 @@ func TestGet(t *testing.T) { _, err := cmd.CallCmd(t, clients, &analytics.NoopClient{}, args) - assert.EqualError(t, err, `required flag(s) "access-token", "environment", "project" not set`+errorHelp) + assert.EqualError(t, err, `required flag(s) "access-token", "environment", "project" not set`+cmd.ExtraErrorHelp("environments", "get")) }) t.Run("with missing short flag value is an error", func(t *testing.T) { diff --git a/cmd/flags/create_test.go b/cmd/flags/create_test.go index adc98ed8..6ad10c87 100644 --- a/cmd/flags/create_test.go +++ b/cmd/flags/create_test.go @@ -99,7 +99,7 @@ func TestCreate(t *testing.T) { _, err := cmd.CallCmd(t, clients, &analytics.NoopClient{}, args) - assert.EqualError(t, err, `required flag(s) "access-token", "data", "project" not set`+errorHelp) + assert.EqualError(t, err, `required flag(s) "access-token", "data", "project" not set`+cmd.ExtraErrorHelp("flags", "create")) }) t.Run("with missing short flag value is an error", func(t *testing.T) { diff --git a/cmd/flags/get_test.go b/cmd/flags/get_test.go index 39320d63..3ccd5bae 100644 --- a/cmd/flags/get_test.go +++ b/cmd/flags/get_test.go @@ -101,7 +101,7 @@ func TestGet(t *testing.T) { _, err := cmd.CallCmd(t, clients, &analytics.NoopClient{}, args) - assert.EqualError(t, err, `required flag(s) "access-token", "environment", "flag", "project" not set`+errorHelp) + assert.EqualError(t, err, `required flag(s) "access-token", "environment", "flag", "project" not set`+cmd.ExtraErrorHelp("flags", "get")) }) t.Run("with invalid base-uri is an error", func(t *testing.T) { diff --git a/cmd/flags/update_test.go b/cmd/flags/update_test.go index a8e2c999..3b6ef128 100644 --- a/cmd/flags/update_test.go +++ b/cmd/flags/update_test.go @@ -108,7 +108,7 @@ func TestUpdate(t *testing.T) { _, err := cmd.CallCmd(t, clients, &analytics.NoopClient{}, args) - assert.EqualError(t, err, `required flag(s) "access-token", "data", "flag", "project" not set`+errorHelp) + assert.EqualError(t, err, `required flag(s) "access-token", "data", "flag", "project" not set`+cmd.ExtraErrorHelp("flags", "update")) }) t.Run("with invalid base-uri is an error", func(t *testing.T) { @@ -235,7 +235,7 @@ func TestToggle(t *testing.T) { _, err := cmd.CallCmd(t, clients, &analytics.NoopClient{}, args) - assert.EqualError(t, err, `required flag(s) "access-token", "environment", "flag", "project" not set`+errorHelp) + assert.EqualError(t, err, `required flag(s) "access-token", "environment", "flag", "project" not set`+cmd.ExtraErrorHelp("flags", "toggle-on")) }) t.Run("with invalid base-uri is an error", func(t *testing.T) { diff --git a/cmd/members/create_test.go b/cmd/members/create_test.go index ad102cc5..21cdd174 100644 --- a/cmd/members/create_test.go +++ b/cmd/members/create_test.go @@ -105,7 +105,7 @@ func TestCreate(t *testing.T) { _, err := cmd.CallCmd(t, clients, &analytics.NoopClient{}, args) - assert.EqualError(t, err, `required flag(s) "access-token", "data" not set`+errorHelp) + assert.EqualError(t, err, `required flag(s) "access-token", "data" not set`+cmd.ExtraErrorHelp("members", "create")) }) t.Run("with invalid base-uri is an error", func(t *testing.T) { @@ -131,7 +131,7 @@ func TestCreate(t *testing.T) { "access-token", "base-uri", "data", - "output", + "output", }, analytics.SUCCESS) client := members.MockClient{} diff --git a/cmd/members/invite_test.go b/cmd/members/invite_test.go index 4e8e2d85..9ee704d8 100644 --- a/cmd/members/invite_test.go +++ b/cmd/members/invite_test.go @@ -105,7 +105,7 @@ func TestInvite(t *testing.T) { _, err := cmd.CallCmd(t, clients, &analytics.NoopClient{}, args) - assert.EqualError(t, err, `required flag(s) "access-token", "emails" not set`+errorHelp) + assert.EqualError(t, err, `required flag(s) "access-token", "emails" not set`+cmd.ExtraErrorHelp("members", "invite")) }) t.Run("with invalid base-uri is an error", func(t *testing.T) { @@ -131,7 +131,7 @@ func TestInvite(t *testing.T) { "access-token", "base-uri", "emails", - "output", + "output", }, analytics.SUCCESS) client := members.MockClient{} diff --git a/cmd/projects/create_test.go b/cmd/projects/create_test.go index 0b9e62f1..ba22ac5a 100644 --- a/cmd/projects/create_test.go +++ b/cmd/projects/create_test.go @@ -104,7 +104,7 @@ func TestCreate(t *testing.T) { _, err := cmd.CallCmd(t, clients, &analytics.NoopClient{}, args) - assert.EqualError(t, err, `required flag(s) "access-token", "data" not set`+errorHelp) + assert.EqualError(t, err, `required flag(s) "access-token", "data" not set`+cmd.ExtraErrorHelp("projects", "create")) }) t.Run("with missing short flag value is an error", func(t *testing.T) { diff --git a/cmd/projects/list_test.go b/cmd/projects/list_test.go index 70ed2a0a..64236aa4 100644 --- a/cmd/projects/list_test.go +++ b/cmd/projects/list_test.go @@ -99,7 +99,7 @@ func TestList(t *testing.T) { _, err := cmd.CallCmd(t, clients, &analytics.NoopClient{}, args) - assert.EqualError(t, err, `required flag(s) "access-token" not set`+errorHelp) + assert.EqualError(t, err, `required flag(s) "access-token" not set`+cmd.ExtraErrorHelp("projects", "list")) }) t.Run("with missing long flag value is an error", func(t *testing.T) { diff --git a/cmd/validators/validators.go b/cmd/validators/validators.go index 8e29e0e8..8aea217c 100644 --- a/cmd/validators/validators.go +++ b/cmd/validators/validators.go @@ -4,6 +4,7 @@ import ( "errors" "fmt" "net/url" + "strings" "github.com/spf13/cobra" "github.com/spf13/pflag" @@ -39,11 +40,16 @@ func Validate() cobra.PositionalArgs { } func CmdError(err error, commandPath string) error { - errorMessage := fmt.Sprintf( - "%s. See `%s --help` for supported flags and usage.", - err.Error(), - commandPath, - ) + errorMessage := err.Error() + "." + + // show additional help if a missing flag can be set in the config file + if strings.Contains(err.Error(), cliflags.AccessTokenFlag) { + errorMessage += "\n\n" + errorMessage += fmt.Sprintf("Use `ldcli config --set %s ` to configure the value to persist across CLI commands.\n\n", cliflags.AccessTokenFlag) + } else { + errorMessage += " " + } + errorMessage += fmt.Sprintf("See `%s --help` for supported flags and usage.", commandPath) return errors.New(errorMessage) } diff --git a/cmd/validators/validators_test.go b/cmd/validators/validators_test.go new file mode 100644 index 00000000..718c76e0 --- /dev/null +++ b/cmd/validators/validators_test.go @@ -0,0 +1,37 @@ +package validators_test + +import ( + "errors" + "testing" + + "github.com/stretchr/testify/assert" + + "ldcli/cmd/validators" +) + +func TestCmdError(t *testing.T) { + t.Run("with missing access-token value shows additional help", func(t *testing.T) { + var expected string + expected += "required flag(s) \"access-token\" not set.\n\n" + expected += "Use `ldcli config --set access-token ` to configure the value to persist across CLI commands.\n\n" + expected += "See `ldcli command action --help` for supported flags and usage." + + err := validators.CmdError( + errors.New(`required flag(s) "access-token" not set`), + "ldcli command action", + ) + + assert.EqualError(t, err, expected) + }) + + t.Run("with missing other flag value shows regular help", func(t *testing.T) { + expected := "required flag(s) \"my-flag\" not set. See `ldcli command action --help` for supported flags and usage." + + err := validators.CmdError( + errors.New(`required flag(s) "my-flag" not set`), + "ldcli command action", + ) + + assert.EqualError(t, err, expected) + }) +}