Support Temurin JEP 322 patch versions like 26.0.2.1+1 (#1270) (#1279)

Accept 4-part versions with build metadata (X.Y.Z.P+B -> X.Y.Z+P.B) and
match exact Temurin requests against OpenJDK-derived version keys, since the
Adoptium API semver folds the patch into the build number (26.0.2+101) and
adds LTS metadata (25.0.4+7.0.LTS).

Co-authored-by: Copilot App <[email protected]>
This commit is contained in:
Bruno Borges
2026-10-02 00:09:56 -04:00
committed by GitHub
co-authored by Copilot App
parent 74920aab4a
commit 47b36480ae
14 changed files with 243 additions and 39 deletions
+5 -8
View File
@@ -5,9 +5,9 @@ import semver from 'semver';
import path from 'path';
import * as httpm from '@actions/http-client';
import {
convertVersionToSemver,
getToolcachePath,
isVersionSatisfies
isVersionSatisfies,
normalizeJavaVersionToSemver
} from '../util.js';
import type {
ChecksumAlgorithm,
@@ -675,12 +675,9 @@ export abstract class JavaBase {
// 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 = convertVersionToSemver(version);
}
// exact versions to SemVer build notation ('18.0.1+1', or '26.0.2+1.1'
// for '26.0.2.1+1') so they are accepted. Ranges are left untouched.
version = normalizeJavaVersionToSemver(version);
if (!semver.validRange(version)) {
throw new Error(
+4 -7
View File
@@ -1,5 +1,5 @@
import semver from 'semver';
import {convertVersionToSemver} from '../util.js';
import {normalizeJavaVersionToSemver} from '../util.js';
export enum JavaDistribution {
Temurin = 'temurin',
@@ -98,12 +98,9 @@ function canResolveTemurinJmods(version: string): boolean {
return true;
}
let normalizedRange = normalizedVersion
.replace(/-ea$/, '')
.replace('-ea.', '+');
if (/^\d+(\.\d+){3,}$/.test(normalizedRange)) {
normalizedRange = convertVersionToSemver(normalizedRange);
}
const normalizedRange = normalizeJavaVersionToSemver(
normalizedVersion.replace(/-ea$/, '').replace('-ea.', '+')
);
if (!semver.validRange(normalizedRange)) {
// JavaBase owns general version validation and its targeted error messages.
return true;
+39 -4
View File
@@ -70,7 +70,7 @@ export class TemurinDistribution extends JavaBase {
const formattedVersion = this.stable
? item.version_data.semver
: item.version_data.semver.replace('-beta+', '+');
return {
const release: JavaDownloadRelease = {
version: formattedVersion,
url: item.binaries[0].package.link,
signatureUrl: item.binaries[0].package.signature_link,
@@ -79,11 +79,29 @@ export class TemurinDistribution extends JavaBase {
value: item.binaries[0].package.checksum,
source: item.binaries[0].package.checksum_link
}
} as JavaDownloadRelease;
};
return {
release,
openjdkVersion: getOpenJdkSemverVersion(item.version_data)
};
});
// The Adoptium API `semver` folds the JEP 322 patch field into the build
// number ('26.0.2.1+1' -> '26.0.2+101') and appends extra metadata for LTS
// releases ('25.0.4+7' -> '25.0.4+7.0.LTS'). Exact versions requested by
// users follow the OpenJDK notation instead, so also match them against a
// key derived from the OpenJDK version fields ('26.0.2+1.1', '25.0.4+7').
const isExactBuildRequest = (semver.parse(version)?.build.length ?? 0) > 0;
const satisfiedVersions = availableVersionsWithBinaries
.filter(item => isVersionSatisfies(version, item.version))
.filter(
({release, openjdkVersion}) =>
isVersionSatisfies(version, release.version) ||
(isExactBuildRequest &&
openjdkVersion !== null &&
semver.compareBuild(version, openjdkVersion) === 0)
)
.map(({release}) => release)
.sort((a, b) => {
return -semver.compareBuild(a.version, b.version);
});
@@ -92,7 +110,7 @@ export class TemurinDistribution extends JavaBase {
satisfiedVersions.length > 0 ? satisfiedVersions[0] : null;
if (!resolvedFullVersion) {
const availableVersionStrings = availableVersionsWithBinaries.map(
item => item.version
({release}) => release.version
);
throw this.createVersionNotFoundError(version, availableVersionStrings);
}
@@ -309,3 +327,20 @@ export class TemurinDistribution extends JavaBase {
return architecture === 'armv7' ? 'arm' : architecture;
}
}
/**
* Builds a SemVer version from the OpenJDK version fields reported by the
* Adoptium API, e.g. '26.0.2.1+1' -> '26.0.2+1.1' and '25.0.4+7-LTS' ->
* '25.0.4+7'. Returns null if the fields cannot form a valid SemVer version.
*/
function getOpenJdkSemverVersion(
versionData: ITemurinAvailableVersions['version_data']
): string | null {
const {major, minor, security, patch, build} = versionData;
if (build === undefined || build === null) {
return null;
}
const buildMetadata = patch ? `${patch}.${build}` : `${build}`;
const version = `${major}.${minor}.${security}+${buildMetadata}`;
return semver.valid(version) ? version : null;
}
+1
View File
@@ -34,6 +34,7 @@ export interface ITemurinAvailableVersions {
minor: number;
openjdk_version: string;
security: string;
patch?: number;
semver: string;
};
}
+15
View File
@@ -510,6 +510,21 @@ export function convertVersionToSemver(version: number[] | string) {
return mainVersion;
}
/**
* Java versions (JEP 322) can contain more numeric fields than SemVer allows,
* e.g. '11.0.9.1' or Temurin respins such as '26.0.2.1+1'. Move the extra
* fields into SemVer build metadata ('11.0.9+1', '26.0.2+1.1'). Any other
* input (ranges, regular SemVer versions) is returned unchanged.
*/
export function normalizeJavaVersionToSemver(version: string): string {
const match = /^(\d+(?:\.\d+){3,})(?:\+([0-9A-Za-z.-]+))?$/.exec(version);
if (!match) {
return version;
}
const converted = convertVersionToSemver(match[1]);
return match[2] ? `${converted}.${match[2]}` : converted;
}
/**
* Builds a validator for the bytes currently served by a URL from the response
* headers of a HEAD request. A vendor's `/latest/` URL never changes, so this