Merge pull request #4316 from SiarheiFedartsou/sf-pulls-draft

Add `--draft` and `--non-draft` filters to `gh pr list`
This commit is contained in:
Sam 2021-09-20 12:07:52 -07:00 committed by GitHub
commit 02ed5a9666
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 131 additions and 27 deletions

View file

@ -10,8 +10,12 @@ import (
"github.com/cli/cli/v2/pkg/githubsearch" "github.com/cli/cli/v2/pkg/githubsearch"
) )
func shouldUseSearch(filters prShared.FilterOptions) bool {
return filters.Draft != "" || filters.Author != "" || filters.Assignee != "" || filters.Search != "" || len(filters.Labels) > 0
}
func listPullRequests(httpClient *http.Client, repo ghrepo.Interface, filters prShared.FilterOptions, limit int) (*api.PullRequestAndTotalCount, error) { func listPullRequests(httpClient *http.Client, repo ghrepo.Interface, filters prShared.FilterOptions, limit int) (*api.PullRequestAndTotalCount, error) {
if filters.Author != "" || filters.Assignee != "" || filters.Search != "" || len(filters.Labels) > 0 { if shouldUseSearch(filters) {
return searchPullRequests(httpClient, repo, filters, limit) return searchPullRequests(httpClient, repo, filters, limit)
} }
@ -177,6 +181,10 @@ func searchPullRequests(httpClient *http.Client, repo ghrepo.Interface, filters
q.SetBaseBranch(filters.BaseBranch) q.SetBaseBranch(filters.BaseBranch)
} }
if filters.Draft != "" {
q.SetDraft(filters.Draft)
}
pageLimit := min(limit, 100) pageLimit := min(limit, 100)
variables := map[string]interface{}{ variables := map[string]interface{}{
"q": q.String(), "q": q.String(),

View file

@ -37,6 +37,7 @@ type ListOptions struct {
Author string Author string
Assignee string Assignee string
Search string Search string
Draft string
} }
func NewCmdList(f *cmdutil.Factory, runF func(*ListOptions) error) *cobra.Command { func NewCmdList(f *cmdutil.Factory, runF func(*ListOptions) error) *cobra.Command {
@ -46,6 +47,8 @@ func NewCmdList(f *cmdutil.Factory, runF func(*ListOptions) error) *cobra.Comman
Browser: f.Browser, Browser: f.Browser,
} }
var draft bool
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "list", Use: "list",
Short: "List and filter pull requests in this repository", Short: "List and filter pull requests in this repository",
@ -74,6 +77,10 @@ func NewCmdList(f *cmdutil.Factory, runF func(*ListOptions) error) *cobra.Comman
return &cmdutil.FlagError{Err: fmt.Errorf("invalid value for --limit: %v", opts.LimitResults)} return &cmdutil.FlagError{Err: fmt.Errorf("invalid value for --limit: %v", opts.LimitResults)}
} }
if cmd.Flags().Changed("draft") {
opts.Draft = strconv.FormatBool(draft)
}
if runF != nil { if runF != nil {
return runF(opts) return runF(opts)
} }
@ -92,6 +99,8 @@ func NewCmdList(f *cmdutil.Factory, runF func(*ListOptions) error) *cobra.Comman
cmd.Flags().StringVarP(&opts.Author, "author", "A", "", "Filter by author") cmd.Flags().StringVarP(&opts.Author, "author", "A", "", "Filter by author")
cmd.Flags().StringVarP(&opts.Assignee, "assignee", "a", "", "Filter by assignee") cmd.Flags().StringVarP(&opts.Assignee, "assignee", "a", "", "Filter by assignee")
cmd.Flags().StringVarP(&opts.Search, "search", "S", "", "Search pull requests with `query`") cmd.Flags().StringVarP(&opts.Search, "search", "S", "", "Search pull requests with `query`")
cmd.Flags().BoolVarP(&draft, "draft", "d", false, "Filter by draft state")
cmdutil.AddJSONFlags(cmd, &opts.Exporter, api.PullRequestFields) cmdutil.AddJSONFlags(cmd, &opts.Exporter, api.PullRequestFields)
return cmd return cmd
@ -132,12 +141,12 @@ func listRun(opts *ListOptions) error {
Labels: opts.Labels, Labels: opts.Labels,
BaseBranch: opts.BaseBranch, BaseBranch: opts.BaseBranch,
Search: opts.Search, Search: opts.Search,
Draft: opts.Draft,
Fields: defaultFields, Fields: defaultFields,
} }
if opts.Exporter != nil { if opts.Exporter != nil {
filters.Fields = opts.Exporter.Fields() filters.Fields = opts.Exporter.Fields()
} }
if opts.WebMode { if opts.WebMode {
prListURL := ghrepo.GenerateRepoURL(baseRepo, "pulls") prListURL := ghrepo.GenerateRepoURL(baseRepo, "pulls")
openURL, err := shared.ListURLWithQuery(prListURL, filters) openURL, err := shared.ListURLWithQuery(prListURL, filters)

View file

@ -176,39 +176,89 @@ func TestPRList_filteringAssignee(t *testing.T) {
} }
} }
func TestPRList_filteringAssigneeLabels(t *testing.T) { func TestPRList_filteringDraft(t *testing.T) {
http := initFakeHTTP() tests := []struct {
defer http.Verify(t) name string
cli string
expectedQuery string
}{
{
name: "draft",
cli: "--draft",
expectedQuery: `repo:OWNER/REPO is:pr is:open draft:true`,
},
{
name: "non-draft",
cli: "--draft=false",
expectedQuery: `repo:OWNER/REPO is:pr is:open draft:false`,
},
}
_, err := runCommand(http, true, `-l one,two -a hubot`) for _, test := range tests {
if err == nil && err.Error() != "multiple labels with --assignee are not supported" { t.Run(test.name, func(t *testing.T) {
t.Fatal(err) http := initFakeHTTP()
defer http.Verify(t)
http.Register(
httpmock.GraphQL(`query PullRequestSearch\b`),
httpmock.GraphQLQuery(`{}`, func(_ string, params map[string]interface{}) {
assert.Equal(t, test.expectedQuery, params["q"].(string))
}))
_, err := runCommand(http, true, test.cli)
if err != nil {
t.Fatal(err)
}
})
} }
} }
func TestPRList_withInvalidLimitFlag(t *testing.T) { func TestPRList_withInvalidLimitFlag(t *testing.T) {
http := initFakeHTTP() http := initFakeHTTP()
defer http.Verify(t) defer http.Verify(t)
_, err := runCommand(http, true, `--limit=0`) _, err := runCommand(http, true, `--limit=0`)
if err == nil && err.Error() != "invalid limit: 0" { assert.EqualError(t, err, "invalid value for --limit: 0")
t.Errorf("error running command `issue list`: %v", err)
}
} }
func TestPRList_web(t *testing.T) { func TestPRList_web(t *testing.T) {
http := initFakeHTTP() tests := []struct {
defer http.Verify(t) name string
cli string
_, cmdTeardown := run.Stub() expectedBrowserURL string
defer cmdTeardown(t) }{
{
output, err := runCommand(http, true, "--web -a peter -l bug -l docs -L 10 -s merged -B trunk") name: "filters",
if err != nil { cli: "-a peter -l bug -l docs -L 10 -s merged -B trunk",
t.Errorf("error running command `pr list` with `--web` flag: %v", err) expectedBrowserURL: "https://github.com/OWNER/REPO/pulls?q=is%3Apr+is%3Amerged+assignee%3Apeter+label%3Abug+label%3Adocs+base%3Atrunk",
},
{
name: "draft",
cli: "--draft=true",
expectedBrowserURL: "https://github.com/OWNER/REPO/pulls?q=is%3Apr+is%3Aopen+draft%3Atrue",
},
{
name: "non-draft",
cli: "--draft=0",
expectedBrowserURL: "https://github.com/OWNER/REPO/pulls?q=is%3Apr+is%3Aopen+draft%3Afalse",
},
} }
assert.Equal(t, "", output.String()) for _, test := range tests {
assert.Equal(t, "Opening github.com/OWNER/REPO/pulls in your browser.\n", output.Stderr()) t.Run(test.name, func(t *testing.T) {
assert.Equal(t, "https://github.com/OWNER/REPO/pulls?q=is%3Apr+is%3Amerged+assignee%3Apeter+label%3Abug+label%3Adocs+base%3Atrunk", output.BrowsedURL) http := initFakeHTTP()
defer http.Verify(t)
_, cmdTeardown := run.Stub()
defer cmdTeardown(t)
output, err := runCommand(http, true, "--web "+test.cli)
if err != nil {
t.Errorf("error running command `pr list` with `--web` flag: %v", err)
}
assert.Equal(t, "", output.String())
assert.Equal(t, "Opening github.com/OWNER/REPO/pulls in your browser.\n", output.Stderr())
assert.Equal(t, test.expectedBrowserURL, output.BrowsedURL)
})
}
} }

