Skip to content

Commit

Permalink
Merge pull request #18 from cloudingcity/refactor/customize-error-han…
Browse files Browse the repository at this point in the history
…dling

Refactor/customize error handling
  • Loading branch information
cloudingcity authored Mar 8, 2020
2 parents c751896 + 45e30a7 commit 75f5092
Show file tree
Hide file tree
Showing 14 changed files with 117 additions and 59 deletions.
3 changes: 2 additions & 1 deletion cmd/ci_lint.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package cmd
import (
"errors"

errs "github.com/cloudingcity/golab/internal/errors"
"github.com/spf13/cobra"
)

Expand All @@ -11,7 +12,7 @@ var ciLintCmd = &cobra.Command{
Short: "Validate the .gitlab-ci.yml",
Args: func(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return &flagError{errors.New("requires a file")}
return &errs.ArgError{Err: errors.New("requires a file")}
}
return nil
},
Expand Down
3 changes: 2 additions & 1 deletion cmd/clone.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package cmd
import (
"errors"

errs "github.com/cloudingcity/golab/internal/errors"
"github.com/spf13/cobra"
)

Expand All @@ -11,7 +12,7 @@ var cloneCmd = &cobra.Command{
Short: "Clone a repository from GitLab",
Args: func(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return &flagError{errors.New("requires a repository")}
return &errs.ArgError{Err: errors.New("requires a repository")}
}
return nil
},
Expand Down
3 changes: 2 additions & 1 deletion cmd/depend_go.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package cmd
import (
"errors"

errs "github.com/cloudingcity/golab/internal/errors"
"github.com/spf13/cobra"
)

Expand All @@ -11,7 +12,7 @@ var dependGOCmd = &cobra.Command{
Short: "List go module package (example.com/hello) dependency",
Args: func(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return &flagError{errors.New("requires a package")}
return &errs.ArgError{Err: errors.New("requires a package")}
}
return nil
},
Expand Down
3 changes: 2 additions & 1 deletion cmd/depend_php.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package cmd
import (
"errors"

errs "github.com/cloudingcity/golab/internal/errors"
"github.com/spf13/cobra"
)

Expand All @@ -11,7 +12,7 @@ var dependPHPCmd = &cobra.Command{
Short: "List composer package (vendor/name) dependency",
Args: func(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return &flagError{errors.New("requires a package")}
return &errs.ArgError{Err: errors.New("requires a package")}
}
return nil
},
Expand Down
39 changes: 0 additions & 39 deletions cmd/error_handler.go

This file was deleted.

5 changes: 3 additions & 2 deletions cmd/mr_open.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"fmt"
"strconv"

errs "github.com/cloudingcity/golab/internal/errors"
"github.com/spf13/cobra"
)

Expand All @@ -14,10 +15,10 @@ var mrOpenCmd = &cobra.Command{
DisableFlagsInUseLine: true,
Args: func(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return &flagError{errors.New("missing MRID")}
return &errs.ArgError{Err: errors.New("missing MRID")}
}
if _, err := strconv.Atoi(args[0]); err != nil {
return &flagError{fmt.Errorf("invalid MRID %q", args[0])}
return &errs.ArgError{Err: fmt.Errorf("invalid MRID %q", args[0])}
}
return nil
},
Expand Down
3 changes: 2 additions & 1 deletion cmd/mr_search.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package cmd
import (
"errors"

errs "github.com/cloudingcity/golab/internal/errors"
"github.com/spf13/cobra"
)

Expand All @@ -11,7 +12,7 @@ var mrSearchCmd = &cobra.Command{
Short: "Search merge requests",
Args: func(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return &flagError{errors.New("requires a query")}
return &errs.ArgError{Err: errors.New("requires a query")}
}
return nil
},
Expand Down
5 changes: 3 additions & 2 deletions cmd/mr_show.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"fmt"
"strconv"

errs "github.com/cloudingcity/golab/internal/errors"
"github.com/spf13/cobra"
)

Expand All @@ -14,10 +15,10 @@ var mrShowCmd = &cobra.Command{
DisableFlagsInUseLine: true,
Args: func(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return &flagError{errors.New("missing MRID")}
return &errs.ArgError{Err: errors.New("missing MRID")}
}
if _, err := strconv.Atoi(args[0]); err != nil {
return &flagError{fmt.Errorf("invalid MRID %q", args[0])}
return &errs.ArgError{Err: fmt.Errorf("invalid MRID %q", args[0])}
}
return nil
},
Expand Down
9 changes: 5 additions & 4 deletions cmd/own_mr_open.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"fmt"
"strconv"

errs "github.com/cloudingcity/golab/internal/errors"
"github.com/spf13/cobra"
)

