Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 7 additions & 8 deletions cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,17 +46,16 @@ func main() {
"Please, check the migration guide to learn how to upgrade your project"

// Bundle plugin which built the golang projects scaffold by Kubebuilder go/v3
gov3Bundle, _ := plugin.NewBundle(golang.DefaultNameQualifier, plugin.Version{Number: 3},
deprecateMessageGoV3Bundle,
kustomizecommonv1.Plugin{},
golangv3.Plugin{},
gov3Bundle, _ := plugin.NewBundleWithOptions(plugin.WithName(golang.DefaultNameQualifier),
plugin.WithVersion(plugin.Version{Number: 3}),
plugin.WithDeprecationMessage(deprecateMessageGoV3Bundle),
plugin.WithPlugins(kustomizecommonv1.Plugin{}, golangv3.Plugin{}),
)

// Bundle plugin which built the golang projects scaffold by Kubebuilder go/v4 with kustomize alpha-v2
gov4Bundle, _ := plugin.NewBundle(golang.DefaultNameQualifier, plugin.Version{Number: 4},
"",
kustomizecommonv2alpha.Plugin{},
golangv4.Plugin{},
gov4Bundle, _ := plugin.NewBundleWithOptions(plugin.WithName(golang.DefaultNameQualifier),
plugin.WithVersion(plugin.Version{Number: 4}),
plugin.WithPlugins(kustomizecommonv2alpha.Plugin{}, golangv4.Plugin{}),
)

fs := machinery.Filesystem{
Expand Down
14 changes: 8 additions & 6 deletions docs/book/src/plugins/creating-plugins.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,10 @@ Note that Kubebuilder provides the `kustomize.common.kubebuilder.io` to help in
In this way, currently, you can [Extend the CLI][extending-cli] and use the `Bundle Plugin` to create your language plugins such as:

```go
mylanguagev1Bundle, _ := plugin.NewBundle(language.DefaultNameQualifier, plugin.Version{Number: 1},
kustomizecommonv1.Plugin{}, // extend the common base from Kubebuilder
mylanguagev1.Plugin{}, // your plugin language which will do the scaffolds for the specific language on top of the common base
mylanguagev1Bundle, _ := plugin.NewBundle(plugin.WithName(language.DefaultNameQualifier),
plugin.WithVersion(plugin.Version{Number: 1}),
plugin.WithPlugins(kustomizecommonv1.Plugin{}, mylanguagev1.Plugin{}), // extend the common base from Kubebuilder
// your plugin language which will do the scaffolds for the specific language on top of the common base
)
```

Expand Down Expand Up @@ -169,9 +170,10 @@ See [example of deploy-image][example-of-deploy-image-3].
Alternatively, you can create a plugin bundle to include the target plugins. For instance:

```go
mylanguagev1Bundle, _ := plugin.NewBundle(language.DefaultNameQualifier, plugin.Version{Number: 1},
kustomizecommonv1.Plugin{}, // extend the common base from Kuebebuilder
mylanguagev1.Plugin{}, // your plugin language which will do the scaffolds for the specific language on top of the common base
mylanguagev1Bundle, _ := plugin.NewBundle(plugin.WithName(language.DefaultNameQualifier),
plugin.WithVersion(plugin.Version{Number: 1}),
plugin.WithPlugins(kustomizecommonv1.Plugin{}, mylanguagev1.Plugin{}), // extend the common base from Kuebebuilder
// your plugin language which will do the scaffolds for the specific language on top of the common base
)
```

Expand Down
13 changes: 6 additions & 7 deletions docs/book/src/plugins/extending-cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,9 @@ var (
// GetPluginsCLI returns the plugins based CLI configured to be used in your CLI binary
func GetPluginsCLI() (*cli.CLI) {
// Bundle plugin which built the golang projects scaffold by Kubebuilder go/v3
gov3Bundle, _ := plugin.NewBundle(golang.DefaultNameQualifier, plugin.Version{Number: 3},
kustomizecommonv1.Plugin{},
golangv3.Plugin{},
gov3Bundle, _ := plugin.NewBundle(plugin.WithName(golang.DefaultNameQualifier),
plugin.WithVersion(plugin.Version{Number: 3}),
plugin.WithPlugins(kustomizecommonv1.Plugin{}, golangv3.Plugin{}),
)


Expand Down Expand Up @@ -175,10 +175,9 @@ Once a plugin is deprecated, have it implement a [Deprecated][deprecate-plugin-d

```go
// see that will be like myplugin.example/v1`
myPluginBundle, _ := plugin.NewBundle(`<plugin-name>`,`<plugin-version>`,
pluginA.Plugin{},
pluginB.Plugin{},
pluginC.Plugin{},
myPluginBundle, _ := plugin.NewBundle(plugin.WithName(`<plugin-name>`),
plugin.WithVersion(`<plugin-version>`),
plugin.WithPlugins(pluginA.Plugin{}, pluginB.Plugin{}, pluginC.Plugin{}),
)

```
Expand Down
7 changes: 4 additions & 3 deletions docs/book/src/plugins/kustomize-v1.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,10 @@ all that is language specific and kustomize for its configuration, see:
// Bundle plugin which built the golang projects scaffold by Kubebuilder go/v3
// The follow code is creating a new plugin with its name and version via composition
// You can define that one plugin is composite by 1 or Many others plugins
gov3Bundle, _ := plugin.NewBundle(golang.DefaultNameQualifier, plugin.Version{Number: 3},
kustomizecommonv1.Plugin{}, // scaffold the config/ directory and all kustomize files
golangv3.Plugin{}, // Scaffold the Golang files and all that specific for the language e.g. go.mod, apis, controllers
gov3Bundle, _ := plugin.NewBundle(plugin.WithName(golang.DefaultNameQualifier),
plugin.WithVersion(plugin.Version{Number: 3}),
plugin.WithPlugins(kustomizecommonv1.Plugin{}, golangv3.Plugin{}), // scaffold the config/ directory and all kustomize files
// Scaffold the Golang files and all that specific for the language e.g. go.mod, apis, controllers
)
```

Expand Down
7 changes: 4 additions & 3 deletions docs/book/src/plugins/kustomize-v2.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,10 @@ import (
// Bundle plugin which built the golang projects scaffold by Kubebuilder go/v3
// The follow code is creating a new plugin with its name and version via composition
// You can define that one plugin is composite by 1 or Many others plugins
gov3Bundle, _ := plugin.NewBundle(golang.DefaultNameQualifier, plugin.Version{Number: 3},
kustomizecommonv2.Plugin{}, // scaffold the config/ directory and all kustomize files
golangv4.Plugin{}, // Scaffold the Golang files and all that specific for the language e.g. go.mod, apis, controllers
gov3Bundle, _ := plugin.NewBundle(plugin.WithName(golang.DefaultNameQualifier),
plugin.WithVersion(plugin.Version{Number: 3}),
plugin.WithPlugins(kustomizecommonv2.Plugin{}, golangv3.Plugin{}), // scaffold the config/ directory and all kustomize files
// Scaffold the Golang files and all that specific for the language e.g. go.mod, apis, controllers
)
```

Expand Down
62 changes: 62 additions & 0 deletions pkg/plugin/bundle.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,33 @@ type bundle struct {
deprecateWarning string
}

Copy link
Member

@camilamacedo86 camilamacedo86 Apr 22, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@NikhilSharmaWe ,\

The changes in Kubebuilder CLI can still.
I mean, we can use the method here.
We need to have the old one available for those that import and use Kubebuilder as a LIB.

Also, please ensure that you rebase with master branch and it is passing in the tests for we get the PR merged.

type BundleOption func(*bundle)

func WithName(name string) BundleOption {
return func(opts *bundle) {
opts.name = name
}
}

func WithVersion(version Version) BundleOption {
return func(opts *bundle) {
opts.version = version
}
}

func WithPlugins(plugins ...Plugin) BundleOption {
return func(opts *bundle) {
opts.plugins = plugins
}
}

func WithDeprecationMessage(msg string) BundleOption {
return func(opts *bundle) {
opts.deprecateWarning = msg
}

}

// NewBundle creates a new Bundle with the provided name and version, and that wraps the provided plugins.
// The list of supported project versions is computed from the provided plugins.
func NewBundle(name string, version Version, deprecateWarning string, plugins ...Plugin) (Bundle, error) {
Expand Down Expand Up @@ -60,6 +87,41 @@ func NewBundle(name string, version Version, deprecateWarning string, plugins ..
}, nil
}

// NewBundleWithOptions creates a new Bundle with the provided BundleOptions.
// The list of supported project versions is computed from the provided plugins in options.
func NewBundleWithOptions(opts ...BundleOption) (Bundle, error) {
bundleOpts := bundle{}

for _, opts := range opts {
opts(&bundleOpts)
}

supportedProjectVersions := CommonSupportedProjectVersions(bundleOpts.plugins...)
Copy link
Contributor

@em-r em-r Mar 23, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

might be worth moving all the logic related to supportedProjectVersions as well as allPlugins down below to the WithPlugins function, it will keep the bundle setup handled completely by the BundleOption funcs, and this way, NewBundle will only need to loop through opts and pass a ref of bundle to them.
Example:

func NewBundle(opts ...BundleOption) (Bundle, error) {
   var b bundle

   for _, opt := range opts {
        if err := opt(&b); err != nil {
             return nil, err
        }
   }

  return b, nil
}

Copy link
Contributor Author

@NikhilSharmaWe NikhilSharmaWe Mar 24, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that is nice for simplicity. But in NewBundle func we also need to return an error when len(supportedProjectVersions) == 0. But we also do not handle the error returned when we use NewBundle, like here. So I think we can ignore returning an error in the func, if we want to implement this since we are not handling the error anyway. Not sure.

Let's see what others think about this.

if len(supportedProjectVersions) == 0 {
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(bundleOpts.plugins))
for _, plugin := range bundleOpts.plugins {
if pluginBundle, isBundle := plugin.(Bundle); isBundle {
allPlugins = append(allPlugins, pluginBundle.Plugins()...)
} else {
allPlugins = append(allPlugins, plugin)
}
}

return bundle{
name: bundleOpts.name,
version: bundleOpts.version,
plugins: allPlugins,
supportedProjectVersions: supportedProjectVersions,
deprecateWarning: bundleOpts.deprecateWarning,
}, nil
}

// Name implements Plugin
func (b bundle) Name() string {
return b.name
Expand Down
80 changes: 80 additions & 0 deletions pkg/plugin/bundle_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,4 +118,84 @@ var _ = Describe("Bundle", func() {
}
})
})

Context("NewBundleWithOptions", func() {
It("should succeed for plugins with common supported project versions", func() {
for _, plugins := range [][]Plugin{
{p1, p2},
{p1, p3},
{p1, p4},
{p2, p3},
{p3, p4},

{p1, p2, p3},
{p1, p3, p4},
} {
b, err := NewBundleWithOptions(WithName(name),
WithVersion(version),
WithDeprecationMessage(""),
WithPlugins(plugins...),
)
Expect(err).NotTo(HaveOccurred())
Expect(b.Name()).To(Equal(name))
Expect(b.Version().Compare(version)).To(Equal(0))
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 accept bundles as input", func() {
var a, b Bundle
var err error
plugins := []Plugin{p1, p2, p3}
a, err = NewBundleWithOptions(WithName("a"),
WithVersion(version),
WithDeprecationMessage(""),
WithPlugins(p1, p2),
)
Expect(err).NotTo(HaveOccurred())
b, err = NewBundleWithOptions(WithName("b"),
WithVersion(version),
WithDeprecationMessage(""),
WithPlugins(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},

{p1, p2, p4},
{p2, p3, p4},

{p1, p2, p3, p4},
} {
_, err := NewBundleWithOptions(WithName(name),
WithVersion(version),
WithDeprecationMessage(""),
WithPlugins(plugins...),
)
Expect(err).To(HaveOccurred())
}
})
})
})