View file

@ -157,8 +157,8 @@ type FilterOptions struct {
Mention string Mention string
Milestone string Milestone string
Search string Search string
Draft string
Fields []string Fields []string
} }
func (opts *FilterOptions) IsDefault() bool { func (opts *FilterOptions) IsDefault() bool {
@ -241,7 +241,9 @@ func SearchQueryBuild(options FilterOptions) string {
if options.Search != "" { if options.Search != "" {
q.AddQuery(options.Search) q.AddQuery(options.Search)
} }
if options.Draft != "" {
q.SetDraft(options.Draft)
}
return q.String() return q.String()
} }

View file

@ -16,6 +16,7 @@ func Test_listURLWithQuery(t *testing.T) {
listURL string listURL string
options FilterOptions options FilterOptions
} }
tests := []struct { tests := []struct {
name string name string
args args args args
@ -34,6 +35,32 @@ func Test_listURLWithQuery(t *testing.T) {
want: "https://example.com/path?a=b&q=is%3Aissue+is%3Aopen", want: "https://example.com/path?a=b&q=is%3Aissue+is%3Aopen",
wantErr: false, wantErr: false,
}, },
{
name: "draft",
args: args{
listURL: "https://example.com/path",
options: FilterOptions{
Entity: "pr",
State: "open",
Draft: "true",
},
},
want: "https://example.com/path?q=is%3Apr+is%3Aopen+draft%3Atrue",
wantErr: false,
},
{
name: "non-draft",
args: args{
listURL: "https://example.com/path",
options: FilterOptions{
Entity: "pr",
State: "open",
Draft: "false",
},
},
want: "https://example.com/path?q=is%3Apr+is%3Aopen+draft%3Afalse",
wantErr: false,
},
{ {
name: "all", name: "all",
args: args{ args: args{

View file

@ -54,6 +54,7 @@ type Query struct {
forkState string forkState string
visibility string visibility string
isArchived *bool isArchived *bool
draft string
} }
func (q *Query) InRepository(nameWithOwner string) { func (q *Query) InRepository(nameWithOwner string) {
@ -139,6 +140,10 @@ func (q *Query) SetArchived(isArchived bool) {
q.isArchived = &isArchived q.isArchived = &isArchived
} }
func (q *Query) SetDraft(draft string) {
q.draft = draft
}
func (q *Query) String() string { func (q *Query) String() string {
var qs string var qs string
@ -198,6 +203,9 @@ func (q *Query) String() string {
if q.headBranch != "" { if q.headBranch != "" {
qs += fmt.Sprintf("head:%s ", quote(q.headBranch)) qs += fmt.Sprintf("head:%s ", quote(q.headBranch))
} }
if q.draft != "" {
qs += fmt.Sprintf("draft:%v ", q.draft)
}
if q.sort != "" { if q.sort != "" {
qs += fmt.Sprintf("sort:%s ", q.sort) qs += fmt.Sprintf("sort:%s ", q.sort)