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. Default value: `jdk`.
- `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`.

- `architecture`: The target architecture of the package. Possible values: `x86`, `x64`, `armv7`, `aarch64`, `ppc64le`. Default value: Derived from the runner machine.

Expand Down
16 changes: 16 additions & 0 deletions __tests__/distributors/distribution-factory.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import {getJavaDistribution} from '../../src/distributions/distribution-factory.js';

describe('getJavaDistribution', () => {
it("rejects java-package 'jdk+jmods' for non-Temurin distributions", () => {
expect(() =>
getJavaDistribution('zulu', {
version: '25',
architecture: 'x64',
packageType: 'jdk+jmods',
checkLatest: false
})
).toThrow(
"java-package 'jdk+jmods' is only supported for distribution 'temurin'."
);
});
});
96 changes: 95 additions & 1 deletion __tests__/distributors/temurin-installer.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import type {TemurinImplementation as TemurinImplementationType} from '../../src
import {HttpClient} from '@actions/http-client';
import fs from 'fs';
import os from 'os';
import path from 'path';

import manifestData from '../data/temurin.json' with {type: 'json'};

Expand Down Expand Up @@ -119,6 +120,16 @@ describe('getAvailableVersions', () => {
TemurinImplementation.Hotspot,
'os=mac&architecture=x64&image_type=jdk&release_type=ga&jvm_impl=hotspot&page_size=20&page=0'
],
[
{
version: '25',
architecture: 'x64',
packageType: 'jdk+jmods',
checkLatest: false
},
TemurinImplementation.Hotspot,
'os=mac&architecture=x64&image_type=jdk&release_type=ga&jvm_impl=hotspot&page_size=20&page=0'
],
[
{
version: '16',
Expand Down Expand Up @@ -169,6 +180,27 @@ describe('getAvailableVersions', () => {
}
);

it('requests the JMOD image type', async () => {
const distribution = new TemurinDistribution(
{
version: '25',
architecture: 'x64',
packageType: 'jdk+jmods',
checkLatest: false
},
TemurinImplementation.Hotspot
);
distribution['getPlatformOption'] = () => 'linux';

await distribution['getAvailableVersions']('jmods');

expect(spyHttpClient).toHaveBeenCalledWith(
expect.stringContaining(
'os=linux&architecture=x64&image_type=jmods&release_type=ga'
)
);
});

it('load available versions', async () => {
const nextPageUrl =
'https://api.adoptium.net/v3/assets/version/%5B1.0,100.0%5D?page=1&page_size=20';
Expand Down Expand Up @@ -229,7 +261,12 @@ describe('getAvailableVersions', () => {

it.each([
[TemurinImplementation.Hotspot, 'jdk', 'Java_Temurin-Hotspot_jdk'],
[TemurinImplementation.Hotspot, 'jre', 'Java_Temurin-Hotspot_jre']
[TemurinImplementation.Hotspot, 'jre', 'Java_Temurin-Hotspot_jre'],
[
TemurinImplementation.Hotspot,
'jdk+jmods',
'Java_Temurin-Hotspot_jdk+jmods'
]
])(
'find right toolchain folder',
(
Expand Down Expand Up @@ -386,6 +423,7 @@ describe('downloadTool', () => {
let spyCacheDir: any;
let spyReadDirSync: any;
let spyRenameWinArchive: any;
let spyCopySync: any;

beforeEach(() => {
spyDownloadTool = tc.downloadTool as jest.Mock;
Expand All @@ -400,6 +438,8 @@ describe('downloadTool', () => {
spyReadDirSync.mockReturnValue(['jdk-17'] as any);
spyRenameWinArchive = util.renameWinArchive as jest.Mock;
spyRenameWinArchive.mockReturnValue('/tmp/jdk.tar.gz.zip');
spyCopySync = jest.spyOn(fs, 'cpSync');
spyCopySync.mockImplementation(() => undefined);
});

afterEach(() => {
Expand Down Expand Up @@ -433,6 +473,60 @@ describe('downloadTool', () => {
);
});

it('downloads and adds matching JMODs to the JDK', async () => {
spyDownloadTool
.mockResolvedValueOnce('/tmp/jdk.tar.gz')
.mockResolvedValueOnce('/tmp/jmods.tar.gz');
spyExtractJdkFile
.mockResolvedValueOnce('/tmp/extracted')
.mockResolvedValueOnce('/tmp/extracted-jmods');
spyReadDirSync
.mockReturnValueOnce(['jdk-25'] as any)
.mockReturnValueOnce(['jdk-25-jmods'] as any);
jest.spyOn(fs, 'existsSync').mockReturnValue(false);

const distribution = new TemurinDistribution(
{
version: '25',
architecture: 'x64',
packageType: 'jdk+jmods',
checkLatest: false
},
TemurinImplementation.Hotspot
);
distribution['resolvePackage'] = jest.fn().mockResolvedValue({
version: '25.0.3+9',
url: 'https://example.com/jmods.tar.gz'
});

await distribution['downloadTool']({
version: '25.0.3+9',
url: 'https://example.com/jdk.tar.gz'
});

expect(distribution['resolvePackage']).toHaveBeenCalledWith(
'25.0.3+9',
'jmods'
);
expect(spyDownloadTool).toHaveBeenNthCalledWith(
2,
'https://example.com/jmods.tar.gz'
);
expect(spyCopySync).toHaveBeenCalledWith(
path.join('/tmp/extracted-jmods', 'jdk-25-jmods'),
process.platform === 'darwin'
? path.join('/tmp/extracted', 'jdk-25', 'Contents', 'Home', 'jmods')
: path.join('/tmp/extracted', 'jdk-25', 'jmods'),
{recursive: true}
);
expect(spyCacheDir).toHaveBeenCalledWith(
path.join('/tmp/extracted', 'jdk-25'),
'Java_Temurin-Hotspot_jdk+jmods',
'25.0.3-9',
'x64'
);
});

it('fails when signature is missing and verification is enabled', async () => {
const distribution = new TemurinDistribution(
{
Expand Down
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)'
description: 'The package type (jdk, jre, jdk+fx, jre+fx, jdk+crac, jre+crac, jdk+jmods)'
required: false
default: 'jdk'
architecture:
Expand Down
65 changes: 46 additions & 19 deletions dist/setup/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -129873,21 +129873,27 @@ wI4qF/KKq9BfyfucAs0ykA==




var TemurinImplementation;
(function (TemurinImplementation) {
TemurinImplementation["Hotspot"] = "Hotspot";
})(TemurinImplementation || (TemurinImplementation = {}));
class TemurinDistribution extends JavaBase {
jvmImpl;
includeJmods;
constructor(installerOptions, jvmImpl) {
super(`Temurin-${jvmImpl}`, installerOptions);
this.jvmImpl = jvmImpl;
this.includeJmods = this.packageType === 'jdk+jmods';
}
/**
* @internal For cross-distribution reuse only. Not intended as a public API.
*/
async findPackageForDownload(version) {
const availableVersionsRaw = await this.getAvailableVersions();
return this.resolvePackage(version, this.includeJmods ? 'jdk' : this.packageType);
}
async resolvePackage(version, imageType) {
const availableVersionsRaw = await this.getAvailableVersions(imageType);
const availableVersionsWithBinaries = availableVersionsRaw
.filter(item => item.binaries.length > 0)
.map(item => {
Expand Down Expand Up @@ -129915,19 +129921,7 @@ class TemurinDistribution extends JavaBase {
}
async downloadTool(javaRelease) {
info(`Downloading Java ${javaRelease.version} (${this.distribution}) from ${javaRelease.url} ...`);
let javaArchivePath = await downloadTool(javaRelease.url);
if (this.verifySignature) {
if (!javaRelease.signatureUrl) {
throw new Error(`Input 'verify-signature' is enabled, but no signature URL was found for Temurin version ${javaRelease.version}.`);
}
info(`Verifying Java package signature...`);
try {
await verifyPackageSignature(javaArchivePath, javaRelease.signatureUrl, this.verifySignaturePublicKey ?? ADOPTIUM_PUBLIC_KEY);
}
catch (error) {
throw new Error(`Failed to verify signature for Temurin version ${javaRelease.version} from ${javaRelease.signatureUrl}: ${error.message}`, { cause: error });
}
}
let javaArchivePath = await this.downloadPackage(javaRelease);
info(`Extracting Java archive...`);
const extension = getDownloadArchiveExtension();
if (process.platform === 'win32') {
Expand All @@ -129936,20 +129930,49 @@ class TemurinDistribution extends JavaBase {
const extractedJavaPath = await extractJdkFile(javaArchivePath, extension);
const archiveName = external_fs_default().readdirSync(extractedJavaPath)[0];
const archivePath = external_path_default().join(extractedJavaPath, archiveName);
const javaHome = process.platform === 'darwin'
? external_path_default().join(archivePath, MACOS_JAVA_CONTENT_POSTFIX)
: archivePath;
if (this.includeJmods && !external_fs_default().existsSync(external_path_default().join(javaHome, 'jmods'))) {
await this.installJmods(javaRelease.version, javaHome);
}
const version = this.getToolcacheVersionName(javaRelease.version);
const javaPath = await cacheDir(archivePath, this.toolcacheFolderName, version, this.architecture);
return { version: javaRelease.version, path: javaPath };
}
get toolcacheFolderName() {
return super.toolcacheFolderName;
}
supportsSignatureVerification() {
return true;
}
async getAvailableVersions() {
async downloadPackage(release) {
const archivePath = await downloadTool(release.url);
if (this.verifySignature) {
if (!release.signatureUrl) {
throw new Error(`Input 'verify-signature' is enabled, but no signature URL was found for Temurin version ${release.version}.`);
}
info(`Verifying Java package signature...`);
try {
await verifyPackageSignature(archivePath, release.signatureUrl, this.verifySignaturePublicKey ?? ADOPTIUM_PUBLIC_KEY);
}
catch (error) {
throw new Error(`Failed to verify signature for Temurin version ${release.version} from ${release.signatureUrl}: ${error.message}`, { cause: error });
}
}
return archivePath;
}
async installJmods(version, javaHome) {
const jmodsRelease = await this.resolvePackage(version, 'jmods');
info(`Downloading JMODs ${jmodsRelease.version} (${this.distribution}) from ${jmodsRelease.url} ...`);
let jmodsArchivePath = await this.downloadPackage(jmodsRelease);
if (process.platform === 'win32') {
jmodsArchivePath = renameWinArchive(jmodsArchivePath);
}
const extractedJmodsPath = await extractJdkFile(jmodsArchivePath, getDownloadArchiveExtension());
const jmodsDirectory = external_path_default().join(extractedJmodsPath, external_fs_default().readdirSync(extractedJmodsPath)[0]);
external_fs_default().cpSync(jmodsDirectory, external_path_default().join(javaHome, 'jmods'), { recursive: true });
}
async getAvailableVersions(imageType = this.includeJmods ? 'jdk' : this.packageType) {
const platform = this.getPlatformOption();
const arch = this.distributionArchitecture();
const imageType = this.packageType;
const versionRange = encodeURI('[1.0,100.0]'); // retrieve all available versions
const releaseType = this.stable ? 'ga' : 'ea';
if (isDebug()) {
Expand Down Expand Up @@ -132025,6 +132048,10 @@ var JavaDistribution;
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'.");
}
switch (distributionName) {
case JavaDistribution.JdkFile:
return new LocalDistribution(installerOptions, jdkFile);
Expand Down
1 change: 1 addition & 0 deletions docs/advanced-usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ steps:
with:
distribution: 'temurin'
java-version: '25'
java-package: 'jdk+jmods' # optional, includes JMOD files with JDK 24 and later
- run: java --version
```

Expand Down
9 changes: 9 additions & 0 deletions src/distributions/distribution-factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,15 @@ export function getJavaDistribution(
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'."
);
}

switch (distributionName) {
case JavaDistribution.JdkFile:
return new LocalDistribution(installerOptions, jdkFile);
Expand Down
Loading
Loading