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

feat: Add more help in error message #72

Merged
merged 4 commits into from
Mar 27, 2024
Merged
Show file tree
Hide file tree
Changes from 3 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
24 changes: 6 additions & 18 deletions cmd/flags/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,21 @@ import (
"context"
"encoding/json"
"fmt"
"net/url"

"github.com/spf13/cobra"
"github.com/spf13/viper"

"ldcli/internal/errors"
"ldcli/cmd/validators"
"ldcli/internal/flags"
)

func NewCreateCmd(client flags.Client) (*cobra.Command, error) {
cmd := &cobra.Command{
Use: "create",
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sorted and moved the validate function into validators.Validate.

Short: "Create a new flag",
Long: "Create a new flag",
PreRunE: validate,
RunE: runCreate(client),
Args: validators.Validate(),
Long: "Create a new flag",
RunE: runCreate(client),
Short: "Create a new flag",
Use: "create",
}

cmd.Flags().StringP("data", "d", "", "Input data in JSON")
Expand Down Expand Up @@ -79,14 +78,3 @@ func runCreate(client flags.Client) func(*cobra.Command, []string) error {
return nil
}
}

// validate ensures the flags are valid before using them.
// TODO: refactor with projects validate().
func validate(cmd *cobra.Command, args []string) error {
_, err := url.ParseRequestURI(viper.GetString("baseUri"))
if err != nil {
return errors.ErrInvalidBaseURI
}

return nil
}
27 changes: 25 additions & 2 deletions cmd/flags/create_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
)

