Skip to content

Commit d933cd9

Browse files
committed
Migrate completion command
1 parent dbbf76d commit d933cd9

5 files changed

Lines changed: 142 additions & 122 deletions

File tree

command/completion.go

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

command/completion_test.go

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

command/root.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ func init() {
4343
cmdFactory := factory.New(Version)
4444
RootCmd = root.NewCmdRoot(cmdFactory, Version, BuildDate)
4545
RootCmd.AddCommand(aliasCmd)
46-
RootCmd.AddCommand(completionCmd)
46+
RootCmd.AddCommand(root.NewCmdCompletion(cmdFactory.IOStreams))
4747
RootCmd.AddCommand(configCmd)
4848
}
4949

pkg/cmd/root/completion.go

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
package root
2+
3+
import (
4+
"errors"
5+
"fmt"
6+
7+
"github.com/MakeNowJust/heredoc"
8+
"github.com/cli/cli/pkg/cmdutil"
9+
"github.com/cli/cli/pkg/iostreams"
10+
"github.com/spf13/cobra"
11+
)
12+
13+
func NewCmdCompletion(io *iostreams.IOStreams) *cobra.Command {
14+
var shellType string
15+
16+
cmd := &cobra.Command{
17+
Use: "completion",
18+
Short: "Generate shell completion scripts",
19+
Long: heredoc.Doc(`
20+
Generate shell completion scripts for GitHub CLI commands.
21+
22+
The output of this command will be computer code and is meant to be saved to a
23+
file or immediately evaluated by an interactive shell.
24+
25+
For example, for bash you could add this to your '~/.bash_profile':
26+
27+
eval "$(gh completion -s bash)"
28+
29+
When installing GitHub CLI through a package manager, however, it's possible that
30+
no additional shell configuration is necessary to gain completion support. For
31+
Homebrew, see https://docs.brew.sh/Shell-Completion
32+
`),
33+
RunE: func(cmd *cobra.Command, args []string) error {
34+
if shellType == "" {
35+
if io.IsStdoutTTY() {
36+
return &cmdutil.FlagError{Err: errors.New("error: the value for `--shell` is required")}
37+
}
38+
shellType = "bash"
39+
}
40+
41+
w := io.Out
42+
rootCmd := cmd.Parent()
43+
44+
switch shellType {
45+
case "bash":
46+
return rootCmd.GenBashCompletion(w)
47+
case "zsh":
48+
return rootCmd.GenZshCompletion(w)
49+
case "powershell":
50+
return rootCmd.GenPowerShellCompletion(w)
51+
case "fish":
52+
return rootCmd.GenFishCompletion(w, true)
53+
default:
54+
return fmt.Errorf("unsupported shell type %q", shellType)
55+
}
56+
},
57+
}
58+
59+
cmd.Flags().StringVarP(&shellType, "shell", "s", "", "Shell type: {bash|zsh|fish|powershell}")
60+
61+
return cmd
62+
}

pkg/cmd/root/completion_test.go

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
package root
2+
3+
import (
4+
"strings"
5+
"testing"
6+
7+
"github.com/cli/cli/pkg/iostreams"
8+
"github.com/google/shlex"
9+
"github.com/spf13/cobra"
10+
)
11+
12+
func TestNewCmdCompletion(t *testing.T) {
13+
tests := []struct {
14+
name string
15+
args string
16+
wantOut string
17+
wantErr string
18+
}{
19+
{
20+
name: "no arguments",
21+
args: "completion",
22+
wantOut: "complete -o default -F __start_gh gh",
23+
},
24+
{
25+
name: "zsh completion",
26+
args: "completion -s zsh",
27+
wantOut: "#compdef _gh gh",
28+
},
29+
{
30+
name: "fish completion",
31+
args: "completion -s fish",
32+
wantOut: "complete -c gh ",
33+
},
34+
{
35+
name: "PowerShell completion",
36+
args: "completion -s powershell",
37+
wantOut: "Register-ArgumentCompleter",
38+
},
39+
{
40+
name: "unsupported shell",
41+
args: "completion -s csh",
42+
wantErr: "unsupported shell type \"csh\"",
43+
},
44+
}
45+
for _, tt := range tests {
46+
t.Run(tt.name, func(t *testing.T) {
47+
io, _, stdout, stderr := iostreams.Test()
48+
completeCmd := NewCmdCompletion(io)
49+
rootCmd := &cobra.Command{Use: "gh"}
50+
rootCmd.AddCommand(completeCmd)
51+
52+
argv, err := shlex.Split(tt.args)
53+
if err != nil {
54+
t.Fatalf("argument splitting error: %v", err)
55+
}
56+
rootCmd.SetArgs(argv)
57+
rootCmd.SetOut(stdout)
58+
rootCmd.SetErr(stderr)
59+
60+
_, err = rootCmd.ExecuteC()
61+
if tt.wantErr != "" {
62+
if err == nil || err.Error() != tt.wantErr {
63+
t.Fatalf("expected error %q, got %q", tt.wantErr, err)
64+
}
65+
return
66+
}
67+
if err != nil {
68+
t.Fatalf("error executing command: %v", err)
69+
}
70+
71+
if !strings.Contains(stdout.String(), tt.wantOut) {
72+
t.Errorf("completion output did not match:\n%s", stdout.String())
73+
}
74+
if len(stderr.String()) > 0 {
75+
t.Errorf("expected nothing on stderr, got %q", stderr.String())
76+
}
77+
})
78+
}
79+
}

0 commit comments

Comments
 (0)