Move pagination safeguard to non-JetBrains installers

This commit is contained in:
copilot-swe-agent[bot] 2026-06-03 15:52:24 +00:00 committed by GitHub
parent a22487fd8c
commit 3b472a4e31
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 118 additions and 40 deletions

View File

@ -14,6 +14,7 @@ import * as core from '@actions/core';
describe('getAvailableVersions', () => {
let spyHttpClient: jest.SpyInstance;
let spyCoreError: jest.SpyInstance;
let spyCoreWarning: jest.SpyInstance;
beforeEach(() => {
spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson');
@ -26,6 +27,8 @@ describe('getAvailableVersions', () => {
// Mock core.error to suppress error logs
spyCoreError = jest.spyOn(core, 'error');
spyCoreError.mockImplementation(() => {});
spyCoreWarning = jest.spyOn(core, 'warning');
spyCoreWarning.mockImplementation(() => {});
});
afterEach(() => {
@ -166,6 +169,32 @@ describe('getAvailableVersions', () => {
expect(spyHttpClient).toHaveBeenNthCalledWith(2, nextPageUrl);
});
it('stops pagination after 1000 pages as a safeguard', async () => {
const nextPageUrl = 'https://example.com/releases?page=2';
spyHttpClient.mockReturnValue({
statusCode: 200,
headers: {link: `<${nextPageUrl}>; rel="next"`},
result: [{version_data: {semver: '17.0.1'}, binaries: []}] as any
});
const distribution = new AdoptDistribution(
{
version: '11',
architecture: 'x64',
packageType: 'jdk',
checkLatest: false
},
AdoptImplementation.Hotspot
);
await distribution['getAvailableVersions']();
expect(spyHttpClient).toHaveBeenCalledTimes(1000);
expect(spyCoreWarning).toHaveBeenCalledWith(
expect.stringContaining('Reached pagination safeguard limit (1000 pages)')
);
});
it.each([
[AdoptImplementation.Hotspot, 'jdk', 'Java_Adopt_jdk'],
[AdoptImplementation.Hotspot, 'jre', 'Java_Adopt_jre'],

View File

@ -9,8 +9,6 @@ import * as core from '@actions/core';
describe('getAvailableVersions', () => {
let spyHttpClient: jest.SpyInstance;
let spyCoreError: jest.SpyInstance;
let spyCoreWarning: jest.SpyInstance;
let spyHeadRequest: jest.SpyInstance;
beforeEach(() => {
spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson');
@ -23,14 +21,6 @@ describe('getAvailableVersions', () => {
// Mock core.error to suppress error logs
spyCoreError = jest.spyOn(core, 'error');
spyCoreError.mockImplementation(() => {});
spyCoreWarning = jest.spyOn(core, 'warning');
spyCoreWarning.mockImplementation(() => {});
spyHeadRequest = jest.spyOn(HttpClient.prototype, 'head');
spyHeadRequest.mockResolvedValue({
message: {
statusCode: 404
}
} as any);
});
afterEach(() => {
@ -60,27 +50,6 @@ describe('getAvailableVersions', () => {
os.platform() === 'win32' ? manifestData.length : manifestData.length + 2;
expect(availableVersions.length).toBe(length);
}, 10_000);
it('stops pagination after 1000 pages as a safeguard', async () => {
spyHttpClient.mockResolvedValue({
statusCode: 200,
headers: {},
result: [{tag_name: 'jbr17-b87.7', name: 'jbr17-b87.7', prerelease: false}]
});
const distribution = new JetBrainsDistribution({
version: '17',
architecture: 'x64',
packageType: 'jdk',
checkLatest: false
});
await distribution['getAvailableVersions']();
expect(spyHttpClient).toHaveBeenCalledTimes(1000);
expect(spyCoreWarning).toHaveBeenCalledWith(
expect.stringContaining('Reached pagination safeguard limit (1000 pages)')
);
}, 20_000);
});
describe('findPackageForDownload', () => {

View File

@ -9,6 +9,7 @@ import * as core from '@actions/core';
describe('getAvailableVersions', () => {
let spyHttpClient: jest.SpyInstance;
let spyCoreError: jest.SpyInstance;
let spyCoreWarning: jest.SpyInstance;
beforeEach(() => {
spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson');
@ -20,6 +21,8 @@ describe('getAvailableVersions', () => {
// Mock core.error to suppress error logs
spyCoreError = jest.spyOn(core, 'error');
spyCoreError.mockImplementation(() => {});
spyCoreWarning = jest.spyOn(core, 'warning');
spyCoreWarning.mockImplementation(() => {});
});
afterEach(() => {
@ -109,6 +112,29 @@ describe('getAvailableVersions', () => {
expect(spyHttpClient).toHaveBeenNthCalledWith(2, nextPageUrl);
});
it('stops pagination after 1000 pages as a safeguard', async () => {
const nextPageUrl = 'https://example.com/releases?page=2';
spyHttpClient.mockReturnValue({
statusCode: 200,
headers: {link: `<${nextPageUrl}>; rel="next"`},
result: [{version_data: {semver: '17.0.1'}, binaries: []}] as any
});
const distribution = new SemeruDistribution({
version: '8',
architecture: 'x64',
packageType: 'jdk',
checkLatest: false
});
await distribution['getAvailableVersions']();
expect(spyHttpClient).toHaveBeenCalledTimes(1000);
expect(spyCoreWarning).toHaveBeenCalledWith(
expect.stringContaining('Reached pagination safeguard limit (1000 pages)')
);
});
it.each([
['jdk', 'Java_IBM_Semeru_jdk'],
['jre', 'Java_IBM_Semeru_jre']

View File

@ -12,6 +12,7 @@ import * as core from '@actions/core';
describe('getAvailableVersions', () => {
let spyHttpClient: jest.SpyInstance;
let spyCoreError: jest.SpyInstance;
let spyCoreWarning: jest.SpyInstance;
beforeEach(() => {
spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson');
@ -23,6 +24,8 @@ describe('getAvailableVersions', () => {
// Mock core.error to suppress error logs
spyCoreError = jest.spyOn(core, 'error');
spyCoreError.mockImplementation(() => {});
spyCoreWarning = jest.spyOn(core, 'warning');
spyCoreWarning.mockImplementation(() => {});
});
afterEach(() => {
@ -123,6 +126,32 @@ describe('getAvailableVersions', () => {
expect(spyHttpClient).toHaveBeenNthCalledWith(2, nextPageUrl);
});
it('stops pagination after 1000 pages as a safeguard', async () => {
const nextPageUrl = 'https://example.com/releases?page=2';
spyHttpClient.mockReturnValue({
statusCode: 200,
headers: {link: `<${nextPageUrl}>; rel="next"`},
result: [{version_data: {semver: '17.0.1'}, binaries: []}] as any
});
const distribution = new TemurinDistribution(
{
version: '8',
architecture: 'x64',
packageType: 'jdk',
checkLatest: false
},
TemurinImplementation.Hotspot
);
await distribution['getAvailableVersions']();
expect(spyHttpClient).toHaveBeenCalledTimes(1000);
expect(spyCoreWarning).toHaveBeenCalledWith(
expect.stringContaining('Reached pagination safeguard limit (1000 pages)')
);
});
it.each([
[TemurinImplementation.Hotspot, 'jdk', 'Java_Temurin-Hotspot_jdk'],
[TemurinImplementation.Hotspot, 'jre', 'Java_Temurin-Hotspot_jre']

View File

@ -20,6 +20,8 @@ import {
renameWinArchive
} from '../../util';
const MAX_PAGINATION_PAGES = 1000;
export enum AdoptImplementation {
Hotspot = 'Hotspot',
OpenJ9 = 'OpenJ9'
@ -129,11 +131,13 @@ export class AdoptDistribution extends JavaBase {
const requestArguments = `${baseRequestArguments}&page_size=20&page=0`;
let availableVersionsUrl: string | null = `https://api.adoptopenjdk.net/v3/assets/version/${versionRange}?${requestArguments}`;
const availableVersions: IAdoptAvailableVersions[] = [];
let pageCount = 0;
if (core.isDebug()) {
core.debug(`Gathering available versions from '${availableVersionsUrl}'`);
}
while (availableVersionsUrl) {
pageCount++;
const response =
await this.http.getJson<IAdoptAvailableVersions[]>(availableVersionsUrl);
const paginationPage = response.result;
@ -143,6 +147,13 @@ export class AdoptDistribution extends JavaBase {
}
availableVersions.push(...paginationPage);
if (pageCount >= MAX_PAGINATION_PAGES && availableVersionsUrl) {
core.warning(
`Reached pagination safeguard limit (${MAX_PAGINATION_PAGES} pages) while listing Adopt releases.`
);
break;
}
}
if (core.isDebug()) {

View File

@ -16,8 +16,6 @@ import {extractJdkFile, isVersionSatisfies} from '../../util';
import {OutgoingHttpHeaders} from 'http';
import {HttpCodes} from '@actions/http-client';
const MAX_PAGINATION_PAGES = 1000;
export class JetBrainsDistribution extends JavaBase {
constructor(installerOptions: JavaInstallerOptions) {
super('JetBrains', installerOptions);
@ -95,7 +93,7 @@ export class JetBrainsDistribution extends JavaBase {
const rawVersions: IJetBrainsRawVersion[] = [];
const bearerToken = process.env.GITHUB_TOKEN;
while (page_index <= MAX_PAGINATION_PAGES) {
while (true) {
const requestArguments = `per_page=100&page=${page_index}`;
const requestHeaders: OutgoingHttpHeaders = {};
@ -131,12 +129,6 @@ export class JetBrainsDistribution extends JavaBase {
page_index++;
}
if (page_index > MAX_PAGINATION_PAGES) {
core.warning(
`Reached pagination safeguard limit (${MAX_PAGINATION_PAGES} pages) while listing JetBrains runtime releases.`
);
}
if (this.stable) {
// Add versions not available from the API but are downloadable
const hidden = ['11_0_10b1145.115', '11_0_11b1341.60'];

View File

@ -18,6 +18,8 @@ import fs from 'fs';
import path from 'path';
import {ISemeruAvailableVersions} from './models';
const MAX_PAGINATION_PAGES = 1000;
const supportedArchitectures = [
'x64',
'x86',
@ -159,11 +161,13 @@ export class SemeruDistribution extends JavaBase {
const requestArguments = `${baseRequestArguments}&page_size=20&page=0`;
let availableVersionsUrl: string | null = `https://api.adoptopenjdk.net/v3/assets/version/${versionRange}?${requestArguments}`;
const availableVersions: ISemeruAvailableVersions[] = [];
let pageCount = 0;
if (core.isDebug()) {
core.debug(`Gathering available versions from '${availableVersionsUrl}'`);
}
while (availableVersionsUrl) {
pageCount++;
const response = await this.http.getJson<ISemeruAvailableVersions[]>(
availableVersionsUrl
);
@ -174,6 +178,13 @@ export class SemeruDistribution extends JavaBase {
}
availableVersions.push(...paginationPage);
if (pageCount >= MAX_PAGINATION_PAGES && availableVersionsUrl) {
core.warning(
`Reached pagination safeguard limit (${MAX_PAGINATION_PAGES} pages) while listing Semeru releases.`
);
break;
}
}
if (core.isDebug()) {

View File

@ -20,6 +20,8 @@ import {
renameWinArchive
} from '../../util';
const MAX_PAGINATION_PAGES = 1000;
export enum TemurinImplementation {
Hotspot = 'Hotspot'
}
@ -127,11 +129,13 @@ export class TemurinDistribution extends JavaBase {
const requestArguments = `${baseRequestArguments}&page_size=20&page=0`;
let availableVersionsUrl: string | null = `https://api.adoptium.net/v3/assets/version/${versionRange}?${requestArguments}`;
const availableVersions: ITemurinAvailableVersions[] = [];
let pageCount = 0;
if (core.isDebug()) {
core.debug(`Gathering available versions from '${availableVersionsUrl}'`);
}
while (availableVersionsUrl) {
pageCount++;
const response = await this.http.getJson<ITemurinAvailableVersions[]>(
availableVersionsUrl
);
@ -143,6 +147,13 @@ export class TemurinDistribution extends JavaBase {
}
availableVersions.push(...paginationPage);
if (pageCount >= MAX_PAGINATION_PAGES && availableVersionsUrl) {
core.warning(
`Reached pagination safeguard limit (${MAX_PAGINATION_PAGES} pages) while listing Temurin releases.`
);
break;
}
}
if (core.isDebug()) {