func TestCreate(t *testing.T) {
errorHelp := ". See `ldcli flags create --help` for supported flags and usage."
Copy link
Contributor Author

Choose a reason for hiding this comment

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

We can refactor these tests to DRY up some duplication.

mockArgs := []interface{}{
"testAccessToken",
"http://test.com",
Expand Down Expand Up @@ -63,7 +64,29 @@ func TestCreate(t *testing.T) {

_, err := cmd.CallCmd(t, &flags.MockClient{}, nil, nil, args)

assert.EqualError(t, err, `required flag(s) "accessToken", "data", "projKey" not set`)
assert.EqualError(t, err, `required flag(s) "accessToken", "data", "projKey" not set`+errorHelp)
})

t.Run("with missing short flag value is an error", func(t *testing.T) {
args := []string{
"flags", "create",
"-d",
}

_, err := cmd.CallCmd(t, &flags.MockClient{}, nil, nil, args)

assert.EqualError(t, err, `flag needs an argument: 'd' in -d`)
})

t.Run("with missing long flag value is an error", func(t *testing.T) {
args := []string{
"flags", "create",
"--data",
}

_, err := cmd.CallCmd(t, &flags.MockClient{}, nil, nil, args)

assert.EqualError(t, err, `flag needs an argument: --data`)
})

t.Run("with invalid baseUri is an error", func(t *testing.T) {
Expand All @@ -77,6 +100,6 @@ func TestCreate(t *testing.T) {

_, err := cmd.CallCmd(t, &flags.MockClient{}, nil, nil, args)

assert.EqualError(t, err, "baseUri is invalid")
assert.EqualError(t, err, "baseUri is invalid"+errorHelp)
})
}
11 changes: 6 additions & 5 deletions cmd/flags/update.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,17 @@ import (
"github.com/spf13/cobra"
"github.com/spf13/viper"

"ldcli/cmd/validators"
"ldcli/internal/flags"
)

func NewUpdateCmd(client flags.Client) (*cobra.Command, error) {
cmd := &cobra.Command{
Use: "update",
Short: "Update a flag",
Long: "Update a flag",
PreRunE: validate,
RunE: runUpdate(client),
Args: validators.Validate(),
Long: "Update a flag",
RunE: runUpdate(client),
Short: "Update a flag",
Use: "update",
}

var data string
Expand Down
24 changes: 6 additions & 18 deletions cmd/members/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,21 @@ import (
"context"
"encoding/json"
"fmt"
"net/url"

"github.com/spf13/cobra"
"github.com/spf13/viper"

"ldcli/internal/errors"
"ldcli/cmd/validators"
"ldcli/internal/members"
)

func NewCreateCmd(client members.Client) (*cobra.Command, error) {
cmd := &cobra.Command{
Use: "create",
Short: "Create a new member",
Long: "Create a new member",
PreRunE: validate,
RunE: runCreate(client),
Args: validators.Validate(),
Long: "Create a new member",
RunE: runCreate(client),
Short: "Create a new member",
Use: "create",
}

cmd.Flags().StringP("data", "d", "", "Input data in JSON")
Expand Down Expand Up @@ -65,14 +64,3 @@ func runCreate(client members.Client) func(*cobra.Command, []string) error {
return nil
}
}

// validate ensures the flags are valid before using them.
// TODO: refactor with flags & projects validate().
func validate(cmd *cobra.Command, args []string) error {
_, err := url.ParseRequestURI(viper.GetString("baseUri"))
if err != nil {
return errors.ErrInvalidBaseURI
}

return nil
}
7 changes: 4 additions & 3 deletions cmd/members/create_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
)

func TestCreate(t *testing.T) {
errorHelp := ". See `ldcli members create --help` for supported flags and usage."
mockArgs := []interface{}{
"testAccessToken",
"http://test.com",
Expand Down Expand Up @@ -69,18 +70,18 @@ func TestCreate(t *testing.T) {

_, err := cmd.CallCmd(t, nil, &members.MockClient{}, nil, args)

assert.EqualError(t, err, `required flag(s) "accessToken", "data" not set`)
assert.EqualError(t, err, `required flag(s) "accessToken", "data" not set`+errorHelp)
})

t.Run("with invalid baseUri is an error", func(t *testing.T) {
args := []string{
"projects",
"members",
"create",
"--baseUri", "invalid",
}

_, err := cmd.CallCmd(t, nil, &members.MockClient{}, nil, args)

assert.EqualError(t, err, "baseUri is invalid")
assert.EqualError(t, err, "baseUri is invalid"+errorHelp)
})
}
11 changes: 6 additions & 5 deletions cmd/projects/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,17 @@ import (
"github.com/spf13/cobra"
"github.com/spf13/viper"

"ldcli/cmd/validators"
"ldcli/internal/projects"
)

func NewCreateCmd(client projects.Client) (*cobra.Command, error) {
cmd := &cobra.Command{
Use: "create",
Short: "Create a new project",
Long: "Create a new project",
PreRunE: validate,
RunE: runCreate(client),
Args: validators.Validate(),
Long: "Create a new project",
RunE: runCreate(client),
Short: "Create a new project",
Use: "create",
}

cmd.Flags().StringP("data", "d", "", "Input data in JSON")
Expand Down
27 changes: 25 additions & 2 deletions cmd/projects/create_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
)

func TestCreate(t *testing.T) {
errorHelp := ". See `ldcli projects create --help` for supported flags and usage."
mockArgs := []interface{}{
"testAccessToken",
"http://test.com",
Expand Down Expand Up @@ -69,7 +70,29 @@ func TestCreate(t *testing.T) {

_, err := cmd.CallCmd(t, nil, nil, &projects.MockClient{}, args)

assert.EqualError(t, err, `required flag(s) "accessToken", "data" not set`)
assert.EqualError(t, err, `required flag(s) "accessToken", "data" not set`+errorHelp)
})

t.Run("with missing short flag value is an error", func(t *testing.T) {
args := []string{
"projects", "create",
"-d",
}

_, err := cmd.CallCmd(t, nil, nil, &projects.MockClient{}, args)

assert.EqualError(t, err, `flag needs an argument: 'd' in -d`)
})

t.Run("with missing long flag value is an error", func(t *testing.T) {
args := []string{
"projects", "create",
"--data",
}

_, err := cmd.CallCmd(t, nil, nil, &projects.MockClient{}, args)

assert.EqualError(t, err, `flag needs an argument: --data`)
})

t.Run("with invalid baseUri is an error", func(t *testing.T) {
Expand All @@ -81,6 +104,6 @@ func TestCreate(t *testing.T) {

_, err := cmd.CallCmd(t, nil, nil, &projects.MockClient{}, args)

assert.EqualError(t, err, "baseUri is invalid")
assert.EqualError(t, err, "baseUri is invalid"+errorHelp)
})
}
24 changes: 6 additions & 18 deletions cmd/projects/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,38 +3,26 @@ package projects
import (
"context"
"fmt"
"net/url"

"github.com/spf13/cobra"
"github.com/spf13/viper"

"ldcli/internal/errors"
"ldcli/cmd/validators"
"ldcli/internal/projects"
)

func NewListCmd(client projects.Client) *cobra.Command {
cmd := &cobra.Command{
Use: "list",
Short: "Return a list of projects",
Long: "Return a list of projects",
PreRunE: validate,
RunE: runList(client),
Args: validators.Validate(),
Long: "Return a list of projects",
RunE: runList(client),
Short: "Return a list of projects",
Use: "list",
}

return cmd
}

// validate ensures the flags are valid before using them.
// TODO: refactor with flags validate().
func validate(cmd *cobra.Command, args []string) error {
_, err := url.ParseRequestURI(viper.GetString("baseUri"))
if err != nil {
return errors.ErrInvalidBaseURI
}

return nil
}

func runList(client projects.Client) func(*cobra.Command, []string) error {
return func(cmd *cobra.Command, args []string) error {
response, err := client.List(
Expand Down
27 changes: 25 additions & 2 deletions cmd/projects/list_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
)

func TestList(t *testing.T) {
errorHelp := ". See `ldcli projects list --help` for supported flags and usage."
mockArgs := []interface{}{
"testAccessToken",
"http://test.com",
Expand Down Expand Up @@ -56,7 +57,29 @@ func TestList(t *testing.T) {

_, err := cmd.CallCmd(t, nil, nil, &projects.MockClient{}, args)

assert.EqualError(t, err, `required flag(s) "accessToken" not set`)
assert.EqualError(t, err, `required flag(s) "accessToken" not set`+errorHelp)
})

t.Run("with missing short flag value is an error", func(t *testing.T) {
args := []string{
"projects", "list",
"-t",
}

_, err := cmd.CallCmd(t, nil, nil, &projects.MockClient{}, args)

assert.EqualError(t, err, `flag needs an argument: 't' in -t`)
})

t.Run("with missing long flag value is an error", func(t *testing.T) {
args := []string{
"projects", "list",
"--accessToken",
}

_, err := cmd.CallCmd(t, nil, nil, &projects.MockClient{}, args)

assert.EqualError(t, err, `flag needs an argument: --accessToken`)
})

t.Run("with invalid baseUri is an error", func(t *testing.T) {
Expand All @@ -68,6 +91,6 @@ func TestList(t *testing.T) {

_, err := cmd.CallCmd(t, nil, nil, &projects.MockClient{}, args)

assert.EqualError(t, err, "baseUri is invalid")
assert.EqualError(t, err, "baseUri is invalid"+errorHelp)
})
}
12 changes: 2 additions & 10 deletions cmd/root.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package cmd

import (
"errors"
"fmt"
"log"
"os"
Expand All @@ -12,7 +11,6 @@ import (
flagscmd "ldcli/cmd/flags"
mbrscmd "ldcli/cmd/members"
projcmd "ldcli/cmd/projects"
errs "ldcli/internal/errors"
"ldcli/internal/flags"
"ldcli/internal/members"
"ldcli/internal/projects"
Expand All @@ -29,8 +27,8 @@ func NewRootCommand(flagsClient flags.Client, membersClient members.Client, proj
// Handle errors differently based on type.
// We don't want to show the usage if the user has the right structure but invalid data such as
// the wrong key.
SilenceUsage: true,
SilenceErrors: true,
SilenceUsage: true,
}

cmd.PersistentFlags().StringP(
Expand Down Expand Up @@ -88,12 +86,6 @@ func Execute() {

err = rootCmd.Execute()
if err != nil {
switch {
case errors.Is(err, errs.Error{}):
fmt.Fprintln(os.Stderr, err.Error())
default:
fmt.Println(err.Error())
fmt.Println(rootCmd.UsageString())
}
fmt.Fprintln(os.Stderr, err.Error())
}
}
Loading
Loading