diff --git a/api/client.go b/api/client.go index c7e8663ab..a5741a42e 100644 --- a/api/client.go +++ b/api/client.go @@ -3,7 +3,6 @@ package api import ( "bytes" "encoding/json" - "errors" "fmt" "io" "io/ioutil" @@ -17,10 +16,6 @@ import ( "github.com/shurcooL/graphql" ) -// The Search API returns a max of 1000 results for each search. -// (https://docs.github.com/en/rest/reference/search#about-the-search-api) -var ErrSearchAPIMaxLimit = errors.New("limit was set to >1000 but Github search API returns max 1000 results") - // ClientOption represents an argument to NewClient type ClientOption = func(http.RoundTripper) http.RoundTripper diff --git a/api/queries_issue.go b/api/queries_issue.go index d035e6ad8..d09497569 100644 --- a/api/queries_issue.go +++ b/api/queries_issue.go @@ -16,8 +16,9 @@ type IssuesPayload struct { } type IssuesAndTotalCount struct { - Issues []Issue - TotalCount int + Issues []Issue + TotalCount int + SearchCapped bool } type Issue struct { diff --git a/api/queries_pr.go b/api/queries_pr.go index 1e060b1da..388446f42 100644 --- a/api/queries_pr.go +++ b/api/queries_pr.go @@ -26,6 +26,7 @@ type PullRequestsPayload struct { type PullRequestAndTotalCount struct { TotalCount int PullRequests []PullRequest + SearchCapped bool } type PullRequest struct { diff --git a/pkg/cmd/issue/list/http.go b/pkg/cmd/issue/list/http.go index b9dac4d0d..a992b553d 100644 --- a/pkg/cmd/issue/list/http.go +++ b/pkg/cmd/issue/list/http.go @@ -126,11 +126,6 @@ loop: } res := api.IssuesAndTotalCount{Issues: issues, TotalCount: totalCount} - - if limit > 1000 { - return &res, api.ErrSearchAPIMaxLimit - } - return &res, nil } @@ -176,7 +171,7 @@ func searchIssues(client *api.Client, repo ghrepo.Interface, filters prShared.Fi "query": searchQuery, } - ic := api.IssuesAndTotalCount{} + ic := api.IssuesAndTotalCount{SearchCapped: limit > 1000} loop: for { diff --git a/pkg/cmd/issue/list/list.go b/pkg/cmd/issue/list/list.go index 2b64bc918..2db0815b4 100644 --- a/pkg/cmd/issue/list/list.go +++ b/pkg/cmd/issue/list/list.go @@ -151,9 +151,9 @@ func listRun(opts *ListOptions) error { filterOptions.Fields = opts.Exporter.Fields() } - listResult, listErr := issueList(httpClient, baseRepo, filterOptions, opts.LimitResults) - if listErr != nil && listErr != api.ErrSearchAPIMaxLimit { - return listErr + listResult, err := issueList(httpClient, baseRepo, filterOptions, opts.LimitResults) + if err != nil { + return err } err = opts.IO.StartPager() @@ -166,16 +166,12 @@ func listRun(opts *ListOptions) error { return opts.Exporter.Write(opts.IO, listResult.Issues) } + if listResult.SearchCapped { + fmt.Fprintln(opts.IO.ErrOut, "warning: this query uses the Search API which is capped at 1000 results maximum") + } if isTerminal { title := prShared.ListHeader(ghrepo.FullName(baseRepo), "issue", len(listResult.Issues), listResult.TotalCount, !filterOptions.IsDefault()) - out := fmt.Sprintf("\n%s\n", title) - - if listErr == api.ErrSearchAPIMaxLimit { - icon := opts.IO.ColorScheme().WarningIcon() - out = fmt.Sprintf("%s%s warning: %s\n", out, icon, listErr.Error()) - } - - fmt.Fprintf(opts.IO.Out, "%s\n", out) + fmt.Fprintf(opts.IO.Out, "\n%s\n\n", title) } issueShared.PrintIssues(opts.IO, "", len(listResult.Issues), listResult.Issues) diff --git a/pkg/cmd/pr/list/http.go b/pkg/cmd/pr/list/http.go index b27e14794..47cbd9d61 100644 --- a/pkg/cmd/pr/list/http.go +++ b/pkg/cmd/pr/list/http.go @@ -182,8 +182,7 @@ func searchPullRequests(httpClient *http.Client, repo ghrepo.Interface, filters "q": q.String(), } - res := api.PullRequestAndTotalCount{} - + res := api.PullRequestAndTotalCount{SearchCapped: limit > 1000} var check = make(map[int]struct{}) client := api.NewClientFromHTTP(httpClient) @@ -218,10 +217,6 @@ loop: } } - if limit > 1000 { - return &res, api.ErrSearchAPIMaxLimit - } - return &res, nil } diff --git a/pkg/cmd/pr/list/http_test.go b/pkg/cmd/pr/list/http_test.go index 2b8f3ab1e..bdb136100 100644 --- a/pkg/cmd/pr/list/http_test.go +++ b/pkg/cmd/pr/list/http_test.go @@ -144,17 +144,6 @@ func Test_listPullRequests(t *testing.T) { })) }, }, - { - name: "with labels and limit above 1000", - args: args{ - repo: ghrepo.New("OWNER", "REPO"), - limit: 2000, - filters: prShared.FilterOptions{ - Labels: []string{"hello", "one world"}, - }, - }, - wantErr: true, - }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/pkg/cmd/pr/list/list.go b/pkg/cmd/pr/list/list.go index a5446090b..dd62da726 100644 --- a/pkg/cmd/pr/list/list.go +++ b/pkg/cmd/pr/list/list.go @@ -151,9 +151,9 @@ func listRun(opts *ListOptions) error { return opts.Browser.Browse(openURL) } - listResult, listErr := listPullRequests(httpClient, baseRepo, filters, opts.LimitResults) - if listErr != nil && listErr != api.ErrSearchAPIMaxLimit { - return listErr + listResult, err := listPullRequests(httpClient, baseRepo, filters, opts.LimitResults) + if err != nil { + return err } err = opts.IO.StartPager() @@ -166,16 +166,12 @@ func listRun(opts *ListOptions) error { return opts.Exporter.Write(opts.IO, listResult.PullRequests) } + if listResult.SearchCapped { + fmt.Fprintln(opts.IO.ErrOut, "warning: this query uses the Search API which is capped at 1000 results maximum") + } if opts.IO.IsStdoutTTY() { title := shared.ListHeader(ghrepo.FullName(baseRepo), "pull request", len(listResult.PullRequests), listResult.TotalCount, !filters.IsDefault()) - out := fmt.Sprintf("\n%s\n", title) - - if listErr == api.ErrSearchAPIMaxLimit { - icon := opts.IO.ColorScheme().WarningIcon() - out = fmt.Sprintf("%s%s warning: %s\n", out, icon, listErr.Error()) - } - - fmt.Fprintln(opts.IO.Out, out) + fmt.Fprintf(opts.IO.Out, "\n%s\n\n", title) } cs := opts.IO.ColorScheme() diff --git a/pkg/cmd/repo/list/http.go b/pkg/cmd/repo/list/http.go index 0ea40e924..fa5319304 100644 --- a/pkg/cmd/repo/list/http.go +++ b/pkg/cmd/repo/list/http.go @@ -175,10 +175,6 @@ pagination: variables["endCursor"] = githubv4.String(result.Search.PageInfo.EndCursor) } - if limit > 1000 { - return &listResult, api.ErrSearchAPIMaxLimit - } - return &listResult, nil } diff --git a/pkg/cmd/repo/list/list.go b/pkg/cmd/repo/list/list.go index 089562d81..af6f505c0 100644 --- a/pkg/cmd/repo/list/list.go +++ b/pkg/cmd/repo/list/list.go @@ -130,9 +130,9 @@ func listRun(opts *ListOptions) error { return err } - listResult, listErr := listRepos(httpClient, host, opts.Limit, opts.Owner, filter) - if listErr != nil { - return listErr + listResult, err := listRepos(httpClient, host, opts.Limit, opts.Owner, filter) + if err != nil { + return err } if err := opts.IO.StartPager(); err != nil { @@ -171,17 +171,13 @@ func listRun(opts *ListOptions) error { tp.EndRow() } + if listResult.FromSearch && opts.Limit > 1000 { + fmt.Fprintln(opts.IO.ErrOut, "warning: this query uses the Search API which is capped at 1000 results maximum") + } if opts.IO.IsStdoutTTY() { hasFilters := filter.Visibility != "" || filter.Fork || filter.Source || filter.Language != "" || filter.Topic != "" title := listHeader(listResult.Owner, len(listResult.Repositories), listResult.TotalCount, hasFilters) - out := fmt.Sprintf("\n%s\n", title) - - if listErr == api.ErrSearchAPIMaxLimit { - icon := opts.IO.ColorScheme().WarningIcon() - out = fmt.Sprintf("%s%s warning: %s\n", out, icon, listErr.Error()) - } - - fmt.Fprintln(opts.IO.Out, out) + fmt.Fprintf(opts.IO.Out, "\n%s\n\n", title) } return tp.Render()