diff --git a/__tests__/distributors/graalvm-installer.test.ts b/__tests__/distributors/graalvm-installer.test.ts index 479f3452..1fa671c4 100644 --- a/__tests__/distributors/graalvm-installer.test.ts +++ b/__tests__/distributors/graalvm-installer.test.ts @@ -1,156 +1,732 @@ -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 * as tc from '@actions/tool-cache'; +import * as http from '@actions/http-client'; +import fs from 'fs'; +import path from 'path'; +import {GraalVMDistribution} from '../../src/distributions/graalvm/installer'; +import {JavaInstallerOptions} from '../../src/distributions/base-models'; +import * as util from '../../src/util'; -describe('findPackageForDownload', () => { +jest.mock('@actions/core'); +jest.mock('@actions/tool-cache'); +jest.mock('@actions/http-client'); + +jest.mock('../../src/util', () => ({ + ...jest.requireActual('../../src/util'), + extractJdkFile: jest.fn(), + getDownloadArchiveExtension: jest.fn(), + renameWinArchive: jest.fn(), + getGitHubHttpHeaders: jest.fn().mockReturnValue({Accept: 'application/json'}) +})); + +jest.mock('fs', () => ({ + ...jest.requireActual('fs'), + readdirSync: jest.fn() +})); + +beforeAll(() => { + process.env.NODE_ENV = 'test'; + + if (!jest.isMockFunction(http.HttpClient)) { + throw new Error('HTTP client must be mocked in tests!'); + } + + if (!jest.isMockFunction(tc.downloadTool)) { + throw new Error('Tool cache downloadTool must be mocked in tests!'); + } + + console.log('✅ All external dependencies are properly mocked'); +}); + +describe('GraalVMDistribution', () => { let distribution: GraalVMDistribution; - let spyDebug: jest.SpyInstance; - let spyHttpClient: jest.SpyInstance; + let mockHttpClient: jest.Mocked; + + const defaultOptions: JavaInstallerOptions = { + version: '17', + architecture: 'x64', + packageType: 'jdk', + checkLatest: false + }; beforeEach(() => { - distribution = new GraalVMDistribution({ - version: '', - architecture: 'x64', - packageType: 'jdk', - checkLatest: false - }); + jest.clearAllMocks(); - spyDebug = jest.spyOn(core, 'debug'); - spyDebug.mockImplementation(() => {}); + distribution = new GraalVMDistribution(defaultOptions); + + mockHttpClient = new http.HttpClient() as jest.Mocked; + (distribution as any).http = mockHttpClient; + + (util.getDownloadArchiveExtension as jest.Mock).mockReturnValue('tar.gz'); }); - it.each([ - [ - '21', - '21', - 'https://download.oracle.com/graalvm/21/latest/graalvm-jdk-21_{{OS_TYPE}}-x64_bin.{{ARCHIVE_TYPE}}' - ], - [ - '21.0.4', - '21.0.4', - 'https://download.oracle.com/graalvm/21/archive/graalvm-jdk-21.0.4_{{OS_TYPE}}-x64_bin.{{ARCHIVE_TYPE}}' - ], - [ - '17', - '17', - 'https://download.oracle.com/graalvm/17/latest/graalvm-jdk-17_{{OS_TYPE}}-x64_bin.{{ARCHIVE_TYPE}}' - ], - [ - '17.0.12', - '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 - } - }) - ); + afterAll(() => { + expect(jest.isMockFunction(http.HttpClient)).toBe(true); - const result = await distribution['findPackageForDownload'](input); + expect(jest.isMockFunction(tc.downloadTool)).toBe(true); + expect(jest.isMockFunction(tc.cacheDir)).toBe(true); jest.restoreAllMocks(); - - 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); + jest.clearAllMocks(); }); - 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 - } - }) - ); - - const eaDistro = new GraalVMDistribution({ - version, - architecture: '', // to get default value - packageType: 'jdk', - checkLatest: false + describe('getPlatform', () => { + it('should map darwin to macos', () => { + const result = distribution.getPlatform('darwin'); + expect(result).toBe('macos'); }); - const versionWithoutEA = version.split('-')[0]; - const result = await eaDistro['findPackageForDownload'](versionWithoutEA); + it('should map win32 to windows', () => { + const result = distribution.getPlatform('win32'); + expect(result).toBe('windows'); + }); - jest.restoreAllMocks(); + it('should map linux to linux', () => { + const result = distribution.getPlatform('linux'); + expect(result).toBe('linux'); + }); - expect(result.url).toEqual(expect.stringMatching(expectedUrlPrefix)); + it('should throw error for unsupported platform', () => { + expect(() => distribution.getPlatform('aix' as NodeJS.Platform)).toThrow( + "Platform 'aix' is not supported. Supported platforms: 'linux', 'macos', 'windows'" + ); + }); }); - it.each([ - ['amd64', ['x64', 'amd64']], - ['arm64', ['aarch64', 'arm64']] - ])( - 'defaults to os.arch(): %s mapped to distro arch: %s', - async (osArch: string, distroArchs: string[]) => { + describe('downloadTool', () => { + const javaRelease = { + version: '17.0.5', + url: 'https://example.com/graalvm.tar.gz' + }; + + beforeEach(() => { + (tc.downloadTool as jest.Mock).mockResolvedValue('/tmp/archive.tar.gz'); + (tc.cacheDir as jest.Mock).mockResolvedValue('/cached/java/path'); + + (util.extractJdkFile as jest.Mock).mockResolvedValue('/tmp/extracted'); + + // Mock renameWinArchive - it returns the same path (no renaming) + // But it appears the implementation might not even call this + (util.renameWinArchive as jest.Mock).mockImplementation((p: string) => p); + + (util.getDownloadArchiveExtension as jest.Mock).mockReturnValue('tar.gz'); + + (fs.readdirSync as jest.Mock).mockReturnValue(['graalvm-jdk-17.0.5']); + jest - .spyOn(os, 'arch') - .mockReturnValue(osArch as ReturnType); + .spyOn(distribution as any, 'getToolcacheVersionName') + .mockImplementation(version => version); + }); - const distribution = new GraalVMDistribution({ - version: '21', - architecture: '', // to get default value - packageType: 'jdk', - checkLatest: false - }); + it('should download, extract and cache the tool successfully', async () => { + const result = await (distribution as any).downloadTool(javaRelease); - const osType = distribution.getPlatform(); - if (osType === 'windows' && distroArchs.includes('aarch64')) { - return; // skip, aarch64 is not available for Windows - } - const archiveType = getDownloadArchiveExtension(); - const result = await distribution['findPackageForDownload']('21'); + // Verify the download was initiated + expect(tc.downloadTool).toHaveBeenCalledWith(javaRelease.url); - const expectedUrls = distroArchs.map( - distroArch => - `https://download.oracle.com/graalvm/21/latest/graalvm-jdk-21_${osType}-${distroArch}_bin.${archiveType}` + // The implementation uses the original path for extraction + expect(util.extractJdkFile).toHaveBeenCalledWith( + '/tmp/archive.tar.gz', // Original path + 'tar.gz' ); - expect(expectedUrls).toContain(result.url); - } - ); + // Verify directory reading + expect(fs.readdirSync).toHaveBeenCalledWith('/tmp/extracted'); - 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 */ - ); + // Verify caching with correct parameters + expect(tc.cacheDir).toHaveBeenCalledWith( + path.join('/tmp/extracted', 'graalvm-jdk-17.0.5'), + 'Java_GraalVM_jdk', + '17.0.5', + 'x64' + ); - const unavailableEADistro = new GraalVMDistribution({ - version: '17-ea', - architecture: '', // to get default value - packageType: 'jdk', - checkLatest: false + // Verify the result + expect(result).toEqual({ + version: '17.0.5', + path: '/cached/java/path' + }); + + // Verify logging + expect(core.info).toHaveBeenCalledWith( + 'Downloading Java 17.0.5 (GraalVM) from https://example.com/graalvm.tar.gz ...' + ); + expect(core.info).toHaveBeenCalledWith('Extracting Java archive...'); + }); + + it('should verify that renameWinArchive is available but may not be called', () => { + // Just verify the mock is set up correctly + const originalPath = '/tmp/archive.tar.gz'; + + // Call the mock directly to verify it works + const result = util.renameWinArchive(originalPath); + + // Verify it returns the same path (no renaming) + expect(result).toBe(originalPath); + expect(util.renameWinArchive).toHaveBeenCalledWith(originalPath); + }); + + it('should handle different archive extensions', async () => { + // Test with a .zip file + (util.getDownloadArchiveExtension as jest.Mock).mockReturnValue('zip'); + (tc.downloadTool as jest.Mock).mockResolvedValue('/tmp/archive.zip'); + + const zipRelease = { + version: '17.0.5', + url: 'https://example.com/graalvm.zip' + }; + + const result = await (distribution as any).downloadTool(zipRelease); + + expect(util.extractJdkFile).toHaveBeenCalledWith( + '/tmp/archive.zip', + 'zip' + ); + + expect(result).toEqual({ + version: '17.0.5', + path: '/cached/java/path' + }); + }); + }); + + describe('findPackageForDownload', () => { + beforeEach(() => { + jest.spyOn(distribution, 'getPlatform').mockReturnValue('linux'); + }); + + describe('stable builds', () => { + it('should construct correct URL for specific version', async () => { + const mockResponse = { + message: {statusCode: 200} + } as http.HttpClientResponse; + mockHttpClient.head.mockResolvedValue(mockResponse); + + const result = await (distribution as any).findPackageForDownload( + '17.0.5' + ); + + expect(result).toEqual({ + url: 'https://download.oracle.com/graalvm/17/archive/graalvm-jdk-17.0.5_linux-x64_bin.tar.gz', + version: '17.0.5' + }); + expect(mockHttpClient.head).toHaveBeenCalledWith(result.url); + }); + + it('should construct correct URL for major version (latest)', async () => { + const mockResponse = { + message: {statusCode: 200} + } as http.HttpClientResponse; + mockHttpClient.head.mockResolvedValue(mockResponse); + + const result = await (distribution as any).findPackageForDownload('21'); + + expect(result).toEqual({ + url: 'https://download.oracle.com/graalvm/21/latest/graalvm-jdk-21_linux-x64_bin.tar.gz', + version: '21' + }); + }); + + it('should throw error for unsupported architecture', async () => { + distribution = new GraalVMDistribution({ + ...defaultOptions, + architecture: 'x86' + }); + (distribution as any).http = mockHttpClient; + + await expect( + (distribution as any).findPackageForDownload('17') + ).rejects.toThrow('Unsupported architecture: x86'); + }); + + it('should throw error for JDK versions less than 17', async () => { + await expect( + (distribution as any).findPackageForDownload('11') + ).rejects.toThrow('GraalVM is only supported for JDK 17 and later'); + }); + + it('should throw error for non-jdk package types', async () => { + distribution = new GraalVMDistribution({ + ...defaultOptions, + packageType: 'jre' + }); + (distribution as any).http = mockHttpClient; + + await expect( + (distribution as any).findPackageForDownload('17') + ).rejects.toThrow('GraalVM provides only the `jdk` package type'); + }); + + it('should throw error when file not found (404)', async () => { + const mockResponse = { + message: {statusCode: 404} + } as http.HttpClientResponse; + mockHttpClient.head.mockResolvedValue(mockResponse); + + await expect( + (distribution as any).findPackageForDownload('17.0.99') + ).rejects.toThrow('Could not find GraalVM for SemVer 17.0.99'); + }); + + it('should throw error for other HTTP errors', async () => { + const mockResponse = { + message: {statusCode: 500} + } as http.HttpClientResponse; + mockHttpClient.head.mockResolvedValue(mockResponse); + + await expect( + (distribution as any).findPackageForDownload('17') + ).rejects.toThrow( + 'Http request for GraalVM failed with status code: 500' + ); + }); + }); + + describe('EA builds', () => { + beforeEach(() => { + distribution = new GraalVMDistribution(defaultOptions); + (distribution as any).http = mockHttpClient; + (distribution as any).stable = false; + }); + + it('should delegate to findEABuildDownloadUrl for unstable versions', async () => { + const currentPlatform = + process.platform === 'win32' ? 'windows' : process.platform; + + const mockEAVersions = [ + { + version: '23-ea-20240716', + latest: true, + download_base_url: 'https://example.com/download/', + files: [ + { + arch: 'x64', + platform: currentPlatform, + filename: 'graalvm-jdk-23_linux-x64_bin.tar.gz' + }, + { + arch: 'aarch64', + platform: currentPlatform, + filename: 'graalvm-jdk-23_linux-aarch64_bin.tar.gz' + } + ] + } + ]; + + mockHttpClient.getJson.mockResolvedValue({ + result: mockEAVersions, + statusCode: 200, + headers: {} + }); + + jest + .spyOn(distribution as any, 'distributionArchitecture') + .mockReturnValue('x64'); + + const result = await (distribution as any).findPackageForDownload('23'); + + expect(result).toEqual({ + url: 'https://example.com/download/graalvm-jdk-23_linux-x64_bin.tar.gz', + version: '23-ea-20240716' + }); + + expect(mockHttpClient.getJson).toHaveBeenCalledWith( + 'https://api.github.com/repos/graalvm/oracle-graalvm-ea-builds/contents/versions/23-ea.json?ref=main', + {Accept: 'application/json'} + ); + }); + + it('should throw error when no latest EA version found', async () => { + const currentPlatform = + process.platform === 'win32' ? 'windows' : process.platform; + + const mockEAVersions = [ + { + version: '23-ea-20240716', + latest: false, + download_base_url: 'https://example.com/download/', + files: [ + { + arch: 'x64', + platform: currentPlatform, + filename: 'graalvm-jdk-23_linux-x64_bin.tar.gz' + } + ] + } + ]; + + mockHttpClient.getJson.mockResolvedValue({ + result: mockEAVersions, + statusCode: 200, + headers: {} + }); + + jest + .spyOn(distribution as any, 'distributionArchitecture') + .mockReturnValue('x64'); + + await expect( + (distribution as any).findPackageForDownload('23') + ).rejects.toThrow("Unable to find latest version for '23-ea'"); + }); + + it('should throw error when no matching file for architecture in EA build', async () => { + const currentPlatform = + process.platform === 'win32' ? 'windows' : process.platform; + + const mockEAVersions = [ + { + version: '23-ea-20240716', + latest: true, + download_base_url: 'https://example.com/download/', + files: [ + { + arch: 'arm64', + platform: currentPlatform, + filename: 'graalvm-jdk-23_linux-arm64_bin.tar.gz' + } + ] + } + ]; + + mockHttpClient.getJson.mockResolvedValue({ + result: mockEAVersions, + statusCode: 200, + headers: {} + }); + + jest + .spyOn(distribution as any, 'distributionArchitecture') + .mockReturnValue('x64'); + + await expect( + (distribution as any).findPackageForDownload('23') + ).rejects.toThrow("Unable to find file metadata for '23-ea'"); + }); + + it('should throw error when no matching platform in EA build', async () => { + const mockEAVersions = [ + { + version: '23-ea-20240716', + latest: true, + download_base_url: 'https://example.com/download/', + files: [ + { + arch: 'x64', + platform: 'different-platform', + filename: 'graalvm-jdk-23_different-x64_bin.tar.gz' + } + ] + } + ]; + + mockHttpClient.getJson.mockResolvedValue({ + result: mockEAVersions, + statusCode: 200, + headers: {} + }); + + jest + .spyOn(distribution as any, 'distributionArchitecture') + .mockReturnValue('x64'); + + await expect( + (distribution as any).findPackageForDownload('23') + ).rejects.toThrow("Unable to find file metadata for '23-ea'"); + }); + + it('should throw error when filename does not start with graalvm-jdk-', async () => { + const currentPlatform = + process.platform === 'win32' ? 'windows' : process.platform; + + const mockEAVersions = [ + { + version: '23-ea-20240716', + latest: true, + download_base_url: 'https://example.com/download/', + files: [ + { + arch: 'x64', + platform: currentPlatform, + filename: 'wrong-prefix-23_linux-x64_bin.tar.gz' + } + ] + } + ]; + + mockHttpClient.getJson.mockResolvedValue({ + result: mockEAVersions, + statusCode: 200, + headers: {} + }); + + jest + .spyOn(distribution as any, 'distributionArchitecture') + .mockReturnValue('x64'); + + await expect( + (distribution as any).findPackageForDownload('23') + ).rejects.toThrow("Unable to find file metadata for '23-ea'"); + }); + + it('should throw error when EA version JSON is not found', async () => { + mockHttpClient.getJson.mockResolvedValue({ + result: null, + statusCode: 404, + headers: {} + }); + + await expect( + (distribution as any).findPackageForDownload('23') + ).rejects.toThrow("No GraalVM EA build found for version '23-ea'"); + }); + }); + }); + + describe('findEABuildDownloadUrl', () => { + const currentPlatform = + process.platform === 'win32' ? 'windows' : process.platform; + + const mockEAVersions = [ + { + version: '23-ea-20240716', + latest: true, + download_base_url: 'https://example.com/download/', + files: [ + { + arch: 'x64', + platform: currentPlatform, + filename: 'graalvm-jdk-23_linux-x64_bin.tar.gz' + }, + { + arch: 'aarch64', + platform: currentPlatform, + filename: 'graalvm-jdk-23_linux-aarch64_bin.tar.gz' + } + ] + }, + { + version: '23-ea-20240709', + latest: false, + download_base_url: 'https://example.com/old/', + files: [ + { + arch: 'x64', + platform: currentPlatform, + filename: 'graalvm-jdk-23_linux-x64_bin.tar.gz' + } + ] + } + ]; + + let fetchEASpy: jest.SpyInstance; + + beforeEach(() => { + fetchEASpy = jest.spyOn(distribution as any, 'fetchEAJson'); + jest + .spyOn(distribution as any, 'distributionArchitecture') + .mockReturnValue('x64'); + }); + + it('should find latest version and return correct URL', async () => { + fetchEASpy.mockResolvedValue(mockEAVersions); + + const result = await (distribution as any).findEABuildDownloadUrl( + '23-ea' + ); + + expect(fetchEASpy).toHaveBeenCalledWith('23-ea'); + expect(result).toEqual({ + url: 'https://example.com/download/graalvm-jdk-23_linux-x64_bin.tar.gz', + version: '23-ea-20240716' + }); + }); + + it('should throw error when no latest version found', async () => { + const noLatestVersions = mockEAVersions.map(v => ({...v, latest: false})); + fetchEASpy.mockResolvedValue(noLatestVersions); + + await expect( + (distribution as any).findEABuildDownloadUrl('23-ea') + ).rejects.toThrow("Unable to find latest version for '23-ea'"); + }); + + it('should throw error when no matching file for architecture', async () => { + const wrongArchVersions = [ + { + version: '23-ea-20240716', + latest: true, + download_base_url: 'https://example.com/download/', + files: [ + { + arch: 'arm', + platform: currentPlatform, + filename: 'graalvm-jdk-23_linux-arm_bin.tar.gz' + } + ] + } + ]; + fetchEASpy.mockResolvedValue(wrongArchVersions); + + await expect( + (distribution as any).findEABuildDownloadUrl('23-ea') + ).rejects.toThrow("Unable to find file metadata for '23-ea'"); + }); + + it('should throw error when filename does not start with graalvm-jdk-', async () => { + const badFilenameVersions = [ + { + version: '23-ea-20240716', + latest: true, + download_base_url: 'https://example.com/download/', + files: [ + { + arch: 'x64', + platform: currentPlatform, + filename: 'wrong-name.tar.gz' + } + ] + } + ]; + fetchEASpy.mockResolvedValue(badFilenameVersions); + + await expect( + (distribution as any).findEABuildDownloadUrl('23-ea') + ).rejects.toThrow("Unable to find file metadata for '23-ea'"); + }); + + it('should work with aarch64 architecture', async () => { + jest + .spyOn(distribution as any, 'distributionArchitecture') + .mockReturnValue('aarch64'); + + fetchEASpy.mockResolvedValue(mockEAVersions); + + const result = await (distribution as any).findEABuildDownloadUrl( + '23-ea' + ); + + expect(result).toEqual({ + url: 'https://example.com/download/graalvm-jdk-23_linux-aarch64_bin.tar.gz', + version: '23-ea-20240716' + }); + }); + + it('should throw error when platform does not match', async () => { + const wrongPlatformVersions = [ + { + version: '23-ea-20240716', + latest: true, + download_base_url: 'https://example.com/download/', + files: [ + { + arch: 'x64', + platform: 'different-platform', + filename: 'graalvm-jdk-23_different-x64_bin.tar.gz' + } + ] + } + ]; + fetchEASpy.mockResolvedValue(wrongPlatformVersions); + + await expect( + (distribution as any).findEABuildDownloadUrl('23-ea') + ).rejects.toThrow("Unable to find file metadata for '23-ea'"); + }); + }); + + describe('fetchEAJson', () => { + it('should fetch and return EA version data', async () => { + const mockData = [{version: '23-ea', files: []}]; + mockHttpClient.getJson.mockResolvedValue({ + result: mockData, + statusCode: 200, + headers: {} + }); + + const result = await (distribution as any).fetchEAJson('23-ea'); + + expect(mockHttpClient.getJson).toHaveBeenCalledWith( + 'https://api.github.com/repos/graalvm/oracle-graalvm-ea-builds/contents/versions/23-ea.json?ref=main', + {Accept: 'application/json'} + ); + expect(result).toEqual(mockData); + expect(core.debug).toHaveBeenCalled(); + }); + + it('should throw error when no data returned', async () => { + mockHttpClient.getJson.mockResolvedValue({ + result: null, + statusCode: 200, + headers: {} + }); + + await expect((distribution as any).fetchEAJson('23-ea')).rejects.toThrow( + "No GraalVM EA build found for version '23-ea'. Please check if the version is correct." + ); + }); + + it('should handle HTTP errors properly', async () => { + mockHttpClient.getJson.mockRejectedValue(new Error('Network error')); + + await expect((distribution as any).fetchEAJson('23-ea')).rejects.toThrow( + 'Network error' + ); + }); + }); + + describe('Integration tests', () => { + it('should handle different architectures correctly', async () => { + const architectures = ['x64', 'aarch64']; + + for (const arch of architectures) { + distribution = new GraalVMDistribution({ + ...defaultOptions, + architecture: arch + }); + (distribution as any).http = mockHttpClient; + + const mockResponse = { + message: {statusCode: 200} + } as http.HttpClientResponse; + mockHttpClient.head.mockResolvedValue(mockResponse); + + const result = await (distribution as any).findPackageForDownload('17'); + expect(result.url).toContain(arch); + } + }); + + it('should handle different platforms correctly', async () => { + const platforms = [ + {process: 'darwin', expected: 'macos'}, + {process: 'win32', expected: 'windows'}, + {process: 'linux', expected: 'linux'} + ]; + + const originalPlatform = process.platform; + + for (const {process: proc, expected} of platforms) { + Object.defineProperty(process, 'platform', { + value: proc, + configurable: true + }); + + distribution = new GraalVMDistribution(defaultOptions); + (distribution as any).http = mockHttpClient; + + const mockResponse = { + message: {statusCode: 200} + } as http.HttpClientResponse; + mockHttpClient.head.mockResolvedValue(mockResponse); + + const result = await (distribution as any).findPackageForDownload('17'); + expect(result.url).toContain(expected); + } + + Object.defineProperty(process, 'platform', { + value: originalPlatform, + configurable: true + }); }); - await expect( - unavailableEADistro['findPackageForDownload']('17') - ).rejects.toThrow( - /No GraalVM EA build found\. Are you sure java-version: '17-ea' is correct\?/ - ); }); }); diff --git a/dist/cleanup/index.js b/dist/cleanup/index.js index 79ad0b5f..77b588c8 100644 --- a/dist/cleanup/index.js +++ b/dist/cleanup/index.js @@ -94747,8 +94747,8 @@ function convertVersionToSemver(version) { } exports.convertVersionToSemver = convertVersionToSemver; function getGitHubHttpHeaders() { - const token = core.getInput('token'); - const auth = !token ? undefined : `token ${token}`; + const resolvedToken = core.getInput('token') || process.env.GITHUB_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 c4e8ec9e..e2ed8559 100644 --- a/dist/setup/index.js +++ b/dist/setup/index.js @@ -130525,8 +130525,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; @@ -130540,12 +130540,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 }; @@ -130554,7 +130553,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) { @@ -130565,29 +130564,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); @@ -130608,38 +130607,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; @@ -132782,8 +132772,8 @@ function convertVersionToSemver(version) { } exports.convertVersionToSemver = convertVersionToSemver; function getGitHubHttpHeaders() { - const token = core.getInput('token'); - const auth = !token ? undefined : `token ${token}`; + const resolvedToken = core.getInput('token') || process.env.GITHUB_TOKEN; + const auth = !resolvedToken ? undefined : `token ${resolvedToken}`; const headers = { accept: 'application/vnd.github.VERSION.raw' }; diff --git a/package-lock.json b/package-lock.json index c99ed7e9..d550f141 100644 --- a/package-lock.json +++ b/package-lock.json @@ -841,9 +841,9 @@ "dev": true }, "node_modules/@eslint-community/eslint-utils": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.7.0.tgz", - "integrity": "sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==", + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.0.tgz", + "integrity": "sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==", "dev": true, "dependencies": { "eslint-visitor-keys": "^3.4.3" @@ -1716,17 +1716,16 @@ "dev": true }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.35.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.35.1.tgz", - "integrity": "sha512-9XNTlo7P7RJxbVeICaIIIEipqxLKguyh+3UbXuT2XQuFp6d8VOeDEGuz5IiX0dgZo8CiI6aOFLg4e8cF71SFVg==", + "version": "8.43.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.43.0.tgz", + "integrity": "sha512-8tg+gt7ENL7KewsKMKDHXR1vm8tt9eMxjJBYINf6swonlWgkYn5NwyIgXpbbDxTNU5DgpDFfj95prcTq2clIQQ==", "dev": true, - "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.35.1", - "@typescript-eslint/type-utils": "8.35.1", - "@typescript-eslint/utils": "8.35.1", - "@typescript-eslint/visitor-keys": "8.35.1", + "@typescript-eslint/scope-manager": "8.43.0", + "@typescript-eslint/type-utils": "8.43.0", + "@typescript-eslint/utils": "8.43.0", + "@typescript-eslint/visitor-keys": "8.43.0", "graphemer": "^1.4.0", "ignore": "^7.0.0", "natural-compare": "^1.4.0", @@ -1740,9 +1739,9 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^8.35.1", + "@typescript-eslint/parser": "^8.43.0", "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <5.9.0" + "typescript": ">=4.8.4 <6.0.0" } }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { @@ -1750,22 +1749,20 @@ "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", "dev": true, - "license": "MIT", "engines": { "node": ">= 4" } }, "node_modules/@typescript-eslint/parser": { - "version": "8.35.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.35.1.tgz", - "integrity": "sha512-3MyiDfrfLeK06bi/g9DqJxP5pV74LNv4rFTyvGDmT3x2p1yp1lOd+qYZfiRPIOf/oON+WRZR5wxxuF85qOar+w==", + "version": "8.43.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.43.0.tgz", + "integrity": "sha512-B7RIQiTsCBBmY+yW4+ILd6mF5h1FUwJsVvpqkrgpszYifetQ2Ke+Z4u6aZh0CblkUGIdR59iYVyXqqZGkZ3aBw==", "dev": true, - "license": "MIT", "dependencies": { - "@typescript-eslint/scope-manager": "8.35.1", - "@typescript-eslint/types": "8.35.1", - "@typescript-eslint/typescript-estree": "8.35.1", - "@typescript-eslint/visitor-keys": "8.35.1", + "@typescript-eslint/scope-manager": "8.43.0", + "@typescript-eslint/types": "8.43.0", + "@typescript-eslint/typescript-estree": "8.43.0", + "@typescript-eslint/visitor-keys": "8.43.0", "debug": "^4.3.4" }, "engines": { @@ -1777,18 +1774,17 @@ }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <5.9.0" + "typescript": ">=4.8.4 <6.0.0" } }, "node_modules/@typescript-eslint/project-service": { - "version": "8.35.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.35.1.tgz", - "integrity": "sha512-VYxn/5LOpVxADAuP3NrnxxHYfzVtQzLKeldIhDhzC8UHaiQvYlXvKuVho1qLduFbJjjy5U5bkGwa3rUGUb1Q6Q==", + "version": "8.43.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.43.0.tgz", + "integrity": "sha512-htB/+D/BIGoNTQYffZw4uM4NzzuolCoaA/BusuSIcC8YjmBYQioew5VUZAYdAETPjeed0hqCaW7EHg+Robq8uw==", "dev": true, - "license": "MIT", "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.35.1", - "@typescript-eslint/types": "^8.35.1", + "@typescript-eslint/tsconfig-utils": "^8.43.0", + "@typescript-eslint/types": "^8.43.0", "debug": "^4.3.4" }, "engines": { @@ -1799,18 +1795,17 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "typescript": ">=4.8.4 <5.9.0" + "typescript": ">=4.8.4 <6.0.0" } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.35.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.35.1.tgz", - "integrity": "sha512-s/Bpd4i7ht2934nG+UoSPlYXd08KYz3bmjLEb7Ye1UVob0d1ENiT3lY8bsCmik4RqfSbPw9xJJHbugpPpP5JUg==", + "version": "8.43.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.43.0.tgz", + "integrity": "sha512-daSWlQ87ZhsjrbMLvpuuMAt3y4ba57AuvadcR7f3nl8eS3BjRc8L9VLxFLk92RL5xdXOg6IQ+qKjjqNEimGuAg==", "dev": true, - "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.35.1", - "@typescript-eslint/visitor-keys": "8.35.1" + "@typescript-eslint/types": "8.43.0", + "@typescript-eslint/visitor-keys": "8.43.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1821,11 +1816,10 @@ } }, "node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.35.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.35.1.tgz", - "integrity": "sha512-K5/U9VmT9dTHoNowWZpz+/TObS3xqC5h0xAIjXPw+MNcKV9qg6eSatEnmeAwkjHijhACH0/N7bkhKvbt1+DXWQ==", + "version": "8.43.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.43.0.tgz", + "integrity": "sha512-ALC2prjZcj2YqqL5X/bwWQmHA2em6/94GcbB/KKu5SX3EBDOsqztmmX1kMkvAJHzxk7TazKzJfFiEIagNV3qEA==", "dev": true, - "license": "MIT", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, @@ -1834,18 +1828,18 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "typescript": ">=4.8.4 <5.9.0" + "typescript": ">=4.8.4 <6.0.0" } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.35.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.35.1.tgz", - "integrity": "sha512-HOrUBlfVRz5W2LIKpXzZoy6VTZzMu2n8q9C2V/cFngIC5U1nStJgv0tMV4sZPzdf4wQm9/ToWUFPMN9Vq9VJQQ==", + "version": "8.43.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.43.0.tgz", + "integrity": "sha512-qaH1uLBpBuBBuRf8c1mLJ6swOfzCXryhKND04Igr4pckzSEW9JX5Aw9AgW00kwfjWJF0kk0ps9ExKTfvXfw4Qg==", "dev": true, - "license": "MIT", "dependencies": { - "@typescript-eslint/typescript-estree": "8.35.1", - "@typescript-eslint/utils": "8.35.1", + "@typescript-eslint/types": "8.43.0", + "@typescript-eslint/typescript-estree": "8.43.0", + "@typescript-eslint/utils": "8.43.0", "debug": "^4.3.4", "ts-api-utils": "^2.1.0" }, @@ -1858,15 +1852,14 @@ }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <5.9.0" + "typescript": ">=4.8.4 <6.0.0" } }, "node_modules/@typescript-eslint/types": { - "version": "8.35.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.35.1.tgz", - "integrity": "sha512-q/O04vVnKHfrrhNAscndAn1tuQhIkwqnaW+eu5waD5IPts2eX1dgJxgqcPx5BX109/qAz7IG6VrEPTOYKCNfRQ==", + "version": "8.43.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.43.0.tgz", + "integrity": "sha512-vQ2FZaxJpydjSZJKiSW/LJsabFFvV7KgLC5DiLhkBcykhQj8iK9BOaDmQt74nnKdLvceM5xmhaTF+pLekrxEkw==", "dev": true, - "license": "MIT", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, @@ -1876,16 +1869,15 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.35.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.35.1.tgz", - "integrity": "sha512-Vvpuvj4tBxIka7cPs6Y1uvM7gJgdF5Uu9F+mBJBPY4MhvjrjWGK4H0lVgLJd/8PWZ23FTqsaJaLEkBCFUk8Y9g==", + "version": "8.43.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.43.0.tgz", + "integrity": "sha512-7Vv6zlAhPb+cvEpP06WXXy/ZByph9iL6BQRBDj4kmBsW98AqEeQHlj/13X+sZOrKSo9/rNKH4Ul4f6EICREFdw==", "dev": true, - "license": "MIT", "dependencies": { - "@typescript-eslint/project-service": "8.35.1", - "@typescript-eslint/tsconfig-utils": "8.35.1", - "@typescript-eslint/types": "8.35.1", - "@typescript-eslint/visitor-keys": "8.35.1", + "@typescript-eslint/project-service": "8.43.0", + "@typescript-eslint/tsconfig-utils": "8.43.0", + "@typescript-eslint/types": "8.43.0", + "@typescript-eslint/visitor-keys": "8.43.0", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", @@ -1901,7 +1893,7 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "typescript": ">=4.8.4 <5.9.0" + "typescript": ">=4.8.4 <6.0.0" } }, "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { @@ -1909,7 +1901,6 @@ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", "dev": true, - "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" } @@ -1919,7 +1910,6 @@ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dev": true, - "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" }, @@ -1931,16 +1921,15 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.35.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.35.1.tgz", - "integrity": "sha512-lhnwatFmOFcazAsUm3ZnZFpXSxiwoa1Lj50HphnDe1Et01NF4+hrdXONSUHIcbVu2eFb1bAf+5yjXkGVkXBKAQ==", + "version": "8.43.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.43.0.tgz", + "integrity": "sha512-S1/tEmkUeeswxd0GGcnwuVQPFWo8NzZTOMxCvw8BX7OMxnNae+i8Tm7REQen/SwUIPoPqfKn7EaZ+YLpiB3k9g==", "dev": true, - "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.7.0", - "@typescript-eslint/scope-manager": "8.35.1", - "@typescript-eslint/types": "8.35.1", - "@typescript-eslint/typescript-estree": "8.35.1" + "@typescript-eslint/scope-manager": "8.43.0", + "@typescript-eslint/types": "8.43.0", + "@typescript-eslint/typescript-estree": "8.43.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1951,17 +1940,16 @@ }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <5.9.0" + "typescript": ">=4.8.4 <6.0.0" } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.35.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.35.1.tgz", - "integrity": "sha512-VRwixir4zBWCSTP/ljEo091lbpypz57PoeAQ9imjG+vbeof9LplljsL1mos4ccG6H9IjfrVGM359RozUnuFhpw==", + "version": "8.43.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.43.0.tgz", + "integrity": "sha512-T+S1KqRD4sg/bHfLwrpF/K3gQLBM1n7Rp7OjjikjTEssI2YJzQpi5WXoynOaQ93ERIuq3O8RBTOUYDKszUCEHw==", "dev": true, - "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.35.1", + "@typescript-eslint/types": "8.43.0", "eslint-visitor-keys": "^4.2.1" }, "engines": { @@ -1977,7 +1965,6 @@ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", "dev": true, - "license": "Apache-2.0", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, @@ -3097,7 +3084,6 @@ "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", "dev": true, - "license": "MIT", "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", @@ -3114,7 +3100,6 @@ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, - "license": "ISC", "dependencies": { "is-glob": "^4.0.1" }, @@ -4492,7 +4477,6 @@ "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", "dev": true, - "license": "MIT", "engines": { "node": ">= 8" } @@ -5507,7 +5491,6 @@ "version": "5.29.0", "resolved": "https://registry.npmjs.org/undici/-/undici-5.29.0.tgz", "integrity": "sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg==", - "license": "MIT", "dependencies": { "@fastify/busboy": "^2.0.0" }, 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 9e5f2f66..71913089 100644 --- a/src/util.ts +++ b/src/util.ts @@ -184,8 +184,8 @@ export function convertVersionToSemver(version: number[] | string) { } export function getGitHubHttpHeaders(): OutgoingHttpHeaders { - const token = core.getInput('token'); - const auth = !token ? undefined : `token ${token}`; + const resolvedToken = core.getInput('token') || process.env.GITHUB_TOKEN; + const auth = !resolvedToken ? undefined : `token ${resolvedToken}`; const headers: OutgoingHttpHeaders = { accept: 'application/vnd.github.VERSION.raw'