Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions cmd/completion/completion.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package completion

import (
"morpherctl/internal/completion"

"github.com/spf13/cobra"
)

var CompletionCmd = &cobra.Command{
Use: "completion [bash|zsh|fish|powershell]",
Short: "Generate shell completion script",
Long: `Generate shell completion script for morpherctl.

The completion script supports bash, zsh, fish, and powershell.
To load completions in your current shell session:

Bash:
$ source <(morpherctl completion bash)

Zsh:
$ source <(morpherctl completion zsh)

Fish:
$ morpherctl completion fish | source

PowerShell:
PS> morpherctl completion powershell | Out-String | Invoke-Expression

To load completions for every new session, write to a file and source in your shell's config file e.g. ~/.bashrc or ~/.zshrc.`,
ValidArgs: completion.GetSupportedShells(),
Args: cobra.MatchAll(cobra.ExactArgs(1), cobra.OnlyValidArgs),
RunE: func(cmd *cobra.Command, args []string) error {
shell := args[0]
return completion.GenerateCompletion(cmd, shell)
},
}
2 changes: 2 additions & 0 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (

"github.com/spf13/cobra"

"morpherctl/cmd/completion"
"morpherctl/cmd/config"
"morpherctl/cmd/controller"
"morpherctl/cmd/version"
Expand All @@ -31,4 +32,5 @@ func init() {
rootCmd.AddCommand(version.VersionCmd)
rootCmd.AddCommand(config.ConfigCmd)
rootCmd.AddCommand(controller.ControllerCmd)
rootCmd.AddCommand(completion.CompletionCmd)
}
44 changes: 44 additions & 0 deletions internal/completion/completion.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package completion

import (
"fmt"
"os"

"github.com/spf13/cobra"
)

// GenerateCompletion generates shell completion script for the given shell.
func GenerateCompletion(cmd *cobra.Command, shell string) error {
switch shell {
case "bash":
if err := cmd.Root().GenBashCompletion(os.Stdout); err != nil {
return fmt.Errorf("failed to generate bash completion: %w", err)
}
return nil
case "zsh":
if err := cmd.Root().GenZshCompletion(os.Stdout); err != nil {
return fmt.Errorf("failed to generate zsh completion: %w", err)
}
return nil
case "fish":
if err := cmd.Root().GenFishCompletion(os.Stdout, true); err != nil {
return fmt.Errorf("failed to generate fish completion: %w", err)
}
return nil
case "powershell":
if err := cmd.Root().GenPowerShellCompletion(os.Stdout); err != nil {
return fmt.Errorf("failed to generate powershell completion: %w", err)
}
return nil
default:
if err := cmd.Help(); err != nil {
return fmt.Errorf("failed to display help: %w", err)
}
return nil
}
}

// GetSupportedShells returns the list of supported shell types.
func GetSupportedShells() []string {
return []string{"bash", "zsh", "fish", "powershell"}
}
65 changes: 65 additions & 0 deletions internal/completion/completion_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package completion

import (
"testing"

"github.com/spf13/cobra"
"github.com/stretchr/testify/assert"
)

func TestGenerateCompletion(t *testing.T) {
// Create a root command for testing.
rootCmd := &cobra.Command{Use: "test"}
rootCmd.AddCommand(&cobra.Command{Use: "subcommand"})

tests := []struct {
name string
shell string
expectError bool
}{
{
name: "bash completion",
shell: "bash",
expectError: false,
},
{
name: "zsh completion",
shell: "zsh",
expectError: false,
},
{
name: "fish completion",
shell: "fish",
expectError: false,
},
{
name: "powershell completion",
shell: "powershell",
expectError: false,
},
{
name: "invalid shell",
shell: "invalid",
expectError: false, // Help() doesn't return an error.
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := GenerateCompletion(rootCmd, tt.shell)
if tt.expectError {
assert.Error(t, err)
} else {
assert.NoError(t, err)
}
})
}
}

func TestGetSupportedShells(t *testing.T) {
shells := GetSupportedShells()
expectedShells := []string{"bash", "zsh", "fish", "powershell"}

assert.ElementsMatch(t, expectedShells, shells)
assert.Len(t, shells, 4)
}
Loading