From aee31662280ec1303910e4df27e67071e87c579b Mon Sep 17 00:00:00 2001 From: Mihir Kandoi Date: Thu, 22 Oct 2026 12:03:23 +0530 Subject: [PATCH 1/2] fix(success): query associated PRs in smaller serial chunks Large releases sent one GraphQL query per 100 commits, all at once. Each query took over GitHub's 10 second limit, so the API returned 502/504 and the success step failed before commenting on any PR. --- lib/success.js | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/lib/success.js b/lib/success.js index 48246f29..02d463e6 100644 --- a/lib/success.js +++ b/lib/success.js @@ -76,7 +76,7 @@ export default async function success(pluginConfig, context, { Octokit }) { const shas = commits.map(({ hash }) => hash); // Get associatedPRs - const associatedPRs = await inChunks(shas, 100, async (chunk) => { + const associatedPRs = await inChunks(shas, 25, async (chunk) => { const responsePRs = []; const { repository } = await octokit.graphql( buildAssociatedPRsQuery(chunk), @@ -333,8 +333,8 @@ export default async function success(pluginConfig, context, { Octokit }) { } /** - * In order to speed up a function call that handles a big array of items, we split up the - * array in chunks and call the function for each chunk in parallel. At the end we combine the + * Split a big array of items in chunks and call the function for each chunk serially, so that + * large releases do not send many heavy GraphQL queries at once. At the end we combine the * results again. * * @template TItem @@ -345,11 +345,10 @@ export default async function success(pluginConfig, context, { Octokit }) { * @returns TCallbackResult */ async function inChunks(items, chunkSize, callback) { - const chunkCalls = []; + const results = []; for (let i = 0; i < items.length; i += chunkSize) { - chunkCalls.push(callback(items.slice(i, i + chunkSize))); + results.push(await callback(items.slice(i, i + chunkSize))); } - const results = await Promise.all(chunkCalls); return results.flat(); } From 58db13fdcd7ba2b49c4b9a239f74be7782c84777 Mon Sep 17 00:00:00 2001 From: Mihir Kandoi Date: Thu, 22 Oct 2026 12:03:57 +0530 Subject: [PATCH 2/2] test(success): cover serial associated PR chunks --- test/success.test.js | 77 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/test/success.test.js b/test/success.test.js index e88e1b70..2478ed71 100644 --- a/test/success.test.js +++ b/test/success.test.js @@ -1387,6 +1387,83 @@ test("Do not add comment and labels if no PR is associated with release commits" t.true(fetch.done()); }); +test("Query associated PRs in serial chunks of 25 commits", async (t) => { + const owner = "test_user"; + const repo = "test_repo"; + const env = { GITHUB_TOKEN: "github_token" }; + const options = { + branch: "master", + repositoryUrl: `https://github.com/${owner}/${repo}.git`, + }; + const commits = Array.from({ length: 30 }, (_, index) => ({ + hash: `${index}`, + message: `Commit ${index} message`, + })); + const nextRelease = { version: "1.0.0" }; + const releases = [ + { name: "GitHub release", url: "https://github.com/release" }, + ]; + const chunkSizes = []; + let inFlight = 0; + + const fetch = fetchMock + .sandbox() + .getOnce(`https://api.github.local/repos/${owner}/${repo}`, { + full_name: `${owner}/${repo}`, + clone_url: `https://api.github.local/${owner}/${repo}.git`, + }) + .post( + (url, { body }) => + JSON.parse(body).query.includes("query getAssociatedPRs("), + async (url, { body }) => { + inFlight += 1; + t.is(inFlight, 1); + const shas = [...JSON.parse(body).query.matchAll(/oid: "(\d+)"/g)].map( + ([, sha]) => sha, + ); + chunkSizes.push(shas.length); + await new Promise((resolve) => setTimeout(resolve, 10)); + inFlight -= 1; + const nodes = { pageInfo: { hasNextPage: false }, nodes: [] }; + return { + data: { + repository: Object.fromEntries( + shas.map((sha) => [ + `commit${sha}`, + { oid: sha, associatedPullRequests: nodes }, + ]), + ), + }, + }; + }, + ) + .postOnce( + (url, { body }) => JSON.parse(body).query.includes("query getSRIssues("), + { data: { repository: { issues: { nodes: [] } } } }, + ); + + await success( + {}, + { + env, + options, + commits, + nextRelease, + releases, + logger: t.context.logger, + }, + { + Octokit: TestOctokit.defaults((options) => ({ + ...options, + request: { ...options.request, fetch }, + })), + }, + ); + + t.deepEqual(chunkSizes, [25, 5]); + t.true(fetch.done()); +}); + test("Do not add comment and labels if no commits is found for release", async (t) => { const owner = "test_user"; const repo = "test_repo";