diff --git a/__tests__/distributors/graalvm-installer.test.ts b/__tests__/distributors/graalvm-installer.test.ts index ae2db43c..e94426de 100644 --- a/__tests__/distributors/graalvm-installer.test.ts +++ b/__tests__/distributors/graalvm-installer.test.ts @@ -2,9 +2,9 @@ import {GraalVMDistribution} from '../../src/distributions/graalvm/installer'; import os from 'os'; import * as core from '@actions/core'; import {getDownloadArchiveExtension} from '../../src/util'; -import {HttpClient} from '@actions/http-client'; +import {HttpClient, HttpClientResponse} from '@actions/http-client'; -describe('findPackageForDownload', () => { +describe('GraalVMDistribution', () => { let distribution: GraalVMDistribution; let spyDebug: jest.SpyInstance; let spyHttpClient: jest.SpyInstance; @@ -17,11 +17,21 @@ describe('findPackageForDownload', () => { checkLatest: false }); - spyDebug = jest.spyOn(core, 'debug'); - spyDebug.mockImplementation(() => {}); + spyDebug = jest.spyOn(core, 'debug').mockImplementation(() => {}); }); - it.each([ + afterEach(() => { + jest.restoreAllMocks(); + }); + + const setupHttpClientSpy = () => { + spyHttpClient = jest.spyOn(HttpClient.prototype, 'head').mockResolvedValue({ + message: {statusCode: 200} as any, // Minimal mock for IncomingMessage + readBody: jest.fn().mockResolvedValue('') + } as HttpClientResponse); + }; + + const testCases = [ [ '21', '21', @@ -42,66 +52,54 @@ describe('findPackageForDownload', () => { '17.0.12', 'https://download.oracle.com/graalvm/17/archive/graalvm-jdk-17.0.12_{{OS_TYPE}}-x64_bin.{{ARCHIVE_TYPE}}' ] - ])('version is %s -> %s', async (input, expectedVersion, expectedUrl) => { - /* Needed only for this particular test because /latest/ urls tend to change */ - spyHttpClient = jest.spyOn(HttpClient.prototype, 'head'); - spyHttpClient.mockReturnValue( - Promise.resolve({ - message: { - statusCode: 200 - } - }) - ); + ]; - const result = await distribution['findPackageForDownload'](input); + it.each(testCases)( + 'should find package for version %s', + async (input, expectedVersion, expectedUrl) => { + setupHttpClientSpy(); - jest.restoreAllMocks(); + const result = await distribution['findPackageForDownload'](input); + const osType = distribution.getPlatform(); + const archiveType = getDownloadArchiveExtension(); + const expectedFormattedUrl = expectedUrl + .replace('{{OS_TYPE}}', osType) + .replace('{{ARCHIVE_TYPE}}', archiveType); - expect(result.version).toBe(expectedVersion); - const osType = distribution.getPlatform(); - const archiveType = getDownloadArchiveExtension(); - const url = expectedUrl - .replace('{{OS_TYPE}}', osType) - .replace('{{ARCHIVE_TYPE}}', archiveType); - expect(result.url).toBe(url); - }); + expect(result.version).toBe(expectedVersion); + expect(result.url).toBe(expectedFormattedUrl); + } + ); it.each([ [ '24-ea', /^https:\/\/github\.com\/graalvm\/oracle-graalvm-ea-builds\/releases\/download\/jdk-24\.0\.0-ea\./ ] - ])('version is %s -> %s', async (version, expectedUrlPrefix) => { - /* Needed only for this particular test because /latest/ urls tend to change */ - spyHttpClient = jest.spyOn(HttpClient.prototype, 'head'); - spyHttpClient.mockReturnValue( - Promise.resolve({ - message: { - statusCode: 200 - } - }) - ); + ])( + 'should find EA package for version %s', + async (version, expectedUrlPrefix) => { + setupHttpClientSpy(); - const eaDistro = new GraalVMDistribution({ - version, - architecture: '', // to get default value - packageType: 'jdk', - checkLatest: false - }); + const eaDistro = new GraalVMDistribution({ + version, + architecture: '', + packageType: 'jdk', + checkLatest: false + }); - const versionWithoutEA = version.split('-')[0]; - const result = await eaDistro['findPackageForDownload'](versionWithoutEA); + const versionWithoutEA = version.split('-')[0]; + const result = await eaDistro['findPackageForDownload'](versionWithoutEA); - jest.restoreAllMocks(); - - expect(result.url).toEqual(expect.stringMatching(expectedUrlPrefix)); - }); + expect(result.url).toEqual(expect.stringMatching(expectedUrlPrefix)); + } + ); it.each([ ['amd64', 'x64'], ['arm64', 'aarch64'] ])( - 'defaults to os.arch(): %s mapped to distro arch: %s', + 'should map OS architecture %s to distribution architecture %s', async (osArch: string, distroArch: string) => { jest.spyOn(os, 'arch').mockReturnValue(osArch); jest.spyOn(os, 'platform').mockReturnValue('linux'); @@ -109,15 +107,16 @@ describe('findPackageForDownload', () => { const version = '21'; const distro = new GraalVMDistribution({ version, - architecture: '', // to get default value + architecture: '', packageType: 'jdk', checkLatest: false }); const osType = distribution.getPlatform(); - if (osType === 'windows' && distroArch == 'aarch64') { + if (osType === 'windows' && distroArch === 'aarch64') { return; // skip, aarch64 is not available for Windows } + const archiveType = getDownloadArchiveExtension(); const result = await distro['findPackageForDownload'](version); const expectedUrl = `https://download.oracle.com/graalvm/21/latest/graalvm-jdk-21_${osType}-${distroArch}_bin.${archiveType}`; @@ -126,27 +125,26 @@ describe('findPackageForDownload', () => { } ); - it('should throw an error', async () => { - await expect(distribution['findPackageForDownload']('8')).rejects.toThrow( - /GraalVM is only supported for JDK 17 and later/ - ); - await expect(distribution['findPackageForDownload']('11')).rejects.toThrow( - /GraalVM is only supported for JDK 17 and later/ - ); - await expect(distribution['findPackageForDownload']('18')).rejects.toThrow( - /Could not find GraalVM for SemVer */ - ); + it('should throw an error for unsupported versions', async () => { + setupHttpClientSpy(); + + const unsupportedVersions = ['8', '11']; + for (const version of unsupportedVersions) { + await expect( + distribution['findPackageForDownload'](version) + ).rejects.toThrow(/GraalVM is only supported for JDK 17 and later/); + } const unavailableEADistro = new GraalVMDistribution({ version: '17-ea', - architecture: '', // to get default value + architecture: '', packageType: 'jdk', checkLatest: false }); await expect( unavailableEADistro['findPackageForDownload']('17') ).rejects.toThrow( - /No GraalVM EA build found\. Are you sure java-version: '17-ea' is correct\?/ + `No GraalVM EA build found for version '17-ea'. Please check if the version is correct.` ); }); }); diff --git a/dist/cleanup/index.js b/dist/cleanup/index.js index b8d03ca1..ebb7797c 100644 --- a/dist/cleanup/index.js +++ b/dist/cleanup/index.js @@ -93676,9 +93676,9 @@ function convertVersionToSemver(version) { return mainVersion; } exports.convertVersionToSemver = convertVersionToSemver; -function getGitHubHttpHeaders() { - const token = core.getInput('token'); - const auth = !token ? undefined : `token ${token}`; +function getGitHubHttpHeaders(token) { + const resolvedToken = token || core.getInput('token'); + const auth = !resolvedToken ? undefined : `token ${resolvedToken}`; const headers = { accept: 'application/vnd.github.VERSION.raw' }; diff --git a/dist/setup/index.js b/dist/setup/index.js index 8bf08ef2..968103d8 100644 --- a/dist/setup/index.js +++ b/dist/setup/index.js @@ -129455,8 +129455,8 @@ const tc = __importStar(__nccwpck_require__(27784)); const fs_1 = __importDefault(__nccwpck_require__(57147)); const path_1 = __importDefault(__nccwpck_require__(71017)); const base_installer_1 = __nccwpck_require__(59741); -const util_1 = __nccwpck_require__(92629); const http_client_1 = __nccwpck_require__(96255); +const util_1 = __nccwpck_require__(92629); const GRAALVM_DL_BASE = 'https://download.oracle.com/graalvm'; const IS_WINDOWS = process.platform === 'win32'; const GRAALVM_PLATFORM = IS_WINDOWS ? 'windows' : process.platform; @@ -129470,12 +129470,11 @@ class GraalVMDistribution extends base_installer_1.JavaBase { let javaArchivePath = yield tc.downloadTool(javaRelease.url); core.info(`Extracting Java archive...`); const extension = (0, util_1.getDownloadArchiveExtension)(); - if (process.platform === 'win32') { + if (IS_WINDOWS) { javaArchivePath = (0, util_1.renameWinArchive)(javaArchivePath); } const extractedJavaPath = yield (0, util_1.extractJdkFile)(javaArchivePath, extension); - const archiveName = fs_1.default.readdirSync(extractedJavaPath)[0]; - const archivePath = path_1.default.join(extractedJavaPath, archiveName); + const archivePath = path_1.default.join(extractedJavaPath, fs_1.default.readdirSync(extractedJavaPath)[0]); const version = this.getToolcacheVersionName(javaRelease.version); const javaPath = yield tc.cacheDir(archivePath, this.toolcacheFolderName, version, this.architecture); return { version: javaRelease.version, path: javaPath }; @@ -129484,7 +129483,7 @@ class GraalVMDistribution extends base_installer_1.JavaBase { findPackageForDownload(range) { return __awaiter(this, void 0, void 0, function* () { const arch = this.distributionArchitecture(); - if (arch !== 'x64' && arch !== 'aarch64') { + if (!['x64', 'aarch64'].includes(arch)) { throw new Error(`Unsupported architecture: ${this.architecture}`); } if (!this.stable) { @@ -129495,29 +129494,29 @@ class GraalVMDistribution extends base_installer_1.JavaBase { } const platform = this.getPlatform(); const extension = (0, util_1.getDownloadArchiveExtension)(); - let major; - let fileUrl; - if (range.includes('.')) { - major = range.split('.')[0]; - fileUrl = `${GRAALVM_DL_BASE}/${major}/archive/graalvm-jdk-${range}_${platform}-${arch}_bin.${extension}`; - } - else { - major = range; - fileUrl = `${GRAALVM_DL_BASE}/${range}/latest/graalvm-jdk-${range}_${platform}-${arch}_bin.${extension}`; - } + const major = range.includes('.') ? range.split('.')[0] : range; + const fileUrl = this.constructFileUrl(range, major, platform, arch, extension); if (parseInt(major) < 17) { throw new Error('GraalVM is only supported for JDK 17 and later'); } const response = yield this.http.head(fileUrl); - if (response.message.statusCode === http_client_1.HttpCodes.NotFound) { - throw new Error(`Could not find GraalVM for SemVer ${range}`); - } - if (response.message.statusCode !== http_client_1.HttpCodes.OK) { - throw new Error(`Http request for GraalVM failed with status code: ${response.message.statusCode}`); - } + this.handleHttpResponse(response, range); return { url: fileUrl, version: range }; }); } + constructFileUrl(range, major, platform, arch, extension) { + return range.includes('.') + ? `${GRAALVM_DL_BASE}/${major}/archive/graalvm-jdk-${range}_${platform}-${arch}_bin.${extension}` + : `${GRAALVM_DL_BASE}/${range}/latest/graalvm-jdk-${range}_${platform}-${arch}_bin.${extension}`; + } + handleHttpResponse(response, range) { + if (response.message.statusCode === http_client_1.HttpCodes.NotFound) { + throw new Error(`Could not find GraalVM for SemVer ${range}`); + } + if (response.message.statusCode !== http_client_1.HttpCodes.OK) { + throw new Error(`Http request for GraalVM failed with status code: ${response.message.statusCode}`); + } + } findEABuildDownloadUrl(javaEaVersion) { return __awaiter(this, void 0, void 0, function* () { const versions = yield this.fetchEAJson(javaEaVersion); @@ -129538,38 +129537,29 @@ class GraalVMDistribution extends base_installer_1.JavaBase { } fetchEAJson(javaEaVersion) { return __awaiter(this, void 0, void 0, function* () { - const owner = 'graalvm'; - const repository = 'oracle-graalvm-ea-builds'; - const branch = 'main'; - const filePath = `versions/${javaEaVersion}.json`; - const url = `https://api.github.com/repos/${owner}/${repository}/contents/${filePath}?ref=${branch}`; + const url = `https://api.github.com/repos/graalvm/oracle-graalvm-ea-builds/contents/versions/${javaEaVersion}.json?ref=main`; const headers = (0, util_1.getGitHubHttpHeaders)(); core.debug(`Trying to fetch available version info for GraalVM EA builds from '${url}'`); - let fetchedJson; - try { - fetchedJson = (yield this.http.getJson(url, headers)) - .result; - } - catch (err) { - throw Error(`Fetching version info for GraalVM EA builds from '${url}' failed with the error: ${err.message}`); - } - if (fetchedJson === null) { - throw Error(`No GraalVM EA build found. Are you sure java-version: '${javaEaVersion}' is correct?`); + const fetchedJson = yield this.http + .getJson(url, headers) + .then(res => res.result); + if (!fetchedJson) { + throw new Error(`No GraalVM EA build found for version '${javaEaVersion}'. Please check if the version is correct.`); } return fetchedJson; }); } getPlatform(platform = process.platform) { - switch (platform) { - case 'darwin': - return 'macos'; - case 'win32': - return 'windows'; - case 'linux': - return 'linux'; - default: - throw new Error(`Platform '${platform}' is not supported. Supported platforms: 'linux', 'macos', 'windows'`); + const platformMap = { + darwin: 'macos', + win32: 'windows', + linux: 'linux' + }; + const result = platformMap[platform]; + if (!result) { + throw new Error(`Platform '${platform}' is not supported. Supported platforms: 'linux', 'macos', 'windows'`); } + return result; } } exports.GraalVMDistribution = GraalVMDistribution; @@ -131704,9 +131694,9 @@ function convertVersionToSemver(version) { return mainVersion; } exports.convertVersionToSemver = convertVersionToSemver; -function getGitHubHttpHeaders() { - const token = core.getInput('token'); - const auth = !token ? undefined : `token ${token}`; +function getGitHubHttpHeaders(token) { + const resolvedToken = token || core.getInput('token'); + const auth = !resolvedToken ? undefined : `token ${resolvedToken}`; const headers = { accept: 'application/vnd.github.VERSION.raw' }; diff --git a/src/distributions/graalvm/installer.ts b/src/distributions/graalvm/installer.ts index be14cee9..ecf3e8a8 100644 --- a/src/distributions/graalvm/installer.ts +++ b/src/distributions/graalvm/installer.ts @@ -1,10 +1,10 @@ import * as core from '@actions/core'; import * as tc from '@actions/tool-cache'; - import fs from 'fs'; import path from 'path'; - import {JavaBase} from '../base-installer'; +import {HttpCodes} from '@actions/http-client'; +import {GraalVMEAVersion} from './models'; import { JavaDownloadRelease, JavaInstallerOptions, @@ -16,8 +16,6 @@ import { getGitHubHttpHeaders, renameWinArchive } from '../../util'; -import {HttpCodes} from '@actions/http-client'; -import {GraalVMEAVersion} from './models'; const GRAALVM_DL_BASE = 'https://download.oracle.com/graalvm'; const IS_WINDOWS = process.platform === 'win32'; @@ -38,13 +36,14 @@ export class GraalVMDistribution extends JavaBase { core.info(`Extracting Java archive...`); const extension = getDownloadArchiveExtension(); - if (process.platform === 'win32') { + if (IS_WINDOWS) { javaArchivePath = renameWinArchive(javaArchivePath); } const extractedJavaPath = await extractJdkFile(javaArchivePath, extension); - - const archiveName = fs.readdirSync(extractedJavaPath)[0]; - const archivePath = path.join(extractedJavaPath, archiveName); + const archivePath = path.join( + extractedJavaPath, + fs.readdirSync(extractedJavaPath)[0] + ); const version = this.getToolcacheVersionName(javaRelease.version); const javaPath = await tc.cacheDir( @@ -53,7 +52,6 @@ export class GraalVMDistribution extends JavaBase { version, this.architecture ); - return {version: javaRelease.version, path: javaPath}; } @@ -61,7 +59,7 @@ export class GraalVMDistribution extends JavaBase { range: string ): Promise { const arch = this.distributionArchitecture(); - if (arch !== 'x64' && arch !== 'aarch64') { + if (!['x64', 'aarch64'].includes(arch)) { throw new Error(`Unsupported architecture: ${this.architecture}`); } @@ -75,33 +73,46 @@ export class GraalVMDistribution extends JavaBase { const platform = this.getPlatform(); const extension = getDownloadArchiveExtension(); - let major; - let fileUrl; - if (range.includes('.')) { - major = range.split('.')[0]; - fileUrl = `${GRAALVM_DL_BASE}/${major}/archive/graalvm-jdk-${range}_${platform}-${arch}_bin.${extension}`; - } else { - major = range; - fileUrl = `${GRAALVM_DL_BASE}/${range}/latest/graalvm-jdk-${range}_${platform}-${arch}_bin.${extension}`; - } + const major = range.includes('.') ? range.split('.')[0] : range; + const fileUrl = this.constructFileUrl( + range, + major, + platform, + arch, + extension + ); if (parseInt(major) < 17) { throw new Error('GraalVM is only supported for JDK 17 and later'); } const response = await this.http.head(fileUrl); + this.handleHttpResponse(response, range); + return {url: fileUrl, version: range}; + } + + private constructFileUrl( + range: string, + major: string, + platform: string, + arch: string, + extension: string + ): string { + return range.includes('.') + ? `${GRAALVM_DL_BASE}/${major}/archive/graalvm-jdk-${range}_${platform}-${arch}_bin.${extension}` + : `${GRAALVM_DL_BASE}/${range}/latest/graalvm-jdk-${range}_${platform}-${arch}_bin.${extension}`; + } + + private handleHttpResponse(response: any, range: string): void { if (response.message.statusCode === HttpCodes.NotFound) { throw new Error(`Could not find GraalVM for SemVer ${range}`); } - if (response.message.statusCode !== HttpCodes.OK) { throw new Error( `Http request for GraalVM failed with status code: ${response.message.statusCode}` ); } - - return {url: fileUrl, version: range}; } private async findEABuildDownloadUrl( @@ -112,6 +123,7 @@ export class GraalVMDistribution extends JavaBase { if (!latestVersion) { throw new Error(`Unable to find latest version for '${javaEaVersion}'`); } + const arch = this.distributionArchitecture(); const file = latestVersion.files.find( f => f.arch === arch && f.platform === GRAALVM_PLATFORM @@ -119,6 +131,7 @@ export class GraalVMDistribution extends JavaBase { if (!file || !file.filename.startsWith('graalvm-jdk-')) { throw new Error(`Unable to find file metadata for '${javaEaVersion}'`); } + return { url: `${latestVersion.download_base_url}${file.filename}`, version: latestVersion.version @@ -128,49 +141,37 @@ export class GraalVMDistribution extends JavaBase { private async fetchEAJson( javaEaVersion: string ): Promise { - const owner = 'graalvm'; - const repository = 'oracle-graalvm-ea-builds'; - const branch = 'main'; - const filePath = `versions/${javaEaVersion}.json`; - - const url = `https://api.github.com/repos/${owner}/${repository}/contents/${filePath}?ref=${branch}`; - + const url = `https://api.github.com/repos/graalvm/oracle-graalvm-ea-builds/contents/versions/${javaEaVersion}.json?ref=main`; const headers = getGitHubHttpHeaders(); core.debug( `Trying to fetch available version info for GraalVM EA builds from '${url}'` ); - let fetchedJson; - try { - fetchedJson = (await this.http.getJson(url, headers)) - .result; - } catch (err) { - throw Error( - `Fetching version info for GraalVM EA builds from '${url}' failed with the error: ${ - (err as Error).message - }` - ); - } - if (fetchedJson === null) { - throw Error( - `No GraalVM EA build found. Are you sure java-version: '${javaEaVersion}' is correct?` + const fetchedJson = await this.http + .getJson(url, headers) + .then(res => res.result); + + if (!fetchedJson) { + throw new Error( + `No GraalVM EA build found for version '${javaEaVersion}'. Please check if the version is correct.` ); } return fetchedJson; } public getPlatform(platform: NodeJS.Platform = process.platform): OsVersions { - switch (platform) { - case 'darwin': - return 'macos'; - case 'win32': - return 'windows'; - case 'linux': - return 'linux'; - default: - throw new Error( - `Platform '${platform}' is not supported. Supported platforms: 'linux', 'macos', 'windows'` - ); + const platformMap: Record = { + darwin: 'macos', + win32: 'windows', + linux: 'linux' + }; + + const result = platformMap[platform]; + if (!result) { + throw new Error( + `Platform '${platform}' is not supported. Supported platforms: 'linux', 'macos', 'windows'` + ); } + return result; } } diff --git a/src/util.ts b/src/util.ts index af75aaac..c59556af 100644 --- a/src/util.ts +++ b/src/util.ts @@ -183,9 +183,9 @@ export function convertVersionToSemver(version: number[] | string) { return mainVersion; } -export function getGitHubHttpHeaders(): OutgoingHttpHeaders { - const token = core.getInput('token'); - const auth = !token ? undefined : `token ${token}`; +export function getGitHubHttpHeaders(token?: string): OutgoingHttpHeaders { + const resolvedToken = token || core.getInput('token'); + const auth = !resolvedToken ? undefined : `token ${resolvedToken}`; const headers: OutgoingHttpHeaders = { accept: 'application/vnd.github.VERSION.raw'