From dad5ef3629b6f9303af8a80b07ab745051d186af Mon Sep 17 00:00:00 2001 From: Omer Mishania Date: Tue, 18 Nov 2025 20:07:10 +0200 Subject: [PATCH 1/3] Fix error message to show correct tag name --- src/github.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/github.ts b/src/github.ts index 033f284..63c3786 100644 --- a/src/github.ts +++ b/src/github.ts @@ -327,7 +327,7 @@ export const release = async ( } catch (error) { if (error.status !== 404) { console.log( - `⚠️ Unexpected error fetching GitHub release for tag ${config.github_ref}: ${error}`, + `⚠️ Unexpected error fetching GitHub release for tag ${tag}: ${error}`, ); throw error; } From 3d29d2e17b19131f58d6241458c2bb6f585e97ef Mon Sep 17 00:00:00 2001 From: Omer Mishania Date: Tue, 18 Nov 2025 20:08:32 +0200 Subject: [PATCH 2/3] fix: use manual pagination to prevent hitting 10k result limit Replace github.paginate.iterator with manual pagination to have full control over when to stop. This prevents the iterator from hitting GitHub's 10,000 result limit before our code can stop it. --- src/github.ts | 110 +++++++++++++++++++++++++++++++++++++------------- 1 file changed, 82 insertions(+), 28 deletions(-) diff --git a/src/github.ts b/src/github.ts index 63c3786..c41b789 100644 --- a/src/github.ts +++ b/src/github.ts @@ -361,44 +361,98 @@ async function findTagByPagination( repo: string, tag: string, ): Promise { - // Limit pagination to avoid hitting GitHub's 10,000 result limit - // Stop aggressively on empty pages to prevent CI blocking - let pageCount = 0; + // Manually paginate to avoid hitting GitHub's 10,000 result limit + // The github.paginate.iterator can hit the limit before we can stop it + // So we manually paginate with strict limits const maxPages = 30; // Stop after 30 pages (3000 releases max) to avoid hitting limits const minPagesBeforeEmptyPageStop = 5; // After checking at least 5 pages, stop immediately on first empty page + const perPage = 100; - for await (const { data: releases } of releaser.allReleases({ - owner, - repo, - })) { - pageCount++; - - // Stop if we've checked too many pages - if (pageCount > maxPages) { - console.warn( - `⚠️ Stopped pagination after ${maxPages} pages to avoid hitting GitHub's result limit`, - ); - break; - } - - // If we get an empty page, stop immediately if we've already checked enough pages - // This prevents getting stuck on empty pages (like pages 300-1000) which blocks CI - if (releases.length === 0) { - if (pageCount >= minPagesBeforeEmptyPageStop) { - console.log( - `Stopped pagination after encountering empty page at page ${pageCount} (to avoid hitting GitHub's result limit)`, + // Use the GitHub API directly for manual pagination + const github = (releaser as GitHubReleaser).github; + if (!github) { + // Fallback to iterator if we can't access github directly + let pageCount = 0; + for await (const { data: releases } of releaser.allReleases({ + owner, + repo, + })) { + pageCount++; + if (pageCount > maxPages) { + console.warn( + `⚠️ Stopped pagination after ${maxPages} pages to avoid hitting GitHub's result limit`, ); break; } - // If we haven't checked many pages yet, continue (might be at the very end) - continue; + if (releases.length === 0 && pageCount >= minPagesBeforeEmptyPageStop) { + console.log( + `Stopped pagination after encountering empty page at page ${pageCount}`, + ); + break; + } + const release = releases.find((release) => release.tag_name === tag); + if (release) { + return release; + } } + return undefined; + } - const release = releases.find((release) => release.tag_name === tag); - if (release) { - return release; + // Manual pagination with full control + let page = 1; + let consecutiveEmptyPages = 0; + + while (page <= maxPages) { + try { + const response = await github.rest.repos.listReleases({ + owner, + repo, + per_page: perPage, + page: page, + }); + + const releases = response.data; + + // If we get an empty page, stop immediately if we've already checked enough pages + if (releases.length === 0) { + consecutiveEmptyPages++; + if (page >= minPagesBeforeEmptyPageStop) { + console.log( + `Stopped pagination after encountering empty page at page ${page} (to avoid hitting GitHub's result limit)`, + ); + break; + } + // If we haven't checked many pages yet, continue (might be at the very end) + page++; + continue; + } + + // Reset empty page counter when we find releases + consecutiveEmptyPages = 0; + + const release = releases.find((release) => release.tag_name === tag); + if (release) { + return release; + } + + // If we got fewer results than per_page, we've reached the end + if (releases.length < perPage) { + break; + } + + page++; + } catch (error: any) { + // If we hit the 10,000 result limit, stop immediately + if (error.status === 422 && error.message?.includes('10000')) { + console.warn( + `⚠️ Stopped pagination at page ${page} due to GitHub's 10,000 result limit`, + ); + break; + } + throw error; } } + return undefined; } From 08c3b6be76f8b3bc464f4036c8542be5290dd55c Mon Sep 17 00:00:00 2001 From: Omer Mishania Date: Tue, 18 Nov 2025 20:09:21 +0200 Subject: [PATCH 3/3] fix: stop immediately on empty pages to prevent iterating through hundreds of empty pages When encountering empty pages (like pages 300-1000), stop immediately instead of continuing to iterate. This prevents hitting GitHub's 10k result limit when there are many empty pages in the middle of pagination. --- src/github.ts | 40 ++++++++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/src/github.ts b/src/github.ts index c41b789..f375ee3 100644 --- a/src/github.ts +++ b/src/github.ts @@ -364,15 +364,17 @@ async function findTagByPagination( // Manually paginate to avoid hitting GitHub's 10,000 result limit // The github.paginate.iterator can hit the limit before we can stop it // So we manually paginate with strict limits + // Stop immediately on empty pages to avoid iterating through hundreds of empty pages const maxPages = 30; // Stop after 30 pages (3000 releases max) to avoid hitting limits - const minPagesBeforeEmptyPageStop = 5; // After checking at least 5 pages, stop immediately on first empty page const perPage = 100; // Use the GitHub API directly for manual pagination const github = (releaser as GitHubReleaser).github; if (!github) { // Fallback to iterator if we can't access github directly + // Stop immediately on empty pages to avoid iterating through hundreds of empty pages let pageCount = 0; + let foundAnyReleases = false; for await (const { data: releases } of releaser.allReleases({ owner, repo, @@ -384,12 +386,18 @@ async function findTagByPagination( ); break; } - if (releases.length === 0 && pageCount >= minPagesBeforeEmptyPageStop) { - console.log( - `Stopped pagination after encountering empty page at page ${pageCount}`, - ); - break; + // Stop immediately on empty pages if we've found releases before + if (releases.length === 0) { + if (foundAnyReleases || pageCount > 1) { + console.log( + `Stopped pagination after encountering empty page at page ${pageCount} (to avoid iterating through empty pages)`, + ); + break; + } + // Page 1 is empty, no releases exist + return undefined; } + foundAnyReleases = true; const release = releases.find((release) => release.tag_name === tag); if (release) { return release; @@ -399,8 +407,9 @@ async function findTagByPagination( } // Manual pagination with full control + // Stop immediately on empty pages to avoid iterating through hundreds of empty pages let page = 1; - let consecutiveEmptyPages = 0; + let foundAnyReleases = false; while (page <= maxPages) { try { @@ -413,22 +422,21 @@ async function findTagByPagination( const releases = response.data; - // If we get an empty page, stop immediately if we've already checked enough pages + // If we get an empty page: + // - If we've found releases before, stop immediately (we've hit a gap or the end) + // - If page 1 is empty, that's fine (no releases exist), return undefined if (releases.length === 0) { - consecutiveEmptyPages++; - if (page >= minPagesBeforeEmptyPageStop) { + if (foundAnyReleases || page > 1) { console.log( - `Stopped pagination after encountering empty page at page ${page} (to avoid hitting GitHub's result limit)`, + `Stopped pagination after encountering empty page at page ${page} (to avoid iterating through empty pages)`, ); break; } - // If we haven't checked many pages yet, continue (might be at the very end) - page++; - continue; + // Page 1 is empty, no releases exist + return undefined; } - // Reset empty page counter when we find releases - consecutiveEmptyPages = 0; + foundAnyReleases = true; const release = releases.find((release) => release.tag_name === tag); if (release) {