Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Upgrade Cobra for improved shell completion support #4028

Merged
merged 5 commits into from Jul 27, 2021
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
10 changes: 5 additions & 5 deletions go.mod
Expand Up @@ -13,7 +13,7 @@ require (
github.com/cpuguy83/go-md2man/v2 v2.0.0
github.com/creack/pty v1.1.13
github.com/gabriel-vasile/mimetype v1.1.2
github.com/google/go-cmp v0.5.4
github.com/google/go-cmp v0.5.5
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510
github.com/hashicorp/go-version v1.2.1
github.com/henvic/httpretty v0.0.6
Expand All @@ -28,14 +28,14 @@ require (
github.com/rivo/uniseg v0.2.0
github.com/shurcooL/githubv4 v0.0.0-20200928013246-d292edc3691b
github.com/shurcooL/graphql v0.0.0-20181231061246-d48a9a75455f
github.com/spf13/cobra v1.1.3
github.com/spf13/cobra v1.2.1
github.com/spf13/pflag v1.0.5
github.com/stretchr/testify v1.6.1
github.com/stretchr/objx v0.1.1 // indirect
github.com/stretchr/testify v1.7.0
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897
golang.org/x/sync v0.0.0-20190423024810-112230192c58
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
golang.org/x/sys v0.0.0-20210601080250-7ecdf8ef093b
golang.org/x/term v0.0.0-20210503060354-a79de5458b56
golang.org/x/text v0.3.4 // indirect
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
)

Expand Down
441 changes: 354 additions & 87 deletions go.sum

Large diffs are not rendered by default.

6 changes: 4 additions & 2 deletions pkg/cmd/completion/completion.go
Expand Up @@ -29,7 +29,9 @@ func NewCmdCompletion(io *iostreams.IOStreams) *cobra.Command {

### bash

Add this to your %[1]s~/.bash_profile%[1]s:
First, ensure that you install %[1]sbash-completion%[1]s using your package manager.

After, add this to your %[1]s~/.bash_profile%[1]s:

eval "$(gh completion -s bash)"

Expand Down Expand Up @@ -65,7 +67,7 @@ func NewCmdCompletion(io *iostreams.IOStreams) *cobra.Command {

switch shellType {
case "bash":
return rootCmd.GenBashCompletion(w)
return rootCmd.GenBashCompletionV2(w, true)
case "zsh":
return rootCmd.GenZshCompletion(w)
case "powershell":
Expand Down
2 changes: 1 addition & 1 deletion pkg/cmd/issue/list/list.go
Expand Up @@ -83,7 +83,7 @@ func NewCmdList(f *cmdutil.Factory, runF func(*ListOptions) error) *cobra.Comman
cmd.Flags().StringSliceVarP(&opts.Labels, "label", "l", nil, "Filter by labels")
cmd.Flags().StringVarP(&opts.State, "state", "s", "open", "Filter by state: {open|closed|all}")
_ = cmd.RegisterFlagCompletionFunc("state", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return []string{"open", "closed", "all"}, cobra.ShellCompDirectiveNoSpace
return []string{"open", "closed", "all"}, cobra.ShellCompDirectiveNoFileComp
})
cmd.Flags().IntVarP(&opts.LimitResults, "limit", "L", 30, "Maximum number of issues to fetch")
cmd.Flags().StringVarP(&opts.Author, "author", "A", "", "Filter by author")
Expand Down
2 changes: 1 addition & 1 deletion pkg/cmd/pr/list/list.go
Expand Up @@ -85,7 +85,7 @@ func NewCmdList(f *cmdutil.Factory, runF func(*ListOptions) error) *cobra.Comman
cmd.Flags().IntVarP(&opts.LimitResults, "limit", "L", 30, "Maximum number of items to fetch")
cmd.Flags().StringVarP(&opts.State, "state", "s", "open", "Filter by state: {open|closed|merged|all}")
_ = cmd.RegisterFlagCompletionFunc("state", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return []string{"open", "closed", "merged", "all"}, cobra.ShellCompDirectiveNoSpace
return []string{"open", "closed", "merged", "all"}, cobra.ShellCompDirectiveNoFileComp
})
cmd.Flags().StringVarP(&opts.BaseBranch, "base", "B", "", "Filter by base branch")
cmd.Flags().StringSliceVarP(&opts.Labels, "label", "l", nil, "Filter by labels")
Expand Down
57 changes: 51 additions & 6 deletions pkg/cmd/repo/create/create.go
Expand Up @@ -135,6 +135,51 @@ func NewCmdCreate(f *cmdutil.Factory, runF func(*CreateOptions) error) *cobra.Co
cmd.Flags().BoolVarP(&opts.ConfirmSubmit, "confirm", "y", false, "Skip the confirmation prompt")
cmd.Flags().StringVarP(&opts.GitIgnoreTemplate, "gitignore", "g", "", "Specify a gitignore template for the repository")
cmd.Flags().StringVarP(&opts.LicenseTemplate, "license", "l", "", "Specify an Open Source License for the repository")

_ = cmd.RegisterFlagCompletionFunc("gitignore", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
httpClient, err := opts.HttpClient()
if err != nil {
return nil, cobra.ShellCompDirectiveError
}
cfg, err := opts.Config()
if err != nil {
return nil, cobra.ShellCompDirectiveError
}
hostname, err := cfg.DefaultHost()
if err != nil {
return nil, cobra.ShellCompDirectiveError
}
results, err := listGitIgnoreTemplates(httpClient, hostname)
if err != nil {
return nil, cobra.ShellCompDirectiveError
}
return results, cobra.ShellCompDirectiveNoFileComp
})

_ = cmd.RegisterFlagCompletionFunc("license", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
httpClient, err := opts.HttpClient()
if err != nil {
return nil, cobra.ShellCompDirectiveError
}
cfg, err := opts.Config()
if err != nil {
return nil, cobra.ShellCompDirectiveError
}
hostname, err := cfg.DefaultHost()
if err != nil {
return nil, cobra.ShellCompDirectiveError
}
licenses, err := listLicenseTemplates(httpClient, hostname)
if err != nil {
return nil, cobra.ShellCompDirectiveError
}
var results []string
for _, license := range licenses {
results = append(results, fmt.Sprintf("%s\t%s", license.Key, license.Name))
}
return results, cobra.ShellCompDirectiveNoFileComp
})

return cmd
}

Expand Down Expand Up @@ -225,14 +270,14 @@ func createRun(opts *CreateOptions) error {
// is passed, or when the confirm flag is set.
if opts.Template == "" && opts.IO.CanPrompt() && !opts.ConfirmSubmit {
if gitIgnoreTemplate == "" {
gt, err := interactiveGitIgnore(api.NewClientFromHTTP(httpClient), host)
gt, err := interactiveGitIgnore(httpClient, host)
if err != nil {
return err
}
gitIgnoreTemplate = gt
}
if repoLicenseTemplate == "" {
lt, err := interactiveLicense(api.NewClientFromHTTP(httpClient), host)
lt, err := interactiveLicense(httpClient, host)
if err != nil {
return err
}
Expand Down Expand Up @@ -384,7 +429,7 @@ func createRun(opts *CreateOptions) error {
return nil
}

func interactiveGitIgnore(client *api.Client, hostname string) (string, error) {
func interactiveGitIgnore(client *http.Client, hostname string) (string, error) {

var addGitIgnore bool
var addGitIgnoreSurvey []*survey.Question
Expand All @@ -408,7 +453,7 @@ func interactiveGitIgnore(client *api.Client, hostname string) (string, error) {
if addGitIgnore {
var gitIg []*survey.Question

gitIgnoretemplates, err := ListGitIgnoreTemplates(client, hostname)
gitIgnoretemplates, err := listGitIgnoreTemplates(client, hostname)
if err != nil {
return "", err
}
Expand All @@ -429,7 +474,7 @@ func interactiveGitIgnore(client *api.Client, hostname string) (string, error) {
return wantedIgnoreTemplate, nil
}

func interactiveLicense(client *api.Client, hostname string) (string, error) {
func interactiveLicense(client *http.Client, hostname string) (string, error) {
var addLicense bool
var addLicenseSurvey []*survey.Question
var wantedLicense string
Expand All @@ -451,7 +496,7 @@ func interactiveLicense(client *api.Client, hostname string) (string, error) {
licenseKey := map[string]string{}

if addLicense {
licenseTemplates, err := ListLicenseTemplates(client, hostname)
licenseTemplates, err := listLicenseTemplates(client, hostname)
if err != nil {
return "", err
}
Expand Down
10 changes: 6 additions & 4 deletions pkg/cmd/repo/create/http.go
Expand Up @@ -230,19 +230,21 @@ func resolveOrganizationTeam(client *api.Client, hostname, orgName, teamSlug str
return &response, err
}

// ListGitIgnoreTemplates uses API v3 here because gitignore template isn't supported by GraphQL yet.
func ListGitIgnoreTemplates(client *api.Client, hostname string) ([]string, error) {
// listGitIgnoreTemplates uses API v3 here because gitignore template isn't supported by GraphQL yet.
func listGitIgnoreTemplates(httpClient *http.Client, hostname string) ([]string, error) {
var gitIgnoreTemplates []string
client := api.NewClientFromHTTP(httpClient)
err := client.REST(hostname, "GET", "gitignore/templates", nil, &gitIgnoreTemplates)
if err != nil {
return []string{}, err
}
return gitIgnoreTemplates, nil
}

// ListLicenseTemplates uses API v3 here because license template isn't supported by GraphQL yet.
func ListLicenseTemplates(client *api.Client, hostname string) ([]api.License, error) {
// listLicenseTemplates uses API v3 here because license template isn't supported by GraphQL yet.
func listLicenseTemplates(httpClient *http.Client, hostname string) ([]api.License, error) {
var licenseTemplates []api.License
client := api.NewClientFromHTTP(httpClient)
err := client.REST(hostname, "GET", "licenses", nil, &licenseTemplates)
if err != nil {
return nil, err
Expand Down
6 changes: 4 additions & 2 deletions pkg/cmdutil/json_flags.go
Expand Up @@ -29,13 +29,15 @@ func AddJSONFlags(cmd *cobra.Command, exportTarget *Exporter, fields []string) {

_ = cmd.RegisterFlagCompletionFunc("json", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
var results []string
if idx := strings.IndexRune(toComplete, ','); idx >= 0 {
var prefix string
if idx := strings.LastIndexByte(toComplete, ','); idx >= 0 {
prefix = toComplete[:idx+1]
toComplete = toComplete[idx+1:]
}
toComplete = strings.ToLower(toComplete)
for _, f := range fields {
if strings.HasPrefix(strings.ToLower(f), toComplete) {
results = append(results, f)
results = append(results, prefix+f)
}
}
sort.Strings(results)
Expand Down