diff --git a/__tests__/mandrel.test.ts b/__tests__/mandrel.test.ts index 1c863c65..e47e459b 100644 --- a/__tests__/mandrel.test.ts +++ b/__tests__/mandrel.test.ts @@ -59,7 +59,7 @@ test('find latest', async () => { test('get known latest Mandrel for specific JDK', async () => { // Test deprecated versions that won't get updates anymore for (const combination of [ - ['11', '22.2.0.0-Final'], + ['11', '21.3.6.0-Final'], ['20', '23.0.1.2-Final'] ]) { const latest = await mandrel.getLatestMandrelReleaseUrl(combination[0]) @@ -75,3 +75,28 @@ test('get latest Mandrel for specific JDK', async () => { expect(latest).toContain(`mandrel-java${javaVersion}`) } }) + +test('matchesMandrelAsset matches correct platform-specific asset names', () => { + // Real asset names from mandrel-23.1.10.0-Final release + const linuxAmd64 = 'mandrel-java21-linux-amd64-23.1.10.0-Final.tar.gz' + const linuxAarch64 = 'mandrel-java21-linux-aarch64-23.1.10.0-Final.tar.gz' + const macosAarch64 = 'mandrel-java21-macos-aarch64-23.1.10.0-Final.tar.gz' + const windowsAmd64 = 'mandrel-java21-windows-amd64-23.1.10.0-Final.zip' + + // Linux x64 + expect(mandrel.matchesMandrelAsset(linuxAmd64, '21', 'linux', 'amd64', '.tar.gz')).toBe(true) + expect(mandrel.matchesMandrelAsset(linuxAarch64, '21', 'linux', 'amd64', '.tar.gz')).toBe(false) + + // macOS uses 'macos', not 'darwin' + expect(mandrel.matchesMandrelAsset(macosAarch64, '21', 'macos', 'aarch64', '.tar.gz')).toBe(true) + expect(mandrel.matchesMandrelAsset(macosAarch64, '21', 'darwin', 'aarch64', '.tar.gz')).toBe(false) + + // Windows + expect(mandrel.matchesMandrelAsset(windowsAmd64, '21', 'windows', 'amd64', '.zip')).toBe(true) + + // Wrong java version + expect(mandrel.matchesMandrelAsset(linuxAmd64, '17', 'linux', 'amd64', '.tar.gz')).toBe(false) + + // Wrong extension + expect(mandrel.matchesMandrelAsset(linuxAmd64, '21', 'linux', 'amd64', '.zip')).toBe(false) +}) diff --git a/dist/main.js b/dist/main.js index d8269df3..d05446c4 100644 --- a/dist/main.js +++ b/dist/main.js @@ -38095,6 +38095,23 @@ async function getLatestRelease(repo) { repo })).data; /** missing digest property */ } +async function findLatestReleaseWithAsset(repo, assetNamePredicate) { + const octokit = getOctokit(); + const iterator = octokit.paginate.iterator(octokit.rest.repos.listReleases, { + owner: GRAALVM_GH_USER, + repo, + per_page: 100 + }); + for await (const { data: releases } of iterator) { + for (const release of releases) { + const matchingAsset = release.assets.find((a) => assetNamePredicate(a.name)); + if (matchingAsset) { + return matchingAsset.browser_download_url; + } + } + } + throw new Error(`Could not find a release in '${repo}' with a matching asset.`); +} async function getContents(repo, path) { const octokit = getOctokit(); return (await octokit.request('GET /repos/{owner}/{repo}/contents/{path}', { @@ -81938,9 +81955,9 @@ async function installGUComponents(gdsToken, graalVMHome, components) { } } +const MANDREL_REPO = 'mandrel'; const MANDREL_TAG_PREFIX = MANDREL_NAMESPACE; const MANDREL_DL_BASE = 'https://github.com/graalvm/mandrel/releases/download'; -const DISCO_API_BASE = 'https://api.foojay.io/disco/v3.0/packages/jdks'; async function setUpMandrel(mandrelVersion, javaVersion) { const version = stripMandrelNamespace(mandrelVersion); let mandrelHome; @@ -81975,33 +81992,16 @@ function getTagFromURI(uri) { throw new Error(`Failed to extract tag from URI ${uri}: ${error}`); } } -async function getLatestMandrelReleaseUrl(javaVersion) { - const url = `${DISCO_API_BASE}?jdk_version=${javaVersion}&distribution=${DISTRIBUTION_MANDREL}&architecture=${JDK_ARCH}&operating_system=${JDK_PLATFORM}&latest=per_distro`; - const _http = new HttpClient(); - const response = await _http.getJson(url); - if (response.statusCode !== 200) { - throw new Error(`Failed to fetch latest Mandrel release for Java ${javaVersion} from DISCO API: ${response.result}`); - } - const result = response.result?.result[0]; - try { - const pkg_info_uri = result.links.pkg_info_uri; - return await getLatestMandrelReleaseUrlHelper(_http, javaVersion, pkg_info_uri); - } - catch (error) { - throw new Error(`Failed to get latest Mandrel release for Java ${javaVersion} from DISCO API: ${error}`); - } +function matchesMandrelAsset(name, javaVersion, platform, arch, extension) { + const expectedPrefix = `mandrel-java${javaVersion}-${platform}-${arch}-`; + return name.startsWith(expectedPrefix) && name.endsWith(extension); } -async function getLatestMandrelReleaseUrlHelper(_http, java_version, pkg_info_uri) { - const response = await _http.getJson(pkg_info_uri); - if (response.statusCode !== 200) { - throw new Error(`Failed to fetch package info of latest Mandrel release for Java ${java_version} from DISCO API: ${response.result}`); - } - const result = response.result?.result[0]; +async function getLatestMandrelReleaseUrl(javaVersion) { try { - return result.direct_download_uri; + return await findLatestReleaseWithAsset(MANDREL_REPO, (name) => matchesMandrelAsset(name, javaVersion, JDK_PLATFORM, GRAALVM_ARCH, GRAALVM_FILE_EXTENSION)); } catch (error) { - throw new Error(`Failed to get download URI of latest Mandrel release for Java ${java_version} from DISCO API: ${error}`); + throw new Error(`Failed to find latest Mandrel release for Java ${javaVersion}. Are you sure java-version: '${javaVersion}' is correct? ${error}`); } } async function setUpMandrelRelease(version, javaVersion) { diff --git a/src/mandrel.ts b/src/mandrel.ts index e6e03015..c8486e04 100644 --- a/src/mandrel.ts +++ b/src/mandrel.ts @@ -1,20 +1,11 @@ import * as c from './constants.js' -import * as httpClient from '@actions/http-client' -import { downloadExtractAndCacheJDK } from './utils.js' +import { downloadExtractAndCacheJDK, findLatestReleaseWithAsset } from './utils.js' import { downloadTool } from '@actions/tool-cache' import { basename } from 'path' export const MANDREL_REPO = 'mandrel' export const MANDREL_TAG_PREFIX = c.MANDREL_NAMESPACE const MANDREL_DL_BASE = 'https://github.com/graalvm/mandrel/releases/download' -const DISCO_API_BASE = 'https://api.foojay.io/disco/v3.0/packages/jdks' - -interface JdkData { - message: string - /* eslint-disable @typescript-eslint/no-explicit-any */ - result: any - /* eslint-enable @typescript-eslint/no-explicit-any */ -} export async function setUpMandrel(mandrelVersion: string, javaVersion: string): Promise { const version = stripMandrelNamespace(mandrelVersion) @@ -54,39 +45,25 @@ function getTagFromURI(uri: string): string { } } -export async function getLatestMandrelReleaseUrl(javaVersion: string): Promise { - const url = `${DISCO_API_BASE}?jdk_version=${javaVersion}&distribution=${c.DISTRIBUTION_MANDREL}&architecture=${c.JDK_ARCH}&operating_system=${c.JDK_PLATFORM}&latest=per_distro` - const _http = new httpClient.HttpClient() - const response = await _http.getJson(url) - if (response.statusCode !== 200) { - throw new Error(`Failed to fetch latest Mandrel release for Java ${javaVersion} from DISCO API: ${response.result}`) - } - const result = response.result?.result[0] - try { - const pkg_info_uri = result.links.pkg_info_uri - return await getLatestMandrelReleaseUrlHelper(_http, javaVersion, pkg_info_uri) - } catch (error) { - throw new Error(`Failed to get latest Mandrel release for Java ${javaVersion} from DISCO API: ${error}`) - } +export function matchesMandrelAsset( + name: string, + javaVersion: string, + platform: string, + arch: string, + extension: string +): boolean { + const expectedPrefix = `mandrel-java${javaVersion}-${platform}-${arch}-` + return name.startsWith(expectedPrefix) && name.endsWith(extension) } -async function getLatestMandrelReleaseUrlHelper( - _http: httpClient.HttpClient, - java_version: string, - pkg_info_uri: string -): Promise { - const response = await _http.getJson(pkg_info_uri) - if (response.statusCode !== 200) { - throw new Error( - `Failed to fetch package info of latest Mandrel release for Java ${java_version} from DISCO API: ${response.result}` - ) - } - const result = response.result?.result[0] +export async function getLatestMandrelReleaseUrl(javaVersion: string): Promise { try { - return result.direct_download_uri + return await findLatestReleaseWithAsset(MANDREL_REPO, (name) => + matchesMandrelAsset(name, javaVersion, c.JDK_PLATFORM, c.GRAALVM_ARCH, c.GRAALVM_FILE_EXTENSION) + ) } catch (error) { throw new Error( - `Failed to get download URI of latest Mandrel release for Java ${java_version} from DISCO API: ${error}` + `Failed to find latest Mandrel release for Java ${javaVersion}. Are you sure java-version: '${javaVersion}' is correct? ${error}` ) } } diff --git a/src/utils.ts b/src/utils.ts index 4d489d33..8ace6e04 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -29,6 +29,27 @@ export async function getLatestRelease(repo: string): Promise boolean +): Promise { + const octokit = getOctokit() + const iterator = octokit.paginate.iterator(octokit.rest.repos.listReleases, { + owner: c.GRAALVM_GH_USER, + repo, + per_page: 100 + }) + for await (const { data: releases } of iterator) { + for (const release of releases) { + const matchingAsset = release.assets.find((a) => assetNamePredicate(a.name)) + if (matchingAsset) { + return matchingAsset.browser_download_url + } + } + } + throw new Error(`Could not find a release in '${repo}' with a matching asset.`) +} + export async function getContents(repo: string, path: string): Promise { const octokit = getOctokit() return (