From 4f53185df81f74ebd039df4f621e3a93ea06f339 Mon Sep 17 00:00:00 2001 From: prafull01 Date: Tue, 27 Oct 2020 18:27:32 +0530 Subject: [PATCH] :sparkles: Make the edit command to be a plugin --- cmd/edit.go | 89 -------------------------------------- cmd/main.go | 1 - pkg/cli/api.go | 1 + pkg/cli/cli.go | 2 + pkg/cli/edit.go | 92 ++++++++++++++++++++++++++++++++++++++++ pkg/cli/webhook.go | 1 + pkg/plugin/interfaces.go | 10 +++++ pkg/plugin/v2/edit.go | 82 +++++++++++++++++++++++++++++++++++ pkg/plugin/v2/plugin.go | 3 ++ pkg/plugin/v3/edit.go | 79 ++++++++++++++++++++++++++++++++++ pkg/plugin/v3/plugin.go | 3 ++ 11 files changed, 273 insertions(+), 90 deletions(-) delete mode 100644 cmd/edit.go create mode 100644 pkg/cli/edit.go create mode 100644 pkg/plugin/v2/edit.go create mode 100644 pkg/plugin/v3/edit.go diff --git a/cmd/edit.go b/cmd/edit.go deleted file mode 100644 index 328fff3cd06..00000000000 --- a/cmd/edit.go +++ /dev/null @@ -1,89 +0,0 @@ -/* -Copyright 2017 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package main - -import ( - "fmt" - "log" - - "github.com/spf13/cobra" - - "sigs.k8s.io/kubebuilder/internal/cmdutil" - "sigs.k8s.io/kubebuilder/internal/config" - "sigs.k8s.io/kubebuilder/pkg/plugin/scaffold" - scaffolds "sigs.k8s.io/kubebuilder/pkg/plugin/v2/scaffolds" -) - -type editError struct { - err error -} - -func (e editError) Error() string { - return fmt.Sprintf("failed to edit configuration: %v", e.err) -} - -func newEditCmd() *cobra.Command { - options := &editOptions{} - - cmd := &cobra.Command{ - Use: "edit", - Short: "This command will edit the project configuration", - Long: `This command will edit the project configuration`, - Example: ` # Enable the multigroup layout - kubebuilder edit --multigroup - - # Disable the multigroup layout - kubebuilder edit --multigroup=false`, - Run: func(_ *cobra.Command, _ []string) { - var err error - if options.config, err = config.LoadInitialized(); err != nil { - log.Fatal(err) - } - if err := cmdutil.Run(options); err != nil { - log.Fatal(editError{err}) - } - }, - } - - options.bindFlags(cmd) - - return cmd -} - -var _ cmdutil.RunOptions = &editOptions{} - -type editOptions struct { - config *config.Config - - multigroup bool -} - -func (o *editOptions) bindFlags(cmd *cobra.Command) { - cmd.Flags().BoolVar(&o.multigroup, "multigroup", false, "enable or disable multigroup layout") -} - -func (o *editOptions) Validate() error { - return nil -} - -func (o *editOptions) GetScaffolder() (scaffold.Scaffolder, error) { - return scaffolds.NewEditScaffolder(&o.config.Config, o.multigroup), nil -} - -func (o *editOptions) PostScaffold() error { - return o.config.Save() -} diff --git a/cmd/main.go b/cmd/main.go index 17e327132d8..0839bcd2ba4 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -35,7 +35,6 @@ func main() { &pluginv2.Plugin{}, ), cli.WithExtraCommands( - newEditCmd(), newCompletionCmd(), version.NewCmd(), ), diff --git a/pkg/cli/api.go b/pkg/cli/api.go index 8e71ab0438d..aa52ef1d817 100644 --- a/pkg/cli/api.go +++ b/pkg/cli/api.go @@ -54,6 +54,7 @@ func (c cli) newAPIContext() plugin.Context { return ctx } +// nolint:dupl func (c cli) bindCreateAPI(ctx plugin.Context, cmd *cobra.Command) { var getter plugin.CreateAPIPluginGetter for _, p := range c.resolvedPlugins { diff --git a/pkg/cli/cli.go b/pkg/cli/cli.go index ad6ffaeb62c..a80cd624729 100644 --- a/pkg/cli/cli.go +++ b/pkg/cli/cli.go @@ -354,6 +354,8 @@ func (c cli) buildRootCmd() *cobra.Command { rootCmd.AddCommand(createCmd) } + // kubebuilder edit + rootCmd.AddCommand(c.newEditCmd()) // kubebuilder init rootCmd.AddCommand(c.newInitCmd()) diff --git a/pkg/cli/edit.go b/pkg/cli/edit.go new file mode 100644 index 00000000000..a0aa1dda2fd --- /dev/null +++ b/pkg/cli/edit.go @@ -0,0 +1,92 @@ +/* +Copyright 2020 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package cli + +import ( + "fmt" + + "github.com/spf13/cobra" + + "sigs.k8s.io/kubebuilder/internal/config" + "sigs.k8s.io/kubebuilder/pkg/plugin" +) + +func (c *cli) newEditCmd() *cobra.Command { + ctx := c.newEditContext() + cmd := &cobra.Command{ + Use: "edit", + Short: "This command will edit the project configuration", + Long: ctx.Description, + Example: ctx.Examples, + RunE: errCmdFunc( + fmt.Errorf("project must be initialized"), + ), + } + + // Lookup the plugin for projectVersion and bind it to the command. + c.bindEdit(ctx, cmd) + return cmd + +} + +func (c *cli) newEditContext() plugin.Context { + ctx := plugin.Context{ + CommandName: c.commandName, + Description: `This command will edit the project configuration. You can have single or multi group project.`, + } + + return ctx +} + +// nolint:dupl +func (c *cli) bindEdit(ctx plugin.Context, cmd *cobra.Command) { + var getter plugin.EditPluginGetter + for _, p := range c.resolvedPlugins { + tmpGetter, isGetter := p.(plugin.EditPluginGetter) + if isGetter { + if getter != nil { + err := fmt.Errorf("duplicate edit project plugins for project version %q (%s, %s), "+ + "use a more specific plugin key", c.projectVersion, plugin.KeyFor(getter), plugin.KeyFor(p)) + cmdErr(cmd, err) + return + } + getter = tmpGetter + } + } + + cfg, err := config.LoadInitialized() + if err != nil { + cmdErr(cmd, err) + return + } + + if getter == nil { + err := fmt.Errorf("layout plugin %q does not support a edit project plugin", cfg.Layout) + cmdErr(cmd, err) + return + } + + editProject := getter.GetEditPlugin() + editProject.InjectConfig(&cfg.Config) + editProject.BindFlags(cmd.Flags()) + editProject.UpdateContext(&ctx) + cmd.Long = ctx.Description + cmd.Example = ctx.Examples + cmd.RunE = runECmdFunc(cfg, editProject, + fmt.Sprintf("failed to edit project with version %q", c.projectVersion)) + +} diff --git a/pkg/cli/webhook.go b/pkg/cli/webhook.go index 08d7ecd3334..bd53033bf68 100644 --- a/pkg/cli/webhook.go +++ b/pkg/cli/webhook.go @@ -54,6 +54,7 @@ func (c cli) newWebhookContext() plugin.Context { return ctx } +// nolint:dupl func (c cli) bindCreateWebhook(ctx plugin.Context, cmd *cobra.Command) { var getter plugin.CreateWebhookPluginGetter for _, p := range c.resolvedPlugins { diff --git a/pkg/plugin/interfaces.go b/pkg/plugin/interfaces.go index f6f0104dfd7..ac10584b100 100644 --- a/pkg/plugin/interfaces.go +++ b/pkg/plugin/interfaces.go @@ -105,3 +105,13 @@ type CreateWebhookPluginGetter interface { type CreateWebhook interface { GenericSubcommand } + +type EditPluginGetter interface { + Base + // GetEditPlugin returns the underlying Edit interface. + GetEditPlugin() Edit +} + +type Edit interface { + GenericSubcommand +} diff --git a/pkg/plugin/v2/edit.go b/pkg/plugin/v2/edit.go new file mode 100644 index 00000000000..1671536a20d --- /dev/null +++ b/pkg/plugin/v2/edit.go @@ -0,0 +1,82 @@ +/* +Copyright 2020 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v2 + +import ( + "fmt" + + "github.com/spf13/pflag" + "sigs.k8s.io/kubebuilder/internal/cmdutil" + "sigs.k8s.io/kubebuilder/pkg/model/config" + "sigs.k8s.io/kubebuilder/pkg/plugin" + "sigs.k8s.io/kubebuilder/pkg/plugin/scaffold" + "sigs.k8s.io/kubebuilder/pkg/plugin/v2/scaffolds" +) + +type editPlugin struct { + config *config.Config + // For help text + commandName string + + multigroup bool +} + +var ( + _ plugin.Edit = &editPlugin{} + _ cmdutil.RunOptions = &editPlugin{} +) + +func (p *editPlugin) UpdateContext(ctx *plugin.Context) { + ctx.Description = `This command will edit the project configuration. You can have single or multi group project.` + + ctx.Examples = fmt.Sprintf(`# Enable the multigroup layout + %s edit --multigroup + + # Disable the multigroup layout + %s edit --multigroup=false + `, ctx.CommandName, ctx.CommandName) + + p.commandName = ctx.CommandName +} + +func (p *editPlugin) BindFlags(fs *pflag.FlagSet) { + fs.BoolVar(&p.multigroup, "multigroup", false, "enable or disable multigroup layout") +} + +func (p *editPlugin) InjectConfig(c *config.Config) { + // v3 project configs get a 'layout' value. + if c.IsV3() { + c.Layout = plugin.KeyFor(Plugin{}) + } + p.config = c +} + +func (p *editPlugin) Run() error { + return cmdutil.Run(p) +} + +func (p *editPlugin) Validate() error { + return nil +} + +func (p *editPlugin) GetScaffolder() (scaffold.Scaffolder, error) { + return scaffolds.NewEditScaffolder(p.config, p.multigroup), nil +} + +func (p *editPlugin) PostScaffold() error { + return nil +} diff --git a/pkg/plugin/v2/plugin.go b/pkg/plugin/v2/plugin.go index c9970bc83b4..8b286f3245b 100644 --- a/pkg/plugin/v2/plugin.go +++ b/pkg/plugin/v2/plugin.go @@ -33,6 +33,7 @@ var ( _ plugin.InitPluginGetter = Plugin{} _ plugin.CreateAPIPluginGetter = Plugin{} _ plugin.CreateWebhookPluginGetter = Plugin{} + _ plugin.EditPluginGetter = Plugin{} ) // Plugin defines the plugins operations for the v2 plugin version. @@ -40,6 +41,7 @@ type Plugin struct { initPlugin createAPIPlugin createWebhookPlugin + editPlugin } // Name returns the name of the plugin for the v2 which is in this case `go.kubebuilder.io` @@ -61,3 +63,4 @@ func (p Plugin) GetCreateAPIPlugin() plugin.CreateAPI { return &p.createAPIPlugi // GetCreateWebhookPlugin will return the plugin for v2 which is responsible for scaffold webhooks for the project func (p Plugin) GetCreateWebhookPlugin() plugin.CreateWebhook { return &p.createWebhookPlugin } +func (p Plugin) GetEditPlugin() plugin.Edit { return &p.editPlugin } diff --git a/pkg/plugin/v3/edit.go b/pkg/plugin/v3/edit.go new file mode 100644 index 00000000000..e94639ca478 --- /dev/null +++ b/pkg/plugin/v3/edit.go @@ -0,0 +1,79 @@ +/* +Copyright 2020 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v3 + +import ( + "fmt" + + "github.com/spf13/pflag" + + "sigs.k8s.io/kubebuilder/internal/cmdutil" + "sigs.k8s.io/kubebuilder/pkg/model/config" + "sigs.k8s.io/kubebuilder/pkg/plugin" + "sigs.k8s.io/kubebuilder/pkg/plugin/scaffold" + "sigs.k8s.io/kubebuilder/pkg/plugin/v3/scaffolds" +) + +type editPlugin struct { + config *config.Config + // For help text + commandName string + + multigroup bool +} + +var ( + _ plugin.Edit = &editPlugin{} + _ cmdutil.RunOptions = &editPlugin{} +) + +func (p *editPlugin) UpdateContext(ctx *plugin.Context) { + ctx.Description = `This command will edit the project configuration. You can have single or multi group project.` + + ctx.Examples = fmt.Sprintf(`# Enable the multigroup layout + %s edit --multigroup + + # Disable the multigroup layout + %s edit --multigroup=false + `, ctx.CommandName, ctx.CommandName) + + p.commandName = ctx.CommandName +} + +func (p *editPlugin) BindFlags(fs *pflag.FlagSet) { + fs.BoolVar(&p.multigroup, "multigroup", false, "enable or disable multigroup layout") +} + +func (p *editPlugin) InjectConfig(c *config.Config) { + p.config = c +} + +func (p *editPlugin) Run() error { + return cmdutil.Run(p) +} + +func (p *editPlugin) Validate() error { + return nil +} + +func (p *editPlugin) GetScaffolder() (scaffold.Scaffolder, error) { + return scaffolds.NewEditScaffolder(p.config, p.multigroup), nil +} + +func (p *editPlugin) PostScaffold() error { + return nil +} diff --git a/pkg/plugin/v3/plugin.go b/pkg/plugin/v3/plugin.go index 72f98637640..bfa78d3c82c 100644 --- a/pkg/plugin/v3/plugin.go +++ b/pkg/plugin/v3/plugin.go @@ -33,6 +33,7 @@ var ( _ plugin.InitPluginGetter = Plugin{} _ plugin.CreateAPIPluginGetter = Plugin{} _ plugin.CreateWebhookPluginGetter = Plugin{} + _ plugin.EditPluginGetter = Plugin{} ) // Plugin defines the plugins operations for the v3+ plugin versions. @@ -40,6 +41,7 @@ type Plugin struct { initPlugin createAPIPlugin createWebhookPlugin + editPlugin } // Name returns the name of the plugin for the v3+ which is in this case `go.kubebuilder.io` @@ -61,3 +63,4 @@ func (p Plugin) GetCreateAPIPlugin() plugin.CreateAPI { return &p.createAPIPlugi // GetCreateWebhookPlugin will return the plugin for v3+ which is responsible for scaffold webhooks for the project func (p Plugin) GetCreateWebhookPlugin() plugin.CreateWebhook { return &p.createWebhookPlugin } +func (p Plugin) GetEditPlugin() plugin.Edit { return &p.editPlugin }