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
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ For more details, see the full release notes on the [releases page](https://git

- `distribution`: Java [distribution](#supported-distributions). Required unless `java-version-file` points to `.sdkmanrc` with a recognized distribution suffix (for example `java=21.0.5-tem`).

- `java-package`: The packaging variant of the chosen distribution. Possible values: `jdk`, `jre`, `jdk+fx`, `jre+fx`. For Azul Zulu, `jdk+crac` and `jre+crac` are also supported. For Eclipse Temurin 24 and later, `jdk+jmods` includes the separately packaged JMOD files. Default value: `jdk`.
- `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.

Expand Down
80 changes: 73 additions & 7 deletions __tests__/distributors/distribution-factory.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,16 @@
import {getJavaDistribution} from '../../src/distributions/distribution-factory.js';
import {RetryingHttpClient} from '../../src/retrying-http-client.js';
import {
JAVA_PACKAGE_CAPABILITIES,
JavaDistribution
} from '../../src/distributions/package-types.js';

const installerOptions = (packageType: string, version = '25') => ({
version,
architecture: 'x64',
packageType,
checkLatest: false
});

describe('getJavaDistribution', () => {
it.each([
Expand Down Expand Up @@ -33,16 +44,71 @@ describe('getJavaDistribution', () => {
expect(distribution!['http']).toBeInstanceOf(RetryingHttpClient);
});

it.each(
Object.entries(JAVA_PACKAGE_CAPABILITIES).flatMap(
([distributionName, packageTypes]) =>
packageTypes.map(packageType => [distributionName, packageType])
)
)('accepts %s with java-package %s', (distributionName, packageType) => {
expect(
getJavaDistribution(
distributionName,
installerOptions(packageType as string)
)
).not.toBeNull();
});

it.each(Object.entries(JAVA_PACKAGE_CAPABILITIES))(
'rejects unsupported java-package values for %s',
(distributionName, packageTypes) => {
expect(() =>
getJavaDistribution(distributionName, installerOptions('jdk+typo'))
).toThrow(
`Java package 'jdk+typo' is not supported for distribution '${distributionName}'. Supported package types: ${packageTypes.join(', ')}.`
);
}
);

it("rejects java-package 'jdk+jmods' for non-Temurin distributions", () => {
expect(() =>
getJavaDistribution('zulu', {
version: '25',
architecture: 'x64',
packageType: 'jdk+jmods',
checkLatest: false
})
getJavaDistribution('zulu', installerOptions('jdk+jmods'))
).toThrow(
"java-package 'jdk+jmods' is only supported for distribution 'temurin'."
"Java package 'jdk+jmods' is not supported for distribution 'zulu'. Supported package types: jdk, jre, jdk+fx, jre+fx, jdk+crac, jre+crac."
);
});

it.each(['8', '23.x', '23.0.1.1', '<24'])(
"rejects Temurin java-package 'jdk+jmods' for version %s",
version => {
expect(() =>
getJavaDistribution(
JavaDistribution.Temurin,
installerOptions('jdk+jmods', version)
)
).toThrow(
`Java package 'jdk+jmods' is not supported for distribution 'temurin'. Supported package types: jdk, jre, jdk+jmods. Package 'jdk+jmods' requires Java 24 or later; requested version '${version}'.`
);
}
);

it.each(['24', '24.0.1.1', '25-ea', '>=21', 'latest'])(
"accepts Temurin java-package 'jdk+jmods' for version %s",
version => {
expect(
getJavaDistribution(
JavaDistribution.Temurin,
installerOptions('jdk+jmods', version)
)
).not.toBeNull();
}
);

it('preserves unsupported distribution handling', () => {
expect(
getJavaDistribution(
'not-a-distribution',
installerOptions('not-a-package')
)
).toBeNull();
});
});
82 changes: 82 additions & 0 deletions __tests__/java-package-contract.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import fs from 'fs';
import path from 'path';
import {
JAVA_PACKAGE_CAPABILITIES,
JavaDistribution
} from '../src/distributions/package-types.js';

const repositoryRoot = process.cwd();
const readRepositoryFile = (filePath: string) =>
fs.readFileSync(path.join(repositoryRoot, filePath), 'utf8');
const allPackageTypes = [
...new Set(Object.values(JAVA_PACKAGE_CAPABILITIES).flat())
];

describe('java-package published contract', () => {
it.each(['action.yml', 'README.md'])(
'documents every supported package type in %s',
filePath => {
const content = readRepositoryFile(filePath);
const contractLine =
filePath === 'action.yml'
? content.match(/ {2}java-package:\n(?: {4}.+\n)+/)?.[0]
: content
.split('\n')
.find(line => line.includes('- `java-package`:'));

expect(contractLine).toBeDefined();
for (const packageType of allPackageTypes) {
expect(contractLine).toContain(`\`${packageType}\``);
}
}
);

