diff --git a/pkg/plugin/bundle.go b/pkg/plugin/bundle.go index cc341739027..7cda2ca8c91 100644 --- a/pkg/plugin/bundle.go +++ b/pkg/plugin/bundle.go @@ -38,10 +38,22 @@ func NewBundle(name string, version Version, plugins ...Plugin) (Bundle, error) return nil, fmt.Errorf("in order to bundle plugins, they must all support at least one common project version") } + // Plugins may be bundles themselves, so unbundle here + // NOTE(Adirio): unbundling here ensures that Bundle.Plugin always returns a flat list of Plugins instead of also + // including Bundles, and therefore we don't have to use a recursive algorithm when resolving. + allPlugins := make([]Plugin, 0, len(plugins)) + for _, plugin := range plugins { + if pluginBundle, isBundle := plugin.(Bundle); isBundle { + allPlugins = append(allPlugins, pluginBundle.Plugins()...) + } else { + allPlugins = append(allPlugins, plugin) + } + } + return bundle{ name: name, version: version, - plugins: plugins, + plugins: allPlugins, supportedProjectVersions: supportedProjectVersions, }, nil } diff --git a/pkg/plugin/bundle_test.go b/pkg/plugin/bundle_test.go index 4592b66680d..5d712c553a5 100644 --- a/pkg/plugin/bundle_test.go +++ b/pkg/plugin/bundle_test.go @@ -84,6 +84,26 @@ var _ = Describe("Bundle", func() { } }) + It("should accept bundles as input", func() { + var a, b Bundle + var err error + plugins := []Plugin{p1, p2, p3} + a, err = NewBundle("a", version, p1, p2) + Expect(err).NotTo(HaveOccurred()) + b, err = NewBundle("b", version, a, p3) + Expect(err).NotTo(HaveOccurred()) + versions := b.SupportedProjectVersions() + sort.Slice(versions, func(i int, j int) bool { + return versions[i].Compare(versions[j]) == -1 + }) + expectedVersions := CommonSupportedProjectVersions(plugins...) + sort.Slice(expectedVersions, func(i int, j int) bool { + return expectedVersions[i].Compare(expectedVersions[j]) == -1 + }) + Expect(versions).To(Equal(expectedVersions)) + Expect(b.Plugins()).To(Equal(plugins)) + }) + It("should fail for plugins with no common supported project version", func() { for _, plugins := range [][]Plugin{ {p2, p4}, diff --git a/pkg/plugin/plugin.go b/pkg/plugin/plugin.go index 131cd555aa4..564c238b348 100644 --- a/pkg/plugin/plugin.go +++ b/pkg/plugin/plugin.go @@ -20,7 +20,7 @@ import ( "sigs.k8s.io/kubebuilder/v3/pkg/config" ) -// Plugin is an interface that defines the common base for all plugins +// Plugin is an interface that defines the common base for all plugins. type Plugin interface { // Name returns a DNS1123 label string identifying the plugin uniquely. This name should be fully-qualified, // i.e. have a short prefix describing the plugin type (like a language) followed by a domain. @@ -41,35 +41,35 @@ type Deprecated interface { DeprecationWarning() string } -// Init is an interface for plugins that provide an `init` subcommand +// Init is an interface for plugins that provide an `init` subcommand. type Init interface { Plugin // GetInitSubcommand returns the underlying InitSubcommand interface. GetInitSubcommand() InitSubcommand } -// CreateAPI is an interface for plugins that provide a `create api` subcommand +// CreateAPI is an interface for plugins that provide a `create api` subcommand. type CreateAPI interface { Plugin // GetCreateAPISubcommand returns the underlying CreateAPISubcommand interface. GetCreateAPISubcommand() CreateAPISubcommand } -// CreateWebhook is an interface for plugins that provide a `create webhook` subcommand +// CreateWebhook is an interface for plugins that provide a `create webhook` subcommand. type CreateWebhook interface { Plugin // GetCreateWebhookSubcommand returns the underlying CreateWebhookSubcommand interface. GetCreateWebhookSubcommand() CreateWebhookSubcommand } -// Edit is an interface for plugins that provide a `edit` subcommand +// Edit is an interface for plugins that provide a `edit` subcommand. type Edit interface { Plugin // GetEditSubcommand returns the underlying EditSubcommand interface. GetEditSubcommand() EditSubcommand } -// Full is an interface for plugins that provide `init`, `create api`, `create webhook` and `edit` subcommands +// Full is an interface for plugins that provide `init`, `create api`, `create webhook` and `edit` subcommands. type Full interface { Init CreateAPI @@ -77,9 +77,10 @@ type Full interface { Edit } -// Bundle allows to group plugins under a single key +// Bundle allows to group plugins under a single key. type Bundle interface { Plugin - // Plugins returns a list of the bundled plugins + // Plugins returns a list of the bundled plugins. + // The returned list should be flattened, i.e., no plugin bundles should be part of this list. Plugins() []Plugin }