Skip to content

Commit

Permalink
Remove CLI interface and expose cli instead
Browse files Browse the repository at this point in the history
Improve the documentation of all the exported pieces of this package.

Signed-off-by: Adrian Orive <[email protected]>
  • Loading branch information
Adirio committed Mar 10, 2021
1 parent dd3942c commit 4e6c400
Show file tree
Hide file tree
Showing 14 changed files with 142 additions and 113 deletions.
6 changes: 3 additions & 3 deletions pkg/cli/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import (
"sigs.k8s.io/kubebuilder/v3/pkg/plugin"
)

func (c cli) newCreateAPICmd() *cobra.Command {
func (c CLI) newCreateAPICmd() *cobra.Command {
ctx := c.newAPIContext()
cmd := &cobra.Command{
Use: "api",
Expand All @@ -42,7 +42,7 @@ func (c cli) newCreateAPICmd() *cobra.Command {
return cmd
}

func (c cli) newAPIContext() plugin.Context {
func (c CLI) newAPIContext() plugin.Context {
return plugin.Context{
CommandName: c.commandName,
Description: `Scaffold a Kubernetes API.
Expand All @@ -51,7 +51,7 @@ func (c cli) newAPIContext() plugin.Context {
}

// nolint:dupl
func (c cli) bindCreateAPI(ctx plugin.Context, cmd *cobra.Command) {
func (c CLI) bindCreateAPI(ctx plugin.Context, cmd *cobra.Command) {
if len(c.resolvedPlugins) == 0 {
cmdErr(cmd, fmt.Errorf(noPluginError))
return
Expand Down
65 changes: 32 additions & 33 deletions pkg/cli/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,16 +57,8 @@ func equalStringSlice(a, b []string) bool {
return true
}

// CLI interacts with a command line interface.
type CLI interface {
// Run runs the CLI, usually returning an error if command line configuration
// is incorrect.
Run() error
}

// cli defines the command line structure and interfaces that are used to
// scaffold kubebuilder project files.
type cli struct { //nolint:maligned
// CLI is the command line utility that is used to scaffold kubebuilder project files.
type CLI struct { //nolint:maligned
/* Fields set by Option */

// Root command name. It is injected downstream to provide correct help, usage, examples and errors.
Expand All @@ -77,11 +69,11 @@ type cli struct { //nolint:maligned
defaultProjectVersion config.Version
// Default plugins in case none is provided and a config file can't be found.
defaultPlugins map[config.Version][]string
// Plugins registered in the cli.
// Plugins registered in the CLI.
plugins map[string]plugin.Plugin
// Commands injected by options.
extraCommands []*cobra.Command
// Whether to add a completion command to the cli.
// Whether to add a completion command to the CLI.
completionCommand bool

/* Internal fields */
Expand All @@ -98,12 +90,17 @@ type cli struct { //nolint:maligned
cmd *cobra.Command
}

// New creates a new cli instance.
// Developer errors (e.g. not registering any plugins, extra commands with conflicting names) return an error
// while user errors (e.g. errors while parsing flags, unresolvable plugins) create a command which return the error.
func New(opts ...Option) (CLI, error) {
// New creates a new CLI instance.
//
// It follows the functional options pattern in order to customize the resulting CLI.
//
// It returns an error if any of the provided options fails. As some processing needs
// to be done, execution errors may be found here. Instead of returning an error, this
// function will return a valid CLI that errors in Run so that help is provided to the
// user.
func New(options ...Option) (*CLI, error) {
// Create the CLI.
c, err := newCLI(opts...)
c, err := newCLI(options...)
if err != nil {
return nil, err
}
Expand All @@ -125,20 +122,20 @@ func New(opts ...Option) (CLI, error) {
return c, nil
}

// newCLI creates a default cli instance and applies the provided options.
// newCLI creates a default CLI instance and applies the provided options.
// It is as a separate function for test purposes.
func newCLI(opts ...Option) (*cli, error) {
// Default cli options.
c := &cli{
func newCLI(options ...Option) (*CLI, error) {
// Default CLI options.
c := &CLI{
commandName: "kubebuilder",
defaultProjectVersion: cfgv3.Version,
defaultPlugins: make(map[config.Version][]string),
plugins: make(map[string]plugin.Plugin),
}

// Apply provided options.
for _, opt := range opts {
if err := opt(c); err != nil {
for _, option := range options {
if err := option(c); err != nil {
return nil, err
}
}
Expand All @@ -147,7 +144,7 @@ func newCLI(opts ...Option) (*cli, error) {
}

// getInfoFromFlags obtains the project version and plugin keys from flags.
func (c *cli) getInfoFromFlags() (string, []string, error) {
func (c *CLI) getInfoFromFlags() (string, []string, error) {
// Partially parse the command line arguments
fs := pflag.NewFlagSet("base", pflag.ContinueOnError)

Expand Down Expand Up @@ -221,7 +218,7 @@ func getInfoFromConfig(projectConfig config.Config) (config.Version, []string, e

// resolveFlagsAndConfigFileConflicts checks if the provided combined input from flags and
// the config file is valid and uses default values in case some info was not provided.
func (c cli) resolveFlagsAndConfigFileConflicts(
func (c CLI) resolveFlagsAndConfigFileConflicts(
flagProjectVersionString string,
cfgProjectVersion config.Version,
flagPlugins, cfgPlugins []string,
Expand Down Expand Up @@ -290,7 +287,7 @@ func (c cli) resolveFlagsAndConfigFileConflicts(
}

// getInfo obtains the project version and plugin keys resolving conflicts among flags and the project config file.
func (c *cli) getInfo() error {
func (c *CLI) getInfo() error {
// Get project version and plugin info from flags
flagProjectVersion, flagPlugins, err := c.getInfoFromFlags()
if err != nil {
Expand All @@ -312,7 +309,7 @@ const unstablePluginMsg = " (plugin version is unstable, there may be an upgrade
"https://kubebuilder.io/migration/plugin/plugins.html)"

// resolve selects from the available plugins those that match the project version and plugin keys provided.
func (c *cli) resolve() error {
func (c *CLI) resolve() error {
var plugins []plugin.Plugin
for _, pluginKey := range c.pluginKeys {
name, version := plugin.SplitKey(pluginKey)
Expand Down Expand Up @@ -402,7 +399,7 @@ func (c *cli) resolve() error {

// addSubcommands returns a root command with a subcommand tree reflecting the
// current project's state.
func (c *cli) addSubcommands() {
func (c *CLI) addSubcommands() {
// kubebuilder completion
// Only add completion if requested
if c.completionCommand {
Expand Down Expand Up @@ -432,7 +429,7 @@ func (c *cli) addSubcommands() {
}

// buildCmd creates the underlying cobra command and stores it internally.
func (c *cli) buildCmd() error {
func (c *CLI) buildCmd() error {
c.cmd = c.newRootCmd()

// Get project version and plugin keys.
Expand All @@ -452,7 +449,7 @@ func (c *cli) buildCmd() error {
}

// addExtraCommands adds the additional commands.
func (c *cli) addExtraCommands() error {
func (c *CLI) addExtraCommands() error {
for _, cmd := range c.extraCommands {
for _, subCmd := range c.cmd.Commands() {
if cmd.Name() == subCmd.Name() {
Expand All @@ -465,15 +462,17 @@ func (c *cli) addExtraCommands() error {
}

// printDeprecationWarnings prints the deprecation warnings of the resolved plugins.
func (c cli) printDeprecationWarnings() {
func (c CLI) printDeprecationWarnings() {
for _, p := range c.resolvedPlugins {
if d, isDeprecated := p.(plugin.Deprecated); isDeprecated {
fmt.Printf(noticeColor, fmt.Sprintf(deprecationFmt, d.DeprecationWarning()))
}
}
}

// Run implements CLI.Run.
func (c cli) Run() error {
// Run executes the CLI utility.
//
// If an error is found, command help and examples will be printed.
func (c CLI) Run() error {
return c.cmd.Execute()
}
Loading

0 comments on commit 4e6c400

Please sign in to comment.