it.each(Object.entries(JAVA_PACKAGE_CAPABILITIES))(
'keeps the advanced compatibility table aligned for %s',
(distributionName, packageTypes) => {
const advancedUsage = readRepositoryFile('docs/advanced-usage.md');
const compatibilityTable = advancedUsage.slice(
advancedUsage.indexOf('### Package compatibility')
);
const compatibilityRow = compatibilityTable
.split('\n')
.find(
line =>
line.startsWith('|') && line.includes(`\`${distributionName}\``)
);

expect(compatibilityRow).toBeDefined();
for (const packageType of packageTypes) {
expect(compatibilityRow).toContain(`\`${packageType}\``);
}
}
);

it('only exercises supported distribution/package combinations in E2E', () => {
const workflow = readRepositoryFile('.github/workflows/e2e-versions.yml');
const defaultMatrix = workflow.match(
/distribution:\s*\n\s*\[([^\]]+)\]\s*\n\s*java-package:\s*\['([^']+)'\]/
);
Comment on lines +57 to +59
expect(defaultMatrix).not.toBeNull();

const defaultDistributions = [
...defaultMatrix![1].matchAll(/'([^']+)'/g)
].map(match => match[1]);
const defaultPackage = defaultMatrix![2];
for (const distributionName of defaultDistributions) {
expect(supportedPackagesFor(distributionName)).toContain(defaultPackage);
}

const includedPackages = workflow.matchAll(
/- distribution: '([^']+)'\s*\n\s*java-package: ([^\s]+)/g
);
for (const match of includedPackages) {
const [, distributionName, packageType] = match;
expect(supportedPackagesFor(distributionName)).toContain(packageType);
}
});
});

function supportedPackagesFor(distributionName: string): readonly string[] {
return JAVA_PACKAGE_CAPABILITIES[distributionName as JavaDistribution] ?? [];
}
2 changes: 1 addition & 1 deletion action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ inputs:
description: 'Java distribution. See the list of supported distributions in README file. This input is required except when java-version-file points to .sdkmanrc with a recognized distribution suffix (e.g., java=21.0.5-tem).'
required: false
java-package:
description: 'The package type (jdk, jre, jdk+fx, jre+fx, jdk+crac, jre+crac, jdk+jmods)'
description: 'The package type (`jdk`, `jre`, `jdk+fx`, `jre+fx`, `jdk+crac`, `jre+crac`, `jdk+jmods`, `jdk+jcef`, `jre+jcef`, `jdk+ft`, or `jre+ft`). Supported values vary by distribution.'
required: false
default: 'jdk'
architecture:
Expand Down
121 changes: 102 additions & 19 deletions dist/setup/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -132121,21 +132121,7 @@ class OpenJdkDistribution extends JavaBase {
}
}

;// CONCATENATED MODULE: ./src/distributions/distribution-factory.ts














;// CONCATENATED MODULE: ./src/distributions/package-types.ts


