Skip to content

Commit

Permalink
Merge remote-tracking branch 'fork/plugin-phase-1.5' into plugin-reso…
Browse files Browse the repository at this point in the history
…lution
  • Loading branch information
Adirio committed Feb 16, 2021
2 parents 6224a06 + ac79c7d commit bee2b1a
Show file tree
Hide file tree
Showing 66 changed files with 2,079 additions and 2,320 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ test-unit: ## Run the unit tests
.PHONY: test-coverage
test-coverage: ## Run unit tests creating the output to report coverage
- rm -rf *.out # Remove all coverage files if exists
go test -race -failfast -tags=integration -coverprofile=coverage-all.out ./cmd/... ./pkg/... ./plugins/...
go test -race -failfast -tags=integration -coverprofile=coverage-all.out ./cmd/... ./pkg/...

.PHONY: test-integration
test-integration: ## Run the integration tests
Expand Down
2 changes: 2 additions & 0 deletions cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"sigs.k8s.io/kubebuilder/v3/pkg/cli"
cfgv2 "sigs.k8s.io/kubebuilder/v3/pkg/config/v2"
cfgv3 "sigs.k8s.io/kubebuilder/v3/pkg/config/v3"
declarativev1 "sigs.k8s.io/kubebuilder/v3/pkg/plugins/declarative/v1"
pluginv2 "sigs.k8s.io/kubebuilder/v3/pkg/plugins/golang/v2"
pluginv3 "sigs.k8s.io/kubebuilder/v3/pkg/plugins/golang/v3"
)
Expand All @@ -34,6 +35,7 @@ func main() {
cli.WithPlugins(
&pluginv2.Plugin{},
&pluginv3.Plugin{},
&declarativev1.Plugin{},
),
cli.WithDefaultPlugins(cfgv2.Version, &pluginv2.Plugin{}),
cli.WithDefaultPlugins(cfgv3.Version, &pluginv3.Plugin{}),
Expand Down
84 changes: 31 additions & 53 deletions pkg/cli/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,80 +14,58 @@ See the License for the specific language governing permissions and
limitations under the License.
*/

package cli // nolint:dupl
package cli //nolint:dupl

import (
"fmt"

"github.com/spf13/cobra"

"sigs.k8s.io/kubebuilder/v3/pkg/cli/internal/config"
"sigs.k8s.io/kubebuilder/v3/pkg/plugin"
)

const apiErrorMsg = "failed to create API"

func (c cli) newCreateAPICmd() *cobra.Command {
ctx := c.newAPIContext()
cmd := &cobra.Command{
Use: "api",
Short: "Scaffold a Kubernetes API",
Long: ctx.Description,
Example: ctx.Examples,
Use: "api",
Short: "Scaffold a Kubernetes API",
Long: `Scaffold a Kubernetes API.
`,
RunE: errCmdFunc(
fmt.Errorf("api subcommand requires an existing project"),
),
}

// Lookup the plugin for projectVersion and bind it to the command.
c.bindCreateAPI(ctx, cmd)
return cmd
}

func (c cli) newAPIContext() plugin.Context {
return plugin.Context{
CommandName: c.commandName,
Description: `Scaffold a Kubernetes API.
`,
}
}

// nolint:dupl
func (c cli) bindCreateAPI(ctx plugin.Context, cmd *cobra.Command) {
// In case no plugin was resolved, instead of failing the construction of the CLI, fail the execution of
// this subcommand. This allows the use of subcommands that do not require resolved plugins like help.
if len(c.resolvedPlugins) == 0 {
cmdErr(cmd, fmt.Errorf(noPluginError))
return
cmdErr(cmd, noResolvedPluginError{})
return cmd
}

var createAPIPlugin plugin.CreateAPI
for _, p := range c.resolvedPlugins {
tmpPlugin, isValid := p.(plugin.CreateAPI)
if isValid {
if createAPIPlugin != nil {
err := fmt.Errorf("duplicate API creation plugins (%s, %s), use a more specific plugin key",
plugin.KeyFor(createAPIPlugin), plugin.KeyFor(p))
cmdErr(cmd, err)
return
}
createAPIPlugin = tmpPlugin
}
}
// Obtain the plugin keys and subcommands from the plugins that implement plugin.CreateAPI.
pluginKeys, subcommands := c.filterSubcommands(
func(p plugin.Plugin) bool {
_, isValid := p.(plugin.CreateAPI)
return isValid
},
func(p plugin.Plugin) plugin.Subcommand {
return p.(plugin.CreateAPI).GetCreateAPISubcommand()
},
)

if createAPIPlugin == nil {
cmdErr(cmd, fmt.Errorf("resolved plugins do not provide an API creation plugin: %v", c.pluginKeys))
return
// Verify that there is at least one remaining plugin.
if len(subcommands) == 0 {
cmdErr(cmd, noAvailablePluginError{"API creation"})
return cmd
}

cfg, err := config.LoadInitialized()
if err != nil {
cmdErr(cmd, err)
return
}
// Initialization methods.
options := c.initializationMethods(cmd, subcommands)

// Execution methods.
cmd.PreRunE, cmd.RunE, cmd.PostRunE = c.executionMethodsFuncs(pluginKeys, subcommands, options, apiErrorMsg)

subcommand := createAPIPlugin.GetCreateAPISubcommand()
subcommand.InjectConfig(cfg.Config)
subcommand.BindFlags(cmd.Flags())
subcommand.UpdateContext(&ctx)
cmd.Long = ctx.Description
cmd.Example = ctx.Examples
cmd.RunE = runECmdFunc(cfg, subcommand,
fmt.Sprintf("failed to create API with %q", plugin.KeyFor(createAPIPlugin)))
return cmd
}
28 changes: 20 additions & 8 deletions pkg/cli/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,17 @@ limitations under the License.
package cli

import (
"errors"
"fmt"
"os"
"strings"

"github.com/spf13/afero"
"github.com/spf13/cobra"
"github.com/spf13/pflag"

internalconfig "sigs.k8s.io/kubebuilder/v3/pkg/cli/internal/config"
"sigs.k8s.io/kubebuilder/v3/pkg/config"
yamlstore "sigs.k8s.io/kubebuilder/v3/pkg/config/store/yaml"
cfgv3 "sigs.k8s.io/kubebuilder/v3/pkg/config/v3"
"sigs.k8s.io/kubebuilder/v3/pkg/plugin"
)
Expand All @@ -36,8 +38,6 @@ const (

projectVersionFlag = "project-version"
pluginsFlag = "plugins"

noPluginError = "invalid config file please verify that the version and layout fields are set and valid"
)

// equalStringSlice checks if two string slices are equal.
Expand Down Expand Up @@ -96,6 +96,9 @@ type cli struct { //nolint:maligned

// Root command.
cmd *cobra.Command

// Underlying fs
fs afero.Fs
}

// New creates a new cli instance.
Expand Down Expand Up @@ -134,6 +137,7 @@ func newCLI(opts ...Option) (*cli, error) {
defaultProjectVersion: cfgv3.Version,
defaultPlugins: make(map[config.Version][]string),
plugins: make(map[string]plugin.Plugin),
fs: afero.NewOsFs(),
}

// Apply provided options.
Expand Down Expand Up @@ -191,18 +195,19 @@ func (c *cli) getInfoFromFlags() (string, []string, error) {
}

// getInfoFromConfigFile obtains the project version and plugin keys from the project config file.
func getInfoFromConfigFile() (config.Version, []string, error) {
func (c cli) getInfoFromConfigFile() (config.Version, []string, error) {
// Read the project configuration file
projectConfig, err := internalconfig.Read()
cfg := yamlstore.New(c.fs)
err := cfg.Load()
switch {
case err == nil:
case os.IsNotExist(err):
case errors.Is(err, os.ErrNotExist):
return config.Version{}, nil, nil
default:
return config.Version{}, nil, err
}

return getInfoFromConfig(projectConfig)
return getInfoFromConfig(cfg.Config())
}

// getInfoFromConfig obtains the project version and plugin keys from the project config.
Expand Down Expand Up @@ -297,7 +302,7 @@ func (c *cli) getInfo() error {
return err
}
// Get project version and plugin info from project configuration file
cfgProjectVersion, cfgPlugins, _ := getInfoFromConfigFile()
cfgProjectVersion, cfgPlugins, _ := c.getInfoFromConfigFile()
// We discard the error because not being able to read a project configuration file
// is not fatal for some commands. The ones that require it need to check its existence.

Expand Down Expand Up @@ -473,6 +478,13 @@ func (c cli) printDeprecationWarnings() {
}
}

// metadata returns CLI's metadata.
func (c cli) metadata() plugin.CLIMetadata {
return plugin.CLIMetadata{
CommandName: c.commandName,
}
}

// Run implements CLI.Run.
func (c cli) Run() error {
return c.cmd.Execute()
Expand Down
2 changes: 2 additions & 0 deletions pkg/cli/cli_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (

. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"github.com/spf13/afero"
"github.com/spf13/cobra"

"sigs.k8s.io/kubebuilder/v3/pkg/config"
Expand Down Expand Up @@ -585,6 +586,7 @@ var _ = Describe("CLI", func() {
defaultPlugins: map[config.Version][]string{
projectVersion: pluginKeys,
},
fs: afero.NewMemMapFs(),
}
c.cmd = c.newRootCmd()
Expect(c.getInfo()).To(Succeed())
Expand Down
Loading

0 comments on commit bee2b1a

Please sign in to comment.