diff --git a/pkg/cmd/cmd.go b/pkg/cmd/cmd.go index 7907ffe6..53359d58 100644 --- a/pkg/cmd/cmd.go +++ b/pkg/cmd/cmd.go @@ -136,7 +136,7 @@ func NewDefaultKubectlCommandWithArgs(o KubectlOptions) *cobra.Command { case "help", cobra.ShellCompRequestCmd, cobra.ShellCompNoDescRequestCmd: // Don't search for a plugin default: - if err := HandlePluginCommand(o.PluginHandler, cmdPathPieces, false); err != nil { + if err := HandlePluginCommand(o.PluginHandler, cmdPathPieces, 1); err != nil { fmt.Fprintf(o.IOStreams.ErrOut, "Error: %v\n", err) os.Exit(1) } @@ -157,7 +157,7 @@ func NewDefaultKubectlCommandWithArgs(o KubectlOptions) *cobra.Command { } if !builtinSubcmdExist { - if err := HandlePluginCommand(o.PluginHandler, cmdPathPieces, true); err != nil { + if err := HandlePluginCommand(o.PluginHandler, cmdPathPieces, len(cmdPathPieces)-len(foundArgs)+1); err != nil { fmt.Fprintf(o.IOStreams.ErrOut, "Error: %v\n", err) os.Exit(1) } @@ -259,7 +259,7 @@ func (h *DefaultPluginHandler) Execute(executablePath string, cmdArgs, environme // HandlePluginCommand receives a pluginHandler and command-line arguments and attempts to find // a plugin executable on the PATH that satisfies the given arguments. -func HandlePluginCommand(pluginHandler PluginHandler, cmdArgs []string, exactMatch bool) error { +func HandlePluginCommand(pluginHandler PluginHandler, cmdArgs []string, minArgs int) error { var remainingArgs []string // all "non-flag" arguments for _, arg := range cmdArgs { if strings.HasPrefix(arg, "-") { @@ -279,13 +279,14 @@ func HandlePluginCommand(pluginHandler PluginHandler, cmdArgs []string, exactMat for len(remainingArgs) > 0 { path, found := pluginHandler.Lookup(strings.Join(remainingArgs, "-")) if !found { - if exactMatch { - // if exactMatch is true, we shouldn't continue searching with shorter names. + remainingArgs = remainingArgs[:len(remainingArgs)-1] + if len(remainingArgs) < minArgs { + // we shouldn't continue searching with shorter names. // this is especially for not searching kubectl-create plugin // when kubectl-create-foo plugin is not found. break } - remainingArgs = remainingArgs[:len(remainingArgs)-1] + continue } diff --git a/pkg/cmd/cmd_test.go b/pkg/cmd/cmd_test.go index 84653461..633bc242 100644 --- a/pkg/cmd/cmd_test.go +++ b/pkg/cmd/cmd_test.go @@ -196,6 +196,18 @@ func TestKubectlCommandHandlesPlugins(t *testing.T) { expectPlugin: "plugin/testdata/kubectl-foo", expectPluginArgs: []string{"--bar"}, }, + { + name: "test that a plugin executable is found based on command args with positional argument", + args: []string{"kubectl", "foo", "positional", "--bar"}, + expectPlugin: "plugin/testdata/kubectl-foo", + expectPluginArgs: []string{"positional", "--bar"}, + }, + { + name: "test that an allowed subcommand plugin executable is found based on command args with positional argument", + args: []string{"kubectl", "create", "foo", "positional", "--bar"}, + expectPlugin: "plugin/testdata/kubectl-create-foo", + expectPluginArgs: []string{"positional", "--bar"}, + }, { name: "test that a plugin does not execute over an existing command by the same name", args: []string{"kubectl", "version", "--client=true"}, @@ -330,6 +342,7 @@ func (h *testPluginHandler) Lookup(filename string) (string, bool) { for _, p := range plugins { filenameWithSuportedPrefix = fmt.Sprintf("%s-%s", prefix, filename) if p.Name() == filenameWithSuportedPrefix { + h.lookupErr = nil return fmt.Sprintf("%s/%s", h.pluginsDirectory, p.Name()), true } }