Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions .github/workflows/e2e-versions.yml
Original file line number Diff line number Diff line change
Expand Up @@ -495,6 +495,25 @@ jobs:
run: bash __tests__/verify-java.sh "$JAVA_VERSION" "$JAVA_PATH"
shell: bash

setup-java-unsupported-platform:
name: Reject unsupported Oracle x86 on Linux
runs-on: ubuntu-latest
steps:
- *checkout_step
- name: Attempt unsupported setup
id: unsupported-setup
continue-on-error: true
uses: ./
with:
distribution: oracle
java-version: '21'
architecture: x86
- name: Verify setup was rejected
if: always()
env:
SETUP_OUTCOME: ${{ steps.unsupported-setup.outcome }}
run: test "$SETUP_OUTCOME" = failure

setup-java-version-both-version-inputs-presents:
name: ${{ matrix.distribution }} version (should be from input) - ${{ matrix.os }}
runs-on: ${{ matrix.os }}
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ For more details, see the full release notes on the [releases page](https://git

- `java-package`: The packaging variant of the chosen distribution. Possible values across all distributions are `jdk`, `jre`, `jdk+fx`, `jre+fx`, `jdk+crac`, `jre+crac`, `jdk+jmods`, `jdk+jcef`, `jre+jcef`, `jdk+ft`, and `jre+ft`. Supported values vary by distribution; see the [package compatibility table](docs/advanced-usage.md#package-compatibility). Default value: `jdk`.

- `architecture`: The target architecture of the package. Possible values: `x86`, `x64`, `armv7`, `aarch64`, `ppc64le`. Default value: Derived from the runner machine.
- `architecture`: The target architecture of the package. Canonical values are `x86`, `x64`, `armv7`, `aarch64`, `ppc64le`, `ppc64`, and `s390x`; the aliases `ia32`, `amd64`, `arm`, and `arm64` normalize to `x86`, `x64`, `armv7`, and `aarch64`. Supported values vary by distribution and operating system. Default value: Derived from the runner machine.

- `jdk-file`: If a use-case requires a custom distribution setup-java uses the compressed JDK from the location pointed by this input and will take care of the installation and caching on the VM. Note: `distribution` must be set to 'jdkfile' (case-sensitive; all lowercase) when using this option. (The camelCase `jdkFile` input is still accepted as a deprecated alias and may be removed in a future release.)

Expand Down
1 change: 1 addition & 0 deletions __tests__/distributors/adopt-installer.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,7 @@ describe('getAvailableVersions', () => {

it.each([
['amd64', 'x64'],
['arm', 'arm'],
['arm64', 'aarch64']
])(
'defaults to os.arch(): %s mapped to distro arch: %s',
Expand Down
13 changes: 13 additions & 0 deletions __tests__/distributors/corretto-installer.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,19 @@ describe('getAvailableVersions', () => {
expect(availableVersion.url).toBe(expectedLink);
}
);

it('keeps the canonical ARM runner value separate from the vendor value', () => {
jest.spyOn(os, 'arch').mockReturnValue('arm');
const distribution = new CorrettoDistribution({
version: '11',
architecture: '',
packageType: 'jdk',
checkLatest: false
});

expect(distribution['architecture']).toBe('armv7');
expect(distribution['distributionArchitecture']()).toBe('arm');
});
});

const mockPlatform = (
Expand Down
94 changes: 64 additions & 30 deletions __tests__/distributors/distribution-factory.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,20 @@ import {
JAVA_PACKAGE_CAPABILITIES,
JavaDistribution
} from '../../src/distributions/package-types.js';
import os from 'os';
import {validateJavaPlatform} from '../../src/distributions/platform-types.js';
import {normalizeArchitecture} from '../../src/distributions/platform-types.js';

const supportedDistributionsOnCurrentPlatform = Object.values(
JavaDistribution
).filter(distributionName => {
try {
validateJavaPlatform(distributionName, process.platform, 'x64', '25');
return distributionName !== JavaDistribution.JdkFile;
} catch {
return false;
}
});

const installerOptions = (packageType: string, version = '25') => ({
version,
Expand All @@ -13,41 +27,29 @@ const installerOptions = (packageType: string, version = '25') => ({
});

describe('getJavaDistribution', () => {
it.each([
'adopt',
'adopt-hotspot',
'adopt-openj9',
'temurin',
'zulu',
'liberica',
'liberica-nik',
'microsoft',
'semeru',
'corretto',
'oracle',
'dragonwell',
'sapmachine',
'graalvm',
'graalvm-community',
'jetbrains',
'kona',
'oracle-openjdk'
])('uses the shared retrying HTTP client for %s', distributionName => {
const distribution = getJavaDistribution(distributionName, {
version: '21',
architecture: 'x64',
packageType: 'jdk',
checkLatest: false
});
it.each(supportedDistributionsOnCurrentPlatform)(
'uses the shared retrying HTTP client for %s',
distributionName => {
const distribution = getJavaDistribution(distributionName, {
version: '25',
architecture: 'x64',
packageType: 'jdk',
checkLatest: false
});

expect(distribution).not.toBeNull();
expect(distribution!['http']).toBeInstanceOf(RetryingHttpClient);
});
expect(distribution).not.toBeNull();
expect(distribution!['http']).toBeInstanceOf(RetryingHttpClient);
}
);

it.each(
Object.entries(JAVA_PACKAGE_CAPABILITIES).flatMap(
([distributionName, packageTypes]) =>
packageTypes.map(packageType => [distributionName, packageType])
supportedDistributionsOnCurrentPlatform.includes(
distributionName as JavaDistribution
) || distributionName === JavaDistribution.JdkFile
? packageTypes.map(packageType => [distributionName, packageType])
: []
)
)('accepts %s with java-package %s', (distributionName, packageType) => {
expect(
Expand Down Expand Up @@ -111,4 +113,36 @@ describe('getJavaDistribution', () => {
)
).toBeNull();
});

it.each([
['amd64', 'x64'],
['ia32', 'x86'],
['arm64', 'aarch64']
])('passes normalized architecture %s as %s', (input, expected) => {
const normalized = getJavaDistribution(JavaDistribution.JdkFile, {
...installerOptions('jdk'),
architecture: input
});

expect(normalized!['architecture']).toBe(expected);
});

it('uses the runner architecture when the input is empty', () => {
const distribution = getJavaDistribution(JavaDistribution.Temurin, {
...installerOptions('jdk'),
architecture: ''
});

const expected = normalizeArchitecture(os.arch());
expect(distribution!['architecture']).toBe(expected);
});

it('rejects an unsupported combination before creating an HTTP client', () => {
expect(() =>
getJavaDistribution(JavaDistribution.Oracle, {
...installerOptions('jdk'),
architecture: 'x86'
})
).toThrow(/does not support operating system/);
});
});
1 change: 1 addition & 0 deletions __tests__/distributors/temurin-installer.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,7 @@ describe('getAvailableVersions', () => {

it.each([
['amd64', 'x64'],
['arm', 'arm'],
['arm64', 'aarch64']
])(
'defaults to os.arch(): %s mapped to distro arch: %s',
Expand Down
136 changes: 136 additions & 0 deletions __tests__/java-platform-contract.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
import fs from 'fs';
import path from 'path';
import {
JAVA_PLATFORM_CAPABILITIES,
normalizeArchitecture,
validateJavaPlatform
} from '../src/distributions/platform-types.js';
import {JavaDistribution} from '../src/distributions/package-types.js';

describe('Java platform capabilities', () => {
it('declares a capability for every distribution', () => {
expect(Object.keys(JAVA_PLATFORM_CAPABILITIES).sort()).toEqual(
Object.values(JavaDistribution).sort()
);
});

it.each([
['x64', 'x64'],
['amd64', 'x64'],
['x86', 'x86'],
['ia32', 'x86'],
['arm', 'armv7'],
['aarch64', 'aarch64'],
['arm64', 'aarch64'],
['ppc64le', 'ppc64le'],
['s390x', 's390x']
])('normalizes architecture %s to %s', (input, expected) => {
expect(normalizeArchitecture(input)).toBe(expected);
});

it('uses the normalized architecture for validation', () => {
expect(validateJavaPlatform('microsoft', 'linux', 'arm64', '25')).toBe(
'aarch64'
);
});

it('rejects OS-specific restrictions with a consistent diagnostic', () => {
expect(() =>
validateJavaPlatform('oracle', 'win32', 'arm64', '21')
).toThrow(
"Distribution 'oracle' does not support operating system 'windows' with architecture 'aarch64' for Java version '21'. Supported combinations: linux (x64, aarch64); macos (x64, aarch64); windows (x64)."
);
});

it('rejects version-dependent architecture restrictions', () => {
expect(() =>
validateJavaPlatform('corretto', 'linux', 'x86', '17')
).toThrow(/x86 \(<12\)/);
expect(() =>
validateJavaPlatform('corretto', 'linux', 'x86', '17.0.2.8.1')
).toThrow(/x86 \(<12\)/);
expect(validateJavaPlatform('corretto', 'linux', 'x86', '11')).toBe('x86');
});

it.each(['corretto', 'kona'])(
'rejects Windows aarch64 for %s',
distributionName => {
expect(() =>
validateJavaPlatform(distributionName, 'win32', 'arm64', '21')
).toThrow(/does not support operating system 'windows'/);
}
);

it('keeps Adopt HotSpot aliases aligned with the Temurin-first resolver', () => {
expect(validateJavaPlatform('adopt', 'darwin', 'arm64', '21')).toBe(
'aarch64'
);
expect(validateJavaPlatform('adopt-hotspot', 'win32', 'arm64', '21')).toBe(
'aarch64'
);
expect(() =>
validateJavaPlatform('adopt-openj9', 'darwin', 'arm64', '16')
).toThrow(/does not support operating system 'macos'/);
});

it('allows local archives on any platform and architecture', () => {
expect(validateJavaPlatform('jdkfile', 'aix', 'mips64', '21')).toBe(
'mips64'
);
});

it('keeps the documented architecture contract aligned', () => {
const repositoryRoot = process.cwd();
const readRepositoryFile = (filePath: string) =>
fs.readFileSync(path.join(repositoryRoot, filePath), 'utf8');

for (const filePath of ['action.yml', 'README.md']) {
const content = readRepositoryFile(filePath);
for (const architecture of [
'x86',
'x64',
'armv7',
'aarch64',
'ppc64le',
'ppc64',
's390x'
]) {
Comment thread
Copilot marked this conversation as resolved.
expect(content).toContain(architecture);
}
}
});

it.each(Object.entries(JAVA_PLATFORM_CAPABILITIES))(
'keeps the advanced compatibility table aligned for %s',
(distributionName, capability) => {
const advancedUsage = fs.readFileSync(
path.join(process.cwd(), 'docs/advanced-usage.md'),
'utf8'
);
const compatibilityTable = advancedUsage.slice(
advancedUsage.indexOf('## Platform and architecture compatibility')
);
const compatibilityRow = compatibilityTable
.split('\n')
.find(
line =>
line.startsWith('|') && line.includes(`\`${distributionName}\``)
);

expect(compatibilityRow).toBeDefined();
if (!('platforms' in capability)) {
expect(compatibilityRow).toContain('Any');
return;
}

const architectures = new Set(
Object.values(capability.platforms)
.flat()
.map(item => (typeof item === 'string' ? item : item.architecture))
);
for (const architecture of architectures) {
expect(compatibilityRow).toContain(`\`${architecture}\``);
}
}
);
});
2 changes: 1 addition & 1 deletion action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ inputs:
required: false
default: 'jdk'
architecture:
description: "The architecture of the package (defaults to the action runner's architecture)"
description: "The architecture of the package (`x86`, `x64`, `armv7`, `aarch64`, `ppc64le`, `ppc64`, or `s390x`). Aliases `ia32`, `amd64`, `arm`, and `arm64` are normalized to `x86`, `x64`, `armv7`, and `aarch64`. Supported values vary by distribution and operating system. Defaults to the action runner's architecture."
required: false
jdk-file:
description: 'Path to where the compressed JDK is located'
Expand Down
Loading
Loading