mirror of
https://gitea.com/actions/setup-java.git
synced 2026-07-10 19:31:55 +08:00
Support pinning java-version as "latest"
Add a `latest` alias for the `java-version` input that floats to the newest available stable (GA) release. It is normalized to the SemVer wildcard at the base-installer layer and always resolves from remote (like `check-latest: true`). List-based distributions resolve it automatically via the existing newest-first matching. Corretto selects its newest available major; Oracle and GraalVM look up the newest GA major via the Adoptium API and request it, failing with an actionable error if that major isn't published yet. The jdkfile distribution rejects `latest`. Closes #832 Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -19,6 +19,7 @@ export abstract class JavaBase {
|
||||
protected architecture: string;
|
||||
protected packageType: string;
|
||||
protected stable: boolean;
|
||||
protected latest: boolean;
|
||||
protected checkLatest: boolean;
|
||||
protected setDefault: boolean;
|
||||
protected verifySignature: boolean;
|
||||
@@ -33,9 +34,11 @@ export abstract class JavaBase {
|
||||
maxRetries: 3
|
||||
});
|
||||
|
||||
({version: this.version, stable: this.stable} = this.normalizeVersion(
|
||||
installerOptions.version
|
||||
));
|
||||
({
|
||||
version: this.version,
|
||||
stable: this.stable,
|
||||
latest: this.latest
|
||||
} = this.normalizeVersion(installerOptions.version));
|
||||
this.architecture = installerOptions.architecture || os.arch();
|
||||
this.packageType = installerOptions.packageType;
|
||||
this.checkLatest = installerOptions.checkLatest;
|
||||
@@ -62,7 +65,7 @@ export abstract class JavaBase {
|
||||
}
|
||||
|
||||
let foundJava = this.findInToolcache();
|
||||
if (foundJava && !this.checkLatest) {
|
||||
if (foundJava && !this.checkLatest && !this.latest) {
|
||||
core.info(`Resolved Java ${foundJava.version} from tool-cache`);
|
||||
} else {
|
||||
core.info('Trying to resolve the latest version from remote');
|
||||
@@ -263,6 +266,18 @@ export abstract class JavaBase {
|
||||
|
||||
protected normalizeVersion(version: string) {
|
||||
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.
|
||||
if (version.trim().toLowerCase() === 'latest') {
|
||||
return {
|
||||
version: 'x',
|
||||
stable: true,
|
||||
latest: true
|
||||
};
|
||||
}
|
||||
|
||||
if (version.endsWith('-ea')) {
|
||||
version = version.replace(/-ea$/, '');
|
||||
@@ -281,7 +296,8 @@ export abstract class JavaBase {
|
||||
|
||||
return {
|
||||
version,
|
||||
stable
|
||||
stable,
|
||||
latest
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -59,10 +59,22 @@ export class CorrettoDistribution extends JavaBase {
|
||||
if (!this.stable) {
|
||||
throw new Error('Early access versions are not supported');
|
||||
}
|
||||
const availableVersions = await this.getAvailableVersions();
|
||||
|
||||
// The `latest` alias is normalized to the SemVer wildcard, but Corretto
|
||||
// matches on an exact major version, so resolve it to the newest available
|
||||
// major from Corretto's own list.
|
||||
if (this.latest) {
|
||||
const latestMajor = availableVersions
|
||||
.map(item => parseInt(item.version, 10))
|
||||
.filter(major => !Number.isNaN(major))
|
||||
.reduce((max, current) => (current > max ? current : max), 0);
|
||||
version = latestMajor.toString();
|
||||
}
|
||||
|
||||
if (version.includes('.')) {
|
||||
throw new Error('Only major versions are supported');
|
||||
}
|
||||
const availableVersions = await this.getAvailableVersions();
|
||||
const matchingVersions = availableVersions
|
||||
.filter(item => item.version == version)
|
||||
.map(item => {
|
||||
|
||||
@@ -16,6 +16,7 @@ import {
|
||||
extractJdkFile,
|
||||
getDownloadArchiveExtension,
|
||||
getGitHubHttpHeaders,
|
||||
getLatestMajorVersion,
|
||||
getNextPageUrlFromLinkHeader,
|
||||
isVersionSatisfies,
|
||||
MAX_PAGINATION_PAGES,
|
||||
@@ -119,6 +120,13 @@ export class GraalVMDistribution extends JavaBase {
|
||||
return this.findEABuildDownloadUrl(`${range}-ea`);
|
||||
}
|
||||
|
||||
// The `latest` alias is normalized to the SemVer wildcard. Oracle GraalVM
|
||||
// builds its download URLs from a concrete major and has no endpoint to list
|
||||
// releases, so resolve the newest available GA major from the Adoptium API.
|
||||
if (this.latest) {
|
||||
range = (await getLatestMajorVersion(this.http)).toString();
|
||||
}
|
||||
|
||||
const {platform, extension, major} = this.validateStableBuildRequest(range);
|
||||
|
||||
const fileUrl = this.constructFileUrl(
|
||||
@@ -203,6 +211,9 @@ export class GraalVMDistribution extends JavaBase {
|
||||
if (statusCode === HttpCodes.NotFound) {
|
||||
// Create the standard error with additional hint about checking the download URL
|
||||
const error = this.createVersionNotFoundError(range);
|
||||
if (this.latest) {
|
||||
error.message += `\nThe latest Java major version (${range}) is not yet available for the ${this.distribution} distribution. Please specify a concrete version instead of 'latest'.`;
|
||||
}
|
||||
error.message += `\nPlease check if this version is available at ${GRAALVM_DOWNLOAD_URL} . Pick a version from the list.`;
|
||||
throw error;
|
||||
}
|
||||
@@ -353,6 +364,13 @@ export class GraalVMCommunityDistribution extends GraalVMDistribution {
|
||||
throw new Error('GraalVM Community does not provide early access builds');
|
||||
}
|
||||
|
||||
// The `latest` alias is normalized to the SemVer wildcard. Resolve the newest
|
||||
// available GA major from the Adoptium API so it can be matched against the
|
||||
// published GraalVM Community releases.
|
||||
if (this.latest) {
|
||||
range = (await getLatestMajorVersion(this.http)).toString();
|
||||
}
|
||||
|
||||
const arch = this.getSupportedArchitecture();
|
||||
const {platform, extension} = this.validateStableBuildRequest(range);
|
||||
// GraalVM Community asset names embed the platform, architecture and
|
||||
|
||||
@@ -22,6 +22,12 @@ export class LocalDistribution extends JavaBase {
|
||||
}
|
||||
|
||||
public async setupJava(): Promise<JavaInstallerResults> {
|
||||
if (this.latest) {
|
||||
throw new Error(
|
||||
"The 'latest' version alias is not supported for the 'jdkfile' distribution. Please specify a concrete version."
|
||||
);
|
||||
}
|
||||
|
||||
let foundJava = this.findInToolcache();
|
||||
|
||||
if (foundJava) {
|
||||
|
||||
@@ -13,6 +13,7 @@ import {
|
||||
import {
|
||||
extractJdkFile,
|
||||
getDownloadArchiveExtension,
|
||||
getLatestMajorVersion,
|
||||
renameWinArchive
|
||||
} from '../../util.js';
|
||||
import {HttpCodes} from '@actions/http-client';
|
||||
@@ -73,6 +74,14 @@ export class OracleDistribution extends JavaBase {
|
||||
const platform = this.getPlatform();
|
||||
const extension = getDownloadArchiveExtension();
|
||||
|
||||
// The `latest` alias is normalized to the SemVer wildcard. Oracle builds its
|
||||
// download URLs from a concrete major and has no endpoint to list releases,
|
||||
// so resolve the newest available GA major from the Adoptium API and use it.
|
||||
if (this.latest) {
|
||||
const latestMajor = await getLatestMajorVersion(this.http);
|
||||
range = latestMajor.toString();
|
||||
}
|
||||
|
||||
const isOnlyMajorProvided = !range.includes('.');
|
||||
const major = isOnlyMajorProvided ? range : range.split('.')[0];
|
||||
|
||||
@@ -113,6 +122,12 @@ export class OracleDistribution extends JavaBase {
|
||||
}
|
||||
}
|
||||
|
||||
if (this.latest) {
|
||||
const error = this.createVersionNotFoundError(range);
|
||||
error.message += `\nThe latest Java major version (${range}) is not yet available for the Oracle JDK distribution. Please specify a concrete version instead of 'latest'.`;
|
||||
throw error;
|
||||
}
|
||||
|
||||
throw this.createVersionNotFoundError(range);
|
||||
}
|
||||
|
||||
|
||||
@@ -186,8 +186,14 @@ async function installVersion(
|
||||
}
|
||||
|
||||
const result = await distribution.setupJava();
|
||||
|
||||
// When the `latest` alias is used, the literal input isn't a real version, so
|
||||
// pass the resolved version to the toolchains configuration instead.
|
||||
const isLatest = version.trim().toLowerCase() === 'latest';
|
||||
const toolchainVersion = isLatest ? result.version : version;
|
||||
|
||||
await toolchains.configureToolchains(
|
||||
version,
|
||||
toolchainVersion,
|
||||
distributionName,
|
||||
result.path,
|
||||
toolchainIds[toolchainId]
|
||||
|
||||
31
src/util.ts
31
src/util.ts
@@ -6,6 +6,7 @@ import * as cache from '@actions/cache';
|
||||
import * as core from '@actions/core';
|
||||
|
||||
import * as tc from '@actions/tool-cache';
|
||||
import * as httpm from '@actions/http-client';
|
||||
import {
|
||||
INPUT_JOB_STATUS,
|
||||
DISTRIBUTIONS_ONLY_MAJOR_VERSION
|
||||
@@ -382,3 +383,33 @@ export function renameWinArchive(javaArchivePath: string): string {
|
||||
fs.renameSync(javaArchivePath, javaArchivePathRenamed);
|
||||
return javaArchivePathRenamed;
|
||||
}
|
||||
|
||||
interface IAdoptiumAvailableReleases {
|
||||
most_recent_feature_release: number;
|
||||
}
|
||||
|
||||
// Resolve the newest available stable/GA feature (major) release.
|
||||
//
|
||||
// Some distributions (e.g. Oracle, GraalVM) construct their download URLs from a
|
||||
// concrete major version and don't expose an endpoint to list every available
|
||||
// release, so a bare `latest` alias can't be resolved from their own metadata.
|
||||
// The Adoptium (Temurin) API is used as a proxy for "what is the newest GA major
|
||||
// version out there", which those distributions typically publish at the same time.
|
||||
export async function getLatestMajorVersion(
|
||||
http: httpm.HttpClient
|
||||
): Promise<number> {
|
||||
const availableReleasesUrl =
|
||||
'https://api.adoptium.net/v3/info/available_releases';
|
||||
|
||||
const response =
|
||||
await http.getJson<IAdoptiumAvailableReleases>(availableReleasesUrl);
|
||||
|
||||
const mostRecent = response.result?.most_recent_feature_release;
|
||||
if (!mostRecent || Number.isNaN(Number(mostRecent))) {
|
||||
throw new Error(
|
||||
`Could not determine the latest available Java major version from ${availableReleasesUrl}`
|
||||
);
|
||||
}
|
||||
|
||||
return Number(mostRecent);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user