From 2240cb3432719dd942c6a9976f9b979e0786804e Mon Sep 17 00:00:00 2001 From: Fabio Niephaus Date: Thu, 3 Mar 2022 17:24:24 +0100 Subject: [PATCH] Add support for GraalVM Enterprise Edition. Fixes #5. --- .github/workflows/test.yml | 42 ++++++- __tests__/gds.test.ts | 44 ++++++++ __tests__/main.test.ts | 5 - action.yml | 5 +- package-lock.json | 28 +++-- package.json | 4 +- src/constants.ts | 3 + src/gds.ts | 220 +++++++++++++++++++++++++++++++++++++ src/graalvm.ts | 53 +++++++-- src/gu.ts | 9 +- src/main.ts | 8 +- src/mandrel.ts | 7 +- src/utils.ts | 28 +++-- 13 files changed, 415 insertions(+), 41 deletions(-) create mode 100644 __tests__/gds.test.ts delete mode 100644 __tests__/main.test.ts create mode 100644 src/gds.ts diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 66e86ce..7dbcfe1 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -18,8 +18,8 @@ jobs: npm install - run: | npm run all - test: # make sure the action works on a clean machine without building - name: ${{ matrix.version }} + JDK${{ matrix.java-version }} on ${{ matrix.os }} + test-ce: # make sure the action works on a clean machine without building + name: CE ${{ matrix.version }} + JDK${{ matrix.java-version }} on ${{ matrix.os }} runs-on: ${{ matrix.os }} strategy: matrix: @@ -62,6 +62,7 @@ jobs: echo "GRAALVM_HOME: $GRAALVM_HOME" echo "JAVA_HOME: $JAVA_HOME" java --version + java --version | grep "GraalVM CE" || exit 12 native-image --version if: runner.os != 'Windows' - name: Check Windows environment @@ -71,6 +72,41 @@ jobs: java --version native-image.cmd --version if: runner.os == 'Windows' + test-ee: + name: EE ${{ matrix.version }} + JDK${{ matrix.java-version }} on ${{ matrix.os }} + if: github.event_name != 'pull_request' + runs-on: ${{ matrix.os }} + strategy: + matrix: + version: ['21.3.0', 'latest'] + java-version: ['11', '17'] + components: [''] # ['native-image'] (activate after 22.1.0 is released) + os: [macos-latest, windows-latest, ubuntu-latest] + steps: + - uses: actions/checkout@v2 + - name: Run setup-graalvm action + uses: ./ + with: + version: ${{ matrix.version }} + gds-token: ${{ secrets.GDS_TOKEN }} + java-version: ${{ matrix.java-version }} + components: ${{ matrix.components }} + github-token: ${{ secrets.GITHUB_TOKEN }} + - name: Check environment + run: | + echo "GRAALVM_HOME: $GRAALVM_HOME" + echo "JAVA_HOME: $JAVA_HOME" + java --version + java --version | grep "GraalVM EE" || exit 12 + # native-image --version (activate after 22.1.0 is released) + if: runner.os != 'Windows' + - name: Check Windows environment + run: | + echo "GRAALVM_HOME: $env:GRAALVM_HOME" + echo "JAVA_HOME: $env:JAVA_HOME" + java --version + # native-image.cmd --version (activate after 22.1.0 is released) + if: runner.os == 'Windows' test-native-image-musl: name: native-image-musl on ubuntu-latest runs-on: ubuntu-latest @@ -90,7 +126,7 @@ jobs: javac HelloWorld.java native-image --static --libc=musl HelloWorld ./helloworld - test-additional: + test-extensive: name: extensive tests on ubuntu-latest runs-on: ubuntu-latest steps: diff --git a/__tests__/gds.test.ts b/__tests__/gds.test.ts new file mode 100644 index 0000000..150b8eb --- /dev/null +++ b/__tests__/gds.test.ts @@ -0,0 +1,44 @@ +import * as path from 'path' +import {downloadGraalVMEE, fetchArtifact} from '../src/gds' +import {expect, test} from '@jest/globals' + +const TEST_USER_AGENT = 'GraalVMGitHubActionTest/1.0.4' + +process.env['RUNNER_TEMP'] = path.join(__dirname, 'TEMP') + +test('fetch artifacts', async () => { + let artifact = await fetchArtifact( + TEST_USER_AGENT, + 'isBase:True', + '21.3.0', + '11' + ) + expect(artifact.id).toBe('D540A9EA0F406A12E0530F15000A38C7') + expect(artifact.checksum).toBe( + '78e1ee14861eb6a58fd0d7f64878d544ad11515c237a6557452f4d3a63a070fc' + ) + artifact = await fetchArtifact(TEST_USER_AGENT, 'isBase:True', '21.3.0', '17') + expect(artifact.id).toBe('D540A9EA10C26A12E0530F15000A38C7') + expect(artifact.checksum).toBe( + '173e0e2b1f80033115216ebbad574c977e74fc4a37fa30ae5e6eff0f215070f4' + ) + + await expect( + fetchArtifact(TEST_USER_AGENT, 'isBase:False', '21.3.0', '11') + ).rejects.toThrow('Found more than one GDS artifact') + await expect( + fetchArtifact(TEST_USER_AGENT, 'isBase:True', '1.0.0', '11') + ).rejects.toThrow('Unable to find JDK11-based GraalVM EE 1.0.0') +}) + +test('errors when downloading artifacts', async () => { + await expect(downloadGraalVMEE('invalid', '21.3.0', '11')).rejects.toThrow( + 'The provided "gds-token" was rejected (reason: "Invalid download token", opc-request-id: /' + ) + await expect(downloadGraalVMEE('invalid', '1.0.0', '11')).rejects.toThrow( + 'Unable to find JDK11-based GraalVM EE 1.0.0' + ) + await expect(downloadGraalVMEE('invalid', '21.3.0', '1')).rejects.toThrow( + 'Unable to find JDK1-based GraalVM EE 21.3.0' + ) +}) diff --git a/__tests__/main.test.ts b/__tests__/main.test.ts deleted file mode 100644 index fe0fff5..0000000 --- a/__tests__/main.test.ts +++ /dev/null @@ -1,5 +0,0 @@ -import {expect, test} from '@jest/globals' - -test('dummy test', async () => { - expect(true).toBeTruthy() -}) diff --git a/action.yml b/action.yml index cb38167..4777298 100644 --- a/action.yml +++ b/action.yml @@ -1,5 +1,5 @@ name: 'GitHub Action for GraalVM' -description: 'Set up a specific version of GraalVM Community Edition' +description: 'Set up a specific version of GraalVM Enterprise Edition (EE) or Community Edition (CE)' author: 'GraalVM Developers' branding: icon: 'terminal' @@ -8,6 +8,9 @@ inputs: version: required: true description: 'GraalVM version (release, latest, dev).' + gds-token: + required: false + description: 'Download token for the GraalVM Download Service. Set this to use GraalVM EE.' java-version: required: true description: 'Java version (11 or 17, 8 or 16 for older releases).' diff --git a/package-lock.json b/package-lock.json index bfbfb18..67de5d8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,10 +15,12 @@ "@actions/io": "^1.1.1", "@actions/tool-cache": "^1.7.1", "@octokit/core": "^3.5.1", - "@octokit/types": "^6.34.0" + "@octokit/types": "^6.34.0", + "uuid": "^3.3.2" }, "devDependencies": { "@types/node": "^17.0.6", + "@types/uuid": "^3.4.10", "@typescript-eslint/parser": "^5.8.1", "@vercel/ncc": "^0.33.1", "eslint": "^8.6.0", @@ -1309,6 +1311,12 @@ "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", "dev": true }, + "node_modules/@types/uuid": { + "version": "3.4.10", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-3.4.10.tgz", + "integrity": "sha512-BgeaZuElf7DEYZhWYDTc/XcLZXdVgFkVSTa13BqKvbnmUrxr3TJFKofUxCtDO9UQOdhnV+HPOESdHiHKZOJV1A==", + "dev": true + }, "node_modules/@types/yargs": { "version": "16.0.4", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", @@ -6096,9 +6104,9 @@ } }, "node_modules/uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", + "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==", "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", "bin": { "uuid": "bin/uuid" @@ -7389,6 +7397,12 @@ "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", "dev": true }, + "@types/uuid": { + "version": "3.4.10", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-3.4.10.tgz", + "integrity": "sha512-BgeaZuElf7DEYZhWYDTc/XcLZXdVgFkVSTa13BqKvbnmUrxr3TJFKofUxCtDO9UQOdhnV+HPOESdHiHKZOJV1A==", + "dev": true + }, "@types/yargs": { "version": "16.0.4", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", @@ -10938,9 +10952,9 @@ } }, "uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", + "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==" }, "v8-compile-cache": { "version": "2.3.0", diff --git a/package.json b/package.json index 4990877..a27298f 100644 --- a/package.json +++ b/package.json @@ -32,10 +32,12 @@ "@actions/io": "^1.1.1", "@actions/tool-cache": "^1.7.1", "@octokit/core": "^3.5.1", - "@octokit/types": "^6.34.0" + "@octokit/types": "^6.34.0", + "uuid": "^3.3.2" }, "devDependencies": { "@types/node": "^17.0.6", + "@types/uuid": "^3.4.10", "@typescript-eslint/parser": "^5.8.1", "@vercel/ncc": "^0.33.1", "eslint": "^8.6.0", diff --git a/src/constants.ts b/src/constants.ts index ad75f8d..40c25e3 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -15,6 +15,9 @@ export const JDK_HOME_SUFFIX = IS_MACOS ? '/Contents/Home' : '' export const MANDREL_NAMESPACE = 'mandrel-' +export const GDS_BASE = 'https://gds.oracle.com/api/20220101' +export const GDS_GRAALVM_PRODUCT_ID = 'D53FAE8052773FFAE0530F15000AA6C6' + export type LatestReleaseResponse = otypes.Endpoints['GET /repos/{owner}/{repo}/releases/latest']['response'] diff --git a/src/gds.ts b/src/gds.ts new file mode 100644 index 0000000..c495f90 --- /dev/null +++ b/src/gds.ts @@ -0,0 +1,220 @@ +import * as c from './constants' +import * as core from '@actions/core' +import * as fs from 'fs' +import * as httpClient from '@actions/http-client' +import * as io from '@actions/io' +import * as path from 'path' +import * as stream from 'stream' +import * as util from 'util' +import {IHeaders} from '@actions/http-client/interfaces' +import {IncomingHttpHeaders} from 'http' +import {RetryHelper} from '@actions/tool-cache/lib/retry-helper' +import {calculateSHA256} from './utils' +import {ok} from 'assert' +import uuidV4 from 'uuid/v4' + +interface GDSArtifactsResponse { + readonly items: GDSArtifact[] +} + +interface GDSArtifact { + readonly id: string + readonly checksum: string +} + +interface GDSErrorResponse { + readonly code: string + readonly message: string +} + +export async function downloadGraalVMEE( + gdsToken: string, + version: string, + javaVersion: string +): Promise { + const userAgent = `GraalVMGitHubAction/1.0.4 (arch:${c.GRAALVM_ARCH}; os:${c.GRAALVM_PLATFORM}; java:${javaVersion})` + const baseArtifact = await fetchArtifact( + userAgent, + 'isBase:True', + version, + javaVersion + ) + return downloadArtifact(gdsToken, userAgent, baseArtifact) +} + +export async function fetchArtifact( + userAgent: string, + metadata: string, + version: string, + javaVersion: string +): Promise { + const http = new httpClient.HttpClient(userAgent) + + let filter + if (version === c.VERSION_LATEST) { + filter = `sortBy=timeCreated&limit=1` // latest and only one item + } else { + filter = `metadata=version:${version}` + } + + const response = await http.get( + `${c.GDS_BASE}/artifacts?productId=${c.GDS_GRAALVM_PRODUCT_ID}&${filter}&metadata=java:jdk${javaVersion}&metadata=os:${c.GRAALVM_PLATFORM}&metadata=arch:${c.GRAALVM_ARCH}&metadata=${metadata}&status=PUBLISHED&responseFields=id&responseFields=checksum`, + {accept: 'application/json'} + ) + if (response.message.statusCode !== 200) { + throw new Error( + `Unable to find JDK${javaVersion}-based GraalVM EE ${version}` + ) + } + const artifactResponse = JSON.parse( + await response.readBody() + ) as GDSArtifactsResponse + if (artifactResponse.items.length !== 1) { + throw new Error(`Found more than one GDS artifact`) + } + return artifactResponse.items[0] +} + +async function downloadArtifact( + gdsToken: string, + userAgent: string, + artifact: GDSArtifact +): Promise { + let downloadPath + try { + downloadPath = await downloadTool( + `${c.GDS_BASE}/artifacts/${artifact.id}/content`, + userAgent, + { + accept: 'application/x-yaml', + 'x-download-token': gdsToken + } + ) + } catch (err) { + if (err instanceof HTTPError && err.httpStatusCode) { + if (err.httpStatusCode === 401) { + throw new Error( + `The provided "gds-token" was rejected (reason: "${err.gdsError.message}", opc-request-id: ${err.headers['opc-request-id']})` + ) + } + } + throw err + } + const sha256 = calculateSHA256(downloadPath) + if (sha256.toLowerCase() !== artifact.checksum.toLowerCase()) { + throw new Error( + `Checksum does not match (expected: "${artifact.checksum}", got: "${sha256}")` + ) + } + return downloadPath +} + +/** + * Simplified fork of tool-cache's downloadTool [1] with the ability to set a custom user agent. + * [1] https://github.com/actions/toolkit/blob/2f164000dcd42fb08287824a3bc3030dbed33687/packages/tool-cache/src/tool-cache.ts + */ + +class HTTPError extends Error { + constructor( + readonly httpStatusCode: number | undefined, + readonly gdsError: GDSErrorResponse, + readonly headers: IncomingHttpHeaders + ) { + super(`Unexpected HTTP response: ${httpStatusCode}`) + Object.setPrototypeOf(this, new.target.prototype) + } +} + +async function downloadTool( + url: string, + userAgent: string, + headers?: IHeaders +): Promise { + const dest = path.join(getTempDirectory(), uuidV4()) + await io.mkdirP(path.dirname(dest)) + core.debug(`Downloading ${url}`) + core.debug(`Destination ${dest}`) + + const maxAttempts = 3 + const minSeconds = 10 + const maxSeconds = 20 + const retryHelper = new RetryHelper(maxAttempts, minSeconds, maxSeconds) + return await retryHelper.execute( + async () => { + return await downloadToolAttempt(url, userAgent, dest || '', headers) + }, + (err: Error) => { + if (err instanceof HTTPError && err.httpStatusCode) { + // Don't retry anything less than 500, except 408 Request Timeout and 429 Too Many Requests + if ( + err.httpStatusCode < 500 && + err.httpStatusCode !== 408 && + err.httpStatusCode !== 429 + ) { + return false + } + } + + // Otherwise retry + return true + } + ) +} + +async function downloadToolAttempt( + url: string, + userAgent: string, + dest: string, + headers?: IHeaders +): Promise { + if (fs.existsSync(dest)) { + throw new Error(`Destination file path ${dest} already exists`) + } + + // Get the response headers + const http = new httpClient.HttpClient(userAgent, [], { + allowRetries: false + }) + + const response: httpClient.HttpClientResponse = await http.get(url, headers) + if (response.message.statusCode !== 200) { + const errorResponse = JSON.parse( + await response.readBody() + ) as GDSErrorResponse + const err = new HTTPError( + response.message.statusCode, + errorResponse, + response.message.headers + ) + core.debug( + `Failed to download from "${url}". Code(${response.message.statusCode}) Message(${response.message.statusMessage})` + ) + throw err + } + + // Download the response body + const pipeline = util.promisify(stream.pipeline) + let succeeded = false + try { + await pipeline(response.message, fs.createWriteStream(dest)) + core.debug('Download complete') + succeeded = true + return dest + } finally { + // Error, delete dest before retry + if (!succeeded) { + core.debug('Download failed') + try { + await io.rmRF(dest) + } catch (err) { + core.debug(`Failed to delete '${dest}'. ${err}`) + } + } + } +} + +function getTempDirectory(): string { + const tempDirectory = process.env['RUNNER_TEMP'] || '' + ok(tempDirectory, 'Expected RUNNER_TEMP to be defined') + return tempDirectory +} diff --git a/src/graalvm.ts b/src/graalvm.ts index 4cc7d73..48d2d83 100644 --- a/src/graalvm.ts +++ b/src/graalvm.ts @@ -4,6 +4,8 @@ import { downloadExtractAndCacheJDK, getLatestRelease } from './utils' +import {downloadGraalVMEE} from './gds' +import {downloadTool} from '@actions/tool-cache' const GRAALVM_CE_DL_BASE = 'https://github.com/graalvm/graalvm-ce-builds/releases/download' @@ -11,7 +13,13 @@ const GRAALVM_REPO_DEV_BUILDS = 'graalvm-ce-dev-builds' const GRAALVM_REPO_RELEASES = 'graalvm-ce-builds' const GRAALVM_TAG_PREFIX = 'vm-' -export async function setUpGraalVMLatest(javaVersion: string): Promise { +export async function setUpGraalVMLatest( + gdsToken: string, + javaVersion: string +): Promise { + if (gdsToken.length > 0) { + return setUpGraalVMRelease(gdsToken, c.VERSION_LATEST, javaVersion) + } const latestRelease = await getLatestRelease(GRAALVM_REPO_RELEASES) const tag_name = latestRelease.tag_name if (tag_name.startsWith(GRAALVM_TAG_PREFIX)) { @@ -19,16 +27,24 @@ export async function setUpGraalVMLatest(javaVersion: string): Promise { GRAALVM_TAG_PREFIX.length, tag_name.length ) - return setUpGraalVMRelease(latestVersion, javaVersion) + return setUpGraalVMRelease(gdsToken, latestVersion, javaVersion) } throw new Error(`Could not find latest GraalVM release: ${tag_name}`) } export async function setUpGraalVMDevBuild( + gdsToken: string, javaVersion: string ): Promise { + if (gdsToken.length > 0) { + throw new Error('Downloading GraalVM EE dev builds is not supported') + } const latestDevBuild = await getLatestRelease(GRAALVM_REPO_DEV_BUILDS) - const graalVMIdentifier = determineGraalVMIdentifier('dev', javaVersion) + const graalVMIdentifier = determineGraalVMIdentifier( + false, + 'dev', + javaVersion + ) const expectedFileName = `${graalVMIdentifier}${c.GRAALVM_FILE_EXTENSION}` for (const asset of latestDevBuild.assets) { if (asset.name === expectedFileName) { @@ -39,22 +55,39 @@ export async function setUpGraalVMDevBuild( } export async function setUpGraalVMRelease( + gdsToken: string, version: string, javaVersion: string ): Promise { - const graalVMIdentifier = determineGraalVMIdentifier(version, javaVersion) - const downloadUrl = `${GRAALVM_CE_DL_BASE}/${GRAALVM_TAG_PREFIX}${version}/${graalVMIdentifier}${c.GRAALVM_FILE_EXTENSION}` - const toolName = determineToolName(javaVersion) - return downloadExtractAndCacheJDK(downloadUrl, toolName, version) + const isEE = gdsToken.length > 0 + const graalVMIdentifier = determineGraalVMIdentifier( + isEE, + version, + javaVersion + ) + const toolName = determineToolName(isEE, javaVersion) + let downloader: () => Promise + if (isEE) { + downloader = async () => downloadGraalVMEE(gdsToken, version, javaVersion) + } else { + const downloadUrl = `${GRAALVM_CE_DL_BASE}/${GRAALVM_TAG_PREFIX}${version}/${graalVMIdentifier}${c.GRAALVM_FILE_EXTENSION}` + downloader = async () => downloadTool(downloadUrl) + } + return downloadExtractAndCacheJDK(downloader, toolName, version) } function determineGraalVMIdentifier( + isEE: boolean, version: string, javaVersion: string ): string { - return `graalvm-ce-java${javaVersion}-${c.GRAALVM_PLATFORM}-${c.GRAALVM_ARCH}-${version}` + return `graalvm-${isEE ? 'ee' : 'ce'}-java${javaVersion}-${ + c.GRAALVM_PLATFORM + }-${c.GRAALVM_ARCH}-${version}` } -function determineToolName(javaVersion: string): string { - return `graalvm-ce-java${javaVersion}-${c.GRAALVM_PLATFORM}` +function determineToolName(isEE: boolean, javaVersion: string): string { + return `graalvm-${isEE ? 'ee' : 'ce'}-java${javaVersion}-${ + c.GRAALVM_PLATFORM + }` } diff --git a/src/gu.ts b/src/gu.ts index fd400d0..b3004b2 100644 --- a/src/gu.ts +++ b/src/gu.ts @@ -2,6 +2,7 @@ import {GRAALVM_PLATFORM} from './constants' import {exec} from '@actions/exec' import {join} from 'path' +const BASE_FLAGS = ['--non-interactive', 'install', '--no-progress'] const COMPONENT_TO_POST_INSTALL_HOOK = new Map>([ [ 'linux', @@ -21,10 +22,16 @@ const COMPONENT_TO_POST_INSTALL_HOOK = new Map>([ ]) export async function setUpGUComponents( + gdsToken: string, graalVMHome: string, components: string[] ): Promise { - await exec('gu', ['install', '--no-progress'].concat(components)) + const optionalFlags = [] + if (gdsToken.length > 0) { + optionalFlags.push('--token', gdsToken) + } + + await exec('gu', BASE_FLAGS.concat(optionalFlags, components)) const platformHooks = COMPONENT_TO_POST_INSTALL_HOOK.get(GRAALVM_PLATFORM) if (platformHooks) { diff --git a/src/main.ts b/src/main.ts index ec3f4c8..27facd0 100644 --- a/src/main.ts +++ b/src/main.ts @@ -11,6 +11,7 @@ import {setUpWindowsEnvironment} from './msvc' async function run(): Promise { try { const graalvmVersion = core.getInput('version', {required: true}) + const gdsToken = core.getInput('gds-token') const javaVersion = core.getInput('java-version', {required: true}) const componentsString: string = core.getInput('components') const components: string[] = @@ -30,16 +31,17 @@ async function run(): Promise { let graalVMHome switch (graalvmVersion) { case c.VERSION_LATEST: - graalVMHome = await graalvm.setUpGraalVMLatest(javaVersion) + graalVMHome = await graalvm.setUpGraalVMLatest(gdsToken, javaVersion) break case c.VERSION_DEV: - graalVMHome = await graalvm.setUpGraalVMDevBuild(javaVersion) + graalVMHome = await graalvm.setUpGraalVMDevBuild(gdsToken, javaVersion) break default: if (graalvmVersion.startsWith(c.MANDREL_NAMESPACE)) { graalVMHome = await setUpMandrel(graalvmVersion, javaVersion) } else { graalVMHome = await graalvm.setUpGraalVMRelease( + gdsToken, graalvmVersion, javaVersion ) @@ -62,7 +64,7 @@ async function run(): Promise { `Mandrel does not support GraalVM components: ${componentsString}` ) } else { - await setUpGUComponents(graalVMHome, components) + await setUpGUComponents(gdsToken, graalVMHome, components) } } } catch (error) { diff --git a/src/mandrel.ts b/src/mandrel.ts index 1a42c39..7c015f8 100644 --- a/src/mandrel.ts +++ b/src/mandrel.ts @@ -1,5 +1,6 @@ import * as c from './constants' import {downloadExtractAndCacheJDK, getLatestRelease} from './utils' +import {downloadTool} from '@actions/tool-cache' const MANDREL_REPO = 'mandrel' const MANDREL_TAG_PREFIX = c.MANDREL_NAMESPACE @@ -47,7 +48,11 @@ async function setUpMandrelRelease( const identifier = determineMandrelIdentifier(version, javaVersion) const downloadUrl = `${MANDREL_DL_BASE}/${MANDREL_TAG_PREFIX}${version}/${identifier}${c.GRAALVM_FILE_EXTENSION}` const toolName = determineToolName(javaVersion) - return downloadExtractAndCacheJDK(downloadUrl, toolName, version) + return downloadExtractAndCacheJDK( + async () => downloadTool(downloadUrl), + toolName, + version + ) } function determineMandrelIdentifier( diff --git a/src/utils.ts b/src/utils.ts index eb9088e..fefbf21 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -2,9 +2,10 @@ import * as c from './constants' import * as core from '@actions/core' import * as httpClient from '@actions/http-client' import * as tc from '@actions/tool-cache' +import {readFileSync, readdirSync} from 'fs' import {Octokit} from '@octokit/core' +import {createHash} from 'crypto' import {join} from 'path' -import {readdirSync} from 'fs' // Set up Octokit in the same way as @actions/github (see https://git.io/Jy9YP) const baseUrl = process.env['GITHUB_API_URL'] || 'https://api.github.com' @@ -32,11 +33,13 @@ export async function getLatestRelease( export async function downloadAndExtractJDK( downloadUrl: string ): Promise { - return findJavaHomeInSubfolder(await downloadAndExtract(downloadUrl)) + return findJavaHomeInSubfolder( + await extract(await tc.downloadTool(downloadUrl)) + ) } export async function downloadExtractAndCacheJDK( - downloadUrl: string, + downloader: () => Promise, toolName: string, version: string ): Promise { @@ -45,21 +48,28 @@ export async function downloadExtractAndCacheJDK( if (toolPath) { core.info(`Found ${toolName} ${version} in tool-cache @ ${toolPath}`) } else { - const extractDir = await downloadAndExtract(downloadUrl) + const extractDir = await extract(await downloader()) core.info(`Adding ${toolName} ${version} to tool-cache ...`) toolPath = await tc.cacheDir(extractDir, toolName, semVersion) } return findJavaHomeInSubfolder(toolPath) } -async function downloadAndExtract(downloadUrl: string): Promise { - const downloadPath = await tc.downloadTool(downloadUrl) - if (downloadUrl.endsWith('.tar.gz')) { +export function calculateSHA256(filePath: string): string { + const hashSum = createHash('sha256') + hashSum.update(readFileSync(filePath)) + return hashSum.digest('hex') +} + +async function extract(downloadPath: string): Promise { + if (c.GRAALVM_FILE_EXTENSION === '.tar.gz') { return await tc.extractTar(downloadPath) - } else if (downloadUrl.endsWith('.zip')) { + } else if (c.GRAALVM_FILE_EXTENSION === '.zip') { return await tc.extractZip(downloadPath) } else { - throw new Error(`Unexpected filetype downloaded: ${downloadUrl}`) + throw new Error( + `Unexpected filetype downloaded: ${c.GRAALVM_FILE_EXTENSION}` + ) } }