Skip to content

feat: list projects err handling#21

Merged
dbolson merged 18 commits intomainfrom
sc-235696/list-projects-err-handling
Mar 13, 2024
Merged

feat: list projects err handling#21
dbolson merged 18 commits intomainfrom
sc-235696/list-projects-err-handling

Conversation

@dbolson
Copy link
Copy Markdown
Contributor

@dbolson dbolson commented Mar 13, 2024

Better error handling for missing flags and invalid responses.

You can see the results by running these commands

go run main.go projects
go run main.go projects list
go run main.go projects list --accessToken invalid
go run main.go projects list --accessToken invalid --baseUri invalid

@shortcut-integration
Copy link
Copy Markdown

This pull request has been linked to Shortcut Story #235696: create command to list existing projects.

Comment thread cmd/projects/list.go
}

func runList(cmd *cobra.Command, args []string) error {
// TODO: handle missing flags
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

These are handled in other places now.

Comment thread cmd/root.go
if err != nil {
os.Exit(1)
switch {
case errors.Is(err, errs.ErrUnauthorized):
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This more closely matches the stripe CLI. If there's a structural error like a missing flag or invalid command, it returns an error and shows usage. If it's a logical error like an invalid access token or project key, it shows the error but not usage.

We can test this type of code once we have a higher level of dependency injection to pass in a mock API client from the highest level. Otherwise the tests will try to execute a real HTTP call.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Nice this makes sense/I like this

Comment thread cmd/root.go
err := rootCmd.MarkPersistentFlagRequired("accessToken")
if err != nil {
os.Exit(1)
panic(err)
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

These errors should never happen, but we should see what they are in case they do.

Comment thread internal/errors/errors.go
@@ -0,0 +1,8 @@
package errors
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This package would shadow the standard library errors package, but the only place that should happen is at the highest level of the call stack. If you find you're creating errors.New then they should probably be defined in here instead.

func ListProjects(ctx context.Context, client2 Client) ([]byte, error) {
projects, err := client2.List(ctx)
func ListProjects(ctx context.Context, client Client) ([]byte, error) {
projects, err := client.List(ctx)
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Renamed.

e, ok := err.(ldapi.GenericOpenAPIError)
if ok {
return e.Body(), err
if err.Error() == "401 Unauthorized" {
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I couldn't set up a test with a GenericOpenAPIError that has specific data in it because its fields aren't exported. This seems simpler, at least for now.

Comment thread cmd/hello_test.go Outdated
rootCmd.SetOut(actual)
rootCmd.SetErr(actual)
rootCmd.SetArgs([]string{"hello"})
rootCmd.SetArgs([]string{"hello", "--accessToken", "test"})
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This is to get the tests to pass. I'll remove the hello world command in another PR.

Comment thread cmd/projects/list.go
if viper.GetString("baseUri") == "" {
return errors.New("baseUri required")
// validate ensures the flags are valid before using them.
func validate(cmd *cobra.Command, args []string) error {
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I'd prefer to have this in the root command so we don't need it for each command that uses the global flags, but we can figure that out later.

Comment thread cmd/root.go
err := rootCmd.Execute()
if err != nil {
os.Exit(1)
switch {
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The idea here is to let errors bubble up and handle them in one spot. We can set whatever error we want in the subcommands to make this switch statement simpler to work with.

Comment thread cmd/root.go
"baseUri",
"u",
"http://localhost:3000",
"https://app.launchdarkly.com",
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This changes the default to production so others aren't surprised when using the CLI.

Comment thread cmd/root.go
panic(err)
}

rootCmd.SetErrPrefix("")
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This removes "Error: {msg}" and just shows the error message.

@dbolson dbolson marked this pull request as ready for review March 13, 2024 21:07
@dbolson dbolson requested review from k3llymariee and sunnyguduru and removed request for sunnyguduru March 13, 2024 21:08
@dbolson dbolson changed the title sc-235696/list projects err handling feat: list projects err handling Mar 13, 2024
Copy link
Copy Markdown
Contributor

@k3llymariee k3llymariee left a comment

Choose a reason for hiding this comment

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

one comment about validating the URI otherwise LGTM!

Comment thread cmd/root.go
if err != nil {
os.Exit(1)
switch {
case errors.Is(err, errs.ErrUnauthorized):
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Nice this makes sense/I like this

Comment thread cmd/projects/list.go
Comment on lines +29 to +31
_, err := url.ParseRequestURI(viper.GetString("baseUri"))
if err != nil {
return errors.ErrInvalidBaseURI
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

should we also make sure that it's a valid LD URI?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I didn't want to do too much validation since it should only be an issue if someone is overriding the default, so they would be able to see the URL they put in. We could add more validation if we find people are confused.

@dbolson dbolson merged commit 2ab3668 into main Mar 13, 2024
@dbolson dbolson deleted the sc-235696/list-projects-err-handling branch March 13, 2024 22:23
This was referenced Mar 13, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants