mirror of
https://github.com/actions/setup-java.git
synced 2026-07-30 17:19:27 +08:00
3cc3643700
* Optimize Temurin tool-cache fast path - Lazy-load distribution installers so only the selected distro module is initialized - Defer cache feature/cache module loading until cache input is provided - Start cache restore early and await it safely alongside Java setup flow - Update orchestration and lazy-loading tests; regenerate dist artifacts Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: cc2c0256-c55e-4a35-a584-5bed7e8b11ad * Address PR review comments - Lazy-load cache save in cleanup path so no-cache runs avoid cache module init in post action - Stage dist/setup/package.json in release script for chunked setup bundle completeness Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: cc2c0256-c55e-4a35-a584-5bed7e8b11ad * Fix CodeQL comment tag filter finding Patch is-unsafe's XML comment-close detector during builds so generated bundles recognize both HTML comment end forms and satisfy CodeQL until the dependency publishes a fix. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 277302b1-aa95-4012-817b-9752cdaee14e * Rebuild generated dist bundles Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: cc2c0256-c55e-4a35-a584-5bed7e8b11ad --------- Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: cc2c0256-c55e-4a35-a584-5bed7e8b11ad Copilot-Session: 277302b1-aa95-4012-817b-9752cdaee14e
563 lines
24 KiB
JavaScript
563 lines
24 KiB
JavaScript
export const id = 242;
|
|
export const ids = [242];
|
|
export const modules = {
|
|
|
|
/***/ 6242:
|
|
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
|
|
|
|
|
|
// EXPORTS
|
|
__webpack_require__.d(__webpack_exports__, {
|
|
O: () => (/* binding */ JavaBase)
|
|
});
|
|
|
|
// EXTERNAL MODULE: ./node_modules/@actions/tool-cache/lib/tool-cache.js + 2 modules
|
|
var tool_cache = __webpack_require__(9805);
|
|
// EXTERNAL MODULE: ./node_modules/@actions/core/lib/core.js + 7 modules
|
|
var core = __webpack_require__(3838);
|
|
// EXTERNAL MODULE: external "fs"
|
|
var external_fs_ = __webpack_require__(9896);
|
|
// EXTERNAL MODULE: ./node_modules/semver/index.js
|
|
var semver = __webpack_require__(2088);
|
|
var semver_default = /*#__PURE__*/__webpack_require__.n(semver);
|
|
// EXTERNAL MODULE: external "path"
|
|
var external_path_ = __webpack_require__(6928);
|
|
var external_path_default = /*#__PURE__*/__webpack_require__.n(external_path_);
|
|
// EXTERNAL MODULE: ./node_modules/@actions/http-client/lib/index.js + 1 modules
|
|
var lib = __webpack_require__(4942);
|
|
// EXTERNAL MODULE: ./src/util.ts
|
|
var util = __webpack_require__(4527);
|
|
// EXTERNAL MODULE: ./src/constants.ts
|
|
var constants = __webpack_require__(7242);
|
|
;// CONCATENATED MODULE: ./src/retrying-http-client.ts
|
|
|
|
|
|
const RETRYABLE_HTTP_STATUS_CODES = new Set([429, 502, 503, 504, 522]);
|
|
const RETRYABLE_NETWORK_ERROR_CODES = new Set([
|
|
'ETIMEDOUT',
|
|
'ECONNRESET',
|
|
'ENOTFOUND',
|
|
'ECONNREFUSED'
|
|
]);
|
|
const RETRYABLE_HTTP_VERBS = new Set(['OPTIONS', 'GET', 'DELETE', 'HEAD']);
|
|
class RetryingHttpClient extends lib/* HttpClient */.Qq {
|
|
maxAttempts;
|
|
baseDelayMs;
|
|
maxDelayMs;
|
|
sleep;
|
|
random;
|
|
now;
|
|
constructor(userAgent, retryOptions = {}) {
|
|
super(userAgent, undefined, { allowRetries: false });
|
|
this.maxAttempts = retryOptions.maxAttempts ?? 4;
|
|
this.baseDelayMs = retryOptions.baseDelayMs ?? 1000;
|
|
this.maxDelayMs = retryOptions.maxDelayMs ?? 10000;
|
|
this.sleep =
|
|
retryOptions.sleep ??
|
|
(delayMs => new Promise(resolve => setTimeout(resolve, delayMs)));
|
|
this.random = retryOptions.random ?? Math.random;
|
|
this.now = retryOptions.now ?? Date.now;
|
|
if (this.maxAttempts < 1) {
|
|
throw new Error('maxAttempts must be at least 1');
|
|
}
|
|
if (this.baseDelayMs < 0 || this.maxDelayMs < this.baseDelayMs) {
|
|
throw new Error('baseDelayMs must be non-negative and no greater than maxDelayMs');
|
|
}
|
|
}
|
|
async request(verb, requestUrl, data, headers) {
|
|
if (!RETRYABLE_HTTP_VERBS.has(verb)) {
|
|
return super.request(verb, requestUrl, data, headers);
|
|
}
|
|
for (let attempt = 1; attempt <= this.maxAttempts; attempt++) {
|
|
try {
|
|
const response = await super.request(verb, requestUrl, data, headers);
|
|
const statusCode = response.message.statusCode;
|
|
if (!statusCode ||
|
|
!RETRYABLE_HTTP_STATUS_CODES.has(statusCode) ||
|
|
attempt === this.maxAttempts) {
|
|
return response;
|
|
}
|
|
const delayMs = this.getDelayMs(attempt, response.message.headers['retry-after']);
|
|
await response.readBody();
|
|
this.logRetry(attempt, delayMs, `HTTP ${statusCode}`);
|
|
await this.sleep(delayMs);
|
|
}
|
|
catch (error) {
|
|
if (!isRetryableNetworkError(error) || attempt === this.maxAttempts) {
|
|
throw error;
|
|
}
|
|
const delayMs = this.getDelayMs(attempt);
|
|
this.logRetry(attempt, delayMs, getErrorMessage(error));
|
|
await this.sleep(delayMs);
|
|
}
|
|
}
|
|
throw new Error('HTTP retry attempts exhausted unexpectedly');
|
|
}
|
|
getDelayMs(failedAttempt, retryAfter) {
|
|
const exponentialDelay = Math.min(this.maxDelayMs, this.baseDelayMs * 2 ** (failedAttempt - 1));
|
|
const jitteredDelay = Math.floor(exponentialDelay / 2 + this.random() * (exponentialDelay / 2));
|
|
const retryAfterDelay = parseRetryAfter(retryAfter, this.now());
|
|
return Math.min(this.maxDelayMs, Math.max(jitteredDelay, retryAfterDelay ?? 0));
|
|
}
|
|
logRetry(failedAttempt, delayMs, reason) {
|
|
core/* info */.pq(`Request attempt ${failedAttempt} of ${this.maxAttempts} failed (${reason}); retrying in ${delayMs} ms`);
|
|
}
|
|
}
|
|
function parseRetryAfter(value, nowMs) {
|
|
const retryAfter = Array.isArray(value) ? value[0] : value;
|
|
if (!retryAfter) {
|
|
return undefined;
|
|
}
|
|
if (/^\d+$/.test(retryAfter.trim())) {
|
|
return Number(retryAfter) * 1000;
|
|
}
|
|
const retryAt = Date.parse(retryAfter);
|
|
if (Number.isNaN(retryAt) || retryAt <= nowMs) {
|
|
return undefined;
|
|
}
|
|
return retryAt - nowMs;
|
|
}
|
|
function isRetryableNetworkError(error) {
|
|
if (!isErrorRecord(error)) {
|
|
return false;
|
|
}
|
|
if (typeof error.code === 'string' &&
|
|
RETRYABLE_NETWORK_ERROR_CODES.has(error.code)) {
|
|
return true;
|
|
}
|
|
return (Array.isArray(error.errors) &&
|
|
error.errors.some(nestedError => isRetryableNetworkError(nestedError)));
|
|
}
|
|
function isErrorRecord(error) {
|
|
return typeof error === 'object' && error !== null;
|
|
}
|
|
function getErrorMessage(error) {
|
|
return error instanceof Error ? error.message : 'network error';
|
|
}
|
|
|
|
// EXTERNAL MODULE: external "os"
|
|
var external_os_ = __webpack_require__(857);
|
|
var external_os_default = /*#__PURE__*/__webpack_require__.n(external_os_);
|
|
// EXTERNAL MODULE: external "crypto"
|
|
var external_crypto_ = __webpack_require__(6982);
|
|
// EXTERNAL MODULE: external "stream/promises"
|
|
var promises_ = __webpack_require__(4548);
|
|
;// CONCATENATED MODULE: ./src/checksum.ts
|
|
|
|
|
|
|
|
function sanitizedSource(source) {
|
|
if (!source) {
|
|
return '';
|
|
}
|
|
try {
|
|
const url = new URL(source);
|
|
return ` from ${url.origin}${url.pathname}`;
|
|
}
|
|
catch {
|
|
return ' from an invalid checksum source';
|
|
}
|
|
}
|
|
// Length, in hex characters, of a digest produced by each supported algorithm.
|
|
// Exported so callers (e.g. fetchChecksum) can infer which algorithm a vendor
|
|
// actually used when it doesn't disclose it via the checksum URL/filename.
|
|
function expectedDigestLength(algorithm) {
|
|
return algorithm === 'sha256' ? 64 : algorithm === 'sha512' ? 128 : 0;
|
|
}
|
|
function normalizeExpectedDigest(checksum) {
|
|
const algorithm = checksum.algorithm;
|
|
const digest = typeof checksum.value === 'string'
|
|
? checksum.value.trim().toLowerCase()
|
|
: '';
|
|
const expectedLength = expectedDigestLength(algorithm);
|
|
if (expectedLength === 0) {
|
|
throw new Error(`Unsupported checksum algorithm '${String(algorithm)}'${sanitizedSource(checksum.source)}. Supported algorithms are sha256 and sha512.`);
|
|
}
|
|
if (!new RegExp(`^[a-f0-9]{${expectedLength}}$`).test(digest)) {
|
|
throw new Error(`Malformed ${algorithm} checksum metadata${sanitizedSource(checksum.source)}: expected a ${expectedLength}-character hexadecimal digest.`);
|
|
}
|
|
return digest;
|
|
}
|
|
async function calculateChecksum(filePath, algorithm) {
|
|
const hash = (0,external_crypto_.createHash)(algorithm);
|
|
await (0,promises_.pipeline)((0,external_fs_.createReadStream)(filePath), hash);
|
|
return hash.digest('hex');
|
|
}
|
|
async function verifyChecksum(filePath, checksum, context) {
|
|
const expected = normalizeExpectedDigest(checksum);
|
|
const actual = await calculateChecksum(filePath, checksum.algorithm);
|
|
const matches = (0,external_crypto_.timingSafeEqual)(Buffer.from(expected, 'hex'), Buffer.from(actual, 'hex'));
|
|
if (!matches) {
|
|
throw new Error(`Checksum verification failed for ${context.distribution} version ${context.version}: ${checksum.algorithm} expected ${expected}, actual ${actual}.`);
|
|
}
|
|
}
|
|
|
|
// EXTERNAL MODULE: ./src/distributions/platform-types.ts
|
|
var platform_types = __webpack_require__(7444);
|
|
;// CONCATENATED MODULE: ./src/distributions/base-installer.ts
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class JavaBase {
|
|
distribution;
|
|
http;
|
|
version;
|
|
architecture;
|
|
packageType;
|
|
stable;
|
|
latest;
|
|
checkLatest;
|
|
forceDownload;
|
|
setDefault;
|
|
verifySignature;
|
|
verifySignaturePublicKey;
|
|
constructor(distribution, installerOptions) {
|
|
this.distribution = distribution;
|
|
this.http = new RetryingHttpClient('actions/setup-java');
|
|
({
|
|
version: this.version,
|
|
stable: this.stable,
|
|
latest: this.latest
|
|
} = this.normalizeVersion(installerOptions.version));
|
|
this.architecture = (0,platform_types/* normalizeArchitecture */.dV)(installerOptions.architecture || external_os_default().arch());
|
|
this.packageType = installerOptions.packageType;
|
|
this.checkLatest = installerOptions.checkLatest;
|
|
this.forceDownload = installerOptions.forceDownload ?? false;
|
|
this.setDefault =
|
|
installerOptions.setDefault !== undefined
|
|
? installerOptions.setDefault
|
|
: true;
|
|
this.verifySignature = installerOptions.verifySignature ?? false;
|
|
this.verifySignaturePublicKey = installerOptions.verifySignaturePublicKey;
|
|
}
|
|
async downloadAndVerify(javaRelease) {
|
|
const archivePath = await tool_cache/* downloadTool */.bq(javaRelease.url);
|
|
const checksum = javaRelease.checksum;
|
|
if (!checksum || !checksum.value?.trim()) {
|
|
core/* debug */.Yz(`No authoritative checksum is available for ${this.distribution} version ${javaRelease.version}; skipping checksum verification.`);
|
|
return archivePath;
|
|
}
|
|
try {
|
|
await verifyChecksum(archivePath, checksum, {
|
|
distribution: this.distribution,
|
|
version: javaRelease.version
|
|
});
|
|
core/* debug */.Yz(`Verified ${checksum.algorithm} checksum for ${this.distribution} version ${javaRelease.version}.`);
|
|
return archivePath;
|
|
}
|
|
catch (error) {
|
|
let cleanupError;
|
|
let cleanupFailed = false;
|
|
try {
|
|
await external_fs_.promises.rm(archivePath, { force: true });
|
|
}
|
|
catch (caughtCleanupError) {
|
|
cleanupError = caughtCleanupError;
|
|
cleanupFailed = true;
|
|
}
|
|
if (cleanupFailed) {
|
|
throw new Error(`${error.message} Failed to remove the downloaded archive after verification failure: ${cleanupError.message}`, { cause: error });
|
|
}
|
|
throw error;
|
|
}
|
|
}
|
|
async fetchChecksum(checksumUrl, algorithm) {
|
|
// Some vendors (e.g. JetBrains) publish a single, generically-named
|
|
// checksum sibling (`.checksum`) whose digest algorithm isn't disclosed
|
|
// by the URL and has changed across releases. Accepting a list of
|
|
// candidate algorithms lets callers pass every algorithm the vendor is
|
|
// known to use; the actual algorithm is then inferred from the length of
|
|
// the returned digest.
|
|
const algorithms = Array.isArray(algorithm) ? algorithm : [algorithm];
|
|
const algorithmLabel = algorithms.join(' or ');
|
|
const response = await this.http.get(checksumUrl);
|
|
const statusCode = response.message.statusCode;
|
|
const source = (() => {
|
|
try {
|
|
const url = new URL(checksumUrl);
|
|
return `${url.origin}${url.pathname}`;
|
|
}
|
|
catch {
|
|
return 'an invalid checksum URL';
|
|
}
|
|
})();
|
|
if (statusCode === lib/* HttpCodes */.Hv.NotFound) {
|
|
core/* debug */.Yz(`No authoritative ${algorithmLabel} checksum is available for ${this.distribution} from ${source}; skipping checksum verification.`);
|
|
return undefined;
|
|
}
|
|
if (statusCode !== lib/* HttpCodes */.Hv.OK) {
|
|
throw new Error(`Failed to fetch the authoritative ${algorithmLabel} checksum for ${this.distribution} from ${source} (HTTP ${statusCode}).`);
|
|
}
|
|
const body = await response.readBody();
|
|
const value = body.trim().split(/\s+/, 1)[0] ?? '';
|
|
if (!value) {
|
|
throw new Error(`Received an empty authoritative ${algorithmLabel} checksum for ${this.distribution} from ${source}.`);
|
|
}
|
|
// Prefer the strongest algorithm whose digest length matches what was
|
|
// actually returned; fall back to the first candidate (preserving prior
|
|
// behavior/error messages) when the digest doesn't match any of them.
|
|
const resolvedAlgorithm = algorithms.find(algo => value.length === expectedDigestLength(algo)) ??
|
|
algorithms[0];
|
|
return { algorithm: resolvedAlgorithm, value, source: checksumUrl };
|
|
}
|
|
async setupJava() {
|
|
if (this.verifySignature && !this.supportsSignatureVerification()) {
|
|
throw new Error(`Input 'verify-signature' is not supported for distribution '${this.distribution}'.`);
|
|
}
|
|
let foundJava = this.forceDownload ? null : this.findInToolcache();
|
|
if (foundJava && !this.checkLatest && !this.latest) {
|
|
core/* info */.pq(`Resolved Java ${foundJava.version} from tool-cache`);
|
|
}
|
|
else {
|
|
core/* info */.pq('Trying to resolve the latest version from remote');
|
|
try {
|
|
const javaRelease = await this.findPackageForDownload(this.version);
|
|
core/* info */.pq(`Resolved latest version as ${javaRelease.version}`);
|
|
if (!this.forceDownload && foundJava?.version === javaRelease.version) {
|
|
core/* info */.pq(`Resolved Java ${foundJava.version} from tool-cache`);
|
|
}
|
|
else {
|
|
core/* info */.pq('Trying to download...');
|
|
foundJava = await this.downloadTool(javaRelease);
|
|
core/* info */.pq(`Java ${foundJava.version} was downloaded`);
|
|
}
|
|
}
|
|
catch (error) {
|
|
this.logSetupError(error);
|
|
throw error;
|
|
}
|
|
}
|
|
if (!foundJava) {
|
|
throw new Error('Failed to resolve Java version');
|
|
}
|
|
// JDK folder may contain postfix "Contents/Home" on macOS
|
|
const macOSPostfixPath = external_path_default().join(foundJava.path, constants/* MACOS_JAVA_CONTENT_POSTFIX */.PG);
|
|
if (process.platform === 'darwin' && external_fs_.existsSync(macOSPostfixPath)) {
|
|
foundJava.path = macOSPostfixPath;
|
|
}
|
|
if (this.setDefault) {
|
|
core/* info */.pq(`Setting Java ${foundJava.version} as the default`);
|
|
this.setJavaDefault(foundJava.version, foundJava.path);
|
|
}
|
|
else {
|
|
core/* info */.pq(`Installing Java ${foundJava.version} (not setting as default)`);
|
|
this.setJavaEnvironment(foundJava.version, foundJava.path);
|
|
}
|
|
return foundJava;
|
|
}
|
|
logSetupError(error) {
|
|
const httpStatusCode = error instanceof tool_cache/* HTTPError */.Hl
|
|
? error.httpStatusCode
|
|
: error instanceof lib/* HttpClientError */.Kg
|
|
? error.statusCode
|
|
: undefined;
|
|
if (httpStatusCode) {
|
|
if (httpStatusCode === 403) {
|
|
core/* error */.z3('HTTP 403: Permission denied or access restricted.');
|
|
}
|
|
else if (httpStatusCode === 429) {
|
|
core/* warning */.$e('HTTP 429: Rate limit exceeded. Please retry later.');
|
|
}
|
|
else {
|
|
core/* error */.z3(`HTTP ${httpStatusCode}: ${error.message}`);
|
|
}
|
|
}
|
|
else if (error && error.errors && Array.isArray(error.errors)) {
|
|
core/* error */.z3(`Java setup failed due to network or configuration error(s)`);
|
|
if (error instanceof Error && error.stack) {
|
|
core/* debug */.Yz(error.stack);
|
|
}
|
|
for (const err of error.errors) {
|
|
const endpoint = err?.address || err?.hostname || '';
|
|
const port = err?.port ? `:${err.port}` : '';
|
|
const message = err?.message || 'Aggregate error';
|
|
const endpointInfo = !message.includes(endpoint)
|
|
? ` ${endpoint}${port}`
|
|
: '';
|
|
const localInfo = err.localAddress && err.localPort
|
|
? ` - Local (${err.localAddress}:${err.localPort})`
|
|
: '';
|
|
const logMessage = `${message}${endpointInfo}${localInfo}`;
|
|
core/* error */.z3(logMessage);
|
|
core/* debug */.Yz(`${err.stack || err.message}`);
|
|
Object.entries(err).forEach(([key, value]) => {
|
|
core/* debug */.Yz(`"${key}": ${JSON.stringify(value)}`);
|
|
});
|
|
}
|
|
}
|
|
else {
|
|
const message = error instanceof Error ? error.message : JSON.stringify(error);
|
|
core/* error */.z3(`Java setup process failed due to: ${message}`);
|
|
if (typeof error?.code === 'string') {
|
|
core/* debug */.Yz(error.stack);
|
|
}
|
|
const errorDetails = {
|
|
name: error.name,
|
|
message: error.message,
|
|
...Object.getOwnPropertyNames(error)
|
|
.filter(prop => !['name', 'message', 'stack'].includes(prop))
|
|
.reduce((acc, prop) => {
|
|
acc[prop] = error[prop];
|
|
return acc;
|
|
}, {})
|
|
};
|
|
Object.entries(errorDetails).forEach(([key, value]) => {
|
|
core/* debug */.Yz(`"${key}": ${JSON.stringify(value)}`);
|
|
});
|
|
}
|
|
}
|
|
get toolcacheFolderName() {
|
|
return `Java_${this.distribution}_${this.packageType}`;
|
|
}
|
|
supportsSignatureVerification() {
|
|
return false;
|
|
}
|
|
getToolcacheVersionName(version) {
|
|
if (!this.stable) {
|
|
if (version.includes('+')) {
|
|
return version.replace('+', '-ea.');
|
|
}
|
|
else {
|
|
return `${version}-ea`;
|
|
}
|
|
}
|
|
// Kotlin and some Java dependencies don't work properly when Java path contains "+" sign
|
|
// so replace "/hostedtoolcache/Java/11.0.3+4/x64" to "/hostedtoolcache/Java/11.0.3-4/x64" when saves to cache
|
|
// related issue: https://github.com/actions/virtual-environments/issues/3014
|
|
return version.replace('+', '-');
|
|
}
|
|
findInToolcache() {
|
|
// we can't use tc.find directly because firstly, we need to filter versions by stability flag
|
|
// if *-ea is provided, take only ea versions from toolcache, otherwise - only stable versions
|
|
const availableVersions = tool_cache/* findAllVersions */.iq(this.toolcacheFolderName, this.architecture)
|
|
.map(item => {
|
|
return {
|
|
version: item
|
|
.replace('-ea.', '+')
|
|
.replace(/-ea$/, '')
|
|
// Kotlin and some Java dependencies don't work properly when Java path contains "+" sign
|
|
// so replace "/hostedtoolcache/Java/11.0.3-4/x64" to "/hostedtoolcache/Java/11.0.3+4/x64" when retrieves to cache
|
|
// related issue: https://github.com/actions/virtual-environments/issues/3014
|
|
.replace('-', '+'),
|
|
path: (0,util/* getToolcachePath */.yH)(this.toolcacheFolderName, item, this.architecture) || '',
|
|
stable: !item.includes('-ea')
|
|
};
|
|
})
|
|
.filter(item => item.stable === this.stable);
|
|
const satisfiedVersions = availableVersions
|
|
.filter(item => (0,util/* isVersionSatisfies */.y)(this.version, item.version))
|
|
.filter(item => item.path)
|
|
.sort((a, b) => {
|
|
return -semver_default().compareBuild(a.version, b.version);
|
|
});
|
|
if (!satisfiedVersions || satisfiedVersions.length === 0) {
|
|
return null;
|
|
}
|
|
return {
|
|
version: satisfiedVersions[0].version,
|
|
path: satisfiedVersions[0].path
|
|
};
|
|
}
|
|
normalizeVersion(version) {
|
|
let stable = true;
|
|
const latest = false;
|
|
// Support the `latest` alias (case-insensitive), which floats to the newest
|
|
// available stable/GA release. It is translated to the SemVer wildcard `x`
|
|
// so the existing "newest satisfying version wins" resolution applies.
|
|
const normalized = version.trim().toLowerCase();
|
|
if (normalized === 'latest') {
|
|
return {
|
|
version: 'x',
|
|
stable: true,
|
|
latest: true
|
|
};
|
|
}
|
|
// Reject `latest` combined with any qualifier (e.g. `latest-ea`). Such inputs
|
|
// would otherwise have their `-ea` suffix stripped and fall through to the
|
|
// generic SemVer check, which fails with a confusing "'latest' is not valid
|
|
// SemVer" message even though `latest` is a supported value. Fail early with a
|
|
// targeted explanation instead.
|
|
if (normalized.startsWith('latest')) {
|
|
throw new Error(`The 'latest' alias resolves stable (GA) releases only and cannot be combined with '-ea' or other qualifiers (received '${version}'). Use 'latest' on its own, or specify a concrete version.`);
|
|
}
|
|
if (version.endsWith('-ea')) {
|
|
version = version.replace(/-ea$/, '');
|
|
stable = false;
|
|
}
|
|
else if (version.includes('-ea.')) {
|
|
// transform '11.0.3-ea.2' -> '11.0.3+2'
|
|
version = version.replace('-ea.', '+');
|
|
stable = false;
|
|
}
|
|
// Java uses a versioning scheme (JEP 322) that can contain more numeric
|
|
// fields than SemVer allows, e.g. '18.0.1.1' or '11.0.9.1'. Convert such
|
|
// exact versions to SemVer build notation ('18.0.1+1') so they are
|
|
// accepted. Ranges and versions that already carry build metadata are
|
|
// left untouched.
|
|
if (/^\d+(\.\d+){3,}$/.test(version)) {
|
|
version = (0,util/* convertVersionToSemver */.ZY)(version);
|
|
}
|
|
if (!semver_default().validRange(version)) {
|
|
throw new Error(`The string '${version}' is not valid SemVer notation for a Java version. Please check README file for code snippets and more detailed information`);
|
|
}
|
|
return {
|
|
version,
|
|
stable,
|
|
latest
|
|
};
|
|
}
|
|
createVersionNotFoundError(versionOrRange, availableVersions, additionalContext) {
|
|
const parts = [
|
|
`No matching version found for SemVer '${versionOrRange}'.`,
|
|
`Distribution: ${this.distribution}`,
|
|
`Package type: ${this.packageType}`,
|
|
`Architecture: ${this.architecture}`
|
|
];
|
|
// Add additional context if provided (e.g., platform/OS info)
|
|
if (additionalContext) {
|
|
parts.push(additionalContext);
|
|
}
|
|
if (availableVersions && availableVersions.length > 0) {
|
|
const maxVersionsToShow = core/* isDebug */._o() ? availableVersions.length : 50;
|
|
const versionsToShow = availableVersions.slice(0, maxVersionsToShow);
|
|
const truncated = availableVersions.length > maxVersionsToShow;
|
|
parts.push(`Available versions: ${versionsToShow.join(', ')}${truncated ? ', ...' : ''}`);
|
|
if (truncated) {
|
|
parts.push(`(showing first ${maxVersionsToShow} of ${availableVersions.length} versions, enable debug mode to see all)`);
|
|
}
|
|
}
|
|
const error = new Error(parts.join('\n'));
|
|
error.name = 'VersionNotFoundError';
|
|
return error;
|
|
}
|
|
setJavaDefault(version, toolPath) {
|
|
core/* exportVariable */.dN('JAVA_HOME', toolPath);
|
|
core/* addPath */.fM(external_path_default().join(toolPath, 'bin'));
|
|
this.setJavaEnvironment(version, toolPath);
|
|
}
|
|
setJavaEnvironment(version, toolPath) {
|
|
const majorVersion = version.split('.')[0];
|
|
core/* setOutput */.uH('distribution', this.distribution);
|
|
core/* setOutput */.uH('path', toolPath);
|
|
core/* setOutput */.uH('version', version);
|
|
core/* exportVariable */.dN(`JAVA_HOME_${majorVersion}_${this.architecture.toUpperCase()}`, toolPath);
|
|
}
|
|
distributionArchitecture() {
|
|
return this.architecture;
|
|
}
|
|
}
|
|
|
|
|
|
/***/ })
|
|
|
|
};
|