From d5b07dd11879e48ada41b5e14ff12b365c6692de Mon Sep 17 00:00:00 2001 From: Fabio Niephaus Date: Fri, 3 Nov 2023 12:36:12 +0100 Subject: [PATCH 1/2] Lock `java-version` to `17.0.8`. This is the last release with access to all tested GU components. --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 6334658..469eabb 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -299,7 +299,7 @@ jobs: - name: Run setup-graalvm action uses: ./ with: - java-version: '17' + java-version: '17.0.8' distribution: 'graalvm' components: 'espresso,llvm-toolchain,native-image,nodejs,python,ruby,wasm' set-java-home: 'false' From 0b782b6b90f760af614396b5c119aeaef4377870 Mon Sep 17 00:00:00 2001 From: Fabio Niephaus Date: Fri, 3 Nov 2023 13:01:11 +0100 Subject: [PATCH 2/2] Support fixed GA versions of Oracle GraalVM. --- .github/workflows/test.yml | 3 ++ __tests__/mandrel.test.ts | 1 - dist/cleanup/index.js | 55 ++++++++++++++++++------ dist/main/index.js | 88 +++++++++++++++++++++++++++----------- src/graalvm.ts | 26 ++++++++--- 5 files changed, 128 insertions(+), 45 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 469eabb..04b5bf3 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -40,6 +40,9 @@ jobs: distribution: 'graalvm-community' os: ubuntu-latest components: 'native-image' # should print a warning but not fail + - java-version: '21.0.0' # test for GA version (see #63) + distribution: 'graalvm' + os: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Run setup-graalvm action diff --git a/__tests__/mandrel.test.ts b/__tests__/mandrel.test.ts index cc9f5da..efa78ce 100644 --- a/__tests__/mandrel.test.ts +++ b/__tests__/mandrel.test.ts @@ -73,4 +73,3 @@ test('get latest Mandrel for specific JDK', async () => { expect(latest).toContain(`mandrel-java${javaVersion}`) } }) - diff --git a/dist/cleanup/index.js b/dist/cleanup/index.js index 2bed224..c6200c0 100644 --- a/dist/cleanup/index.js +++ b/dist/cleanup/index.js @@ -58304,7 +58304,7 @@ class Range { this.set = this.raw .split('||') // map the range to a 2d array of comparators - .map(r => this.parseRange(r)) + .map(r => this.parseRange(r.trim())) // throw out any comparator lists that are empty // this generally means that it was not a valid range, which is allowed // in loose mode, but will still throw if the WHOLE range is invalid. @@ -58364,15 +58364,18 @@ class Range { const hr = loose ? re[t.HYPHENRANGELOOSE] : re[t.HYPHENRANGE] range = range.replace(hr, hyphenReplace(this.options.includePrerelease)) debug('hyphen replace', range) + // `> 1.2.3 < 1.2.5` => `>1.2.3 <1.2.5` range = range.replace(re[t.COMPARATORTRIM], comparatorTrimReplace) debug('comparator trim', range) // `~ 1.2.3` => `~1.2.3` range = range.replace(re[t.TILDETRIM], tildeTrimReplace) + debug('tilde trim', range) // `^ 1.2.3` => `^1.2.3` range = range.replace(re[t.CARETTRIM], caretTrimReplace) + debug('caret trim', range) // At this point, the range is completely trimmed and // ready to be split into comparators. @@ -59674,6 +59677,10 @@ const MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER || // Max safe segment length for coercion. const MAX_SAFE_COMPONENT_LENGTH = 16 +// Max safe length for a build identifier. The max length minus 6 characters for +// the shortest version with a build 0.0.0+BUILD. +const MAX_SAFE_BUILD_LENGTH = MAX_LENGTH - 6 + const RELEASE_TYPES = [ 'major', 'premajor', @@ -59687,6 +59694,7 @@ const RELEASE_TYPES = [ module.exports = { MAX_LENGTH, MAX_SAFE_COMPONENT_LENGTH, + MAX_SAFE_BUILD_LENGTH, MAX_SAFE_INTEGER, RELEASE_TYPES, SEMVER_SPEC_VERSION, @@ -59768,7 +59776,11 @@ module.exports = parseOptions /***/ 9523: /***/ ((module, exports, __nccwpck_require__) => { -const { MAX_SAFE_COMPONENT_LENGTH } = __nccwpck_require__(2293) +const { + MAX_SAFE_COMPONENT_LENGTH, + MAX_SAFE_BUILD_LENGTH, + MAX_LENGTH, +} = __nccwpck_require__(2293) const debug = __nccwpck_require__(427) exports = module.exports = {} @@ -59779,16 +59791,31 @@ const src = exports.src = [] const t = exports.t = {} let R = 0 +const LETTERDASHNUMBER = '[a-zA-Z0-9-]' + +// Replace some greedy regex tokens to prevent regex dos issues. These regex are +// used internally via the safeRe object since all inputs in this library get +// normalized first to trim and collapse all extra whitespace. The original +// regexes are exported for userland consumption and lower level usage. A +// future breaking change could export the safer regex only with a note that +// all input should have extra whitespace removed. +const safeRegexReplacements = [ + ['\\s', 1], + ['\\d', MAX_LENGTH], + [LETTERDASHNUMBER, MAX_SAFE_BUILD_LENGTH], +] + +const makeSafeRegex = (value) => { + for (const [token, max] of safeRegexReplacements) { + value = value + .split(`${token}*`).join(`${token}{0,${max}}`) + .split(`${token}+`).join(`${token}{1,${max}}`) + } + return value +} + const createToken = (name, value, isGlobal) => { - // Replace all greedy whitespace to prevent regex dos issues. These regex are - // used internally via the safeRe object since all inputs in this library get - // normalized first to trim and collapse all extra whitespace. The original - // regexes are exported for userland consumption and lower level usage. A - // future breaking change could export the safer regex only with a note that - // all input should have extra whitespace removed. - const safe = value - .split('\\s*').join('\\s{0,1}') - .split('\\s+').join('\\s') + const safe = makeSafeRegex(value) const index = R++ debug(name, index, value) t[name] = index @@ -59804,13 +59831,13 @@ const createToken = (name, value, isGlobal) => { // A single `0`, or a non-zero digit followed by zero or more digits. createToken('NUMERICIDENTIFIER', '0|[1-9]\\d*') -createToken('NUMERICIDENTIFIERLOOSE', '[0-9]+') +createToken('NUMERICIDENTIFIERLOOSE', '\\d+') // ## Non-numeric Identifier // Zero or more digits, followed by a letter or hyphen, and then zero or // more letters, digits, or hyphens. -createToken('NONNUMERICIDENTIFIER', '\\d*[a-zA-Z-][a-zA-Z0-9-]*') +createToken('NONNUMERICIDENTIFIER', `\\d*[a-zA-Z-]${LETTERDASHNUMBER}*`) // ## Main Version // Three dot-separated numeric identifiers. @@ -59845,7 +59872,7 @@ createToken('PRERELEASELOOSE', `(?:-?(${src[t.PRERELEASEIDENTIFIERLOOSE] // ## Build Metadata Identifier // Any combination of digits, letters, or hyphens. -createToken('BUILDIDENTIFIER', '[0-9A-Za-z-]+') +createToken('BUILDIDENTIFIER', `${LETTERDASHNUMBER}+`) // ## Build Metadata // Plus sign, followed by one or more period-separated build metadata diff --git a/dist/main/index.js b/dist/main/index.js index 15cd593..2b089f2 100644 --- a/dist/main/index.js +++ b/dist/main/index.js @@ -8029,7 +8029,7 @@ Object.defineProperty(exports, "__esModule", ({ value: true })); exports.HttpClient = exports.isHttps = exports.HttpClientResponse = exports.HttpClientError = exports.getProxyUrl = exports.MediaTypes = exports.Headers = exports.HttpCodes = void 0; const http = __importStar(__nccwpck_require__(3685)); const https = __importStar(__nccwpck_require__(5687)); -const pm = __importStar(__nccwpck_require__(3466)); +const pm = __importStar(__nccwpck_require__(3186)); const tunnel = __importStar(__nccwpck_require__(4294)); var HttpCodes; (function (HttpCodes) { @@ -8603,7 +8603,7 @@ const lowercaseKeys = (obj) => Object.keys(obj).reduce((c, k) => ((c[k.toLowerCa /***/ }), -/***/ 3466: +/***/ 3186: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -58304,7 +58304,7 @@ class Range { this.set = this.raw .split('||') // map the range to a 2d array of comparators - .map(r => this.parseRange(r)) + .map(r => this.parseRange(r.trim())) // throw out any comparator lists that are empty // this generally means that it was not a valid range, which is allowed // in loose mode, but will still throw if the WHOLE range is invalid. @@ -58364,15 +58364,18 @@ class Range { const hr = loose ? re[t.HYPHENRANGELOOSE] : re[t.HYPHENRANGE] range = range.replace(hr, hyphenReplace(this.options.includePrerelease)) debug('hyphen replace', range) + // `> 1.2.3 < 1.2.5` => `>1.2.3 <1.2.5` range = range.replace(re[t.COMPARATORTRIM], comparatorTrimReplace) debug('comparator trim', range) // `~ 1.2.3` => `~1.2.3` range = range.replace(re[t.TILDETRIM], tildeTrimReplace) + debug('tilde trim', range) // `^ 1.2.3` => `^1.2.3` range = range.replace(re[t.CARETTRIM], caretTrimReplace) + debug('caret trim', range) // At this point, the range is completely trimmed and // ready to be split into comparators. @@ -59185,7 +59188,7 @@ module.exports = cmp /***/ }), -/***/ 5280: +/***/ 3466: /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { const SemVer = __nccwpck_require__(8088) @@ -59594,7 +59597,7 @@ const neq = __nccwpck_require__(6017) const gte = __nccwpck_require__(5522) const lte = __nccwpck_require__(7520) const cmp = __nccwpck_require__(5098) -const coerce = __nccwpck_require__(5280) +const coerce = __nccwpck_require__(3466) const Comparator = __nccwpck_require__(1532) const Range = __nccwpck_require__(9828) const satisfies = __nccwpck_require__(6055) @@ -59674,6 +59677,10 @@ const MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER || // Max safe segment length for coercion. const MAX_SAFE_COMPONENT_LENGTH = 16 +// Max safe length for a build identifier. The max length minus 6 characters for +// the shortest version with a build 0.0.0+BUILD. +const MAX_SAFE_BUILD_LENGTH = MAX_LENGTH - 6 + const RELEASE_TYPES = [ 'major', 'premajor', @@ -59687,6 +59694,7 @@ const RELEASE_TYPES = [ module.exports = { MAX_LENGTH, MAX_SAFE_COMPONENT_LENGTH, + MAX_SAFE_BUILD_LENGTH, MAX_SAFE_INTEGER, RELEASE_TYPES, SEMVER_SPEC_VERSION, @@ -59768,7 +59776,11 @@ module.exports = parseOptions /***/ 9523: /***/ ((module, exports, __nccwpck_require__) => { -const { MAX_SAFE_COMPONENT_LENGTH } = __nccwpck_require__(2293) +const { + MAX_SAFE_COMPONENT_LENGTH, + MAX_SAFE_BUILD_LENGTH, + MAX_LENGTH, +} = __nccwpck_require__(2293) const debug = __nccwpck_require__(427) exports = module.exports = {} @@ -59779,16 +59791,31 @@ const src = exports.src = [] const t = exports.t = {} let R = 0 +const LETTERDASHNUMBER = '[a-zA-Z0-9-]' + +// Replace some greedy regex tokens to prevent regex dos issues. These regex are +// used internally via the safeRe object since all inputs in this library get +// normalized first to trim and collapse all extra whitespace. The original +// regexes are exported for userland consumption and lower level usage. A +// future breaking change could export the safer regex only with a note that +// all input should have extra whitespace removed. +const safeRegexReplacements = [ + ['\\s', 1], + ['\\d', MAX_LENGTH], + [LETTERDASHNUMBER, MAX_SAFE_BUILD_LENGTH], +] + +const makeSafeRegex = (value) => { + for (const [token, max] of safeRegexReplacements) { + value = value + .split(`${token}*`).join(`${token}{0,${max}}`) + .split(`${token}+`).join(`${token}{1,${max}}`) + } + return value +} + const createToken = (name, value, isGlobal) => { - // Replace all greedy whitespace to prevent regex dos issues. These regex are - // used internally via the safeRe object since all inputs in this library get - // normalized first to trim and collapse all extra whitespace. The original - // regexes are exported for userland consumption and lower level usage. A - // future breaking change could export the safer regex only with a note that - // all input should have extra whitespace removed. - const safe = value - .split('\\s*').join('\\s{0,1}') - .split('\\s+').join('\\s') + const safe = makeSafeRegex(value) const index = R++ debug(name, index, value) t[name] = index @@ -59804,13 +59831,13 @@ const createToken = (name, value, isGlobal) => { // A single `0`, or a non-zero digit followed by zero or more digits. createToken('NUMERICIDENTIFIER', '0|[1-9]\\d*') -createToken('NUMERICIDENTIFIERLOOSE', '[0-9]+') +createToken('NUMERICIDENTIFIERLOOSE', '\\d+') // ## Non-numeric Identifier // Zero or more digits, followed by a letter or hyphen, and then zero or // more letters, digits, or hyphens. -createToken('NONNUMERICIDENTIFIER', '\\d*[a-zA-Z-][a-zA-Z0-9-]*') +createToken('NONNUMERICIDENTIFIER', `\\d*[a-zA-Z-]${LETTERDASHNUMBER}*`) // ## Main Version // Three dot-separated numeric identifiers. @@ -59845,7 +59872,7 @@ createToken('PRERELEASELOOSE', `(?:-?(${src[t.PRERELEASEIDENTIFIERLOOSE] // ## Build Metadata Identifier // Any combination of digits, letters, or hyphens. -createToken('BUILDIDENTIFIER', '[0-9A-Za-z-]+') +createToken('BUILDIDENTIFIER', `${LETTERDASHNUMBER}+`) // ## Build Metadata // Plus sign, followed by one or more period-separated build metadata @@ -71001,11 +71028,11 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge Object.defineProperty(exports, "__esModule", ({ value: true })); exports.setUpGraalVMRelease = exports.findGraalVMVersion = exports.setUpGraalVMLatest_22_X = exports.findHighestJavaVersion = exports.setUpGraalVMJDKDevBuild = exports.findLatestGraalVMJDKCEJavaVersion = exports.setUpGraalVMJDKCE = exports.setUpGraalVMJDK = void 0; const c = __importStar(__nccwpck_require__(9042)); +const semver = __importStar(__nccwpck_require__(1383)); const utils_1 = __nccwpck_require__(1314); const gds_1 = __nccwpck_require__(9543); const tool_cache_1 = __nccwpck_require__(7784); const path_1 = __nccwpck_require__(1017); -const semver_1 = __nccwpck_require__(1383); const GRAALVM_DL_BASE = 'https://download.oracle.com/graalvm'; const GRAALVM_CE_DL_BASE = `https://github.com/graalvm/${c.GRAALVM_RELEASES_REPO}/releases/download`; const GRAALVM_REPO_DEV_BUILDS = 'graalvm-ce-dev-builds'; @@ -71018,11 +71045,24 @@ function setUpGraalVMJDK(javaVersionOrDev) { return setUpGraalVMJDKDevBuild(); } const javaVersion = javaVersionOrDev; - const toolName = determineToolName(javaVersion, false); + let toolName = determineToolName(javaVersion, false); let downloadUrl; if (javaVersion.includes('.')) { - const majorJavaVersion = javaVersion.split('.')[0]; - downloadUrl = `${GRAALVM_DL_BASE}/${majorJavaVersion}/archive/${toolName}${c.GRAALVM_FILE_EXTENSION}`; + if (semver.valid(javaVersion)) { + const majorJavaVersion = semver.major(javaVersion); + const minorJavaVersion = semver.minor(javaVersion); + const patchJavaVersion = semver.patch(javaVersion); + const isGARelease = minorJavaVersion === 0 && patchJavaVersion === 0; + let downloadName = toolName; + if (isGARelease) { + // For GA versions of JDKs, /archive/ does not use minor and patch version (see https://www.oracle.com/java/technologies/jdk-script-friendly-urls/) + downloadName = determineToolName(majorJavaVersion.toString(), false); + } + downloadUrl = `${GRAALVM_DL_BASE}/${majorJavaVersion}/archive/${downloadName}${c.GRAALVM_FILE_EXTENSION}`; + } + else { + throw new Error(`java-version set to '${javaVersion}'. Please make sure the java-version is set correctly. ${c.ERROR_HINT}`); + } } else { downloadUrl = `${GRAALVM_DL_BASE}/${javaVersion}/latest/${toolName}${c.GRAALVM_FILE_EXTENSION}`; @@ -71059,8 +71099,8 @@ function findLatestGraalVMJDKCEJavaVersion(majorJavaVersion) { const versionNumberStartIndex = `refs/tags/${GRAALVM_JDK_TAG_PREFIX}`.length; for (const matchingRef of matchingRefs) { const currentVersion = matchingRef.ref.substring(versionNumberStartIndex); - if ((0, semver_1.valid)(currentVersion) && - (0, semver_1.gt)(currentVersion, highestVersion)) { + if (semver.valid(currentVersion) && + semver.gt(currentVersion, highestVersion)) { highestVersion = currentVersion; } } diff --git a/src/graalvm.ts b/src/graalvm.ts index edf7ef7..f2be101 100644 --- a/src/graalvm.ts +++ b/src/graalvm.ts @@ -1,4 +1,5 @@ import * as c from './constants' +import * as semver from 'semver' import { downloadAndExtractJDK, downloadExtractAndCacheJDK, @@ -9,7 +10,6 @@ import { import {downloadGraalVMEELegacy} from './gds' import {downloadTool} from '@actions/tool-cache' import {basename} from 'path' -import {gt as semverGt, valid as semverValid} from 'semver' const GRAALVM_DL_BASE = 'https://download.oracle.com/graalvm' const GRAALVM_CE_DL_BASE = `https://github.com/graalvm/${c.GRAALVM_RELEASES_REPO}/releases/download` @@ -26,11 +26,25 @@ export async function setUpGraalVMJDK( return setUpGraalVMJDKDevBuild() } const javaVersion = javaVersionOrDev - const toolName = determineToolName(javaVersion, false) + let toolName = determineToolName(javaVersion, false) let downloadUrl: string if (javaVersion.includes('.')) { - const majorJavaVersion = javaVersion.split('.')[0] - downloadUrl = `${GRAALVM_DL_BASE}/${majorJavaVersion}/archive/${toolName}${c.GRAALVM_FILE_EXTENSION}` + if (semver.valid(javaVersion)) { + const majorJavaVersion = semver.major(javaVersion) + const minorJavaVersion = semver.minor(javaVersion) + const patchJavaVersion = semver.patch(javaVersion) + const isGARelease = minorJavaVersion === 0 && patchJavaVersion === 0 + let downloadName = toolName + if (isGARelease) { + // For GA versions of JDKs, /archive/ does not use minor and patch version (see https://www.oracle.com/java/technologies/jdk-script-friendly-urls/) + downloadName = determineToolName(majorJavaVersion.toString(), false) + } + downloadUrl = `${GRAALVM_DL_BASE}/${majorJavaVersion}/archive/${downloadName}${c.GRAALVM_FILE_EXTENSION}` + } else { + throw new Error( + `java-version set to '${javaVersion}'. Please make sure the java-version is set correctly. ${c.ERROR_HINT}` + ) + } } else { downloadUrl = `${GRAALVM_DL_BASE}/${javaVersion}/latest/${toolName}${c.GRAALVM_FILE_EXTENSION}` } @@ -71,8 +85,8 @@ export async function findLatestGraalVMJDKCEJavaVersion( for (const matchingRef of matchingRefs) { const currentVersion = matchingRef.ref.substring(versionNumberStartIndex) if ( - semverValid(currentVersion) && - semverGt(currentVersion, highestVersion) + semver.valid(currentVersion) && + semver.gt(currentVersion, highestVersion) ) { highestVersion = currentVersion }