Enable issue list pagination

Makes it possible to set a `--limit` greater than 100.
This commit is contained in:
Mislav Marohnić 2020-02-24 22:11:09 +01:00
parent c60ccf9a16
commit ad0dedd1ac
2 changed files with 108 additions and 13 deletions

View file

@ -185,20 +185,23 @@ func IssueList(client *Client, repo ghrepo.Interface, state string, labels []str
}
query := fragments + `
query($owner: String!, $repo: String!, $limit: Int, $states: [IssueState!] = OPEN, $labels: [String!], $assignee: String) {
query($owner: String!, $repo: String!, $limit: Int, $endCursor: String, $states: [IssueState!] = OPEN, $labels: [String!], $assignee: String) {
repository(owner: $owner, name: $repo) {
hasIssuesEnabled
issues(first: $limit, orderBy: {field: CREATED_AT, direction: DESC}, states: $states, labels: $labels, filterBy: {assignee: $assignee}) {
issues(first: $limit, after: $endCursor, orderBy: {field: CREATED_AT, direction: DESC}, states: $states, labels: $labels, filterBy: {assignee: $assignee}) {
nodes {
...issue
}
pageInfo {
hasNextPage
endCursor
}
}
}
}
`
variables := map[string]interface{}{
"limit": limit,
"owner": repo.RepoOwner(),
"repo": repo.RepoName(),
"states": states,
@ -210,25 +213,49 @@ func IssueList(client *Client, repo ghrepo.Interface, state string, labels []str
variables["assignee"] = assigneeString
}
var resp struct {
var response struct {
Repository struct {
Issues struct {
Nodes []Issue
Nodes []Issue
PageInfo struct {
HasNextPage bool
EndCursor string
}
}
HasIssuesEnabled bool
}
}
err := client.GraphQL(query, variables, &resp)
if err != nil {
return nil, err
var issues []Issue
pageLimit := min(limit, 100)
loop:
for {
variables["limit"] = pageLimit
err := client.GraphQL(query, variables, &response)
if err != nil {
return nil, err
}
if !response.Repository.HasIssuesEnabled {
return nil, fmt.Errorf("the '%s' repository has disabled issues", ghrepo.FullName(repo))
}
for _, issue := range response.Repository.Issues.Nodes {
issues = append(issues, issue)
if len(issues) == limit {
break loop
}
}
if response.Repository.Issues.PageInfo.HasNextPage {
variables["endCursor"] = response.Repository.Issues.PageInfo.EndCursor
pageLimit = min(pageLimit, limit-len(issues))
} else {
break
}
}
if !resp.Repository.HasIssuesEnabled {
return nil, fmt.Errorf("the '%s' repository has disabled issues", ghrepo.FullName(repo))
}
return resp.Repository.Issues.Nodes, nil
return issues, nil
}
func IssueByNumber(client *Client, repo ghrepo.Interface, number int) (*Issue, error) {

68
api/queries_issue_test.go Normal file
View file

@ -0,0 +1,68 @@
package api
import (
"bytes"
"encoding/json"
"io/ioutil"
"testing"
"github.com/cli/cli/internal/ghrepo"
)
func TestIssueList(t *testing.T) {
http := &FakeHTTP{}
client := NewClient(ReplaceTripper(http))
http.StubResponse(200, bytes.NewBufferString(`
{ "data": { "repository": {
"hasIssuesEnabled": true,
"issues": {
"nodes": [],
"pageInfo": {
"hasNextPage": true,
"endCursor": "ENDCURSOR"
}
}
} } }
`))
http.StubResponse(200, bytes.NewBufferString(`
{ "data": { "repository": {
"hasIssuesEnabled": true,
"issues": {
"nodes": [],
"pageInfo": {
"hasNextPage": false,
"endCursor": "ENDCURSOR"
}
}
} } }
`))
_, err := IssueList(client, ghrepo.FromFullName("OWNER/REPO"), "open", []string{}, "", 251)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if len(http.Requests) != 2 {
t.Fatalf("expected 2 HTTP requests, seen %d", len(http.Requests))
}
var reqBody struct {
Query string
Variables map[string]interface{}
}
bodyBytes, _ := ioutil.ReadAll(http.Requests[0].Body)
json.Unmarshal(bodyBytes, &reqBody)
if reqLimit := reqBody.Variables["limit"].(float64); reqLimit != 100 {
t.Errorf("expected 100, got %v", reqLimit)
}
if _, cursorPresent := reqBody.Variables["endCursor"]; cursorPresent {
t.Error("did not expect first request to pass 'endCursor'")
}
bodyBytes, _ = ioutil.ReadAll(http.Requests[1].Body)
json.Unmarshal(bodyBytes, &reqBody)
if endCursor := reqBody.Variables["endCursor"].(string); endCursor != "ENDCURSOR" {
t.Errorf("expected %q, got %q", "ENDCURSOR", endCursor)
}
}