diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index bc7f9dc5b..fac439f4c 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -30,6 +30,10 @@ | Check DeleteTimestamp before updating resource | https://github.com/knative/client/pull/805[#805] +| 🎁 +| Allow plugins to extend fixed list of command groups, currently `source` +| https://github.com/knative/client/pull/818[#818] + | 🎁 | Add `-a` flag as an alias for `--annotation` | https://github.com/knative/client/pull/782[#782] diff --git a/pkg/kn/commands/plugin/list_test.go b/pkg/kn/commands/plugin/list_test.go index e33d8d021..230cd0a15 100644 --- a/pkg/kn/commands/plugin/list_test.go +++ b/pkg/kn/commands/plugin/list_test.go @@ -71,7 +71,6 @@ func (ctx *testContext) createTestPluginWithPath(pluginName string, fileMode os. } func TestPluginList(t *testing.T) { - setup := func(t *testing.T) *testContext { knParams := &commands.KnParams{} pluginCmd := NewPluginCommand(knParams) @@ -159,7 +158,6 @@ func TestPluginList(t *testing.T) { }) t.Run("with plugins with same name", func(t *testing.T) { - t.Run("warns user about second (in $PATH) plugin shadowing first", func(t *testing.T) { ctx := setup(t) defer ctx.cleanup() @@ -201,6 +199,24 @@ func TestPluginList(t *testing.T) { assert.ErrorContains(t, err, "overwrite", "built-in") assert.Assert(t, util.ContainsAll(ctx.output(), "ERROR", "overwrite", "built-in")) }) + + t.Run("allows plugin under the `source` command group", func(t *testing.T) { + ctx := setup(t) + defer ctx.cleanup() + + sourceCmd := &cobra.Command{ + Use: "source", + } + ctx.rootCmd.AddCommand(sourceCmd) + defer ctx.rootCmd.RemoveCommand(sourceCmd) + + err := ctx.createTestPlugin("kn-source-fake", FileModeExecutable, true) + assert.NilError(t, err) + + err = ctx.execute("plugin", "list", "--lookup-plugins=true") + assert.NilError(t, err) + }) + }) }) }) diff --git a/pkg/kn/commands/plugin/plugin.go b/pkg/kn/commands/plugin/plugin.go index 211b3d78f..58143957c 100644 --- a/pkg/kn/commands/plugin/plugin.go +++ b/pkg/kn/commands/plugin/plugin.go @@ -52,3 +52,20 @@ func BindPluginsFlagToViper(cmd *cobra.Command) { viper.SetDefault("plugins-dir", commands.Cfg.DefaultPluginDir) viper.SetDefault("lookup-plugins", false) } + +// AllowedExtensibleCommandGroups the list of command groups that can be +// extended with plugins, e.g., a plugin named `kn-source-kafka` for Kafka +// event sources is allowed. This is defined as a fixed [...]string since +// cannot defined Golang []string constants +var AllowedExtensibleCommandGroups = [...]string{"source"} + +// InAllowedExtensibleCommandGroups checks that the name is in the list of allowed +// extensible command groups +func InAllowedExtensibleCommandGroups(name string) bool { + for _, groupName := range AllowedExtensibleCommandGroups { + if name == groupName { + return true + } + } + return false +} diff --git a/pkg/kn/commands/plugin/plugin_test.go b/pkg/kn/commands/plugin/plugin_test.go index fb34cfb59..ac604b391 100644 --- a/pkg/kn/commands/plugin/plugin_test.go +++ b/pkg/kn/commands/plugin/plugin_test.go @@ -72,3 +72,13 @@ func TestNewPluginCommand(t *testing.T) { assert.Assert(t, pluginCmd.Args == nil) }) } + +func TestInAllowedExtensibleCommandGroups(t *testing.T) { + isExtensibleCommand := InAllowedExtensibleCommandGroups("fake") + assert.Assert(t, isExtensibleCommand == false) + + for _, name := range AllowedExtensibleCommandGroups { + isExtensibleCommand = InAllowedExtensibleCommandGroups(name) + assert.Assert(t, isExtensibleCommand == true) + } +} diff --git a/pkg/kn/commands/plugin/verifier.go b/pkg/kn/commands/plugin/verifier.go index 5d40b662c..8ed479f99 100644 --- a/pkg/kn/commands/plugin/verifier.go +++ b/pkg/kn/commands/plugin/verifier.go @@ -110,7 +110,9 @@ func (v *pluginVerifier) addErrorIfOverwritingExistingCommand(eaw errorsAndWarni for _, c := range [][]string{cmds, convertUnderscoresToDashes(cmds)} { cmd, _, err := v.root.Find(c) if err == nil { - overwrittenCommands[cmd.CommandPath()] = true + if !InAllowedExtensibleCommandGroups(cmd.Name()) { + overwrittenCommands[cmd.CommandPath()] = true + } } } for command := range overwrittenCommands { diff --git a/pkg/kn/commands/plugin/verifier_test.go b/pkg/kn/commands/plugin/verifier_test.go index 1af5488e6..d401169c9 100644 --- a/pkg/kn/commands/plugin/verifier_test.go +++ b/pkg/kn/commands/plugin/verifier_test.go @@ -33,7 +33,6 @@ import ( ) func TestPluginVerifier(t *testing.T) { - var ( pluginPath string rootCmd *cobra.Command @@ -143,6 +142,20 @@ func TestPluginVerifier(t *testing.T) { assert.Assert(t, util.ContainsAll(eaw.errors[0], "overwrite", "kn-plugin")) }) }) + + t.Run("when kn plugin in path overwrites 'source' command (which is allowed)", func(t *testing.T) { + setup(t) + defer cleanup(t) + var overwritingPluginPath = CreateTestPlugin(t, "kn-source-test", KnTestPluginScript, FileModeExecutable) + defer DeleteTestPlugin(t, overwritingPluginPath) + + t.Run("runs successfully", func(t *testing.T) { + eaw := errorsAndWarnings{} + eaw = verifier.verify(eaw, overwritingPluginPath) + assert.Assert(t, len(eaw.errors) == 0) + assert.Assert(t, len(eaw.warnings) == 0) + }) + }) }) } diff --git a/pkg/kn/core/root.go b/pkg/kn/core/root.go index b6877a8fb..1693fcef0 100644 --- a/pkg/kn/core/root.go +++ b/pkg/kn/core/root.go @@ -81,7 +81,7 @@ func NewDefaultKnCommandWithArgs(rootCmd *cobra.Command, // only look for suitable extension executables if // the specified command does not already exist foundCmd, innerArgs, err := rootCmd.Find(cmdPathPieces) - if err != nil { + if err != nil || plugin.InAllowedExtensibleCommandGroups(foundCmd.Name()) { err := plugin.HandlePluginCommand(pluginHandler, cmdPathPieces) if err != nil { fmt.Fprintf(rootCmd.OutOrStderr(), "Error: unknown command '%s' \nRun 'kn --help' for usage.\n", args[1])