Expand All @@ -14,16 +15,16 @@ var ownMrOpenCmd = &cobra.Command{
DisableFlagsInUseLine: true,
Args: func(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return &flagError{errors.New("missing MRID")}
return &errs.ArgError{Err: errors.New("missing MRID")}
}
if _, err := strconv.Atoi(args[0]); err != nil {
return &flagError{fmt.Errorf("invalid MRID %q", args[0])}
return &errs.ArgError{Err: fmt.Errorf("invalid MRID %q", args[0])}
}
if len(args) < 2 {
return &flagError{errors.New("missing PID")}
return &errs.ArgError{Err: errors.New("missing PID")}
}
if _, err := strconv.Atoi(args[1]); err != nil {
return &flagError{fmt.Errorf("invalid PID %q", args[0])}
return &errs.ArgError{Err: fmt.Errorf("invalid PID %q", args[0])}
}
return nil
},
Expand Down
9 changes: 5 additions & 4 deletions cmd/own_mr_show.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"fmt"
"strconv"

errs "github.com/cloudingcity/golab/internal/errors"
"github.com/spf13/cobra"
)

Expand All @@ -14,16 +15,16 @@ var ownMrShowCmd = &cobra.Command{
DisableFlagsInUseLine: true,
Args: func(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return &flagError{errors.New("missing MRID")}
return &errs.ArgError{Err: errors.New("missing MRID")}
}
if _, err := strconv.Atoi(args[0]); err != nil {
return &flagError{fmt.Errorf("invalid MRID %q", args[0])}
return &errs.ArgError{Err: fmt.Errorf("invalid MRID %q", args[0])}
}
if len(args) < 2 {
return &flagError{errors.New("missing PID")}
return &errs.ArgError{Err: errors.New("missing PID")}
}
if _, err := strconv.Atoi(args[1]); err != nil {
return &flagError{fmt.Errorf("invalid PID %q", args[0])}
return &errs.ArgError{Err: fmt.Errorf("invalid PID %q", args[0])}
}
return nil
},
Expand Down
3 changes: 2 additions & 1 deletion cmd/project_search.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package cmd
import (
"errors"

errs "github.com/cloudingcity/golab/internal/errors"
"github.com/spf13/cobra"
)

Expand All @@ -11,7 +12,7 @@ var projectSearchCmd = &cobra.Command{
Short: "Search projects",
Args: func(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return &flagError{errors.New("requires a query")}
return &errs.ArgError{Err: errors.New("requires a query")}
}
return nil
},
Expand Down
5 changes: 3 additions & 2 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"time"

conf "github.com/cloudingcity/golab/internal/config"
"github.com/cloudingcity/golab/internal/errors"
"github.com/cloudingcity/golab/internal/git"
"github.com/cloudingcity/golab/internal/gitlab/global"
"github.com/cloudingcity/golab/internal/gitlab/group"
Expand All @@ -27,14 +28,14 @@ var rootCmd = &cobra.Command{
// Execute adds all child commands to the root command and sets flags appropriately.
func Execute() {
if cmd, err := rootCmd.ExecuteC(); err != nil {
handleError(cmd, err)
errors.Handle(cmd, err)
}
}

func init() {
rootCmd.SetHelpCommand(&cobra.Command{Hidden: true})
rootCmd.SetFlagErrorFunc(func(cmd *cobra.Command, err error) error {
return &flagError{err}
return &errors.FlagError{Err: err}
})
cobra.OnInitialize(initConfig)

Expand Down
54 changes: 54 additions & 0 deletions internal/errors/handler.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package errors

import (
"errors"
"fmt"
"strings"

"github.com/spf13/cobra"
)

type FlagError struct {
Err error
}

func (e *FlagError) Error() string {
return e.Err.Error()
}

func (e *FlagError) Unwrap() error {
return e.Err
}

type ArgError struct {
Err error
}

func (e *ArgError) Error() string {
return e.Err.Error()
}

func (e *ArgError) Unwrap() error {
return e.Err
}

func Handle(cmd *cobra.Command, err error) {
fmt.Println(err)

var (
flagError *FlagError
argError *ArgError
)
if errors.As(err, &flagError) || errors.As(err, &argError) || isUnknownCommand(err) || isDefaultFlagError(err) {
fmt.Println()
fmt.Println(cmd.UsageString())
}
}

func isUnknownCommand(err error) bool {
return strings.HasPrefix(err.Error(), "unknown command")
}

func isDefaultFlagError(err error) bool {
return strings.HasPrefix(err.Error(), "required flag")
}
32 changes: 32 additions & 0 deletions internal/errors/handler_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package errors

import (
"errors"
"testing"

"github.com/spf13/cobra"
"github.com/stretchr/testify/assert"
)

func TestIsUnknownCommand(t *testing.T) {
err := errors.New("unknown command")

assert.True(t, isUnknownCommand(err))
}

func TestIsDefaultFlagError(t *testing.T) {
err := errors.New("required flag")

assert.True(t, isDefaultFlagError(err))
}

func ExampleHandle() {
cmd := &cobra.Command{}
err := &FlagError{Err: errors.New("something wrong")}

Handle(cmd, err)

// Output: something wrong
//
// Usage:
}

0 comments on commit 75f5092

Please sign in to comment.