mirror of
https://github.com/spf13/cobra
synced 2024-11-24 14:47:12 +00:00
closes #2130 new command flag ErrorOnUnknownSubcommand
This commit is contained in:
parent
3a5efaede9
commit
971a0f75db
2 changed files with 109 additions and 2 deletions
22
command.go
22
command.go
|
@ -44,6 +44,10 @@ type Group struct {
|
||||||
Title string
|
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.
|
// Command is just that, a command for your application.
|
||||||
// E.g. 'go run ...' - 'run' is the command. Cobra requires
|
// E.g. 'go run ...' - 'run' is the command. Cobra requires
|
||||||
// you to define the usage and description as part of your command
|
// you to define the usage and description as part of your command
|
||||||
|
@ -254,6 +258,17 @@ type Command struct {
|
||||||
// SuggestionsMinimumDistance defines minimum levenshtein distance to display suggestions.
|
// SuggestionsMinimumDistance defines minimum levenshtein distance to display suggestions.
|
||||||
// Must be > 0.
|
// Must be > 0.
|
||||||
SuggestionsMinimumDistance int
|
SuggestionsMinimumDistance int
|
||||||
|
|
||||||
|
// ErrorOnUnknownSubcommand 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
|
||||||
|
// 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.
|
||||||
|
// Example: in root/service/run - there would be an existing subcommand `run`
|
||||||
|
// in root/service/unknown - there would be an unknown subcommand `unknown` therefore returning an error
|
||||||
|
// `service` must have a nil Command.Run() function for this.
|
||||||
|
ErrorOnUnknownSubcommand bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// Context returns underlying command context. If command was executed
|
// Context returns underlying command context. If command was executed
|
||||||
|
@ -924,9 +939,12 @@ func (c *Command) execute(a []string) (err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if !c.Runnable() {
|
if !c.Runnable() {
|
||||||
return flag.ErrHelp
|
if c.ErrorOnUnknownSubcommand {
|
||||||
|
return ErrUnknownSubcommand
|
||||||
|
} else {
|
||||||
|
return flag.ErrHelp
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
c.preRun()
|
c.preRun()
|
||||||
|
|
||||||
defer c.postRun()
|
defer c.postRun()
|
||||||
|
|
|
@ -17,6 +17,7 @@ package cobra
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
|
@ -174,6 +175,94 @@ func TestSubcommandExecuteC(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSubcommandExecuteMissingSubcommand(t *testing.T) {
|
||||||
|
rootCmd := &Command{Use: "root", Run: emptyRun}
|
||||||
|
childCmd := &Command{Use: "child", Run: nil, ErrorOnUnknownSubcommand: false}
|
||||||
|
child2Cmd := &Command{Use: "child2", Run: emptyRun}
|
||||||
|
rootCmd.AddCommand(childCmd)
|
||||||
|
childCmd.AddCommand(child2Cmd)
|
||||||
|
|
||||||
|
// test existing command
|
||||||
|
c, output, err := executeCommandC(rootCmd, "child")
|
||||||
|
if !strings.HasPrefix(output, "Usage:") {
|
||||||
|
t.Errorf("Unexpected output: %v", output)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
if c.Name() != "child" {
|
||||||
|
t.Errorf(`invalid command returned from ExecuteC: expected "child"', got: %q`, c.Name())
|
||||||
|
}
|
||||||
|
|
||||||
|
// test existing sub command
|
||||||
|
c, output, err = executeCommandC(rootCmd, "child", "child2")
|
||||||
|
if output != "" {
|
||||||
|
t.Errorf("Unexpected output: %v", output)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
if c.Name() != "child2" {
|
||||||
|
t.Errorf(`invalid command returned from ExecuteC: expected "child"', got: %q`, c.Name())
|
||||||
|
}
|
||||||
|
|
||||||
|
// now test a command which does not exist, we will get no error, just "Usage:" is printed
|
||||||
|
c, output, err = executeCommandC(rootCmd, "child", "unknownChild")
|
||||||
|
if !strings.HasPrefix(output, "Usage:") {
|
||||||
|
t.Errorf("Expected: 'Usage: ...'\nGot:\n %q\n", output)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
if c.Name() != "child" {
|
||||||
|
t.Errorf(`invalid command returned from ExecuteC: expected "child"', got: %q`, c.Name())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSubcommandExecuteMissingSubcommandWithErrorOnUnknownSubcommand(t *testing.T) {
|
||||||
|
rootCmd := &Command{Use: "root", Run: emptyRun}
|
||||||
|
childCmd := &Command{Use: "child", Run: nil, ErrorOnUnknownSubcommand: true}
|
||||||
|
child2Cmd := &Command{Use: "child2", Run: emptyRun}
|
||||||
|
rootCmd.AddCommand(childCmd)
|
||||||
|
childCmd.AddCommand(child2Cmd)
|
||||||
|
|
||||||
|
// test existing command
|
||||||
|
c, output, err := executeCommandC(rootCmd, "child")
|
||||||
|
if !strings.HasPrefix(output, "Error:") {
|
||||||
|
t.Errorf("Unexpected output: %v", output)
|
||||||
|
}
|
||||||
|
if !errors.Is(err, ErrUnknownSubcommand) {
|
||||||
|
t.Errorf("Unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
if c.Name() != "child" {
|
||||||
|
t.Errorf(`invalid command returned from ExecuteC: expected "child"', got: %q`, c.Name())
|
||||||
|
}
|
||||||
|
|
||||||
|
// test existing sub command
|
||||||
|
c, output, err = executeCommandC(rootCmd, "child", "child2")
|
||||||
|
if output != "" {
|
||||||
|
t.Errorf("Unexpected output: %v", output)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
if c.Name() != "child2" {
|
||||||
|
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, "child", "unknownChild")
|
||||||
|
if !strings.HasPrefix(output, "Error:") {
|
||||||
|
t.Errorf("Unexpected output: %v", output)
|
||||||
|
}
|
||||||
|
if !errors.Is(err, ErrUnknownSubcommand) {
|
||||||
|
t.Errorf("Unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
if c.Name() != "child" {
|
||||||
|
t.Errorf(`invalid command returned from ExecuteC: expected "child"', got: %q`, c.Name())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestExecuteContext(t *testing.T) {
|
func TestExecuteContext(t *testing.T) {
|
||||||
ctx := context.TODO()
|
ctx := context.TODO()
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue