fix(cli): show error/hide help for unsupported subcommands (#10760) (#12624)

Fixes #10760 

The coder CLI quietly accepts any subcommand arguments and silently swallows them.

Currently:
```sh
❯ coder | head -n5
coder v2.3.3+e491217

USAGE:
  coder [global-flags] <subcommand>
```

```sh
❯ coder idontexist | head -n5
coder v2.3.3+e491217

USAGE:
  coder [global-flags] <subcommand>
```

Now help output will not be show when there is an unknown subcommand error. Instead users will be given the command for the help output.

```sh
❯ coder idontexist
Encountered an error running "coder", see "coder --help" for more information 
error: unrecognized subcommand "idontexist"
```
```sh
❯ coder iexistbut idontexist
Encountered an error running "coder iexistbut", see "coder iexistbut --help" for more information 
error: unrecognized subcommand "idontexist"
```

Also this stuff: `Encountered an error running "coder iexistbut"... ` gets written to `os.Stdout` in `prettyErrorFormatter{w: os.Stderr, verbose: r.verbose}`, not sure how to test that output.
This commit is contained in:
elasticspoon
2024-03-17 22:17:43 -05:00
committed by GitHub
parent c189cc93e4
commit 5011edc292
6 changed files with 69 additions and 16 deletions
+21 -3
View File
@@ -4,7 +4,9 @@ import (
"bufio"
_ "embed"
"fmt"
"os"
"regexp"
"slices"
"sort"
"strings"
"text/tabwriter"
@@ -320,6 +322,25 @@ var usageWantsArgRe = regexp.MustCompile(`<.*>`)
// output for a given command.
func helpFn() serpent.HandlerFunc {
return func(inv *serpent.Invocation) error {
// Check for invalid subcommands before printing help.
if len(inv.Args) > 0 && !usageWantsArgRe.MatchString(inv.Command.Use) {
_, _ = fmt.Fprintf(inv.Stderr, "---\nerror: unrecognized subcommand %q\n", inv.Args[0])
}
if len(inv.Args) > 0 {
// Return an error so that exit status is non-zero when
// a subcommand is not found.
err := xerrors.Errorf("unrecognized subcommand %q", strings.Join(inv.Args, " "))
if slices.Contains(os.Args, "--help") {
// Subcommand error is not wrapped in RunCommandErr if command
// is invoked with --help with no HelpHandler
return &serpent.RunCommandError{
Cmd: inv.Command,
Err: err,
}
}
return err
}
// We use stdout for help and not stderr since there's no straightforward
// way to distinguish between a user error and a help request.
//
@@ -340,9 +361,6 @@ func helpFn() serpent.HandlerFunc {
if err != nil {
return err
}
if len(inv.Args) > 0 && !usageWantsArgRe.MatchString(inv.Command.Use) {
_, _ = fmt.Fprintf(inv.Stderr, "---\nerror: unknown subcommand %q\n", inv.Args[0])
}
return nil
}
}