From dc85cdbe01c1c958f7a5ef963395c0dbdf3d7da1 Mon Sep 17 00:00:00 2001 From: Harsh Batheja <40922251+harsh-batheja@users.noreply.github.com> Date: Thu, 12 Mar 2026 21:00:52 +0530 Subject: [PATCH] fix: fetch automated PR comments via explicit GET pagination (#447) --- packages/plugins/scm-github/src/index.ts | 39 ++++++++++++---- .../plugins/scm-github/test/index.test.ts | 45 +++++++++++++++++++ 2 files changed, 75 insertions(+), 9 deletions(-) diff --git a/packages/plugins/scm-github/src/index.ts b/packages/plugins/scm-github/src/index.ts index f57860cd0..60782ca3b 100644 --- a/packages/plugins/scm-github/src/index.ts +++ b/packages/plugins/scm-github/src/index.ts @@ -860,14 +860,7 @@ function createGitHubSCM(): SCM { async getAutomatedComments(pr: PRInfo): Promise { try { - // Fetch all review comments with max page size (100 is GitHub's limit) - const raw = await gh([ - "api", - "-F", - "per_page=100", - `repos/${repoFlag(pr)}/pulls/${pr.number}/comments`, - ]); - + const perPage = 100; const comments: Array<{ id: number; user: { login: string }; @@ -877,7 +870,35 @@ function createGitHubSCM(): SCM { original_line: number | null; created_at: string; html_url: string; - }> = JSON.parse(raw); + }> = []; + + for (let page = 1; ; page++) { + const raw = await gh([ + "api", + "--method", + "GET", + `repos/${repoFlag(pr)}/pulls/${pr.number}/comments?per_page=${perPage}&page=${page}`, + ]); + const pageComments: Array<{ + id: number; + user: { login: string }; + body: string; + path: string; + line: number | null; + original_line: number | null; + created_at: string; + html_url: string; + }> = JSON.parse(raw); + + if (pageComments.length === 0) { + break; + } + + comments.push(...pageComments); + if (pageComments.length < perPage) { + break; + } + } return comments .filter((c) => BOT_AUTHORS.has(c.user?.login ?? "")) diff --git a/packages/plugins/scm-github/test/index.test.ts b/packages/plugins/scm-github/test/index.test.ts index c910cffed..873c1b7a8 100644 --- a/packages/plugins/scm-github/test/index.test.ts +++ b/packages/plugins/scm-github/test/index.test.ts @@ -908,6 +908,51 @@ describe("scm-github plugin", () => { // ---- getAutomatedComments ---------------------------------------------- describe("getAutomatedComments", () => { + it("uses explicit GET query for pulls comments and paginates", async () => { + const page1 = Array.from({ length: 100 }, (_, i) => ({ + id: i + 1, + user: { login: "cursor[bot]" }, + body: "Potential issue detected", + path: "a.ts", + line: i + 1, + original_line: null, + created_at: "2025-01-01T00:00:00Z", + html_url: `u${i + 1}`, + })); + + const page2 = [ + { + id: 101, + user: { login: "cursor[bot]" }, + body: "Warning: check this", + path: "b.ts", + line: 7, + original_line: null, + created_at: "2025-01-01T00:00:00Z", + html_url: "u101", + }, + ]; + + mockGh(page1); + mockGh(page2); + + const comments = await scm.getAutomatedComments(pr); + + expect(comments).toHaveLength(101); + expect(ghMock).toHaveBeenNthCalledWith( + 1, + "gh", + ["api", "--method", "GET", "repos/acme/repo/pulls/42/comments?per_page=100&page=1"], + expect.any(Object), + ); + expect(ghMock).toHaveBeenNthCalledWith( + 2, + "gh", + ["api", "--method", "GET", "repos/acme/repo/pulls/42/comments?per_page=100&page=2"], + expect.any(Object), + ); + }); + it("returns bot comments filtered from all PR comments", async () => { mockGh([ {