diff --git a/cli/clibase/cmd.go b/cli/clibase/cmd.go index 1830d75059460..d1d03b45fd2b7 100644 --- a/cli/clibase/cmd.go +++ b/cli/clibase/cmd.go @@ -562,6 +562,16 @@ func Chain(ms ...MiddlewareFunc) MiddlewareFunc { return chain(reversed...) } +func ShowUsageOnError(next HandlerFunc) HandlerFunc { + return func(i *Invocation) error { + err := next(i) + if err != nil { + return xerrors.Errorf("Usage: %s\nError: %w", i.Command.FullUsage(), err) + } + return nil + } +} + func RequireNArgs(want int) MiddlewareFunc { return RequireRangeArgs(want, want) } @@ -574,7 +584,8 @@ func RequireRangeArgs(start, end int) MiddlewareFunc { panic("start must be >= 0") } return func(next HandlerFunc) HandlerFunc { - return func(i *Invocation) error { + // ShowUsageOnError will add the command usage before the error message. + return ShowUsageOnError(func(i *Invocation) error { got := len(i.Args) switch { case start == end && got != start: @@ -614,7 +625,7 @@ func RequireRangeArgs(start, end int) MiddlewareFunc { default: return next(i) } - } + }) } } diff --git a/cli/errors.go b/cli/errors.go index ee12ca036af24..cbcf4f2224199 100644 --- a/cli/errors.go +++ b/cli/errors.go @@ -45,7 +45,8 @@ func (RootCmd) errorExample() *clibase.Cmd { apiError.(*codersdk.Error).Helper = "Have you tried turning it off and on again?" //nolint:errorlint,forcetypeassert - apiErrorNoHelper := apiError.(*codersdk.Error) + cpy := *apiError.(*codersdk.Error) + apiErrorNoHelper := &cpy apiErrorNoHelper.Helper = "" // Some flags @@ -94,7 +95,6 @@ func (RootCmd) errorExample() *clibase.Cmd { ) }, }, - { Use: "validation", Options: clibase.OptionSet{ @@ -114,6 +114,16 @@ func (RootCmd) errorExample() *clibase.Cmd { return nil }, }, + { + Use: "arg-required <required>", + Middleware: clibase.Chain( + clibase.RequireNArgs(1), + ), + Handler: func(i *clibase.Invocation) error { + _, _ = fmt.Fprint(i.Stdout, "Try running this without an argument\n") + return nil + }, + }, }, }