Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 26 additions & 1 deletion __tests__/mandrel.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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])
Expand All @@ -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)
})
48 changes: 24 additions & 24 deletions dist/main.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

53 changes: 15 additions & 38 deletions src/mandrel.ts
Original file line number Diff line number Diff line change
@@ -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<string> {
const version = stripMandrelNamespace(mandrelVersion)
Expand Down Expand Up @@ -54,39 +45,25 @@ function getTagFromURI(uri: string): string {
}
}

export async function getLatestMandrelReleaseUrl(javaVersion: string): Promise<string> {
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<JdkData>(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<string> {
const response = await _http.getJson<JdkData>(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<string> {
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}`
)
}
}
Expand Down
21 changes: 21 additions & 0 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,27 @@ export async function getLatestRelease(repo: string): Promise<c.LatestReleaseRes
).data as c.LatestReleaseResponseData /** missing digest property */
}

export async function findLatestReleaseWithAsset(
repo: string,
assetNamePredicate: (name: string) => boolean
): Promise<string> {
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<c.ContentsResponseData> {
const octokit = getOctokit()
return (
Expand Down
Loading