var JavaDistribution;
Expand All @@ -132160,11 +132146,108 @@ var JavaDistribution;
JavaDistribution["Kona"] = "kona";
JavaDistribution["OracleOpenJdk"] = "oracle-openjdk";
})(JavaDistribution || (JavaDistribution = {}));
function getJavaDistribution(distributionName, installerOptions, jdkFile) {
if (installerOptions.packageType === 'jdk+jmods' &&
distributionName !== JavaDistribution.Temurin) {
throw new Error("java-package 'jdk+jmods' is only supported for distribution 'temurin'.");
const JAVA_PACKAGE_CAPABILITIES = {
[JavaDistribution.Adopt]: ['jdk', 'jre'],
[JavaDistribution.AdoptHotspot]: ['jdk', 'jre'],
[JavaDistribution.AdoptOpenJ9]: ['jdk', 'jre'],
[JavaDistribution.Temurin]: ['jdk', 'jre', 'jdk+jmods'],
[JavaDistribution.Zulu]: [
'jdk',
'jre',
'jdk+fx',
'jre+fx',
'jdk+crac',
'jre+crac'
],
[JavaDistribution.Liberica]: ['jdk', 'jre', 'jdk+fx', 'jre+fx'],
[JavaDistribution.LibericaNik]: ['jdk', 'jdk+fx'],
[JavaDistribution.JdkFile]: ['jdk'],
[JavaDistribution.Microsoft]: ['jdk'],
[JavaDistribution.Semeru]: ['jdk', 'jre'],
[JavaDistribution.Corretto]: ['jdk', 'jre'],
[JavaDistribution.Oracle]: ['jdk'],
[JavaDistribution.Dragonwell]: ['jdk'],
[JavaDistribution.SapMachine]: ['jdk', 'jre'],
[JavaDistribution.GraalVM]: ['jdk'],
[JavaDistribution.GraalVMCommunity]: ['jdk'],
[JavaDistribution.JetBrains]: [
'jdk',
'jre',
'jdk+jcef',
'jre+jcef',
'jdk+ft',
'jre+ft'
],
[JavaDistribution.Kona]: ['jdk'],
[JavaDistribution.OracleOpenJdk]: ['jdk']
};
function validateJavaPackage(distributionName, packageType, version) {
if (!isJavaDistribution(distributionName)) {
return;
}
const supportedPackages = JAVA_PACKAGE_CAPABILITIES[distributionName];
if (!supportedPackages.includes(packageType)) {
throw createUnsupportedPackageError(distributionName, packageType, supportedPackages);
}
if (distributionName === JavaDistribution.Temurin &&
packageType === 'jdk+jmods' &&
!canResolveTemurinJmods(version)) {
throw createUnsupportedPackageError(distributionName, packageType, supportedPackages, `Package 'jdk+jmods' requires Java 24 or later; requested version '${version}'.`);
}
}
function isJavaDistribution(value) {
return Object.prototype.hasOwnProperty.call(JAVA_PACKAGE_CAPABILITIES, value);
}
function canResolveTemurinJmods(version) {
const normalizedVersion = version.trim().toLowerCase();
if (normalizedVersion === 'latest') {
return true;
}
let normalizedRange = normalizedVersion
.replace(/-ea$/, '')
.replace('-ea.', '+');
if (/^\d+(\.\d+){3,}$/.test(normalizedRange)) {
normalizedRange = convertVersionToSemver(normalizedRange);
}
if (!semver_default().validRange(normalizedRange)) {
// JavaBase owns general version validation and its targeted error messages.
return true;
}
return semver_default().intersects(normalizedRange, '>=24.0.0', {
includePrerelease: true
});
}
function createUnsupportedPackageError(distributionName, packageType, supportedPackages, detail) {
const message = [
`Java package '${packageType}' is not supported for distribution '${distributionName}'.`,
`Supported package types: ${supportedPackages.join(', ')}.`
];
if (detail) {
message.push(detail);
}
return new Error(message.join(' '));
}

;// CONCATENATED MODULE: ./src/distributions/distribution-factory.ts

















function getJavaDistribution(distributionName, installerOptions, jdkFile) {
validateJavaPackage(distributionName, installerOptions.packageType, installerOptions.version);
switch (distributionName) {
case JavaDistribution.JdkFile:
return new LocalDistribution(installerOptions, jdkFile);
Expand Down
8 changes: 3 additions & 5 deletions docs/advanced-usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -321,12 +321,10 @@ The package types have these meanings:
| `graalvm-community` | `jdk` | Stable GraalVM Community releases for JDK 17 and later only. |
| `jetbrains` | `jdk`, `jre`, `jdk+jcef`, `jre+jcef`, `jdk+ft`, `jre+ft` | JetBrains publishes selected LTS-based releases rather than every OpenJDK patch. JDK/JRE and JCEF bundles start with the Java 11 release family; FreeType bundles start with Java 17. Exact package, LTS family, patch, OS, and architecture availability is determined from release assets. |
| `kona` | `jdk` | Stable Java 8, 11, 17, 21, and 25 releases only. |
| `jdkfile` | `jdk` (recommended) | The package contents and version are supplied by `jdk-file`; `setup-java` does not validate them. `java-package` only separates the local archive's tool-cache entry, so use `jdk` unless separate cache namespaces are required. |
| `jdkfile` | `jdk` | The package contents and version are supplied by `jdk-file`; `setup-java` validates the package type but does not inspect the archive contents. |

Values outside this table are unsupported even when a distribution forwards the
value to its vendor API instead of rejecting it immediately. In that case, the
action normally fails with a version-not-found error because no matching
artifact exists.
Values outside this table are unsupported. The action rejects them before
checking the tool cache or requesting a vendor catalog.

```yaml
steps:
Expand Down
36 changes: 6 additions & 30 deletions src/distributions/distribution-factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,42 +22,18 @@ import {
import {JetBrainsDistribution} from './jetbrains/installer.js';
import {KonaDistribution} from './kona/installer.js';
import {OpenJdkDistribution} from './openjdk/installer.js';

enum JavaDistribution {
Adopt = 'adopt',
AdoptHotspot = 'adopt-hotspot',
AdoptOpenJ9 = 'adopt-openj9',
Temurin = 'temurin',
Zulu = 'zulu',
Liberica = 'liberica',
LibericaNik = 'liberica-nik',
JdkFile = 'jdkfile',
Microsoft = 'microsoft',
Semeru = 'semeru',
Corretto = 'corretto',
Oracle = 'oracle',
Dragonwell = 'dragonwell',
SapMachine = 'sapmachine',
GraalVM = 'graalvm',
GraalVMCommunity = 'graalvm-community',
JetBrains = 'jetbrains',
Kona = 'kona',
OracleOpenJdk = 'oracle-openjdk'
}
import {JavaDistribution, validateJavaPackage} from './package-types.js';

export function getJavaDistribution(
distributionName: string,
installerOptions: JavaInstallerOptions,
jdkFile?: string
): JavaBase | null {
if (
installerOptions.packageType === 'jdk+jmods' &&
distributionName !== JavaDistribution.Temurin
) {
throw new Error(
"java-package 'jdk+jmods' is only supported for distribution 'temurin'."
);
}
validateJavaPackage(
distributionName,
installerOptions.packageType,
installerOptions.version
);

switch (distributionName) {
case JavaDistribution.JdkFile:
Expand Down
Loading
Loading