Right now there is a difference in handling between unknown command and unknown subcommand.
Let's consider the example:
package main
import "github.com/spf13/cobra"
func main() {
subCmd := &cobra.Command{
Use: "foo",
}
subCmd.AddCommand(&cobra.Command{
Use: "bar",
Run: func(cmd *cobra.Command, args []string) {
cmd.Println("bar")
},
})
subCmd.AddCommand(&cobra.Command{
Use: "baz",
Run: func(cmd *cobra.Command, args []string) {
cmd.Println("baz")
},
})
rootCmd := &cobra.Command{
Use: "test",
}
rootCmd.AddCommand(subCmd)
rootCmd.Execute()
}
When I run it as ./test unknown I get 'unknown command' error:
Error: unknown command "unknown" for "test"
Run 'test --help' for usage.
If I run it as ./test foo unknown I receive help message:
$ go run main.go foo unknown
Usage:
test foo [command]
Available Commands:
bar
baz
Flags:
-h, --help help for foo
Use "test foo [command] --help" for more information about a command.
It seems very much like inconsistency.
I suppose that we don't need to return flag.ErrHelp on not runnable command and treat it like "unknown subcommand".
It's a really dumb inconsistency, but one which has been here since day 1 and we haven't 'fixed' for fear of breaking expectations for someone. I believe it's possible to get the behavior you want by setting the Command.PositionalArgs to a function which does what you want. Maybe something like MaximumNArgs(0) ?
Thanks for the response.
Actually, setting Run field is needed too (even if it is just an empty function).
instead of setting, PositionalArgs: MaximumNArgs(0), you can set Args: cobra.NoArgs, the result of which is that the subcommand's 'unknown command' behavior will be consistent with that of the top-level command. Run needs to be set to some dummy function. e.g.:
var someCmd = &cobra.Command{
Use: "some",
Args: cobra.NoArgs,
Run: func(*cobra.Command, []string) {},
}
While what the previous commenter said is true, now we have an unfortunate double usage output, which we don't want and is not valid
Error: unknown command "fla" for "prog subcommand"
Usage:
prog subcommand [flags]
prog subcommand [command]
...
and since I want it to error when no subcommand is called, I define RunE():
...,
RunE: func(*cobra.Command, []string) error {
return fmt.Errorf("missing command")
},
How about a cobra.NoFunc variable which cobra can check against to, which it can detect to not output the additional usage line?
@dionysius I guess you need to set SilenceUsage to true in that case.
Unfortunately not, referring to your example
Original returning an error (by cobra), the usage but exit 0
With Run we can return an error (by ourselves), optionally the usage and Exit 1, but as you can see, the Usage line is double (what I'm referring to in my last comment) - Which is technically the truth, since we've provided a Run() function! (It can be run by itself with persistentFlags OR using a subcommand which will have its own flags)
With Run + SilenceUsage everywhere no change in the effective Usage() output
That's why - since we don't want to change break the current behaviour, I'm suggesting that we have a way for defining, that example "Original" exits with 1 - without all these hacky workarounds in the following examples, which lead to technically correct behaviour!
That means, my suggestion with cobra.NoFunc is actually not a good idea, better would be rootCmd = cobra.Command{..., ExitErrorOnMissingSubcommand: true, ...} or something like that
Or actually changing the behaviour and exit 1 on usage error always and note that as breaking change for a new major release branch
While writing this up, checking some of the current tooling for their behaviour, I realized
git has only 1 command level (e.g. git log)ip has 2 levels, but if only provided the first level (e.g. ip netns), it automatically means list of the 2nd levelkubectl errors 1 if there are missing subcommands (e.g. kubectl get), but they have overridden anyway all possible aspects of cobralxc errors 0 (e.g. kubectl profile), but they also use cobra so "suffering" from the exactly this topic hereopenstack python client errors 2 (e.g. openstack server) - the first real-world example I've found without go or cobraThis issue is being marked as stale due to a long period of inactivity
Most helpful comment
instead of setting,
PositionalArgs: MaximumNArgs(0), you can setArgs: cobra.NoArgs, the result of which is that the subcommand's 'unknown command' behavior will be consistent with that of the top-level command.Runneeds to be set to some dummy function. e.g.: