Skip to content

Commit 8266268

Browse files
bchadwicmislav
andauthored
Autocomplete branch flags (cli#6031)
Co-authored-by: Mislav Marohnić <mislav@github.com>
1 parent 3b23978 commit 8266268

File tree

13 files changed

+72
-1
lines changed

13 files changed

+72
-1
lines changed

git/client.go

+29
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,22 @@ func (c *Client) HasLocalBranch(ctx context.Context, branch string) bool {
354354
return err == nil
355355
}
356356

357+
func (c *Client) TrackingBranchNames(ctx context.Context, prefix string) []string {
358+
args := []string{"branch", "-r", "--format", "%(refname:strip=3)"}
359+
if prefix != "" {
360+
args = append(args, "--list", fmt.Sprintf("*/%s*", escapeGlob(prefix)))
361+
}
362+
cmd, err := c.Command(ctx, args...)
363+
if err != nil {
364+
return nil
365+
}
366+
output, err := cmd.Output()
367+
if err != nil {
368+
return nil
369+
}
370+
return strings.Split(string(output), "\n")
371+
}
372+
357373
// ToplevelDir returns the top-level directory path of the current repository.
358374
func (c *Client) ToplevelDir(ctx context.Context) (string, error) {
359375
out, err := c.revParse(ctx, "--show-toplevel")
@@ -623,3 +639,16 @@ func populateResolvedRemotes(remotes RemoteSet, resolved []string) {
623639
}
624640
}
625641
}
642+
643+
var globReplacer = strings.NewReplacer(
644+
"*", `\*`,
645+
"?", `\?`,
646+
"[", `\[`,
647+
"]", `\]`,
648+
"{", `\{`,
649+
"}", `\}`,
650+
)
651+
652+
func escapeGlob(p string) string {
653+
return globReplacer.Replace(p)
654+
}

pkg/cmd/browse/browse.go

+2
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,8 @@ func NewCmdBrowse(f *cmdutil.Factory, runF func(*BrowseOptions) error) *cobra.Co
144144
cmd.Flags().StringVarP(&opts.Commit, "commit", "c", "", "Select another commit by passing in the commit SHA, default is the last commit")
145145
cmd.Flags().StringVarP(&opts.Branch, "branch", "b", "", "Select another branch by passing in the branch name")
146146

147+
_ = cmdutil.RegisterBranchCompletionFlags(f.GitClient, cmd, "branch")
148+
147149
// Preserve backwards compatibility for when commit flag used to be a boolean flag.
148150
cmd.Flags().Lookup("commit").NoOptDefVal = emptyCommitFlag
149151

pkg/cmd/pr/create/create.go

+2
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,8 @@ func NewCmdCreate(f *cmdutil.Factory, runF func(*CreateOptions) error) *cobra.Co
189189
fl.StringVar(&opts.RecoverFile, "recover", "", "Recover input from a failed run of create")
190190
fl.StringVarP(&opts.Template, "template", "T", "", "Template `file` to use as starting body text")
191191

192+
_ = cmdutil.RegisterBranchCompletionFlags(f.GitClient, cmd, "base", "head")
193+
192194
_ = cmd.RegisterFlagCompletionFunc("reviewer", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
193195
results, err := requestableReviewersForCompletion(opts)
194196
if err != nil {

pkg/cmd/pr/edit/edit.go

+2
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,8 @@ func NewCmdEdit(f *cmdutil.Factory, runF func(*EditOptions) error) *cobra.Comman
148148
cmd.Flags().StringSliceVar(&opts.Editable.Projects.Remove, "remove-project", nil, "Remove the pull request from projects by `name`")
149149
cmd.Flags().StringVarP(&opts.Editable.Milestone.Value, "milestone", "m", "", "Edit the milestone the pull request belongs to by `name`")
150150

151+
_ = cmdutil.RegisterBranchCompletionFlags(f.GitClient, cmd, "base")
152+
151153
for _, flagName := range []string{"add-reviewer", "remove-reviewer"} {
152154
_ = cmd.RegisterFlagCompletionFunc(flagName, func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
153155
baseRepo, err := f.BaseRepo()

pkg/cmd/pr/list/list.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -109,9 +109,10 @@ func NewCmdList(f *cmdutil.Factory, runF func(*ListOptions) error) *cobra.Comman
109109
cmd.Flags().StringVarP(&opts.Assignee, "assignee", "a", "", "Filter by assignee")
110110
cmd.Flags().StringVarP(&opts.Search, "search", "S", "", "Search pull requests with `query`")
111111
cmdutil.NilBoolFlag(cmd, &opts.Draft, "draft", "d", "Filter by draft state")
112-
113112
cmdutil.AddJSONFlags(cmd, &opts.Exporter, api.PullRequestFields)
114113

114+
_ = cmdutil.RegisterBranchCompletionFlags(f.GitClient, cmd, "base", "head")
115+
115116
return cmd
116117
}
117118

pkg/cmd/release/create/create.go

+2
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,8 @@ func NewCmdCreate(f *cmdutil.Factory, runF func(*CreateOptions) error) *cobra.Co
177177
cmdutil.NilBoolFlag(cmd, &opts.IsLatest, "latest", "", "Mark this release as \"Latest\" (default: automatic based on date and version)")
178178
cmd.Flags().BoolVarP(&opts.VerifyTag, "verify-tag", "", false, "Abort in case the git tag doesn't already exist in the remote repository")
179179

180+
_ = cmdutil.RegisterBranchCompletionFlags(f.GitClient, cmd, "target")
181+
180182
return cmd
181183
}
182184

pkg/cmd/release/edit/edit.go

+2
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,8 @@ func NewCmdEdit(f *cmdutil.Factory, runF func(*EditOptions) error) *cobra.Comman
8282
cmd.Flags().StringVar(&opts.TagName, "tag", "", "The name of the tag")
8383
cmd.Flags().StringVarP(&notesFile, "notes-file", "F", "", "Read release notes from `file` (use \"-\" to read from standard input)")
8484

85+
_ = cmdutil.RegisterBranchCompletionFlags(f.GitClient, cmd, "target")
86+
8587
return cmd
8688
}
8789

pkg/cmd/repo/view/view.go

+2
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,8 @@ With '--branch', view a specific branch of the repository.`,
6868
cmd.Flags().StringVarP(&opts.Branch, "branch", "b", "", "View a specific branch of the repository")
6969
cmdutil.AddJSONFlags(cmd, &opts.Exporter, api.RepositoryFields)
7070

71+
_ = cmdutil.RegisterBranchCompletionFlags(f.GitClient, cmd, "branch")
72+
7173
return cmd
7274
}
7375

pkg/cmd/run/list/list.go

+2
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,8 @@ func NewCmdList(f *cmdutil.Factory, runF func(*ListOptions) error) *cobra.Comman
6969
cmd.Flags().StringVarP(&opts.Actor, "user", "u", "", "Filter runs by user who triggered the run")
7070
cmdutil.AddJSONFlags(cmd, &opts.Exporter, shared.RunFields)
7171

72+
_ = cmdutil.RegisterBranchCompletionFlags(f.GitClient, cmd, "branch")
73+
7274
return cmd
7375
}
7476

pkg/cmd/search/prs/prs.go

+2
Original file line numberDiff line numberDiff line change
@@ -184,5 +184,7 @@ func NewCmdPrs(f *cmdutil.Factory, runF func(*shared.IssuesOptions) error) *cobr
184184
cmd.Flags().StringVar(&opts.Query.Qualifiers.ReviewedBy, "reviewed-by", "", "Filter on `user` who reviewed")
185185
cmdutil.StringEnumFlag(cmd, &opts.Query.Qualifiers.Status, "checks", "", "", []string{"pending", "success", "failure"}, "Filter based on status of the checks")
186186

187+
_ = cmdutil.RegisterBranchCompletionFlags(f.GitClient, cmd, "base", "head")
188+
187189
return cmd
188190
}

pkg/cmd/workflow/run/run.go

+2
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,8 @@ func NewCmdRun(f *cmdutil.Factory, runF func(*RunOptions) error) *cobra.Command
128128
cmd.Flags().StringArrayVarP(&opts.RawFields, "raw-field", "f", nil, "Add a string parameter in `key=value` format")
129129
cmd.Flags().BoolVar(&opts.JSON, "json", false, "Read workflow inputs as JSON via STDIN")
130130

131+
_ = cmdutil.RegisterBranchCompletionFlags(f.GitClient, cmd, "ref")
132+
131133
return cmd
132134
}
133135

pkg/cmd/workflow/view/view.go

+2
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,8 @@ func NewCmdView(f *cmdutil.Factory, runF func(*ViewOptions) error) *cobra.Comman
8585
cmd.Flags().BoolVarP(&opts.YAML, "yaml", "y", false, "View the workflow yaml file")
8686
cmd.Flags().StringVarP(&opts.Ref, "ref", "r", "", "The branch or tag name which contains the version of the workflow file you'd like to view")
8787

88+
_ = cmdutil.RegisterBranchCompletionFlags(f.GitClient, cmd, "ref")
89+
8890
return cmd
8991
}
9092

pkg/cmdutil/flags.go

+21
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package cmdutil
22

33
import (
4+
"context"
45
"fmt"
56
"strconv"
67
"strings"
@@ -44,6 +45,26 @@ func StringSliceEnumFlag(cmd *cobra.Command, p *[]string, name, shorthand string
4445
return f
4546
}
4647

48+
type gitClient interface {
49+
TrackingBranchNames(context.Context, string) []string
50+
}
51+
52+
// RegisterBranchCompletionFlags suggests and autocompletes known remote git branches for flags passed
53+
func RegisterBranchCompletionFlags(gitc gitClient, cmd *cobra.Command, flags ...string) error {
54+
for _, flag := range flags {
55+
err := cmd.RegisterFlagCompletionFunc(flag, func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
56+
if repoFlag := cmd.Flag("repo"); repoFlag != nil && repoFlag.Changed {
57+
return nil, cobra.ShellCompDirectiveNoFileComp
58+
}
59+
return gitc.TrackingBranchNames(context.TODO(), toComplete), cobra.ShellCompDirectiveNoFileComp
60+
})
61+
if err != nil {
62+
return err
63+
}
64+
}
65+
return nil
66+
}
67+
4768
func formatValuesForUsageDocs(values []string) string {
4869
return fmt.Sprintf("{%s}", strings.Join(values, "|"))
4970
}

0 commit comments

Comments
 (0)