Skip to content

Commit 48d06e5

Browse files
committed
feat(completion): Implement completion commands
1 parent b4c379a commit 48d06e5

File tree

4 files changed

+147
-0
lines changed

4 files changed

+147
-0
lines changed

cmd/completion/completion.go

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package completion
2+
3+
import (
4+
"morpherctl/internal/completion"
5+
6+
"github.com/spf13/cobra"
7+
)
8+
9+
var CompletionCmd = &cobra.Command{
10+
Use: "completion [bash|zsh|fish|powershell]",
11+
Short: "Generate shell completion script",
12+
Long: `Generate shell completion script for morpherctl.
13+
14+
The completion script supports bash, zsh, fish, and powershell.
15+
To load completions in your current shell session:
16+
17+
Bash:
18+
$ source <(morpherctl completion bash)
19+
20+
Zsh:
21+
$ source <(morpherctl completion zsh)
22+
23+
Fish:
24+
$ morpherctl completion fish | source
25+
26+
PowerShell:
27+
PS> morpherctl completion powershell | Out-String | Invoke-Expression
28+
29+
To load completions for every new session, write to a file and source in your shell's config file e.g. ~/.bashrc or ~/.zshrc.`,
30+
ValidArgs: completion.GetSupportedShells(),
31+
Args: cobra.MatchAll(cobra.ExactArgs(1), cobra.OnlyValidArgs),
32+
RunE: func(cmd *cobra.Command, args []string) error {
33+
shell := args[0]
34+
return completion.GenerateCompletion(cmd, shell)
35+
},
36+
}

cmd/root.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55

66
"github.com/spf13/cobra"
77

8+
"morpherctl/cmd/completion"
89
"morpherctl/cmd/config"
910
"morpherctl/cmd/controller"
1011
"morpherctl/cmd/version"
@@ -31,4 +32,5 @@ func init() {
3132
rootCmd.AddCommand(version.VersionCmd)
3233
rootCmd.AddCommand(config.ConfigCmd)
3334
rootCmd.AddCommand(controller.ControllerCmd)
35+
rootCmd.AddCommand(completion.CompletionCmd)
3436
}

internal/completion/completion.go

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package completion
2+
3+
import (
4+
"fmt"
5+
"os"
6+
7+
"github.com/spf13/cobra"
8+
)
9+
10+
// GenerateCompletion generates shell completion script for the given shell.
11+
func GenerateCompletion(cmd *cobra.Command, shell string) error {
12+
switch shell {
13+
case "bash":
14+
if err := cmd.Root().GenBashCompletion(os.Stdout); err != nil {
15+
return fmt.Errorf("failed to generate bash completion: %w", err)
16+
}
17+
return nil
18+
case "zsh":
19+
if err := cmd.Root().GenZshCompletion(os.Stdout); err != nil {
20+
return fmt.Errorf("failed to generate zsh completion: %w", err)
21+
}
22+
return nil
23+
case "fish":
24+
if err := cmd.Root().GenFishCompletion(os.Stdout, true); err != nil {
25+
return fmt.Errorf("failed to generate fish completion: %w", err)
26+
}
27+
return nil
28+
case "powershell":
29+
if err := cmd.Root().GenPowerShellCompletion(os.Stdout); err != nil {
30+
return fmt.Errorf("failed to generate powershell completion: %w", err)
31+
}
32+
return nil
33+
default:
34+
if err := cmd.Help(); err != nil {
35+
return fmt.Errorf("failed to display help: %w", err)
36+
}
37+
return nil
38+
}
39+
}
40+
41+
// GetSupportedShells returns the list of supported shell types.
42+
func GetSupportedShells() []string {
43+
return []string{"bash", "zsh", "fish", "powershell"}
44+
}
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
package completion
2+
3+
import (
4+
"testing"
5+
6+
"github.com/spf13/cobra"
7+
"github.com/stretchr/testify/assert"
8+
)
9+
10+
func TestGenerateCompletion(t *testing.T) {
11+
// Create a root command for testing.
12+
rootCmd := &cobra.Command{Use: "test"}
13+
rootCmd.AddCommand(&cobra.Command{Use: "subcommand"})
14+
15+
tests := []struct {
16+
name string
17+
shell string
18+
expectError bool
19+
}{
20+
{
21+
name: "bash completion",
22+
shell: "bash",
23+
expectError: false,
24+
},
25+
{
26+
name: "zsh completion",
27+
shell: "zsh",
28+
expectError: false,
29+
},
30+
{
31+
name: "fish completion",
32+
shell: "fish",
33+
expectError: false,
34+
},
35+
{
36+
name: "powershell completion",
37+
shell: "powershell",
38+
expectError: false,
39+
},
40+
{
41+
name: "invalid shell",
42+
shell: "invalid",
43+
expectError: false, // Help() doesn't return an error.
44+
},
45+
}
46+
47+
for _, tt := range tests {
48+
t.Run(tt.name, func(t *testing.T) {
49+
err := GenerateCompletion(rootCmd, tt.shell)
50+
if tt.expectError {
51+
assert.Error(t, err)
52+
} else {
53+
assert.NoError(t, err)
54+
}
55+
})
56+
}
57+
}
58+
59+
func TestGetSupportedShells(t *testing.T) {
60+
shells := GetSupportedShells()
61+
expectedShells := []string{"bash", "zsh", "fish", "powershell"}
62+
63+
assert.ElementsMatch(t, expectedShells, shells)
64+
assert.Len(t, shells, 4)
65+
}

0 commit comments

Comments
 (0)