Skip to content

Commit 0489c99

Browse files
authored
Merge pull request #1776 from Adirio/completion-cmd
✨ Provide a cli option to enable and disable completion command
2 parents 5ff9d7d + 15aa5ad commit 0489c99

File tree

6 files changed

+142
-74
lines changed

6 files changed

+142
-74
lines changed

cmd/completion.go

Lines changed: 0 additions & 72 deletions
This file was deleted.

cmd/main.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,9 @@ func main() {
3535
&pluginv2.Plugin{},
3636
),
3737
cli.WithExtraCommands(
38-
newCompletionCmd(),
3938
version.NewCmd(),
4039
),
40+
cli.WithCompletion,
4141
)
4242
if err != nil {
4343
log.Fatal(err)

docs/book/src/reference/completion.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# Enabling shell autocompletion
2-
The Kubebuilder completion script for Bash can be generated with the command `kubebuilder completion bash` as the Kubebuilder completion script for Zsh can be generated with the command `kubebuilder completion zsh`.
2+
The Kubebuilder completion script can be generated with the command `kubebuilder completion [bash|zsh|powershell]`.
33
Note that sourcing the completion script in your shell enables Kubebuilder autocompletion.
44

55
<aside class="note">

pkg/cli/cli.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,9 @@ type cli struct {
6666
// Whether the command is requesting help.
6767
doGenericHelp bool
6868

69+
// Whether to add a completion command to the cli
70+
completionCommand bool
71+
6972
// Plugins injected by options.
7073
pluginsFromOptions map[string][]plugin.Base
7174
// Default plugins injected by options. Only one plugin per project version
@@ -173,6 +176,12 @@ func WithExtraCommands(cmds ...*cobra.Command) Option {
173176
}
174177
}
175178

179+
// WithCompletion is an Option that adds the completion subcommand.
180+
func WithCompletion(c *cli) error {
181+
c.completionCommand = true
182+
return nil
183+
}
184+
176185
// initialize initializes the cli.
177186
func (c *cli) initialize() error {
178187
// Initialize cli with globally-relevant flags or flags that determine
@@ -345,6 +354,12 @@ func (c cli) buildRootCmd() *cobra.Command {
345354
rootCmd.AddCommand(alphaCmd)
346355
}
347356

357+
// kubebuilder completion
358+
// Only add completion if requested
359+
if c.completionCommand {
360+
rootCmd.AddCommand(c.newCompletionCmd())
361+
}
362+
348363
// kubebuilder create
349364
createCmd := c.newCreateCmd()
350365
// kubebuilder create api

pkg/cli/cli_test.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,23 @@ var _ = Describe("CLI", func() {
244244
Expect(c.(*cli).extraCommands[0].Use).To(Equal(commandTest.Use))
245245
})
246246
})
247+
248+
Context("WithCompletion", func() {
249+
It("should add the completion command if requested", func() {
250+
By("not providing WithCompletion")
251+
c, err = New(WithDefaultPlugins(pluginAV1), WithPlugins(allPlugins...))
252+
Expect(err).NotTo(HaveOccurred())
253+
Expect(c).NotTo(BeNil())
254+
Expect(c.(*cli).completionCommand).To(BeFalse())
255+
256+
By("providing WithCompletion")
257+
c, err = New(WithCompletion, WithDefaultPlugins(pluginAV1), WithPlugins(allPlugins...))
258+
Expect(err).NotTo(HaveOccurred())
259+
Expect(c).NotTo(BeNil())
260+
Expect(c.(*cli).completionCommand).To(BeTrue())
261+
})
262+
})
263+
247264
})
248265

249266
})

pkg/cli/completion.go

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
/*
2+
Copyright 2020 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package cli
18+
19+
import (
20+
"fmt"
21+
"os"
22+
23+
"github.com/spf13/cobra"
24+
)
25+
26+
func (c *cli) newBashCmd() *cobra.Command {
27+
return &cobra.Command{
28+
Use: "bash",
29+
Short: "Load bash completions",
30+
Example: fmt.Sprintf(`# To load completion for this session, execute:
31+
$ source <(%[1]s completion bash)
32+
33+
# To load completions for each session, execute once:
34+
Linux:
35+
$ %[1]s completion bash > /etc/bash_completion.d/%[1]s
36+
MacOS:
37+
$ %[1]s completion bash > /usr/local/etc/bash_completion.d/%[1]s
38+
`, c.commandName),
39+
RunE: func(cmd *cobra.Command, cmdArgs []string) error {
40+
return cmd.Root().GenBashCompletion(os.Stdout)
41+
},
42+
}
43+
}
44+
45+
func (c *cli) newZshCmd() *cobra.Command {
46+
return &cobra.Command{
47+
Use: "zsh",
48+
Short: "Load zsh completions",
49+
Example: fmt.Sprintf(`# If shell completion is not already enabled in your environment you will need
50+
# to enable it. You can execute the following once:
51+
$ echo "autoload -U compinit; compinit" >> ~/.zshrc
52+
53+
# To load completions for each session, execute once:
54+
$ %[1]s completion zsh > "${fpath[1]}/_%[1]s"
55+
56+
# You will need to start a new shell for this setup to take effect.
57+
`, c.commandName),
58+
RunE: func(cmd *cobra.Command, cmdArgs []string) error {
59+
return cmd.Root().GenZshCompletion(os.Stdout)
60+
},
61+
}
62+
}
63+
64+
/* TODO: support fish code completion
65+
At the time this comment is written, the imported spf13.cobra version does not support fish completion.
66+
However, fish completion has been added to new spf13.cobra versions. When a new spf13.cobra version that
67+
supports it is used, uncomment this command and add it to the base completion command.
68+
func (c *cli) newFishCmd() *cobra.Command {
69+
return &cobra.Command{
70+
Use: "fish",
71+
Short: "Load fish completions",
72+
Example: fmt.Sprintf(`# To load completion for this session, execute:
73+
$ %[1]s completion fish | source
74+
75+
# To load completions for each session, execute once:
76+
$ %[1]s completion fish > ~/.config/fish/completions/%[1]s.fish`, c.commandName),
77+
RunE: func(cmd *cobra.Command, cmdArgs []string) error {
78+
return cmd.Root().GenFishCompletion(os.Stdout)
79+
},
80+
}
81+
}
82+
*/
83+
84+
func (c *cli) newPowerShellCmd() *cobra.Command {
85+
return &cobra.Command{
86+
Use: "powershell",
87+
Short: "Load powershell completions",
88+
RunE: func(cmd *cobra.Command, cmdArgs []string) error {
89+
return cmd.Root().GenPowerShellCompletion(os.Stdout)
90+
},
91+
}
92+
}
93+
94+
func (c *cli) newCompletionCmd() *cobra.Command {
95+
cmd := &cobra.Command{
96+
Use: "completion",
97+
Short: "Load completions for the specified shell",
98+
Long: fmt.Sprintf(`Output shell completion code for the specified shell.
99+
The shell code must be evaluated to provide interactive completion of %[1]s commands.
100+
Detailed instructions on how to do this for each shell are provided in their own commands.
101+
`, c.commandName),
102+
}
103+
cmd.AddCommand(c.newBashCmd())
104+
cmd.AddCommand(c.newZshCmd())
105+
// cmd.AddCommand(c.newFishCmd()) // TODO: uncomment when adding fish completion
106+
cmd.AddCommand(c.newPowerShellCmd())
107+
return cmd
108+
}

0 commit comments

Comments
 (0)