Wrap relationship JSON output in {nodes, totalCount}, fetch full pages
The subIssues, blockedBy, and blocking JSON output is currently shaped
as a flat array, which silently truncates when there are more entries
than the GraphQL fragment fetches. That's misleading once a user
crosses the page size, so this switches each connection to a
{nodes, totalCount} object so consumers can see when there's more.
While confirming page sizes, the GitHub limits turn out to be:
- sub-issues: up to 100 per parent
https://docs.github.com/en/issues/tracking-your-work-with-issues/using-issues/adding-sub-issues
- blocked-by / blocking: up to 50 per relationship type
https://github.blog/changelog/2025-08-21-dependencies-on-issues/
So subIssues moves to first:100 to fetch the full set; blockedBy and
blocking stay at first:50, which already covers their cap.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
parent
20105edbcb
commit
a78bedb772
4 changed files with 39 additions and 15 deletions
|
|
@ -71,7 +71,10 @@ func (issue *Issue) ExportData(fields []string) map[string]interface{} {
|
|||
"state": n.State,
|
||||
})
|
||||
}
|
||||
data[f] = items
|
||||
data[f] = map[string]interface{}{
|
||||
"nodes": items,
|
||||
"totalCount": issue.SubIssues.TotalCount,
|
||||
}
|
||||
case "subIssuesSummary":
|
||||
data[f] = map[string]interface{}{
|
||||
"total": issue.SubIssuesSummary.Total,
|
||||
|
|
@ -89,7 +92,10 @@ func (issue *Issue) ExportData(fields []string) map[string]interface{} {
|
|||
"state": n.State,
|
||||
})
|
||||
}
|
||||
data[f] = items
|
||||
data[f] = map[string]interface{}{
|
||||
"nodes": items,
|
||||
"totalCount": issue.BlockedBy.TotalCount,
|
||||
}
|
||||
case "blocking":
|
||||
items := make([]map[string]interface{}, 0, len(issue.Blocking.Nodes))
|
||||
for _, n := range issue.Blocking.Nodes {
|
||||
|
|
@ -101,7 +107,10 @@ func (issue *Issue) ExportData(fields []string) map[string]interface{} {
|
|||
"state": n.State,
|
||||
})
|
||||
}
|
||||
data[f] = items
|
||||
data[f] = map[string]interface{}{
|
||||
"nodes": items,
|
||||
"totalCount": issue.Blocking.TotalCount,
|
||||
}
|
||||
default:
|
||||
sf := fieldByName(v, f)
|
||||
data[f] = sf.Interface()
|
||||
|
|
|
|||
|
|
@ -91,7 +91,8 @@ type SubIssuesSummary struct {
|
|||
|
||||
// LinkedIssueConnection is a connection of related issues (blocked-by or blocking).
|
||||
type LinkedIssueConnection struct {
|
||||
Nodes []LinkedIssue `json:"nodes"`
|
||||
Nodes []LinkedIssue `json:"nodes"`
|
||||
TotalCount int `json:"totalCount"`
|
||||
}
|
||||
|
||||
type ClosedByPullRequestsReferences struct {
|
||||
|
|
|
|||
|
|
@ -447,13 +447,13 @@ func IssueGraphQL(fields []string) string {
|
|||
case "parent":
|
||||
q = append(q, `parent{id,number,title,url,state,repository{nameWithOwner}}`)
|
||||
case "subIssues":
|
||||
q = append(q, `subIssues(first:50){nodes{id,number,title,url,state,repository{nameWithOwner}},totalCount}`)
|
||||
q = append(q, `subIssues(first:100){nodes{id,number,title,url,state,repository{nameWithOwner}},totalCount}`)
|
||||
case "subIssuesSummary":
|
||||
q = append(q, `subIssuesSummary{total,completed,percentCompleted}`)
|
||||
case "blockedBy":
|
||||
q = append(q, `blockedBy(first:50){nodes{id,number,title,url,state,repository{nameWithOwner}}}`)
|
||||
q = append(q, `blockedBy(first:50){nodes{id,number,title,url,state,repository{nameWithOwner}},totalCount}`)
|
||||
case "blocking":
|
||||
q = append(q, `blocking(first:50){nodes{id,number,title,url,state,repository{nameWithOwner}}}`)
|
||||
q = append(q, `blocking(first:50){nodes{id,number,title,url,state,repository{nameWithOwner}},totalCount}`)
|
||||
default:
|
||||
q = append(q, field)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -674,10 +674,12 @@ func issueResponseAllIssues2Fields() string {
|
|||
},
|
||||
"subIssuesSummary": {"total":2,"completed":1,"percentCompleted":50.0},
|
||||
"blockedBy": {
|
||||
"nodes": [{"number":200,"title":"API rate limiting","url":"https://github.com/OWNER/REPO/issues/200","state":"OPEN","repository":{"nameWithOwner":"OWNER/REPO"}}]
|
||||
"nodes": [{"number":200,"title":"API rate limiting","url":"https://github.com/OWNER/REPO/issues/200","state":"OPEN","repository":{"nameWithOwner":"OWNER/REPO"}}],
|
||||
"totalCount": 1
|
||||
},
|
||||
"blocking": {
|
||||
"nodes": [{"number":300,"title":"Release v2.0","url":"https://github.com/OWNER/REPO/issues/300","state":"OPEN","repository":{"nameWithOwner":"OWNER/REPO"}}]
|
||||
"nodes": [{"number":300,"title":"Release v2.0","url":"https://github.com/OWNER/REPO/issues/300","state":"OPEN","repository":{"nameWithOwner":"OWNER/REPO"}}],
|
||||
"totalCount": 1
|
||||
}
|
||||
} } } }`
|
||||
}
|
||||
|
|
@ -878,8 +880,12 @@ func TestIssueView_json_ParentSubIssues(t *testing.T) {
|
|||
assert.Equal(t, "OPEN", parent["state"])
|
||||
|
||||
// Sub-issues
|
||||
subIssues, ok := data["subIssues"].([]interface{})
|
||||
require.True(t, ok, "subIssues should be an array")
|
||||
subIssuesObj, ok := data["subIssues"].(map[string]interface{})
|
||||
require.True(t, ok, "subIssues should be an object")
|
||||
assert.Equal(t, float64(2), subIssuesObj["totalCount"])
|
||||
|
||||
subIssues, ok := subIssuesObj["nodes"].([]interface{})
|
||||
require.True(t, ok, "subIssues.nodes should be an array")
|
||||
require.Len(t, subIssues, 2)
|
||||
|
||||
sub0 := subIssues[0].(map[string]interface{})
|
||||
|
|
@ -916,8 +922,12 @@ func TestIssueView_json_BlockedByBlocking(t *testing.T) {
|
|||
require.NoError(t, json.Unmarshal(output.OutBuf.Bytes(), &data))
|
||||
|
||||
// Blocked by
|
||||
blockedBy, ok := data["blockedBy"].([]interface{})
|
||||
require.True(t, ok, "blockedBy should be an array")
|
||||
blockedByObj, ok := data["blockedBy"].(map[string]interface{})
|
||||
require.True(t, ok, "blockedBy should be an object")
|
||||
assert.Equal(t, float64(1), blockedByObj["totalCount"])
|
||||
|
||||
blockedBy, ok := blockedByObj["nodes"].([]interface{})
|
||||
require.True(t, ok, "blockedBy.nodes should be an array")
|
||||
require.Len(t, blockedBy, 1)
|
||||
|
||||
blocked0 := blockedBy[0].(map[string]interface{})
|
||||
|
|
@ -927,8 +937,12 @@ func TestIssueView_json_BlockedByBlocking(t *testing.T) {
|
|||
assert.Equal(t, "OPEN", blocked0["state"])
|
||||
|
||||
// Blocking
|
||||
blocking, ok := data["blocking"].([]interface{})
|
||||
require.True(t, ok, "blocking should be an array")
|
||||
blockingObj, ok := data["blocking"].(map[string]interface{})
|
||||
require.True(t, ok, "blocking should be an object")
|
||||
assert.Equal(t, float64(1), blockingObj["totalCount"])
|
||||
|
||||
blocking, ok := blockingObj["nodes"].([]interface{})
|
||||
require.True(t, ok, "blocking.nodes should be an array")
|
||||
require.Len(t, blocking, 1)
|
||||
|
||||
blocking0 := blocking[0].(map[string]interface{})
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue