diff --git a/src/sweep/prs.ts b/src/sweep/prs.ts index 77980ad..c3095d8 100644 --- a/src/sweep/prs.ts +++ b/src/sweep/prs.ts @@ -29,15 +29,29 @@ const PR_LIST_LIMIT = 500 const ListedPr = Pr.omit({ baseRefOid: true }) const RestPull = z.object({ number: z.number(), base: z.object({ sha: z.string() }) }) +const REST_PAGE = 100 + // `gh pr list --json` on Ubuntu's 2.45 gh has headRefOid but not baseRefOid — unknown field → empty // stdout, which the sweep used to log as "auth/network down". Pull base SHAs from REST instead. +// Page by hand, NOT `--paginate`: gh follows GitHub's Link header verbatim, and that header names +// api.github.com — so behind an exe.dev GH_HOST proxy, page 2 escapes the proxy, goes out unauthenticated, +// and 404s the whole call. Only a repo with >100 open PRs ever has a page 2 (bevyl, 5 days of dead sweeps). function pullBaseOids(slug: string): Map | null { - const r = exec('gh', ['api', `repos/${slug}/pulls?state=open&per_page=100`, '--paginate']) - if (!r.ok) { - return null + const bases = new Map() + for (let page = 1; ; page++) { + const r = exec('gh', ['api', `repos/${slug}/pulls?state=open&per_page=${REST_PAGE}&page=${page}`]) + if (!r.ok) { + log(`gh api pulls failed — aborting sweep: ${r.combined.trim().split('\n')[0] ?? 'unknown error'}`) + return null + } + const pulls = z.array(RestPull).parse(JSON.parse(r.stdout)) + for (const p of pulls) { + bases.set(p.number, p.base.sha) + } + if (pulls.length < REST_PAGE) { + return bases + } } - const pulls = z.array(RestPull).parse(JSON.parse(r.stdout)) - return new Map(pulls.map((p) => [p.number, p.base.sha])) } export function listPrs(cfg: Config): Pr[] | null { @@ -62,7 +76,6 @@ export function listPrs(cfg: Config): Pr[] | null { const listed = z.array(ListedPr).parse(JSON.parse(r.stdout)) const bases = pullBaseOids(cfg.slug) if (bases === null) { - log('gh api pulls failed (auth/network down?) — aborting sweep') return null } const out: Pr[] = []