fix(tools-pr): chunk stats fetch through cursor-paginated GraphQL (#1285)

`fetchOpenPrs` was reading the stats chunk via
`gh pr list --limit 1000 --json mergeStateStatus,...`. With the default
limit raised to 1000 in #1259, this 502s reliably on the live open
queue (107 PRs): GitHub's GraphQL gateway has to recompute
mergeStateStatus for every PR up front, and the resulting query exceeds
the gateway budget once the requested page passes ~60 PRs.

Switch the stats chunk to `fetchPaginatedPrList`, the same cursor-
paginated GraphQL helper that already drives reviews / comments /
commits / assignment-timelines. Page size stays at PR_LIST_PAGE_SIZE
(30), well within the gateway budget, and the heavy stats fetch is now
consistent with the other heavy chunks.

Verified locally: `pnpm tools-pr list` now completes against the live
107-PR queue without a 502.
This commit is contained in:
PerishFire 2026-05-11 20:51:29 +08:00 committed by GitHub
parent be77dc0394
commit c3d41c7d45
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -193,6 +193,29 @@ async function fetchPaginatedPrList<N>(nodeFields: string): Promise<N[]> {
* the other heavy chunks (reviews, comments, assignment timelines).
*/
/**
* Per-PR merge/diff stats `additions`, `mergeStateStatus`, etc. `gh pr
* list --json mergeStateStatus,...` 502s once the requested page is
* above ~60 because the gateway has to recompute merge state for every
* PR up front. Cursor-paginated GraphQL at PR_LIST_PAGE_SIZE keeps each
* round trip well within the budget and consistent with how the other
* heavy chunks (reviews, comments, commits, assignment timelines) are
* fetched.
*/
async function fetchOpenPrStats(): Promise<GhStats[]> {
return fetchPaginatedPrList<GhStats>(
`number
additions
deletions
changedFiles
headRefName
headRefOid
baseRefName
mergeable
mergeStateStatus`,
);
}
async function fetchOpenPrReviews(): Promise<GhReviewsLite[]> {
type Node = {
number: number;
@ -424,11 +447,7 @@ export async function fetchOpenPrs(
"--json",
"number,title,author,createdAt,updatedAt,isDraft,reviewDecision,labels,maintainerCanModify,assignees",
]);
const statsPromise = gh<GhStats[]>([
...baseArgs,
"--json",
"number,additions,deletions,changedFiles,headRefName,headRefOid,baseRefName,mergeable,mergeStateStatus",
]);
const statsPromise = fetchOpenPrStats();
const filesPromise = gh<GhFiles[]>([...baseArgs, "--json", "number,files"]);
const reviewsPromise = fetchOpenPrReviews();
const commitsPromise = options.includeCommits