From 41b8340b2b3c40b19c67ce927bbf50102e9e991b Mon Sep 17 00:00:00 2001 From: Andre Mueller Date: Fri, 25 Oct 2024 11:09:09 +0200 Subject: [PATCH] Backward compatibility An error is only thrown if there are arguments to a valid command. Without any arguments the help is printed as before. An invalid subcommand will return an error. --- cobra.go | 2 +- command.go | 18 +++++++----------- command_test.go | 32 +++++++++++++++++++++++++------- 3 files changed, 33 insertions(+), 19 deletions(-) diff --git a/cobra.go b/cobra.go index 67c5799e..aea6a0e8 100644 --- a/cobra.go +++ b/cobra.go @@ -68,7 +68,7 @@ var EnableTraverseRunHooks = defaultTraverseRunHooks // EnableErrorOnUnknownSubcommand controls the behavior of subcommand handling. // When the flag is set true the behavior of Command.Execute() will change: -// If a sub-subcommand is not found ErrUnknownSubcommand will be returned on calling +// If a sub-subcommand is not found an error will be returned on calling // Command.Exec() instead of the old behavior where a nil error was sent. // If the flag is false (default) the old behavior is performed. // For this behavior the child subcommand must be nil. diff --git a/command.go b/command.go index af61b49b..483fbcf7 100644 --- a/command.go +++ b/command.go @@ -44,10 +44,6 @@ type Group struct { Title string } -// ErrUnknownSubcommand is returned by Command.Execute() when the subcommand was not found. -// Hereto, the ErrorOnUnknownSubcommand flag must be set true. -var ErrUnknownSubcommand = errors.New("subcommand is unknown") - // Command is just that, a command for your application. // E.g. 'go run ...' - 'run' is the command. Cobra requires // you to define the usage and description as part of your command @@ -927,9 +923,14 @@ func (c *Command) execute(a []string) (err error) { } } + argWoFlags := c.Flags().Args() + if c.DisableFlagParsing { + argWoFlags = a + } + if !c.Runnable() { - if EnableErrorOnUnknownSubcommand { - return ErrUnknownSubcommand + if EnableErrorOnUnknownSubcommand && len(argWoFlags) > 0 { + return fmt.Errorf("unknown command %q for %q%s", argWoFlags[0], c.CommandPath(), c.findSuggestions(argWoFlags[0])) } else { return flag.ErrHelp } @@ -938,11 +939,6 @@ func (c *Command) execute(a []string) (err error) { defer c.postRun() - argWoFlags := c.Flags().Args() - if c.DisableFlagParsing { - argWoFlags = a - } - if err := c.ValidateArgs(argWoFlags); err != nil { return err } diff --git a/command_test.go b/command_test.go index b901b569..fa652ccb 100644 --- a/command_test.go +++ b/command_test.go @@ -17,7 +17,6 @@ package cobra import ( "bytes" "context" - "errors" "fmt" "io" "os" @@ -224,7 +223,8 @@ func TestSubcommandExecuteMissingSubcommand(t *testing.T) { } func TestSubcommandExecuteMissingSubcommandWithErrorOnUnknownSubcommand(t *testing.T) { - rootCmd := &Command{Use: "root", Run: emptyRun} + const rootName = "root" + rootCmd := &Command{Use: rootName, Run: emptyRun} const childName = "child" const grandchildName = "grandchild" EnableErrorOnUnknownSubcommand = true @@ -236,10 +236,10 @@ func TestSubcommandExecuteMissingSubcommandWithErrorOnUnknownSubcommand(t *testi // test existing command c, output, err := executeCommandC(rootCmd, childName) - if !strings.HasPrefix(output, "Error:") { + if strings.HasPrefix(output, "Error:") { t.Errorf("Unexpected output: %v", output) } - if !errors.Is(err, ErrUnknownSubcommand) { + if err != nil { t.Errorf("Unexpected error: %v", err) } if c.Name() != childName { @@ -258,12 +258,30 @@ func TestSubcommandExecuteMissingSubcommandWithErrorOnUnknownSubcommand(t *testi t.Errorf(`invalid command returned from ExecuteC: expected "child"', got: %q`, c.Name()) } - // now test a command which does not exist, we expect an error because of the ErrorOnUnknownSubcommand flag - c, output, err = executeCommandC(rootCmd, childName, "unknownChild") + // test a child command which does not exist, we expect an error because of the ErrorOnUnknownSubcommand flag + c, output, err = executeCommandC(rootCmd, "unknownChild") if !strings.HasPrefix(output, "Error:") { t.Errorf("Unexpected output: %v", output) } - if !errors.Is(err, ErrUnknownSubcommand) { + if err == nil { + t.Error("Expected error") + } + if err != nil && !strings.HasPrefix(err.Error(), "unknown command") { + t.Errorf("Unexpected error: %v", err) + } + if c.Name() != rootName { + t.Errorf(`invalid command returned from ExecuteC: expected "child"', got: %q`, c.Name()) + } + + // test a grandchild command which does not exist, we expect an error because of the ErrorOnUnknownSubcommand flag + c, output, err = executeCommandC(rootCmd, childName, "unknownGrandChild") + if !strings.HasPrefix(output, "Error:") { + t.Errorf("Unexpected output: %v", output) + } + if err == nil { + t.Error("Expected error") + } + if err != nil && !strings.HasPrefix(err.Error(), "unknown command") { t.Errorf("Unexpected error: %v", err) } if c.Name() != childName {