5
0
mirror of https://gitea.com/actions/setup-java.git synced 2026-08-05 02:31:18 +00:00

Centralize OS/architecture capability validation (#1178)

* Centralize platform capability validation

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 10e35b75-928f-4ef7-984e-605895c5d88e

* Address PR review feedback

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 10e35b75-928f-4ef7-984e-605895c5d88e

* Regenerate dist after platform validation updates

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 10e35b75-928f-4ef7-984e-605895c5d88e
This commit is contained in:
Bruno Borges
2026-07-29 15:46:29 -04:00
committed by GitHub
parent 0b56831a10
commit 6937f5eb31
17 changed files with 1014 additions and 212 deletions
+5
View File
@@ -260,4 +260,9 @@ export class AdoptDistribution extends JavaBase {
return process.platform;
}
}
protected distributionArchitecture(): string {
const architecture = super.distributionArchitecture();
return architecture === 'armv7' ? 'arm' : architecture;
}
}
+5 -18
View File
@@ -20,6 +20,7 @@ import {MACOS_JAVA_CONTENT_POSTFIX} from '../constants.js';
import {RetryingHttpClient} from '../retrying-http-client.js';
import os from 'os';
import {expectedDigestLength, verifyChecksum} from '../checksum.js';
import {normalizeArchitecture} from './platform-types.js';
export abstract class JavaBase {
protected http: httpm.HttpClient;
@@ -45,7 +46,9 @@ export abstract class JavaBase {
stable: this.stable,
latest: this.latest
} = this.normalizeVersion(installerOptions.version));
this.architecture = installerOptions.architecture || os.arch();
this.architecture = normalizeArchitecture(
installerOptions.architecture || os.arch()
);
this.packageType = installerOptions.packageType;
this.checkLatest = installerOptions.checkLatest;
this.forceDownload = installerOptions.forceDownload ?? false;
@@ -451,22 +454,6 @@ export abstract class JavaBase {
}
protected distributionArchitecture(): string {
// default mappings of config architectures to distribution architectures
// override if a distribution uses any different names; see liberica for an example
// node's os.arch() - which this defaults to - can return any of:
// 'arm', 'arm64', 'ia32', 'mips', 'mipsel', 'ppc', 'ppc64', 's390', 's390x', and 'x64'
// so we need to map these to java distribution architectures
// 'amd64' is included here too b/c it's a common alias for 'x64' people might use explicitly
switch (this.architecture) {
case 'amd64':
return 'x64';
case 'ia32':
return 'x86';
case 'arm64':
return 'aarch64';
default:
return this.architecture;
}
return this.architecture;
}
}
+5
View File
@@ -194,6 +194,11 @@ export class CorrettoDistribution extends JavaBase {
}
}
protected distributionArchitecture(): string {
const architecture = super.distributionArchitecture();
return architecture === 'armv7' ? 'arm' : architecture;
}
private getCorrettoVersion(resource: string): string {
const regex = /(\d+.+)\//;
const match = regex.exec(resource);
+30 -18
View File
@@ -23,6 +23,8 @@ import {JetBrainsDistribution} from './jetbrains/installer.js';
import {KonaDistribution} from './kona/installer.js';
import {OpenJdkDistribution} from './openjdk/installer.js';
import {JavaDistribution, validateJavaPackage} from './package-types.js';
import os from 'os';
import {validateJavaPlatform} from './platform-types.js';
export function getJavaDistribution(
distributionName: string,
@@ -34,54 +36,64 @@ export function getJavaDistribution(
installerOptions.packageType,
installerOptions.version
);
const architecture = validateJavaPlatform(
distributionName,
process.platform,
installerOptions.architecture || os.arch(),
installerOptions.version
);
const normalizedInstallerOptions = {
...installerOptions,
architecture
};
switch (distributionName) {
case JavaDistribution.JdkFile:
return new LocalDistribution(installerOptions, jdkFile);
return new LocalDistribution(normalizedInstallerOptions, jdkFile);
case JavaDistribution.Adopt:
case JavaDistribution.AdoptHotspot:
return new AdoptDistribution(
installerOptions,
normalizedInstallerOptions,
AdoptImplementation.Hotspot
);
case JavaDistribution.AdoptOpenJ9:
return new AdoptDistribution(
installerOptions,
normalizedInstallerOptions,
AdoptImplementation.OpenJ9
);
case JavaDistribution.Temurin:
return new TemurinDistribution(
installerOptions,
normalizedInstallerOptions,
TemurinImplementation.Hotspot
);
case JavaDistribution.Zulu:
return new ZuluDistribution(installerOptions);
return new ZuluDistribution(normalizedInstallerOptions);
case JavaDistribution.Liberica:
return new LibericaDistributions(installerOptions);
return new LibericaDistributions(normalizedInstallerOptions);
case JavaDistribution.LibericaNik:
return new LibericaNikDistributions(installerOptions);
return new LibericaNikDistributions(normalizedInstallerOptions);
case JavaDistribution.Microsoft:
return new MicrosoftDistributions(installerOptions);
return new MicrosoftDistributions(normalizedInstallerOptions);
case JavaDistribution.Semeru:
return new SemeruDistribution(installerOptions);
return new SemeruDistribution(normalizedInstallerOptions);
case JavaDistribution.Corretto:
return new CorrettoDistribution(installerOptions);
return new CorrettoDistribution(normalizedInstallerOptions);
case JavaDistribution.Oracle:
return new OracleDistribution(installerOptions);
return new OracleDistribution(normalizedInstallerOptions);
case JavaDistribution.Dragonwell:
return new DragonwellDistribution(installerOptions);
return new DragonwellDistribution(normalizedInstallerOptions);
case JavaDistribution.SapMachine:
return new SapMachineDistribution(installerOptions);
return new SapMachineDistribution(normalizedInstallerOptions);
case JavaDistribution.GraalVM:
return new GraalVMDistribution(installerOptions);
return new GraalVMDistribution(normalizedInstallerOptions);
case JavaDistribution.GraalVMCommunity:
return new GraalVMCommunityDistribution(installerOptions);
return new GraalVMCommunityDistribution(normalizedInstallerOptions);
case JavaDistribution.JetBrains:
return new JetBrainsDistribution(installerOptions);
return new JetBrainsDistribution(normalizedInstallerOptions);
case JavaDistribution.Kona:
return new KonaDistribution(installerOptions);
return new KonaDistribution(normalizedInstallerOptions);
case JavaDistribution.OracleOpenJdk:
return new OpenJdkDistribution(installerOptions);
return new OpenJdkDistribution(normalizedInstallerOptions);
default:
return null;
}
+306
View File
@@ -0,0 +1,306 @@
import semver from 'semver';
import {JavaDistribution} from './package-types.js';
export type JavaPlatform = 'linux' | 'macos' | 'windows' | 'solaris';
export type JavaArchitecture =
'x86' | 'x64' | 'armv7' | 'aarch64' | 'ppc64le' | 'ppc64' | 's390x';
interface VersionedArchitecture {
architecture: JavaArchitecture;
versionRange: string;
}
type ArchitectureCapability = JavaArchitecture | VersionedArchitecture;
interface RestrictedPlatformCapability {
unrestricted?: false;
platforms: Partial<Record<JavaPlatform, readonly ArchitectureCapability[]>>;
}
interface UnrestrictedPlatformCapability {
unrestricted: true;
}
export type JavaPlatformCapability =
RestrictedPlatformCapability | UnrestrictedPlatformCapability;
const X64_ARM64 = ['x64', 'aarch64'] as const;
const X64_X86 = ['x64', 'x86'] as const;
const STANDARD_LINUX = ['x64', 'x86', 'aarch64', 'ppc64le', 's390x'] as const;
export const JAVA_PLATFORM_CAPABILITIES: Record<
JavaDistribution,
JavaPlatformCapability
> = {
[JavaDistribution.Adopt]: {
platforms: {
linux: [...STANDARD_LINUX, {architecture: 'armv7', versionRange: '<18'}],
macos: X64_ARM64,
windows: ['x64', 'x86', 'aarch64']
}
},
[JavaDistribution.AdoptHotspot]: {
platforms: {
linux: [...STANDARD_LINUX, {architecture: 'armv7', versionRange: '<18'}],
macos: X64_ARM64,
windows: ['x64', 'x86', 'aarch64']
}
},
[JavaDistribution.AdoptOpenJ9]: {
platforms: {
linux: STANDARD_LINUX,
macos: ['x64'],
windows: X64_X86
}
},
[JavaDistribution.Temurin]: {
platforms: {
linux: [...STANDARD_LINUX, {architecture: 'armv7', versionRange: '<18'}],
macos: X64_ARM64,
windows: ['x64', 'x86', 'aarch64']
}
},
[JavaDistribution.Zulu]: {
platforms: {
linux: ['x64', 'x86', 'armv7', 'aarch64'],
macos: X64_ARM64,
windows: ['x64', 'x86', 'aarch64']
}
},
[JavaDistribution.Liberica]: {
platforms: {
linux: ['x64', 'x86', 'armv7', 'aarch64', 'ppc64le'],
macos: X64_ARM64,
windows: ['x64', 'x86', 'aarch64'],
solaris: ['x64']
}
},
[JavaDistribution.LibericaNik]: {
platforms: {
linux: X64_ARM64,
macos: X64_ARM64,
windows: X64_ARM64
}
},
[JavaDistribution.JdkFile]: {
unrestricted: true
},
[JavaDistribution.Microsoft]: {
platforms: {
linux: X64_ARM64,
macos: X64_ARM64,
windows: X64_ARM64
}
},
[JavaDistribution.Semeru]: {
platforms: {
linux: ['x64', 'x86', 'ppc64le', 'ppc64', 's390x', 'aarch64'],
macos: X64_ARM64,
windows: ['x64', 'aarch64']
}
},
[JavaDistribution.Corretto]: {
platforms: {
linux: [
'x64',
{architecture: 'x86', versionRange: '<12'},
{architecture: 'armv7', versionRange: '11'},
'aarch64'
],
macos: X64_ARM64,
windows: ['x64', {architecture: 'x86', versionRange: '<12'}]
}
},
[JavaDistribution.Oracle]: {
platforms: {
linux: X64_ARM64,
macos: X64_ARM64,
windows: ['x64']
}
},
[JavaDistribution.Dragonwell]: {
platforms: {
linux: X64_ARM64,
windows: ['x64']
}
},
[JavaDistribution.SapMachine]: {
platforms: {
linux: ['x64', 'aarch64', 'ppc64le'],
macos: X64_ARM64,
windows: X64_ARM64
}
},
[JavaDistribution.GraalVM]: {
platforms: {
linux: X64_ARM64,
macos: X64_ARM64,
windows: ['x64']
}
},
[JavaDistribution.GraalVMCommunity]: {
platforms: {
linux: X64_ARM64,
macos: X64_ARM64,
windows: ['x64']
}
},
[JavaDistribution.JetBrains]: {
platforms: {
linux: X64_ARM64,
macos: X64_ARM64,
windows: X64_ARM64
}
},
[JavaDistribution.Kona]: {
platforms: {
linux: X64_ARM64,
macos: X64_ARM64,
windows: ['x64']
}
},
[JavaDistribution.OracleOpenJdk]: {
platforms: {
linux: X64_ARM64,
macos: X64_ARM64,
windows: ['x64']
}
}
};
const ARCHITECTURE_ALIASES: Readonly<Record<string, JavaArchitecture>> = {
amd64: 'x64',
arm: 'armv7',
ia32: 'x86',
arm64: 'aarch64'
};
const CANONICAL_ARCHITECTURES: readonly JavaArchitecture[] = [
'x86',
'x64',
'armv7',
'aarch64',
'ppc64le',
'ppc64',
's390x'
];
const PLATFORM_ALIASES: Readonly<
Partial<Record<NodeJS.Platform, JavaPlatform>>
> = {
darwin: 'macos',
linux: 'linux',
sunos: 'solaris',
win32: 'windows'
};
export function normalizeArchitecture(architecture: string): string {
const trimmedArchitecture = architecture.trim();
const normalizedArchitecture = trimmedArchitecture.toLowerCase();
return (
ARCHITECTURE_ALIASES[normalizedArchitecture] ??
(CANONICAL_ARCHITECTURES.includes(
normalizedArchitecture as JavaArchitecture
)
? normalizedArchitecture
: trimmedArchitecture)
);
}
export function normalizePlatform(
platform: NodeJS.Platform
): JavaPlatform | undefined {
return PLATFORM_ALIASES[platform];
}
export function validateJavaPlatform(
distributionName: string,
platform: NodeJS.Platform,
architecture: string,
version: string
): string {
const normalizedArchitecture = normalizeArchitecture(architecture);
if (!isJavaDistribution(distributionName)) {
return normalizedArchitecture;
}
const capability = JAVA_PLATFORM_CAPABILITIES[distributionName];
if ('unrestricted' in capability && capability.unrestricted === true) {
return normalizedArchitecture;
}
const normalizedPlatform = normalizePlatform(platform);
const architectures = normalizedPlatform
? capability.platforms[normalizedPlatform]
: undefined;
const supported = architectures?.some(item => {
const architectureCapability =
typeof item === 'string' ? {architecture: item} : item;
return (
architectureCapability.architecture === normalizedArchitecture &&
(!('versionRange' in architectureCapability) ||
isVersionCompatible(version, architectureCapability.versionRange))
);
});
if (!supported) {
throw new Error(
`Distribution '${distributionName}' does not support operating system '${normalizedPlatform ?? platform}' with architecture '${normalizedArchitecture}' for Java version '${version}'. Supported combinations: ${formatSupportedCombinations(capability)}.`
);
}
return normalizedArchitecture;
}
function isJavaDistribution(value: string): value is JavaDistribution {
return Object.prototype.hasOwnProperty.call(
JAVA_PLATFORM_CAPABILITIES,
value
);
}
function isVersionCompatible(version: string, supportedRange: string): boolean {
let normalizedVersion = version.trim().toLowerCase();
if (normalizedVersion === 'latest') {
return true;
}
if (/^\d+(\.\d+){3,}$/.test(normalizedVersion)) {
normalizedVersion = normalizeExtendedVersionToSemver(normalizedVersion);
}
const requestedRange = semver.validRange(
normalizedVersion.replace(/-ea$/, '')
);
const capabilityRange = semver.validRange(supportedRange);
if (!requestedRange || !capabilityRange) {
return true;
}
function normalizeExtendedVersionToSemver(version: string): string {
const versionParts = version.split('.');
const mainVersion = versionParts.slice(0, 3).join('.');
if (versionParts.length > 3) {
return `${mainVersion}+${versionParts.slice(3).join('.')}`;
}
return version;
}
return semver.intersects(requestedRange, capabilityRange, {
includePrerelease: true
});
}
function formatSupportedCombinations(
capability: RestrictedPlatformCapability
): string {
return Object.entries(capability.platforms)
.map(([platform, architectures]) => {
const values = architectures.map(item =>
typeof item === 'string'
? item
: `${item.architecture} (${item.versionRange})`
);
return `${platform} (${values.join(', ')})`;
})
.join('; ');
}
+5
View File
@@ -282,4 +282,9 @@ export class TemurinDistribution extends JavaBase {
return process.platform;
}
}
protected distributionArchitecture(): string {
const architecture = super.distributionArchitecture();
return architecture === 'armv7' ? 'arm' : architecture;
}
}
+2
View File
@@ -221,6 +221,8 @@ export class ZuluDistribution extends JavaBase {
// would let a 32-bit request resolve to a 64-bit JDK. Use "i686" to
// target only genuine 32-bit builds, matching the legacy API behavior.
return 'i686';
case 'armv7':
return 'arm';
case 'aarch64':
case 'arm64':
return 'aarch64';