Skip to content

Commit

Permalink
Support usage as plugin for tools like kubectl
Browse files Browse the repository at this point in the history
In this case the executable is `kubectl-plugin`, but we run it as:

    kubectl plugin

And the help text should reflect the actual usage of the command.

To create a plugin create the root command like:

    rootCmd := &cobra.Command{
        CommandName: "kubectl plugin",
    }

When `CommandName` is set, Name() use it as is instead of guessing the
command name from the `Use` line.

Issues:
- Need to update the docs.

Fixes: #2017
Signed-off-by: Nir Soffer <nsoffer@redhat.com>
  • Loading branch information
nirs committed Aug 16, 2023
1 parent fd865a4 commit 71ef96a
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 1 deletion.
9 changes: 8 additions & 1 deletion command.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,10 @@ type Command struct {
// Example: add [-F file | -D dir]... [-f format] profile
Use string

// CommandName is the command name if set. Otherwise the command
// name is the first word of the `Use` line.
CommandName string

// Aliases is an array of aliases that can be used instead of the first word in Use.
Aliases []string

Expand Down Expand Up @@ -1441,8 +1445,11 @@ func (c *Command) DebugFlags() {
debugflags(c)
}

// Name returns the command's name: the first word in the use line.
// Name returns CommandName or the first word in the use line.
func (c *Command) Name() string {
if c.CommandName != "" {
return c.CommandName
}
name := c.Use
i := strings.Index(name, " ")
if i >= 0 {
Expand Down
23 changes: 23 additions & 0 deletions command_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,29 @@ func TestAliasPrefixMatching(t *testing.T) {
EnablePrefixMatching = defaultPrefixMatching
}

// TestPlugin checks usage as plugin for aother commmand such as kubectl. The
// executable is `kubectl-plugin`, but we run it as `kubectl plugin`. The help
// text should reflect the way we run the commmand.
func TestPlugin(t *testing.T) {
rootCmd := &Command{CommandName: "kubectl plugin", Args: NoArgs}
subCmd := &Command{Use: "sub [flags]", Args: NoArgs, Run: emptyRun}
rootCmd.AddCommand(subCmd)

rootHelp, err := executeCommand(rootCmd, "-h")
if err != nil {
t.Errorf("Unexpected error: %v", err)
}

checkStringContains(t, rootHelp, "kubectl plugin [command]")

childHelp, err := executeCommand(rootCmd, "sub", "-h")
if err != nil {
t.Errorf("Unexpected error: %v", err)
}

checkStringContains(t, childHelp, "kubectl plugin sub [flags]")
}

// TestChildSameName checks the correct behaviour of cobra in cases,
// when an application with name "foo" and with subcommand "foo"
// is executed with args "foo foo".
Expand Down

0 comments on commit 71ef96a

Please sign in to comment.