Skip to content

Commit fdb87df

Browse files
authored
Merge pull request #2089 from Adirio/extra-alpha-commands
✨ Provide third-party devs the option to provide their own alpha subcommands
2 parents e9caa6e + bca394b commit fdb87df

File tree

4 files changed

+65
-2
lines changed

4 files changed

+65
-2
lines changed

pkg/cli/alpha.go

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,19 +17,24 @@ limitations under the License.
1717
package cli
1818

1919
import (
20+
"fmt"
2021
"strings"
2122

2223
"github.com/spf13/cobra"
2324
configgen "sigs.k8s.io/kubebuilder/v3/pkg/cli/alpha/config-gen"
2425
)
2526

27+
const (
28+
alphaCommand = "alpha"
29+
)
30+
2631
var alphaCommands = []*cobra.Command{
2732
configgen.NewCommand(),
2833
}
2934

3035
func (c *CLI) newAlphaCmd() *cobra.Command {
3136
alpha := &cobra.Command{
32-
Use: "alpha",
37+
Use: alphaCommand,
3338
SuggestFor: []string{"experimental"},
3439
Short: "Alpha kubebuilder subcommands",
3540
Long: strings.TrimSpace(`
@@ -46,7 +51,31 @@ Alpha kubebuilder commands are for unstable features.
4651
}
4752

4853
func (c *CLI) addAlphaCmd() {
49-
if len(alphaCommands) > 0 {
54+
if (len(alphaCommands) + len(c.extraAlphaCommands)) > 0 {
5055
c.cmd.AddCommand(c.newAlphaCmd())
5156
}
5257
}
58+
59+
func (c *CLI) addExtraAlphaCommands() error {
60+
// Search for the alpha subcommand
61+
var alpha *cobra.Command
62+
for _, subCmd := range c.cmd.Commands() {
63+
if subCmd.Name() == alphaCommand {
64+
alpha = subCmd
65+
break
66+
}
67+
}
68+
if alpha == nil {
69+
return fmt.Errorf("no %q command found", alphaCommand)
70+
}
71+
72+
for _, cmd := range c.extraAlphaCommands {
73+
for _, subCmd := range alpha.Commands() {
74+
if cmd.Name() == subCmd.Name() {
75+
return fmt.Errorf("command %q already exists", fmt.Sprintf("%s %s", alphaCommand, cmd.Name()))
76+
}
77+
}
78+
c.cmd.AddCommand(cmd)
79+
}
80+
return nil
81+
}

pkg/cli/cli.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,8 @@ type CLI struct { //nolint:maligned
7676
plugins map[string]plugin.Plugin
7777
// Commands injected by options.
7878
extraCommands []*cobra.Command
79+
// Alpha commands injected by options.
80+
extraAlphaCommands []*cobra.Command
7981
// Whether to add a completion command to the CLI.
8082
completionCommand bool
8183

@@ -122,6 +124,11 @@ func New(options ...Option) (*CLI, error) {
122124
return nil, err
123125
}
124126

127+
// Add extra alpha commands injected by options.
128+
if err := c.addExtraAlphaCommands(); err != nil {
129+
return nil, err
130+
}
131+
125132
// Write deprecation notices after all commands have been constructed.
126133
c.printDeprecationWarnings()
127134

pkg/cli/options.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,18 @@ func WithExtraCommands(cmds ...*cobra.Command) Option {
112112
}
113113
}
114114

115+
// WithExtraAlphaCommands is an Option that adds extra alpha subcommands to the CLI.
116+
//
117+
// Adding extra alpha commands that duplicate existing commands results in an error.
118+
func WithExtraAlphaCommands(cmds ...*cobra.Command) Option {
119+
return func(c *CLI) error {
120+
// We don't know the commands defined by the CLI yet so we are not checking if the extra alpha commands
121+
// conflict with a pre-existing one yet. We do this after creating the base commands.
122+
c.extraAlphaCommands = append(c.extraAlphaCommands, cmds...)
123+
return nil
124+
}
125+
}
126+
115127
// WithCompletion is an Option that adds the completion subcommand.
116128
func WithCompletion() Option {
117129
return func(c *CLI) error {

pkg/cli/options_test.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,21 @@ var _ = Describe("CLI options", func() {
221221
})
222222
})
223223

224+
Context("WithExtraAlphaCommands", func() {
225+
It("should return a valid CLI with extra alpha commands", func() {
226+
commandTest := &cobra.Command{
227+
Use: "example",
228+
}
229+
c, err = newCLI(WithExtraAlphaCommands(commandTest))
230+
Expect(err).NotTo(HaveOccurred())
231+
Expect(c).NotTo(BeNil())
232+
Expect(c.extraAlphaCommands).NotTo(BeNil())
233+
Expect(len(c.extraAlphaCommands)).To(Equal(1))
234+
Expect(c.extraAlphaCommands[0]).NotTo(BeNil())
235+
Expect(c.extraAlphaCommands[0].Use).To(Equal(commandTest.Use))
236+
})
237+
})
238+
224239
Context("WithCompletion", func() {
225240
It("should not add the completion command by default", func() {
226241
c, err = newCLI()

0 commit comments

Comments
 (0)