diff --git a/.licenses/npm/@actions/cache.dep.yml b/.licenses/npm/@actions/cache.dep.yml
index 8bc7efe..d9a80f6 100644
Binary files a/.licenses/npm/@actions/cache.dep.yml and b/.licenses/npm/@actions/cache.dep.yml differ
diff --git a/.licenses/npm/@actions/core.dep.yml b/.licenses/npm/@actions/core.dep.yml
index 2e0762e..a2682b8 100644
Binary files a/.licenses/npm/@actions/core.dep.yml and b/.licenses/npm/@actions/core.dep.yml differ
diff --git a/README.md b/README.md
index 5508fa2..cdb0848 100644
--- a/README.md
+++ b/README.md
@@ -12,6 +12,7 @@ The `setup-java` action provides the following functionality for GitHub Actions
- Caching dependencies managed by Apache Maven
- Caching dependencies managed by Gradle
- Caching dependencies managed by sbt
+- [Maven Toolchains declaration](https://maven.apache.org/guides/mini/guide-using-toolchains.html) for specified JDK versions
This action allows you to work with Java and Scala projects.
@@ -22,7 +23,40 @@ This action allows you to work with Java and Scala projects.
## Usage
-Inputs `java-version` and `distribution` are mandatory. See [Supported distributions](#supported-distributions) section for a list of available options.
+ - `java-version`: _(required)_ The Java version to set up. Takes a whole or [semver](#supported-version-syntax) Java version.
+
+ - `distribution`: _(required)_ Java [distribution](#supported-distributions).
+
+ - `java-package`: The packaging variant of the choosen distribution. Possible values: `jdk`, `jre`, `jdk+fx`, `jre+fx`. Default value: `jdk`.
+
+ - `architecture`: The target architecture of the package. Possible values: `x86`, `x64`, `armv7`, `aarch64`, `ppc64le`. Default value: `x64`.
+
+ - `jdkFile`: 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.
+
+ - `check-latest`: Setting this option makes the action to check for the latest available version for the version spec.
+
+ - `cache`: Quick [setup caching](#caching-packages-dependencies) for the dependencies managed through one of the predifined package managers. It can be one of "maven", "gradle" or "sbt".
+
+ #### Maven options
+ The action has a bunch of inputs to generate maven's [settings.xml](https://maven.apache.org/settings.html) on the fly and pass the values to Apache Maven GPG Plugin as well as Apache Maven Toolchains. See [advanced usage](docs/advanced-usage.md) for more.
+
+ - `overwrite-settings`: By default action overwrites the settings.xml. In order to skip generation of file if it exists set this to `false`.
+
+ - `server-id`: ID of the distributionManagement repository in the pom.xml file. Default is `github`.
+
+ - `server-username`: Environment variable name for the username for authentication to the Apache Maven repository. Default is GITHUB_ACTOR.
+
+ - `server-password`: Environment variable name for password or token for authentication to the Apache Maven repository. Default is GITHUB_TOKEN.
+
+ - `settings-path`: Maven related setting to point to the diractory where the settings.xml file will be written. Default is ~/.m2.
+
+ - `gpg-private-key`: GPG private key to import. Default is empty string.'
+
+ - `gpg-passphrase`: description: 'Environment variable name for the GPG private key passphrase. Default is GPG_PASSPHRASE.
+
+ - `mvn-toolchain-id`: Name of Maven Toolchain ID if the default name of `${distribution}_${java-version}` is not wanted.
+
+ - `mvn-toolchain-vendor`: Name of Maven Toolchain Vendor if the default name of `${distribution}` is not wanted.
### Basic Configuration
@@ -75,7 +109,7 @@ Currently, the following distributions are supported:
### Caching packages dependencies
The action has a built-in functionality for caching and restoring dependencies. It uses [actions/cache](https://github.com/actions/cache) under hood for caching dependencies but requires less configuration settings. Supported package managers are gradle, maven and sbt. The format of the used cache key is `setup-java-${{ platform }}-${{ packageManager }}-${{ fileHash }}`, where the hash is based on the following files:
-- gradle: `**/*.gradle*`, `**/gradle-wrapper.properties`, `buildSrc/**/Versions.kt`, `buildSrc/**/Dependencies.kt`
+- gradle: `**/*.gradle*`, `**/gradle-wrapper.properties`, `buildSrc/**/Versions.kt`, `buildSrc/**/Dependencies.kt`, and `gradle/*.versions.toml`
- maven: `**/pom.xml`
- sbt: all sbt build definition files `**/*.sbt`, `**/project/build.properties`, `**/project/**.{scala,sbt}`
@@ -135,7 +169,7 @@ steps:
- uses: actions/checkout@v3
- uses: actions/setup-java@v3
with:
- distribution: 'adopt'
+ distribution: 'temurin'
java-version: '17'
check-latest: true
- run: java HelloWorldApp.java
@@ -175,7 +209,11 @@ All versions are added to the PATH. The last version will be used and available
15
```
+### Using Maven Toolchains
+In the example above multiple JDKs are installed for the same job. The result after the last JDK is installed is a Maven Toolchains declaration containing references to all three JDKs. The values for `id`, `version`, and `vendor` of the individual Toolchain entries are the given input values for `distribution` and `java-version` (`vendor` being the combination of `${distribution}_${java-version}`) by default.
+
### Advanced Configuration
+
- [Selecting a Java distribution](docs/advanced-usage.md#Selecting-a-Java-distribution)
- [Eclipse Temurin](docs/advanced-usage.md#Eclipse-Temurin)
- [Adopt](docs/advanced-usage.md#Adopt)
@@ -191,6 +229,7 @@ All versions are added to the PATH. The last version will be used and available
- [Publishing using Apache Maven](docs/advanced-usage.md#Publishing-using-Apache-Maven)
- [Publishing using Gradle](docs/advanced-usage.md#Publishing-using-Gradle)
- [Hosted Tool Cache](docs/advanced-usage.md#Hosted-Tool-Cache)
+- [Modifying Maven Toolchains](docs/advanced-usage.md#Modifying-Maven-Toolchains)
## License
diff --git a/__tests__/auth.test.ts b/__tests__/auth.test.ts
index 94ad7e1..c5d2ffc 100644
--- a/__tests__/auth.test.ts
+++ b/__tests__/auth.test.ts
@@ -5,9 +5,10 @@ import * as core from '@actions/core';
import os from 'os';
import * as auth from '../src/auth';
+import { M2_DIR, MVN_SETTINGS_FILE } from '../src/constants';
-const m2Dir = path.join(__dirname, auth.M2_DIR);
-const settingsFile = path.join(m2Dir, auth.SETTINGS_FILE);
+const m2Dir = path.join(__dirname, M2_DIR);
+const settingsFile = path.join(m2Dir, MVN_SETTINGS_FILE);
describe('auth tests', () => {
let spyOSHomedir: jest.SpyInstance;
@@ -38,7 +39,7 @@ describe('auth tests', () => {
const password = 'TOLKIEN';
const altHome = path.join(__dirname, 'runner', 'settings');
- const altSettingsFile = path.join(altHome, auth.SETTINGS_FILE);
+ const altSettingsFile = path.join(altHome, MVN_SETTINGS_FILE);
await io.rmRF(altHome); // ensure it doesn't already exist
await auth.createAuthenticationSettings(id, username, password, altHome, true);
diff --git a/__tests__/cache.test.ts b/__tests__/cache.test.ts
index 46fb994..987da4a 100644
--- a/__tests__/cache.test.ts
+++ b/__tests__/cache.test.ts
@@ -98,7 +98,7 @@ describe('dependency cache', () => {
await expect(restore('gradle')).rejects.toThrowError(
`No file in ${projectRoot(
workspace
- )} matched to [**/*.gradle*,**/gradle-wrapper.properties,buildSrc/**/Versions.kt,buildSrc/**/Dependencies.kt], make sure you have checked out the target repository`
+ )} matched to [**/*.gradle*,**/gradle-wrapper.properties,buildSrc/**/Versions.kt,buildSrc/**/Dependencies.kt,gradle/*.versions.toml], make sure you have checked out the target repository`
);
});
it('downloads cache based on build.gradle', async () => {
@@ -112,6 +112,15 @@ describe('dependency cache', () => {
it('downloads cache based on build.gradle.kts', async () => {
createFile(join(workspace, 'build.gradle.kts'));
+ await restore('gradle');
+ expect(spyCacheRestore).toBeCalled();
+ expect(spyWarning).not.toBeCalled();
+ expect(spyInfo).toBeCalledWith('gradle cache is not found');
+ });
+ it('downloads cache based on libs.versions.toml', async () => {
+ createDirectory(join(workspace, 'gradle'));
+ createFile(join(workspace, 'gradle', 'libs.versions.toml'));
+
await restore('gradle');
expect(spyCacheRestore).toBeCalled();
expect(spyWarning).not.toBeCalled();
diff --git a/__tests__/distributors/adopt-installer.test.ts b/__tests__/distributors/adopt-installer.test.ts
index ce862c2..a900f85 100644
--- a/__tests__/distributors/adopt-installer.test.ts
+++ b/__tests__/distributors/adopt-installer.test.ts
@@ -3,6 +3,8 @@ import { HttpClient } from '@actions/http-client';
import { AdoptDistribution, AdoptImplementation } from '../../src/distributions/adopt/installer';
import { JavaInstallerOptions } from '../../src/distributions/base-models';
+import os from 'os';
+
let manifestData = require('../data/adopt.json') as [];
describe('getAvailableVersions', () => {
@@ -128,6 +130,35 @@ describe('getAvailableVersions', () => {
expect(distribution.toolcacheFolderName).toBe(expected);
}
);
+
+ it.each([
+ ['amd64', 'x64'],
+ ['arm64', 'aarch64']
+ ])(
+ 'defaults to os.arch(): %s mapped to distro arch: %s',
+ async (osArch: string, distroArch: string) => {
+ jest.spyOn(os, 'arch').mockReturnValue(osArch);
+
+ const installerOptions: JavaInstallerOptions = {
+ version: '17',
+ architecture: '', // to get default value
+ packageType: 'jdk',
+ checkLatest: false
+ };
+
+ const expectedParameters = `os=mac&architecture=${distroArch}&image_type=jdk&release_type=ga&jvm_impl=hotspot&page_size=20&page=0`;
+
+ const distribution = new AdoptDistribution(installerOptions, AdoptImplementation.Hotspot);
+ const baseUrl = 'https://api.adoptopenjdk.net/v3/assets/version/%5B1.0,100.0%5D';
+ const expectedUrl = `${baseUrl}?project=jdk&vendor=adoptopenjdk&heap_size=normal&sort_method=DEFAULT&sort_order=DESC&${expectedParameters}`;
+ distribution['getPlatformOption'] = () => 'mac';
+
+ await distribution['getAvailableVersions']();
+
+ expect(spyHttpClient.mock.calls).toHaveLength(1);
+ expect(spyHttpClient.mock.calls[0][0]).toBe(expectedUrl);
+ }
+ );
});
describe('findPackageForDownload', () => {
diff --git a/__tests__/distributors/base-installer.test.ts b/__tests__/distributors/base-installer.test.ts
index 5ac3a82..44ec50b 100644
--- a/__tests__/distributors/base-installer.test.ts
+++ b/__tests__/distributors/base-installer.test.ts
@@ -12,6 +12,8 @@ import {
JavaInstallerResults
} from '../../src/distributions/base-models';
+import os from 'os';
+
class EmptyJavaBase extends JavaBase {
constructor(installerOptions: JavaInstallerOptions) {
super('Empty', installerOptions);
@@ -192,6 +194,8 @@ describe('setupJava', () => {
spyCoreSetOutput = jest.spyOn(core, 'setOutput');
spyCoreSetOutput.mockImplementation(() => undefined);
+
+ jest.spyOn(os, 'arch').mockReturnValue('x86');
});
afterEach(() => {
@@ -212,6 +216,10 @@ describe('setupJava', () => {
[
{ version: '11.0.8', architecture: 'x86', packageType: 'jdk', checkLatest: false },
{ version: installedJavaVersion, path: javaPath }
+ ],
+ [
+ { version: '11', architecture: '', packageType: 'jdk', checkLatest: false },
+ { version: installedJavaVersion, path: javaPath }
]
])('should find java locally for %s', (input, expected) => {
mockJavaBase = new EmptyJavaBase(input);
@@ -237,6 +245,10 @@ describe('setupJava', () => {
[
{ version: '11', architecture: 'x64', packageType: 'jre', checkLatest: false },
{ path: path.join('toolcache', 'Java_Empty_jre', '11.0.9', 'x64'), version: '11.0.9' }
+ ],
+ [
+ { version: '11', architecture: '', packageType: 'jre', checkLatest: false },
+ { path: path.join('toolcache', 'Java_Empty_jre', '11.0.9', 'x86'), version: '11.0.9' }
]
])('download java with configuration %s', async (input, expected) => {
mockJavaBase = new EmptyJavaBase(input);
@@ -245,7 +257,7 @@ describe('setupJava', () => {
expect(spyCoreAddPath).toHaveBeenCalled();
expect(spyCoreExportVariable).toHaveBeenCalled();
expect(spyCoreExportVariable).toHaveBeenCalledWith(
- `JAVA_HOME_${input.version}_${input.architecture.toLocaleUpperCase()}`,
+ `JAVA_HOME_${input.version}_${(input.architecture || 'x86').toLocaleUpperCase()}`,
expected.path
);
expect(spyCoreSetOutput).toHaveBeenCalled();
@@ -260,6 +272,10 @@ describe('setupJava', () => {
[
{ version: '11.0.9', architecture: 'x86', packageType: 'jdk', checkLatest: true },
{ version: '11.0.9', path: javaPathInstalled }
+ ],
+ [
+ { version: '11.0.9', architecture: '', packageType: 'jdk', checkLatest: true },
+ { version: '11.0.9', path: javaPathInstalled }
]
])('should check the latest java version for %s and resolve locally', async (input, expected) => {
mockJavaBase = new EmptyJavaBase(input);
@@ -283,6 +299,10 @@ describe('setupJava', () => {
[
{ version: '11.0.x', architecture: 'x86', packageType: 'jdk', checkLatest: true },
{ version: actualJavaVersion, path: javaPathInstalled }
+ ],
+ [
+ { version: '11', architecture: '', packageType: 'jdk', checkLatest: true },
+ { version: actualJavaVersion, path: javaPathInstalled }
]
])('should check the latest java version for %s and download', async (input, expected) => {
mockJavaBase = new EmptyJavaBase(input);
diff --git a/__tests__/distributors/corretto-installer.test.ts b/__tests__/distributors/corretto-installer.test.ts
index 3e3322f..eae259d 100644
--- a/__tests__/distributors/corretto-installer.test.ts
+++ b/__tests__/distributors/corretto-installer.test.ts
@@ -3,6 +3,8 @@ import { JavaInstallerOptions } from '../../src/distributions/base-models';
import { CorrettoDistribution } from '../../src/distributions/corretto/installer';
import * as util from '../../src/util';
+import os from 'os';
+import { isGeneratorFunction } from 'util/types';
const manifestData = require('../data/corretto.json') as [];
@@ -142,6 +144,33 @@ describe('getAvailableVersions', () => {
"Could not find satisfied version for SemVer '4'"
);
});
+
+ it.each([
+ ['arm64', 'aarch64'],
+ ['amd64', 'x64']
+ ])(
+ 'defaults to os.arch(): %s mapped to distro arch: %s',
+ async (osArch: string, distroArch: string) => {
+ jest.spyOn(os, 'arch').mockReturnValue(osArch);
+
+ const version = '17';
+ const installerOptions: JavaInstallerOptions = {
+ version,
+ architecture: '', // to get default value
+ packageType: 'jdk',
+ checkLatest: false
+ };
+
+ const distribution = new CorrettoDistribution(installerOptions);
+ mockPlatform(distribution, 'macos');
+
+ const expectedLink = `https://corretto.aws/downloads/resources/17.0.2.8.1/amazon-corretto-17.0.2.8.1-macosx-${distroArch}.tar.gz`;
+
+ const availableVersion = await distribution['findPackageForDownload'](version);
+ expect(availableVersion).not.toBeNull();
+ expect(availableVersion.url).toBe(expectedLink);
+ }
+ );
});
const mockPlatform = (distribution: CorrettoDistribution, platform: string) => {
diff --git a/__tests__/distributors/liberica-installer.test.ts b/__tests__/distributors/liberica-installer.test.ts
index 1044e7f..18135f2 100644
--- a/__tests__/distributors/liberica-installer.test.ts
+++ b/__tests__/distributors/liberica-installer.test.ts
@@ -1,6 +1,7 @@
import { LibericaDistributions } from '../../src/distributions/liberica/installer';
import { ArchitectureOptions, LibericaVersion } from '../../src/distributions/liberica/models';
import { HttpClient } from '@actions/http-client';
+import os from 'os';
const manifestData = require('../data/liberica.json') as LibericaVersion[];
@@ -61,6 +62,39 @@ describe('getAvailableVersions', () => {
expect(spyHttpClient.mock.calls[0][0]).toBe(buildUrl);
});
+ type DistroArch = {
+ bitness: string;
+ arch: string;
+ };
+ it.each([
+ ['amd64', { bitness: '64', arch: 'x86' }],
+ ['arm64', { bitness: '64', arch: 'arm' }]
+ ])(
+ 'defaults to os.arch(): %s mapped to distro arch: %s',
+ async (osArch: string, distroArch: DistroArch) => {
+ jest.spyOn(os, 'arch').mockReturnValue(osArch);
+
+ const distribution = new LibericaDistributions({
+ version: '17',
+ architecture: '', // to get default value
+ packageType: 'jdk',
+ checkLatest: false
+ });
+
+ const additionalParams =
+ '&installation-type=archive&fields=downloadUrl%2Cversion%2CfeatureVersion%2CinterimVersion%2C' +
+ 'updateVersion%2CbuildVersion';
+ distribution['getPlatformOption'] = () => 'macos';
+
+ const buildUrl = `https://api.bell-sw.com/v1/liberica/releases?os=macos&bundle-type=jdk&bitness=${distroArch.bitness}&arch=${distroArch.arch}&build-type=all${additionalParams}`;
+
+ await distribution['getAvailableVersions']();
+
+ expect(spyHttpClient.mock.calls).toHaveLength(1);
+ expect(spyHttpClient.mock.calls[0][0]).toBe(buildUrl);
+ }
+ );
+
it('load available versions', async () => {
const distribution = new LibericaDistributions({
version: '11',
diff --git a/__tests__/distributors/microsoft-installer.test.ts b/__tests__/distributors/microsoft-installer.test.ts
index 9be0f50..e35d8c8 100644
--- a/__tests__/distributors/microsoft-installer.test.ts
+++ b/__tests__/distributors/microsoft-installer.test.ts
@@ -1,7 +1,13 @@
import { MicrosoftDistributions } from '../../src/distributions/microsoft/installer';
+import os from 'os';
+import data from '../../src/distributions/microsoft/microsoft-openjdk-versions.json';
+import * as httpm from '@actions/http-client';
+import * as core from '@actions/core';
describe('findPackageForDownload', () => {
let distribution: MicrosoftDistributions;
+ let spyGetManifestFromRepo: jest.SpyInstance;
+ let spyDebug: jest.SpyInstance;
beforeEach(() => {
distribution = new MicrosoftDistributions({
@@ -10,12 +16,22 @@ describe('findPackageForDownload', () => {
packageType: 'jdk',
checkLatest: false
});
+
+ spyGetManifestFromRepo = jest.spyOn(httpm.HttpClient.prototype, 'getJson');
+ spyGetManifestFromRepo.mockReturnValue({
+ result: data,
+ statusCode: 200,
+ headers: {}
+ });
+
+ spyDebug = jest.spyOn(core, 'debug');
+ spyDebug.mockImplementation(() => {});
});
it.each([
[
'17.0.1',
- '17.0.1',
+ '17.0.1+12.1',
'https://aka.ms/download-jdk/microsoft-jdk-17.0.1.12.1-{{OS_TYPE}}-x64.{{ARCHIVE_TYPE}}'
],
[
@@ -25,12 +41,12 @@ describe('findPackageForDownload', () => {
],
[
'16.0.x',
- '16.0.2',
+ '16.0.2+7.1',
'https://aka.ms/download-jdk/microsoft-jdk-16.0.2.7.1-{{OS_TYPE}}-x64.{{ARCHIVE_TYPE}}'
],
[
'11.0.13',
- '11.0.13',
+ '11.0.13+8.1',
'https://aka.ms/download-jdk/microsoft-jdk-11.0.13.8.1-{{OS_TYPE}}-x64.{{ARCHIVE_TYPE}}'
],
[
@@ -61,38 +77,33 @@ describe('findPackageForDownload', () => {
expect(result.url).toBe(url);
});
+ it.each([
+ ['amd64', 'x64'],
+ ['arm64', 'aarch64']
+ ])(
+ 'defaults to os.arch(): %s mapped to distro arch: %s',
+ async (osArch: string, distroArch: string) => {
+ jest.spyOn(os, 'arch').mockReturnValue(osArch);
+ jest.spyOn(os, 'platform').mockReturnValue('linux');
+
+ const version = '17';
+ const distro = new MicrosoftDistributions({
+ version,
+ architecture: '', // to get default value
+ packageType: 'jdk',
+ checkLatest: false
+ });
+
+ const result = await distro['findPackageForDownload'](version);
+ const expectedUrl = `https://aka.ms/download-jdk/microsoft-jdk-17.0.3-linux-${distroArch}.tar.gz`;
+
+ expect(result.url).toBe(expectedUrl);
+ }
+ );
+
it('should throw an error', async () => {
await expect(distribution['findPackageForDownload']('8')).rejects.toThrow(
/Could not find satisfied version for SemVer */
);
});
});
-
-describe('getPlatformOption', () => {
- const distributions = new MicrosoftDistributions({
- architecture: 'x64',
- version: '11',
- packageType: 'jdk',
- checkLatest: false
- });
-
- it.each([
- ['linux', 'tar.gz', 'linux'],
- ['darwin', 'tar.gz', 'macos'],
- ['win32', 'zip', 'windows']
- ])('os version %s -> %s', (input, expectedArchive, expectedOs) => {
- const actual = distributions['getPlatformOption'](input as NodeJS.Platform);
-
- expect(actual.archive).toEqual(expectedArchive);
- expect(actual.os).toEqual(expectedOs);
- });
-
- it.each(['aix', 'android', 'freebsd', 'openbsd', 'netbsd', 'solaris', 'cygwin'])(
- 'not support os version %s',
- input => {
- expect(() => distributions['getPlatformOption'](input as NodeJS.Platform)).toThrow(
- /Platform '\w+' is not supported\. Supported platforms: .+/
- );
- }
- );
-});
diff --git a/__tests__/distributors/temurin-installer.test.ts b/__tests__/distributors/temurin-installer.test.ts
index c8904f8..554668b 100644
--- a/__tests__/distributors/temurin-installer.test.ts
+++ b/__tests__/distributors/temurin-installer.test.ts
@@ -1,5 +1,5 @@
import { HttpClient } from '@actions/http-client';
-
+import os from 'os';
import {
TemurinDistribution,
TemurinImplementation
@@ -109,6 +109,35 @@ describe('getAvailableVersions', () => {
expect(distribution.toolcacheFolderName).toBe(expected);
}
);
+
+ it.each([
+ ['amd64', 'x64'],
+ ['arm64', 'aarch64']
+ ])(
+ 'defaults to os.arch(): %s mapped to distro arch: %s',
+ async (osArch: string, distroArch: string) => {
+ jest.spyOn(os, 'arch').mockReturnValue(distroArch);
+
+ const installerOptions: JavaInstallerOptions = {
+ version: '17',
+ architecture: '',
+ packageType: 'jdk',
+ checkLatest: false
+ };
+
+ const expectedParameters = `os=mac&architecture=${distroArch}&image_type=jdk&release_type=ga&jvm_impl=hotspot&page_size=20&page=0`;
+
+ const distribution = new TemurinDistribution(installerOptions, TemurinImplementation.Hotspot);
+ const baseUrl = 'https://api.adoptium.net/v3/assets/version/%5B1.0,100.0%5D';
+ const expectedUrl = `${baseUrl}?project=jdk&vendor=adoptium&heap_size=normal&sort_method=DEFAULT&sort_order=DESC&${expectedParameters}`;
+ distribution['getPlatformOption'] = () => 'mac';
+
+ await distribution['getAvailableVersions']();
+
+ expect(spyHttpClient.mock.calls).toHaveLength(1);
+ expect(spyHttpClient.mock.calls[0][0]).toBe(expectedUrl);
+ }
+ );
});
describe('findPackageForDownload', () => {
diff --git a/__tests__/distributors/zulu-installer.test.ts b/__tests__/distributors/zulu-installer.test.ts
index 8f73192..4a43c78 100644
--- a/__tests__/distributors/zulu-installer.test.ts
+++ b/__tests__/distributors/zulu-installer.test.ts
@@ -3,6 +3,7 @@ import * as semver from 'semver';
import { ZuluDistribution } from '../../src/distributions/zulu/installer';
import { IZuluVersions } from '../../src/distributions/zulu/models';
import * as utils from '../../src/util';
+import os from 'os';
const manifestData = require('../data/zulu-releases-default.json') as [];
@@ -72,6 +73,34 @@ describe('getAvailableVersions', () => {
expect(spyHttpClient.mock.calls[0][0]).toBe(buildUrl);
});
+ type DistroArch = {
+ bitness: string;
+ arch: string;
+ };
+ it.each([
+ ['amd64', { bitness: '64', arch: 'x86' }],
+ ['arm64', { bitness: '64', arch: 'arm' }]
+ ])(
+ 'defaults to os.arch(): %s mapped to distro arch: %s',
+ async (osArch: string, distroArch: DistroArch) => {
+ jest.spyOn(os, 'arch').mockReturnValue(osArch);
+
+ const distribution = new ZuluDistribution({
+ version: '17',
+ architecture: '', // to get default value
+ packageType: 'jdk',
+ checkLatest: false
+ });
+ distribution['getPlatformOption'] = () => 'macos';
+ const buildUrl = `https://api.azul.com/zulu/download/community/v1.0/bundles/?os=macos&ext=tar.gz&bundle_type=jdk&javafx=false&arch=${distroArch.arch}&hw_bitness=${distroArch.bitness}&release_status=ga`;
+
+ await distribution['getAvailableVersions']();
+
+ expect(spyHttpClient.mock.calls).toHaveLength(1);
+ expect(spyHttpClient.mock.calls[0][0]).toBe(buildUrl);
+ }
+ );
+
it('load available versions', async () => {
const distribution = new ZuluDistribution({
version: '11',
diff --git a/__tests__/toolchains.test.ts b/__tests__/toolchains.test.ts
new file mode 100644
index 0000000..ff6fdab
--- /dev/null
+++ b/__tests__/toolchains.test.ts
@@ -0,0 +1,292 @@
+import * as fs from 'fs';
+import os from 'os';
+import * as path from 'path';
+import * as core from '@actions/core';
+import * as io from '@actions/io';
+import * as toolchains from '../src/toolchains';
+import { M2_DIR, MVN_TOOLCHAINS_FILE } from '../src/constants';
+
+const m2Dir = path.join(__dirname, M2_DIR);
+const toolchainsFile = path.join(m2Dir, MVN_TOOLCHAINS_FILE);
+
+describe('toolchains tests', () => {
+ let spyOSHomedir: jest.SpyInstance;
+ let spyInfo: jest.SpyInstance;
+
+ beforeEach(async () => {
+ await io.rmRF(m2Dir);
+ spyOSHomedir = jest.spyOn(os, 'homedir');
+ spyOSHomedir.mockReturnValue(__dirname);
+ spyInfo = jest.spyOn(core, 'info');
+ spyInfo.mockImplementation(() => null);
+ }, 300000);
+
+ afterAll(async () => {
+ try {
+ await io.rmRF(m2Dir);
+ } catch {
+ console.log('Failed to remove test directories');
+ }
+ jest.resetAllMocks();
+ jest.clearAllMocks();
+ jest.restoreAllMocks();
+ }, 100000);
+
+ it('creates toolchains.xml in alternate locations', async () => {
+ const jdkInfo = {
+ version: '17',
+ vendor: 'Eclipse Temurin',
+ id: 'temurin_17',
+ jdkHome: '/opt/hostedtoolcache/Java_Temurin-Hotspot_jdk/17.0.1-12/x64'
+ };
+
+ const altHome = path.join(__dirname, 'runner', 'toolchains');
+ const altToolchainsFile = path.join(altHome, MVN_TOOLCHAINS_FILE);
+ await io.rmRF(altHome); // ensure it doesn't already exist
+
+ await toolchains.createToolchainsSettings({
+ jdkInfo,
+ settingsDirectory: altHome,
+ overwriteSettings: true
+ });
+
+ expect(fs.existsSync(m2Dir)).toBe(false);
+ expect(fs.existsSync(toolchainsFile)).toBe(false);
+
+ expect(fs.existsSync(altHome)).toBe(true);
+ expect(fs.existsSync(altToolchainsFile)).toBe(true);
+ expect(fs.readFileSync(altToolchainsFile, 'utf-8')).toEqual(
+ toolchains.generateToolchainDefinition(
+ '',
+ jdkInfo.version,
+ jdkInfo.vendor,
+ jdkInfo.id,
+ jdkInfo.jdkHome
+ )
+ );
+
+ await io.rmRF(altHome);
+ }, 100000);
+
+ it('creates toolchains.xml with minimal configuration', async () => {
+ const jdkInfo = {
+ version: '17',
+ vendor: 'Eclipse Temurin',
+ id: 'temurin_17',
+ jdkHome: '/opt/hostedtoolcache/Java_Temurin-Hotspot_jdk/17.0.1-12/x64'
+ };
+
+ const result = `
+
+
+ jdk
+
+ 17
+ Eclipse Temurin
+ temurin_17
+
+
+ /opt/hostedtoolcache/Java_Temurin-Hotspot_jdk/17.0.1-12/x64
+
+
+`;
+
+ await toolchains.createToolchainsSettings({
+ jdkInfo,
+ settingsDirectory: m2Dir,
+ overwriteSettings: true
+ });
+
+ expect(fs.existsSync(m2Dir)).toBe(true);
+ expect(fs.existsSync(toolchainsFile)).toBe(true);
+ expect(fs.readFileSync(toolchainsFile, 'utf-8')).toEqual(
+ toolchains.generateToolchainDefinition(
+ '',
+ jdkInfo.version,
+ jdkInfo.vendor,
+ jdkInfo.id,
+ jdkInfo.jdkHome
+ )
+ );
+ expect(
+ toolchains.generateToolchainDefinition(
+ '',
+ jdkInfo.version,
+ jdkInfo.vendor,
+ jdkInfo.id,
+ jdkInfo.jdkHome
+ )
+ ).toEqual(result);
+ }, 100000);
+
+ it('reuses existing toolchains.xml files', async () => {
+ const jdkInfo = {
+ version: '17',
+ vendor: 'Eclipse Temurin',
+ id: 'temurin_17',
+ jdkHome: '/opt/hostedtoolcache/Java_Temurin-Hotspot_jdk/17.0.1-12/x64'
+ };
+
+ const originalFile = `
+
+ jdk
+
+ 1.6
+ Sun
+ sun_1.6
+
+
+ /opt/jdk/sun/1.6
+
+
+ `;
+ const result = `
+
+
+ jdk
+
+ 1.6
+ Sun
+ sun_1.6
+
+
+ /opt/jdk/sun/1.6
+
+
+
+ jdk
+
+ 17
+ Eclipse Temurin
+ temurin_17
+
+
+ /opt/hostedtoolcache/Java_Temurin-Hotspot_jdk/17.0.1-12/x64
+
+
+`;
+
+ fs.mkdirSync(m2Dir, { recursive: true });
+ fs.writeFileSync(toolchainsFile, originalFile);
+ expect(fs.existsSync(m2Dir)).toBe(true);
+ expect(fs.existsSync(toolchainsFile)).toBe(true);
+
+ await toolchains.createToolchainsSettings({
+ jdkInfo,
+ settingsDirectory: m2Dir,
+ overwriteSettings: true
+ });
+
+ expect(fs.existsSync(m2Dir)).toBe(true);
+ expect(fs.existsSync(toolchainsFile)).toBe(true);
+ expect(fs.readFileSync(toolchainsFile, 'utf-8')).toEqual(
+ toolchains.generateToolchainDefinition(
+ originalFile,
+ jdkInfo.version,
+ jdkInfo.vendor,
+ jdkInfo.id,
+ jdkInfo.jdkHome
+ )
+ );
+ expect(
+ toolchains.generateToolchainDefinition(
+ originalFile,
+ jdkInfo.version,
+ jdkInfo.vendor,
+ jdkInfo.id,
+ jdkInfo.jdkHome
+ )
+ ).toEqual(result);
+ }, 100000);
+
+ it('does not overwrite existing toolchains.xml files', async () => {
+ const jdkInfo = {
+ version: '17',
+ vendor: 'Eclipse Temurin',
+ id: 'temurin_17',
+ jdkHome: '/opt/hostedtoolcache/Java_Temurin-Hotspot_jdk/17.0.1-12/x64'
+ };
+
+ const originalFile = `
+
+ jdk
+
+ 1.6
+ Sun
+ sun_1.6
+
+
+ /opt/jdk/sun/1.6
+
+
+ `;
+
+ fs.mkdirSync(m2Dir, { recursive: true });
+ fs.writeFileSync(toolchainsFile, originalFile);
+ expect(fs.existsSync(m2Dir)).toBe(true);
+ expect(fs.existsSync(toolchainsFile)).toBe(true);
+
+ await toolchains.createToolchainsSettings({
+ jdkInfo,
+ settingsDirectory: m2Dir,
+ overwriteSettings: false
+ });
+
+ expect(fs.existsSync(m2Dir)).toBe(true);
+ expect(fs.existsSync(toolchainsFile)).toBe(true);
+ expect(fs.readFileSync(toolchainsFile, 'utf-8')).toEqual(originalFile);
+ }, 100000);
+
+ it('generates valid toolchains.xml with minimal configuration', () => {
+ const jdkInfo = {
+ version: 'JAVA_VERSION',
+ vendor: 'JAVA_VENDOR',
+ id: 'VENDOR_VERSION',
+ jdkHome: 'JAVA_HOME'
+ };
+
+ const expectedToolchains = `
+
+
+ jdk
+
+ ${jdkInfo.version}
+ ${jdkInfo.vendor}
+ ${jdkInfo.id}
+
+
+ ${jdkInfo.jdkHome}
+
+
+`;
+
+ expect(
+ toolchains.generateToolchainDefinition(
+ '',
+ jdkInfo.version,
+ jdkInfo.vendor,
+ jdkInfo.id,
+ jdkInfo.jdkHome
+ )
+ ).toEqual(expectedToolchains);
+ }, 100000);
+
+ it('creates toolchains.xml with correct id when none is supplied', async () => {
+ const version = '17';
+ const distributionName = 'temurin';
+ const id = 'temurin_17';
+ const jdkHome = '/opt/hostedtoolcache/Java_Temurin-Hotspot_jdk/17.0.1-12/x64';
+
+ await toolchains.configureToolchains(version, distributionName, jdkHome, undefined);
+
+ expect(fs.existsSync(m2Dir)).toBe(true);
+ expect(fs.existsSync(toolchainsFile)).toBe(true);
+ expect(fs.readFileSync(toolchainsFile, 'utf-8')).toEqual(
+ toolchains.generateToolchainDefinition('', version, distributionName, id, jdkHome)
+ );
+ }, 100000);
+});
diff --git a/action.yml b/action.yml
index 8a7214b..3ace2c6 100644
--- a/action.yml
+++ b/action.yml
@@ -14,9 +14,8 @@ inputs:
required: false
default: 'jdk'
architecture:
- description: 'The architecture of the package'
+ description: "The architecture of the package (defaults to the action runner's architecture)"
required: false
- default: 'x64'
jdkFile:
description: 'Path to where the compressed JDK is located'
required: false
@@ -59,6 +58,15 @@ inputs:
job-status:
description: 'Workaround to pass job status to post job step. This variable is not intended for manual setting'
default: ${{ job.status }}
+ token:
+ description: Used to pull java versions from setup-java. Since there is a default value, token is typically not supplied by the user.
+ default: ${{ github.token }}
+ mvn-toolchain-id:
+ description: 'Name of Maven Toolchain ID if the default name of "${distribution}_${java-version}" is not wanted. See examples of supported syntax in Advanced Usage file'
+ required: false
+ mvn-toolchain-vendor:
+ description: 'Name of Maven Toolchain Vendor if the default name of "${distribution}" is not wanted. See examples of supported syntax in Advanced Usage file'
+ required: false
outputs:
distribution:
description: 'Distribution of Java that has been installed'
diff --git a/dist/cleanup/index.js b/dist/cleanup/index.js
index 7e0210c..8d0a5bd 100644
--- a/dist/cleanup/index.js
+++ b/dist/cleanup/index.js
@@ -525,7 +525,13 @@ function resolvePaths(patterns) {
.replace(new RegExp(`\\${path.sep}`, 'g'), '/');
core.debug(`Matched: ${relativeFile}`);
// Paths are made relative so the tar entries are all relative to the root of the workspace.
- paths.push(`${relativeFile}`);
+ if (relativeFile === '') {
+ // path.relative returns empty string if workspace and file are equal
+ paths.push('.');
+ }
+ else {
+ paths.push(`${relativeFile}`);
+ }
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
@@ -683,6 +689,7 @@ const util = __importStar(__nccwpck_require__(3837));
const utils = __importStar(__nccwpck_require__(1518));
const constants_1 = __nccwpck_require__(8840);
const requestUtils_1 = __nccwpck_require__(3981);
+const abort_controller_1 = __nccwpck_require__(2557);
/**
* Pipes the body of a HTTP response to a stream
*
@@ -866,15 +873,24 @@ function downloadCacheStorageSDK(archiveLocation, archivePath, options) {
const fd = fs.openSync(archivePath, 'w');
try {
downloadProgress.startDisplayTimer();
+ const controller = new abort_controller_1.AbortController();
+ const abortSignal = controller.signal;
while (!downloadProgress.isDone()) {
const segmentStart = downloadProgress.segmentOffset + downloadProgress.segmentSize;
const segmentSize = Math.min(maxSegmentSize, contentLength - segmentStart);
downloadProgress.nextSegment(segmentSize);
- const result = yield client.downloadToBuffer(segmentStart, segmentSize, {
+ const result = yield promiseWithTimeout(options.segmentTimeoutInMs || 3600000, client.downloadToBuffer(segmentStart, segmentSize, {
+ abortSignal,
concurrency: options.downloadConcurrency,
onProgress: downloadProgress.onProgress()
- });
- fs.writeFileSync(fd, result);
+ }));
+ if (result === 'timeout') {
+ controller.abort();
+ throw new Error('Aborting cache download as the download time exceeded the timeout.');
+ }
+ else if (Buffer.isBuffer(result)) {
+ fs.writeFileSync(fd, result);
+ }
}
}
finally {
@@ -885,6 +901,16 @@ function downloadCacheStorageSDK(archiveLocation, archivePath, options) {
});
}
exports.downloadCacheStorageSDK = downloadCacheStorageSDK;
+const promiseWithTimeout = (timeoutMs, promise) => __awaiter(void 0, void 0, void 0, function* () {
+ let timeoutHandle;
+ const timeoutPromise = new Promise(resolve => {
+ timeoutHandle = setTimeout(() => resolve('timeout'), timeoutMs);
+ });
+ return Promise.race([promise, timeoutPromise]).then(result => {
+ clearTimeout(timeoutHandle);
+ return result;
+ });
+});
//# sourceMappingURL=downloadUtils.js.map
/***/ }),
@@ -1044,6 +1070,7 @@ const fs_1 = __nccwpck_require__(7147);
const path = __importStar(__nccwpck_require__(1017));
const utils = __importStar(__nccwpck_require__(1518));
const constants_1 = __nccwpck_require__(8840);
+const IS_WINDOWS = process.platform === 'win32';
function getTarPath(args, compressionMethod) {
return __awaiter(this, void 0, void 0, function* () {
switch (process.platform) {
@@ -1091,26 +1118,43 @@ function getWorkingDirectory() {
var _a;
return (_a = process.env['GITHUB_WORKSPACE']) !== null && _a !== void 0 ? _a : process.cwd();
}
+// Common function for extractTar and listTar to get the compression method
+function getCompressionProgram(compressionMethod) {
+ // -d: Decompress.
+ // unzstd is equivalent to 'zstd -d'
+ // --long=#: Enables long distance matching with # bits. Maximum is 30 (1GB) on 32-bit OS and 31 (2GB) on 64-bit.
+ // Using 30 here because we also support 32-bit self-hosted runners.
+ switch (compressionMethod) {
+ case constants_1.CompressionMethod.Zstd:
+ return [
+ '--use-compress-program',
+ IS_WINDOWS ? 'zstd -d --long=30' : 'unzstd --long=30'
+ ];
+ case constants_1.CompressionMethod.ZstdWithoutLong:
+ return ['--use-compress-program', IS_WINDOWS ? 'zstd -d' : 'unzstd'];
+ default:
+ return ['-z'];
+ }
+}
+function listTar(archivePath, compressionMethod) {
+ return __awaiter(this, void 0, void 0, function* () {
+ const args = [
+ ...getCompressionProgram(compressionMethod),
+ '-tf',
+ archivePath.replace(new RegExp(`\\${path.sep}`, 'g'), '/'),
+ '-P'
+ ];
+ yield execTar(args, compressionMethod);
+ });
+}
+exports.listTar = listTar;
function extractTar(archivePath, compressionMethod) {
return __awaiter(this, void 0, void 0, function* () {
// Create directory to extract tar into
const workingDirectory = getWorkingDirectory();
yield io.mkdirP(workingDirectory);
- // --d: Decompress.
- // --long=#: Enables long distance matching with # bits. Maximum is 30 (1GB) on 32-bit OS and 31 (2GB) on 64-bit.
- // Using 30 here because we also support 32-bit self-hosted runners.
- function getCompressionProgram() {
- switch (compressionMethod) {
- case constants_1.CompressionMethod.Zstd:
- return ['--use-compress-program', 'zstd -d --long=30'];
- case constants_1.CompressionMethod.ZstdWithoutLong:
- return ['--use-compress-program', 'zstd -d'];
- default:
- return ['-z'];
- }
- }
const args = [
- ...getCompressionProgram(),
+ ...getCompressionProgram(compressionMethod),
'-xf',
archivePath.replace(new RegExp(`\\${path.sep}`, 'g'), '/'),
'-P',
@@ -1129,15 +1173,19 @@ function createTar(archiveFolder, sourceDirectories, compressionMethod) {
fs_1.writeFileSync(path.join(archiveFolder, manifestFilename), sourceDirectories.join('\n'));
const workingDirectory = getWorkingDirectory();
// -T#: Compress using # working thread. If # is 0, attempt to detect and use the number of physical CPU cores.
+ // zstdmt is equivalent to 'zstd -T0'
// --long=#: Enables long distance matching with # bits. Maximum is 30 (1GB) on 32-bit OS and 31 (2GB) on 64-bit.
// Using 30 here because we also support 32-bit self-hosted runners.
// Long range mode is added to zstd in v1.3.2 release, so we will not use --long in older version of zstd.
function getCompressionProgram() {
switch (compressionMethod) {
case constants_1.CompressionMethod.Zstd:
- return ['--use-compress-program', 'zstd -T0 --long=30'];
+ return [
+ '--use-compress-program',
+ IS_WINDOWS ? 'zstd -T0 --long=30' : 'zstdmt --long=30'
+ ];
case constants_1.CompressionMethod.ZstdWithoutLong:
- return ['--use-compress-program', 'zstd -T0'];
+ return ['--use-compress-program', IS_WINDOWS ? 'zstd -T0' : 'zstdmt'];
default:
return ['-z'];
}
@@ -1159,32 +1207,6 @@ function createTar(archiveFolder, sourceDirectories, compressionMethod) {
});
}
exports.createTar = createTar;
-function listTar(archivePath, compressionMethod) {
- return __awaiter(this, void 0, void 0, function* () {
- // --d: Decompress.
- // --long=#: Enables long distance matching with # bits.
- // Maximum is 30 (1GB) on 32-bit OS and 31 (2GB) on 64-bit.
- // Using 30 here because we also support 32-bit self-hosted runners.
- function getCompressionProgram() {
- switch (compressionMethod) {
- case constants_1.CompressionMethod.Zstd:
- return ['--use-compress-program', 'zstd -d --long=30'];
- case constants_1.CompressionMethod.ZstdWithoutLong:
- return ['--use-compress-program', 'zstd -d'];
- default:
- return ['-z'];
- }
- }
- const args = [
- ...getCompressionProgram(),
- '-tf',
- archivePath.replace(new RegExp(`\\${path.sep}`, 'g'), '/'),
- '-P'
- ];
- yield execTar(args, compressionMethod);
- });
-}
-exports.listTar = listTar;
//# sourceMappingURL=tar.js.map
/***/ }),
@@ -1235,7 +1257,8 @@ function getDownloadOptions(copy) {
const result = {
useAzureSdk: true,
downloadConcurrency: 8,
- timeoutInMs: 30000
+ timeoutInMs: 30000,
+ segmentTimeoutInMs: 3600000
};
if (copy) {
if (typeof copy.useAzureSdk === 'boolean') {
@@ -1247,10 +1270,21 @@ function getDownloadOptions(copy) {
if (typeof copy.timeoutInMs === 'number') {
result.timeoutInMs = copy.timeoutInMs;
}
+ if (typeof copy.segmentTimeoutInMs === 'number') {
+ result.segmentTimeoutInMs = copy.segmentTimeoutInMs;
+ }
+ }
+ const segmentDownloadTimeoutMins = process.env['SEGMENT_DOWNLOAD_TIMEOUT_MINS'];
+ if (segmentDownloadTimeoutMins &&
+ !isNaN(Number(segmentDownloadTimeoutMins)) &&
+ isFinite(Number(segmentDownloadTimeoutMins))) {
+ result.segmentTimeoutInMs = Number(segmentDownloadTimeoutMins) * 60 * 1000;
}
core.debug(`Use Azure SDK: ${result.useAzureSdk}`);
core.debug(`Download concurrency: ${result.downloadConcurrency}`);
core.debug(`Request timeout (ms): ${result.timeoutInMs}`);
+ core.debug(`Cache segment download timeout mins env var: ${process.env['SEGMENT_DOWNLOAD_TIMEOUT_MINS']}`);
+ core.debug(`Segment download timeout (ms): ${result.segmentTimeoutInMs}`);
return result;
}
exports.getDownloadOptions = getDownloadOptions;
@@ -4831,7 +4865,6 @@ const file_command_1 = __nccwpck_require__(717);
const utils_1 = __nccwpck_require__(5278);
const os = __importStar(__nccwpck_require__(2037));
const path = __importStar(__nccwpck_require__(1017));
-const uuid_1 = __nccwpck_require__(8974);
const oidc_utils_1 = __nccwpck_require__(8041);
/**
* The code to exit an action
@@ -4861,20 +4894,9 @@ function exportVariable(name, val) {
process.env[name] = convertedVal;
const filePath = process.env['GITHUB_ENV'] || '';
if (filePath) {
- const delimiter = `ghadelimiter_${uuid_1.v4()}`;
- // These should realistically never happen, but just in case someone finds a way to exploit uuid generation let's not allow keys or values that contain the delimiter.
- if (name.includes(delimiter)) {
- throw new Error(`Unexpected input: name should not contain the delimiter "${delimiter}"`);
- }
- if (convertedVal.includes(delimiter)) {
- throw new Error(`Unexpected input: value should not contain the delimiter "${delimiter}"`);
- }
- const commandValue = `${name}<<${delimiter}${os.EOL}${convertedVal}${os.EOL}${delimiter}`;
- file_command_1.issueCommand('ENV', commandValue);
- }
- else {
- command_1.issueCommand('set-env', { name }, convertedVal);
+ return file_command_1.issueFileCommand('ENV', file_command_1.prepareKeyValueMessage(name, val));
}
+ command_1.issueCommand('set-env', { name }, convertedVal);
}
exports.exportVariable = exportVariable;
/**
@@ -4892,7 +4914,7 @@ exports.setSecret = setSecret;
function addPath(inputPath) {
const filePath = process.env['GITHUB_PATH'] || '';
if (filePath) {
- file_command_1.issueCommand('PATH', inputPath);
+ file_command_1.issueFileCommand('PATH', inputPath);
}
else {
command_1.issueCommand('add-path', {}, inputPath);
@@ -4932,7 +4954,10 @@ function getMultilineInput(name, options) {
const inputs = getInput(name, options)
.split('\n')
.filter(x => x !== '');
- return inputs;
+ if (options && options.trimWhitespace === false) {
+ return inputs;
+ }
+ return inputs.map(input => input.trim());
}
exports.getMultilineInput = getMultilineInput;
/**
@@ -4965,8 +4990,12 @@ exports.getBooleanInput = getBooleanInput;
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function setOutput(name, value) {
+ const filePath = process.env['GITHUB_OUTPUT'] || '';
+ if (filePath) {
+ return file_command_1.issueFileCommand('OUTPUT', file_command_1.prepareKeyValueMessage(name, value));
+ }
process.stdout.write(os.EOL);
- command_1.issueCommand('set-output', { name }, value);
+ command_1.issueCommand('set-output', { name }, utils_1.toCommandValue(value));
}
exports.setOutput = setOutput;
/**
@@ -5095,7 +5124,11 @@ exports.group = group;
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function saveState(name, value) {
- command_1.issueCommand('save-state', { name }, value);
+ const filePath = process.env['GITHUB_STATE'] || '';
+ if (filePath) {
+ return file_command_1.issueFileCommand('STATE', file_command_1.prepareKeyValueMessage(name, value));
+ }
+ command_1.issueCommand('save-state', { name }, utils_1.toCommandValue(value));
}
exports.saveState = saveState;
/**
@@ -5161,13 +5194,14 @@ var __importStar = (this && this.__importStar) || function (mod) {
return result;
};
Object.defineProperty(exports, "__esModule", ({ value: true }));
-exports.issueCommand = void 0;
+exports.prepareKeyValueMessage = exports.issueFileCommand = void 0;
// We use any as a valid input type
/* eslint-disable @typescript-eslint/no-explicit-any */
const fs = __importStar(__nccwpck_require__(7147));
const os = __importStar(__nccwpck_require__(2037));
+const uuid_1 = __nccwpck_require__(8974);
const utils_1 = __nccwpck_require__(5278);
-function issueCommand(command, message) {
+function issueFileCommand(command, message) {
const filePath = process.env[`GITHUB_${command}`];
if (!filePath) {
throw new Error(`Unable to find environment variable for file command ${command}`);
@@ -5179,7 +5213,22 @@ function issueCommand(command, message) {
encoding: 'utf8'
});
}
-exports.issueCommand = issueCommand;
+exports.issueFileCommand = issueFileCommand;
+function prepareKeyValueMessage(key, value) {
+ const delimiter = `ghadelimiter_${uuid_1.v4()}`;
+ const convertedValue = utils_1.toCommandValue(value);
+ // These should realistically never happen, but just in case someone finds a
+ // way to exploit uuid generation let's not allow keys or values that contain
+ // the delimiter.
+ if (key.includes(delimiter)) {
+ throw new Error(`Unexpected input: name should not contain the delimiter "${delimiter}"`);
+ }
+ if (convertedValue.includes(delimiter)) {
+ throw new Error(`Unexpected input: value should not contain the delimiter "${delimiter}"`);
+ }
+ return `${key}<<${delimiter}${os.EOL}${convertedValue}${os.EOL}${delimiter}`;
+}
+exports.prepareKeyValueMessage = prepareKeyValueMessage;
//# sourceMappingURL=file-command.js.map
/***/ }),
@@ -68175,7 +68224,8 @@ const supportedPackageManager = [
'**/*.gradle*',
'**/gradle-wrapper.properties',
'buildSrc/**/Versions.kt',
- 'buildSrc/**/Dependencies.kt'
+ 'buildSrc/**/Dependencies.kt',
+ 'gradle/*.versions.toml'
]
},
{
@@ -68406,7 +68456,7 @@ else {
"use strict";
Object.defineProperty(exports, "__esModule", ({ value: true }));
-exports.STATE_GPG_PRIVATE_KEY_FINGERPRINT = exports.INPUT_JOB_STATUS = exports.INPUT_CACHE = exports.INPUT_DEFAULT_GPG_PASSPHRASE = exports.INPUT_DEFAULT_GPG_PRIVATE_KEY = exports.INPUT_GPG_PASSPHRASE = exports.INPUT_GPG_PRIVATE_KEY = exports.INPUT_OVERWRITE_SETTINGS = exports.INPUT_SETTINGS_PATH = exports.INPUT_SERVER_PASSWORD = exports.INPUT_SERVER_USERNAME = exports.INPUT_SERVER_ID = exports.INPUT_CHECK_LATEST = exports.INPUT_JDK_FILE = exports.INPUT_DISTRIBUTION = exports.INPUT_JAVA_PACKAGE = exports.INPUT_ARCHITECTURE = exports.INPUT_JAVA_VERSION = exports.MACOS_JAVA_CONTENT_POSTFIX = void 0;
+exports.INPUT_MVN_TOOLCHAIN_VENDOR = exports.INPUT_MVN_TOOLCHAIN_ID = exports.MVN_TOOLCHAINS_FILE = exports.MVN_SETTINGS_FILE = exports.M2_DIR = exports.STATE_GPG_PRIVATE_KEY_FINGERPRINT = exports.INPUT_JOB_STATUS = exports.INPUT_CACHE = exports.INPUT_DEFAULT_GPG_PASSPHRASE = exports.INPUT_DEFAULT_GPG_PRIVATE_KEY = exports.INPUT_GPG_PASSPHRASE = exports.INPUT_GPG_PRIVATE_KEY = exports.INPUT_OVERWRITE_SETTINGS = exports.INPUT_SETTINGS_PATH = exports.INPUT_SERVER_PASSWORD = exports.INPUT_SERVER_USERNAME = exports.INPUT_SERVER_ID = exports.INPUT_CHECK_LATEST = exports.INPUT_JDK_FILE = exports.INPUT_DISTRIBUTION = exports.INPUT_JAVA_PACKAGE = exports.INPUT_ARCHITECTURE = exports.INPUT_JAVA_VERSION = exports.MACOS_JAVA_CONTENT_POSTFIX = void 0;
exports.MACOS_JAVA_CONTENT_POSTFIX = 'Contents/Home';
exports.INPUT_JAVA_VERSION = 'java-version';
exports.INPUT_ARCHITECTURE = 'architecture';
@@ -68426,6 +68476,11 @@ exports.INPUT_DEFAULT_GPG_PASSPHRASE = 'GPG_PASSPHRASE';
exports.INPUT_CACHE = 'cache';
exports.INPUT_JOB_STATUS = 'job-status';
exports.STATE_GPG_PRIVATE_KEY_FINGERPRINT = 'gpg-private-key-fingerprint';
+exports.M2_DIR = '.m2';
+exports.MVN_SETTINGS_FILE = 'settings.xml';
+exports.MVN_TOOLCHAINS_FILE = 'toolchains.xml';
+exports.INPUT_MVN_TOOLCHAIN_ID = 'mvn-toolchain-id';
+exports.INPUT_MVN_TOOLCHAIN_VENDOR = 'mvn-toolchain-vendor';
/***/ }),
diff --git a/dist/setup/index.js b/dist/setup/index.js
index d1efc13..3a9203b 100644
--- a/dist/setup/index.js
+++ b/dist/setup/index.js
@@ -525,7 +525,13 @@ function resolvePaths(patterns) {
.replace(new RegExp(`\\${path.sep}`, 'g'), '/');
core.debug(`Matched: ${relativeFile}`);
// Paths are made relative so the tar entries are all relative to the root of the workspace.
- paths.push(`${relativeFile}`);
+ if (relativeFile === '') {
+ // path.relative returns empty string if workspace and file are equal
+ paths.push('.');
+ }
+ else {
+ paths.push(`${relativeFile}`);
+ }
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
@@ -683,6 +689,7 @@ const util = __importStar(__nccwpck_require__(3837));
const utils = __importStar(__nccwpck_require__(1518));
const constants_1 = __nccwpck_require__(8840);
const requestUtils_1 = __nccwpck_require__(3981);
+const abort_controller_1 = __nccwpck_require__(2557);
/**
* Pipes the body of a HTTP response to a stream
*
@@ -866,15 +873,24 @@ function downloadCacheStorageSDK(archiveLocation, archivePath, options) {
const fd = fs.openSync(archivePath, 'w');
try {
downloadProgress.startDisplayTimer();
+ const controller = new abort_controller_1.AbortController();
+ const abortSignal = controller.signal;
while (!downloadProgress.isDone()) {
const segmentStart = downloadProgress.segmentOffset + downloadProgress.segmentSize;
const segmentSize = Math.min(maxSegmentSize, contentLength - segmentStart);
downloadProgress.nextSegment(segmentSize);
- const result = yield client.downloadToBuffer(segmentStart, segmentSize, {
+ const result = yield promiseWithTimeout(options.segmentTimeoutInMs || 3600000, client.downloadToBuffer(segmentStart, segmentSize, {
+ abortSignal,
concurrency: options.downloadConcurrency,
onProgress: downloadProgress.onProgress()
- });
- fs.writeFileSync(fd, result);
+ }));
+ if (result === 'timeout') {
+ controller.abort();
+ throw new Error('Aborting cache download as the download time exceeded the timeout.');
+ }
+ else if (Buffer.isBuffer(result)) {
+ fs.writeFileSync(fd, result);
+ }
}
}
finally {
@@ -885,6 +901,16 @@ function downloadCacheStorageSDK(archiveLocation, archivePath, options) {
});
}
exports.downloadCacheStorageSDK = downloadCacheStorageSDK;
+const promiseWithTimeout = (timeoutMs, promise) => __awaiter(void 0, void 0, void 0, function* () {
+ let timeoutHandle;
+ const timeoutPromise = new Promise(resolve => {
+ timeoutHandle = setTimeout(() => resolve('timeout'), timeoutMs);
+ });
+ return Promise.race([promise, timeoutPromise]).then(result => {
+ clearTimeout(timeoutHandle);
+ return result;
+ });
+});
//# sourceMappingURL=downloadUtils.js.map
/***/ }),
@@ -1044,6 +1070,7 @@ const fs_1 = __nccwpck_require__(7147);
const path = __importStar(__nccwpck_require__(1017));
const utils = __importStar(__nccwpck_require__(1518));
const constants_1 = __nccwpck_require__(8840);
+const IS_WINDOWS = process.platform === 'win32';
function getTarPath(args, compressionMethod) {
return __awaiter(this, void 0, void 0, function* () {
switch (process.platform) {
@@ -1091,26 +1118,43 @@ function getWorkingDirectory() {
var _a;
return (_a = process.env['GITHUB_WORKSPACE']) !== null && _a !== void 0 ? _a : process.cwd();
}
+// Common function for extractTar and listTar to get the compression method
+function getCompressionProgram(compressionMethod) {
+ // -d: Decompress.
+ // unzstd is equivalent to 'zstd -d'
+ // --long=#: Enables long distance matching with # bits. Maximum is 30 (1GB) on 32-bit OS and 31 (2GB) on 64-bit.
+ // Using 30 here because we also support 32-bit self-hosted runners.
+ switch (compressionMethod) {
+ case constants_1.CompressionMethod.Zstd:
+ return [
+ '--use-compress-program',
+ IS_WINDOWS ? 'zstd -d --long=30' : 'unzstd --long=30'
+ ];
+ case constants_1.CompressionMethod.ZstdWithoutLong:
+ return ['--use-compress-program', IS_WINDOWS ? 'zstd -d' : 'unzstd'];
+ default:
+ return ['-z'];
+ }
+}
+function listTar(archivePath, compressionMethod) {
+ return __awaiter(this, void 0, void 0, function* () {
+ const args = [
+ ...getCompressionProgram(compressionMethod),
+ '-tf',
+ archivePath.replace(new RegExp(`\\${path.sep}`, 'g'), '/'),
+ '-P'
+ ];
+ yield execTar(args, compressionMethod);
+ });
+}
+exports.listTar = listTar;
function extractTar(archivePath, compressionMethod) {
return __awaiter(this, void 0, void 0, function* () {
// Create directory to extract tar into
const workingDirectory = getWorkingDirectory();
yield io.mkdirP(workingDirectory);
- // --d: Decompress.
- // --long=#: Enables long distance matching with # bits. Maximum is 30 (1GB) on 32-bit OS and 31 (2GB) on 64-bit.
- // Using 30 here because we also support 32-bit self-hosted runners.
- function getCompressionProgram() {
- switch (compressionMethod) {
- case constants_1.CompressionMethod.Zstd:
- return ['--use-compress-program', 'zstd -d --long=30'];
- case constants_1.CompressionMethod.ZstdWithoutLong:
- return ['--use-compress-program', 'zstd -d'];
- default:
- return ['-z'];
- }
- }
const args = [
- ...getCompressionProgram(),
+ ...getCompressionProgram(compressionMethod),
'-xf',
archivePath.replace(new RegExp(`\\${path.sep}`, 'g'), '/'),
'-P',
@@ -1129,15 +1173,19 @@ function createTar(archiveFolder, sourceDirectories, compressionMethod) {
fs_1.writeFileSync(path.join(archiveFolder, manifestFilename), sourceDirectories.join('\n'));
const workingDirectory = getWorkingDirectory();
// -T#: Compress using # working thread. If # is 0, attempt to detect and use the number of physical CPU cores.
+ // zstdmt is equivalent to 'zstd -T0'
// --long=#: Enables long distance matching with # bits. Maximum is 30 (1GB) on 32-bit OS and 31 (2GB) on 64-bit.
// Using 30 here because we also support 32-bit self-hosted runners.
// Long range mode is added to zstd in v1.3.2 release, so we will not use --long in older version of zstd.
function getCompressionProgram() {
switch (compressionMethod) {
case constants_1.CompressionMethod.Zstd:
- return ['--use-compress-program', 'zstd -T0 --long=30'];
+ return [
+ '--use-compress-program',
+ IS_WINDOWS ? 'zstd -T0 --long=30' : 'zstdmt --long=30'
+ ];
case constants_1.CompressionMethod.ZstdWithoutLong:
- return ['--use-compress-program', 'zstd -T0'];
+ return ['--use-compress-program', IS_WINDOWS ? 'zstd -T0' : 'zstdmt'];
default:
return ['-z'];
}
@@ -1159,32 +1207,6 @@ function createTar(archiveFolder, sourceDirectories, compressionMethod) {
});
}
exports.createTar = createTar;
-function listTar(archivePath, compressionMethod) {
- return __awaiter(this, void 0, void 0, function* () {
- // --d: Decompress.
- // --long=#: Enables long distance matching with # bits.
- // Maximum is 30 (1GB) on 32-bit OS and 31 (2GB) on 64-bit.
- // Using 30 here because we also support 32-bit self-hosted runners.
- function getCompressionProgram() {
- switch (compressionMethod) {
- case constants_1.CompressionMethod.Zstd:
- return ['--use-compress-program', 'zstd -d --long=30'];
- case constants_1.CompressionMethod.ZstdWithoutLong:
- return ['--use-compress-program', 'zstd -d'];
- default:
- return ['-z'];
- }
- }
- const args = [
- ...getCompressionProgram(),
- '-tf',
- archivePath.replace(new RegExp(`\\${path.sep}`, 'g'), '/'),
- '-P'
- ];
- yield execTar(args, compressionMethod);
- });
-}
-exports.listTar = listTar;
//# sourceMappingURL=tar.js.map
/***/ }),
@@ -1235,7 +1257,8 @@ function getDownloadOptions(copy) {
const result = {
useAzureSdk: true,
downloadConcurrency: 8,
- timeoutInMs: 30000
+ timeoutInMs: 30000,
+ segmentTimeoutInMs: 3600000
};
if (copy) {
if (typeof copy.useAzureSdk === 'boolean') {
@@ -1247,10 +1270,21 @@ function getDownloadOptions(copy) {
if (typeof copy.timeoutInMs === 'number') {
result.timeoutInMs = copy.timeoutInMs;
}
+ if (typeof copy.segmentTimeoutInMs === 'number') {
+ result.segmentTimeoutInMs = copy.segmentTimeoutInMs;
+ }
+ }
+ const segmentDownloadTimeoutMins = process.env['SEGMENT_DOWNLOAD_TIMEOUT_MINS'];
+ if (segmentDownloadTimeoutMins &&
+ !isNaN(Number(segmentDownloadTimeoutMins)) &&
+ isFinite(Number(segmentDownloadTimeoutMins))) {
+ result.segmentTimeoutInMs = Number(segmentDownloadTimeoutMins) * 60 * 1000;
}
core.debug(`Use Azure SDK: ${result.useAzureSdk}`);
core.debug(`Download concurrency: ${result.downloadConcurrency}`);
core.debug(`Request timeout (ms): ${result.timeoutInMs}`);
+ core.debug(`Cache segment download timeout mins env var: ${process.env['SEGMENT_DOWNLOAD_TIMEOUT_MINS']}`);
+ core.debug(`Segment download timeout (ms): ${result.segmentTimeoutInMs}`);
return result;
}
exports.getDownloadOptions = getDownloadOptions;
@@ -4831,7 +4865,6 @@ const file_command_1 = __nccwpck_require__(717);
const utils_1 = __nccwpck_require__(5278);
const os = __importStar(__nccwpck_require__(2037));
const path = __importStar(__nccwpck_require__(1017));
-const uuid_1 = __nccwpck_require__(8974);
const oidc_utils_1 = __nccwpck_require__(8041);
/**
* The code to exit an action
@@ -4861,20 +4894,9 @@ function exportVariable(name, val) {
process.env[name] = convertedVal;
const filePath = process.env['GITHUB_ENV'] || '';
if (filePath) {
- const delimiter = `ghadelimiter_${uuid_1.v4()}`;
- // These should realistically never happen, but just in case someone finds a way to exploit uuid generation let's not allow keys or values that contain the delimiter.
- if (name.includes(delimiter)) {
- throw new Error(`Unexpected input: name should not contain the delimiter "${delimiter}"`);
- }
- if (convertedVal.includes(delimiter)) {
- throw new Error(`Unexpected input: value should not contain the delimiter "${delimiter}"`);
- }
- const commandValue = `${name}<<${delimiter}${os.EOL}${convertedVal}${os.EOL}${delimiter}`;
- file_command_1.issueCommand('ENV', commandValue);
- }
- else {
- command_1.issueCommand('set-env', { name }, convertedVal);
+ return file_command_1.issueFileCommand('ENV', file_command_1.prepareKeyValueMessage(name, val));
}
+ command_1.issueCommand('set-env', { name }, convertedVal);
}
exports.exportVariable = exportVariable;
/**
@@ -4892,7 +4914,7 @@ exports.setSecret = setSecret;
function addPath(inputPath) {
const filePath = process.env['GITHUB_PATH'] || '';
if (filePath) {
- file_command_1.issueCommand('PATH', inputPath);
+ file_command_1.issueFileCommand('PATH', inputPath);
}
else {
command_1.issueCommand('add-path', {}, inputPath);
@@ -4932,7 +4954,10 @@ function getMultilineInput(name, options) {
const inputs = getInput(name, options)
.split('\n')
.filter(x => x !== '');
- return inputs;
+ if (options && options.trimWhitespace === false) {
+ return inputs;
+ }
+ return inputs.map(input => input.trim());
}
exports.getMultilineInput = getMultilineInput;
/**
@@ -4965,8 +4990,12 @@ exports.getBooleanInput = getBooleanInput;
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function setOutput(name, value) {
+ const filePath = process.env['GITHUB_OUTPUT'] || '';
+ if (filePath) {
+ return file_command_1.issueFileCommand('OUTPUT', file_command_1.prepareKeyValueMessage(name, value));
+ }
process.stdout.write(os.EOL);
- command_1.issueCommand('set-output', { name }, value);
+ command_1.issueCommand('set-output', { name }, utils_1.toCommandValue(value));
}
exports.setOutput = setOutput;
/**
@@ -5095,7 +5124,11 @@ exports.group = group;
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function saveState(name, value) {
- command_1.issueCommand('save-state', { name }, value);
+ const filePath = process.env['GITHUB_STATE'] || '';
+ if (filePath) {
+ return file_command_1.issueFileCommand('STATE', file_command_1.prepareKeyValueMessage(name, value));
+ }
+ command_1.issueCommand('save-state', { name }, utils_1.toCommandValue(value));
}
exports.saveState = saveState;
/**
@@ -5161,13 +5194,14 @@ var __importStar = (this && this.__importStar) || function (mod) {
return result;
};
Object.defineProperty(exports, "__esModule", ({ value: true }));
-exports.issueCommand = void 0;
+exports.prepareKeyValueMessage = exports.issueFileCommand = void 0;
// We use any as a valid input type
/* eslint-disable @typescript-eslint/no-explicit-any */
const fs = __importStar(__nccwpck_require__(7147));
const os = __importStar(__nccwpck_require__(2037));
+const uuid_1 = __nccwpck_require__(8974);
const utils_1 = __nccwpck_require__(5278);
-function issueCommand(command, message) {
+function issueFileCommand(command, message) {
const filePath = process.env[`GITHUB_${command}`];
if (!filePath) {
throw new Error(`Unable to find environment variable for file command ${command}`);
@@ -5179,7 +5213,22 @@ function issueCommand(command, message) {
encoding: 'utf8'
});
}
-exports.issueCommand = issueCommand;
+exports.issueFileCommand = issueFileCommand;
+function prepareKeyValueMessage(key, value) {
+ const delimiter = `ghadelimiter_${uuid_1.v4()}`;
+ const convertedValue = utils_1.toCommandValue(value);
+ // These should realistically never happen, but just in case someone finds a
+ // way to exploit uuid generation let's not allow keys or values that contain
+ // the delimiter.
+ if (key.includes(delimiter)) {
+ throw new Error(`Unexpected input: name should not contain the delimiter "${delimiter}"`);
+ }
+ if (convertedValue.includes(delimiter)) {
+ throw new Error(`Unexpected input: value should not contain the delimiter "${delimiter}"`);
+ }
+ return `${key}<<${delimiter}${os.EOL}${convertedValue}${os.EOL}${delimiter}`;
+}
+exports.prepareKeyValueMessage = prepareKeyValueMessage;
//# sourceMappingURL=file-command.js.map
/***/ }),
@@ -103216,7 +103265,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
});
};
Object.defineProperty(exports, "__esModule", ({ value: true }));
-exports.generate = exports.createAuthenticationSettings = exports.configureAuthentication = exports.SETTINGS_FILE = exports.M2_DIR = void 0;
+exports.generate = exports.createAuthenticationSettings = exports.configureAuthentication = void 0;
const path = __importStar(__nccwpck_require__(1017));
const core = __importStar(__nccwpck_require__(2186));
const io = __importStar(__nccwpck_require__(7436));
@@ -103226,14 +103275,12 @@ const xmlbuilder2_1 = __nccwpck_require__(151);
const constants = __importStar(__nccwpck_require__(9042));
const gpg = __importStar(__nccwpck_require__(3759));
const util_1 = __nccwpck_require__(2629);
-exports.M2_DIR = '.m2';
-exports.SETTINGS_FILE = 'settings.xml';
function configureAuthentication() {
return __awaiter(this, void 0, void 0, function* () {
const id = core.getInput(constants.INPUT_SERVER_ID);
const username = core.getInput(constants.INPUT_SERVER_USERNAME);
const password = core.getInput(constants.INPUT_SERVER_PASSWORD);
- const settingsDirectory = core.getInput(constants.INPUT_SETTINGS_PATH) || path.join(os.homedir(), exports.M2_DIR);
+ const settingsDirectory = core.getInput(constants.INPUT_SETTINGS_PATH) || path.join(os.homedir(), constants.M2_DIR);
const overwriteSettings = util_1.getBooleanInput(constants.INPUT_OVERWRITE_SETTINGS, true);
const gpgPrivateKey = core.getInput(constants.INPUT_GPG_PRIVATE_KEY) || constants.INPUT_DEFAULT_GPG_PRIVATE_KEY;
const gpgPassphrase = core.getInput(constants.INPUT_GPG_PASSPHRASE) ||
@@ -103252,7 +103299,7 @@ function configureAuthentication() {
exports.configureAuthentication = configureAuthentication;
function createAuthenticationSettings(id, username, password, settingsDirectory, overwriteSettings, gpgPassphrase = undefined) {
return __awaiter(this, void 0, void 0, function* () {
- core.info(`Creating ${exports.SETTINGS_FILE} with server-id: ${id}`);
+ core.info(`Creating ${constants.MVN_SETTINGS_FILE} with server-id: ${id}`);
// when an alternate m2 location is specified use only that location (no .m2 directory)
// otherwise use the home/.m2/ path
yield io.mkdirP(settingsDirectory);
@@ -103294,7 +103341,7 @@ function generate(id, username, password, gpgPassphrase) {
exports.generate = generate;
function write(directory, settings, overwriteSettings) {
return __awaiter(this, void 0, void 0, function* () {
- const location = path.join(directory, exports.SETTINGS_FILE);
+ const location = path.join(directory, constants.MVN_SETTINGS_FILE);
const settingsExists = fs.existsSync(location);
if (settingsExists && overwriteSettings) {
core.info(`Overwriting existing file ${location}`);
@@ -103380,7 +103427,8 @@ const supportedPackageManager = [
'**/*.gradle*',
'**/gradle-wrapper.properties',
'buildSrc/**/Versions.kt',
- 'buildSrc/**/Dependencies.kt'
+ 'buildSrc/**/Dependencies.kt',
+ 'gradle/*.versions.toml'
]
},
{
@@ -103510,7 +103558,7 @@ function isProbablyGradleDaemonProblem(packageManager, error) {
"use strict";
Object.defineProperty(exports, "__esModule", ({ value: true }));
-exports.STATE_GPG_PRIVATE_KEY_FINGERPRINT = exports.INPUT_JOB_STATUS = exports.INPUT_CACHE = exports.INPUT_DEFAULT_GPG_PASSPHRASE = exports.INPUT_DEFAULT_GPG_PRIVATE_KEY = exports.INPUT_GPG_PASSPHRASE = exports.INPUT_GPG_PRIVATE_KEY = exports.INPUT_OVERWRITE_SETTINGS = exports.INPUT_SETTINGS_PATH = exports.INPUT_SERVER_PASSWORD = exports.INPUT_SERVER_USERNAME = exports.INPUT_SERVER_ID = exports.INPUT_CHECK_LATEST = exports.INPUT_JDK_FILE = exports.INPUT_DISTRIBUTION = exports.INPUT_JAVA_PACKAGE = exports.INPUT_ARCHITECTURE = exports.INPUT_JAVA_VERSION = exports.MACOS_JAVA_CONTENT_POSTFIX = void 0;
+exports.INPUT_MVN_TOOLCHAIN_VENDOR = exports.INPUT_MVN_TOOLCHAIN_ID = exports.MVN_TOOLCHAINS_FILE = exports.MVN_SETTINGS_FILE = exports.M2_DIR = exports.STATE_GPG_PRIVATE_KEY_FINGERPRINT = exports.INPUT_JOB_STATUS = exports.INPUT_CACHE = exports.INPUT_DEFAULT_GPG_PASSPHRASE = exports.INPUT_DEFAULT_GPG_PRIVATE_KEY = exports.INPUT_GPG_PASSPHRASE = exports.INPUT_GPG_PRIVATE_KEY = exports.INPUT_OVERWRITE_SETTINGS = exports.INPUT_SETTINGS_PATH = exports.INPUT_SERVER_PASSWORD = exports.INPUT_SERVER_USERNAME = exports.INPUT_SERVER_ID = exports.INPUT_CHECK_LATEST = exports.INPUT_JDK_FILE = exports.INPUT_DISTRIBUTION = exports.INPUT_JAVA_PACKAGE = exports.INPUT_ARCHITECTURE = exports.INPUT_JAVA_VERSION = exports.MACOS_JAVA_CONTENT_POSTFIX = void 0;
exports.MACOS_JAVA_CONTENT_POSTFIX = 'Contents/Home';
exports.INPUT_JAVA_VERSION = 'java-version';
exports.INPUT_ARCHITECTURE = 'architecture';
@@ -103530,6 +103578,11 @@ exports.INPUT_DEFAULT_GPG_PASSPHRASE = 'GPG_PASSPHRASE';
exports.INPUT_CACHE = 'cache';
exports.INPUT_JOB_STATUS = 'job-status';
exports.STATE_GPG_PRIVATE_KEY_FINGERPRINT = 'gpg-private-key-fingerprint';
+exports.M2_DIR = '.m2';
+exports.MVN_SETTINGS_FILE = 'settings.xml';
+exports.MVN_TOOLCHAINS_FILE = 'toolchains.xml';
+exports.INPUT_MVN_TOOLCHAIN_ID = 'mvn-toolchain-id';
+exports.INPUT_MVN_TOOLCHAIN_VENDOR = 'mvn-toolchain-vendor';
/***/ }),
@@ -103643,7 +103696,7 @@ class AdoptDistribution extends base_installer_1.JavaBase {
getAvailableVersions() {
return __awaiter(this, void 0, void 0, function* () {
const platform = this.getPlatformOption();
- const arch = this.architecture;
+ 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';
@@ -103754,6 +103807,7 @@ const path_1 = __importDefault(__nccwpck_require__(1017));
const httpm = __importStar(__nccwpck_require__(9925));
const util_1 = __nccwpck_require__(2629);
const constants_1 = __nccwpck_require__(9042);
+const os_1 = __importDefault(__nccwpck_require__(2037));
class JavaBase {
constructor(distribution, installerOptions) {
this.distribution = distribution;
@@ -103762,7 +103816,7 @@ class JavaBase {
maxRetries: 3
});
({ version: this.version, stable: this.stable } = this.normalizeVersion(installerOptions.version));
- this.architecture = installerOptions.architecture;
+ this.architecture = installerOptions.architecture || os_1.default.arch();
this.packageType = installerOptions.packageType;
this.checkLatest = installerOptions.checkLatest;
}
@@ -103873,6 +103927,24 @@ class JavaBase {
core.setOutput('version', version);
core.exportVariable(`JAVA_HOME_${majorVersion}_${this.architecture.toUpperCase()}`, toolPath);
}
+ distributionArchitecture() {
+ // 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;
+ }
+ }
}
exports.JavaBase = JavaBase;
@@ -103972,7 +104044,7 @@ class CorrettoDistribution extends base_installer_1.JavaBase {
var _a, _b;
return __awaiter(this, void 0, void 0, function* () {
const platform = this.getPlatformOption();
- const arch = this.architecture;
+ const arch = this.distributionArchitecture();
const imageType = this.packageType;
if (core.isDebug()) {
console.time('corretto-retrieve-available-versions');
@@ -104151,7 +104223,7 @@ const tc = __importStar(__nccwpck_require__(7784));
const fs_1 = __importDefault(__nccwpck_require__(7147));
const path_1 = __importDefault(__nccwpck_require__(1017));
const supportedPlatform = `'linux', 'linux-musl', 'macos', 'solaris', 'windows'`;
-const supportedArchitecture = `'x86', 'x64', 'armv7', 'aarch64', 'ppc64le'`;
+const supportedArchitectures = `'x86', 'x64', 'armv7', 'aarch64', 'ppc64le'`;
class LibericaDistributions extends base_installer_1.JavaBase {
constructor(installerOptions) {
super('Liberica', installerOptions);
@@ -104223,7 +104295,8 @@ class LibericaDistributions extends base_installer_1.JavaBase {
return bundleType;
}
getArchitectureOptions() {
- switch (this.architecture) {
+ const arch = this.distributionArchitecture();
+ switch (arch) {
case 'x86':
return { bitness: '32', arch: 'x86' };
case 'x64':
@@ -104235,7 +104308,7 @@ class LibericaDistributions extends base_installer_1.JavaBase {
case 'ppc64le':
return { bitness: '64', arch: 'ppc' };
default:
- throw new Error(`Architecture '${this.architecture}' is not supported. Supported architectures: ${supportedArchitecture}`);
+ throw new Error(`Architecture '${this.architecture}' is not supported. Supported architectures: ${supportedArchitectures}`);
}
}
getPlatformOption(platform = process.platform) {
@@ -104261,6 +104334,15 @@ class LibericaDistributions extends base_installer_1.JavaBase {
}
return mainVersion;
}
+ distributionArchitecture() {
+ let arch = super.distributionArchitecture();
+ switch (arch) {
+ case 'arm':
+ return 'armv7';
+ default:
+ return arch;
+ }
+ }
}
exports.LibericaDistributions = LibericaDistributions;
@@ -104409,7 +104491,6 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.MicrosoftDistributions = void 0;
const base_installer_1 = __nccwpck_require__(9741);
-const semver_1 = __importDefault(__nccwpck_require__(1383));
const util_1 = __nccwpck_require__(2629);
const core = __importStar(__nccwpck_require__(2186));
const tc = __importStar(__nccwpck_require__(7784));
@@ -104434,7 +104515,8 @@ class MicrosoftDistributions extends base_installer_1.JavaBase {
}
findPackageForDownload(range) {
return __awaiter(this, void 0, void 0, function* () {
- if (this.architecture !== 'x64' && this.architecture !== 'aarch64') {
+ const arch = this.distributionArchitecture();
+ if (arch !== 'x64' && arch !== 'aarch64') {
throw new Error(`Unsupported architecture: ${this.architecture}`);
}
if (!this.stable) {
@@ -104443,70 +104525,51 @@ class MicrosoftDistributions extends base_installer_1.JavaBase {
if (this.packageType !== 'jdk') {
throw new Error('Microsoft Build of OpenJDK provides only the `jdk` package type');
}
- const availableVersionsRaw = yield this.getAvailableVersions();
- const opts = this.getPlatformOption();
- const availableVersions = availableVersionsRaw.map(item => ({
- url: `https://aka.ms/download-jdk/microsoft-jdk-${item.version.join('.')}-${opts.os}-${this.architecture}.${opts.archive}`,
- version: this.convertVersionToSemver(item)
- }));
- const satisfiedVersion = availableVersions
- .filter(item => util_1.isVersionSatisfies(range, item.version))
- .sort((a, b) => -semver_1.default.compareBuild(a.version, b.version))[0];
- if (!satisfiedVersion) {
- const availableOptions = availableVersions.map(item => item.version).join(', ');
- const availableOptionsMessage = availableOptions
- ? `\nAvailable versions: ${availableOptions}`
- : '';
- throw new Error(`Could not find satisfied version for SemVer ${range}. ${availableOptionsMessage}`);
+ const manifest = yield this.getAvailableVersions();
+ if (!manifest) {
+ throw new Error('Could not load manifest for Microsoft Build of OpenJDK');
}
- return satisfiedVersion;
+ const foundRelease = yield tc.findFromManifest(range, true, manifest, arch);
+ if (!foundRelease) {
+ throw new Error(`Could not find satisfied version for SemVer ${range}. ${manifest
+ .map(item => item.version)
+ .join(', ')}`);
+ }
+ return { url: foundRelease.files[0].download_url, version: foundRelease.version };
});
}
getAvailableVersions() {
return __awaiter(this, void 0, void 0, function* () {
// TODO get these dynamically!
// We will need Microsoft to add an endpoint where we can query for versions.
- const jdkVersions = [
- {
- version: [17, 0, 3]
- },
- {
- version: [17, 0, 1, 12, 1]
- },
- {
- version: [16, 0, 2, 7, 1]
- },
- {
- version: [11, 0, 15]
+ const token = core.getInput('token');
+ const owner = 'actions';
+ const repository = 'setup-java';
+ const branch = 'main';
+ const filePath = 'src/distributions/microsoft/microsoft-openjdk-versions.json';
+ let releases = null;
+ const fileUrl = `https://api.github.com/repos/${owner}/${repository}/contents/${filePath}?ref=${branch}`;
+ const headers = {
+ authorization: token,
+ accept: 'application/vnd.github.VERSION.raw'
+ };
+ let response = null;
+ try {
+ response = yield this.http.getJson(fileUrl, headers);
+ if (!response.result) {
+ return null;
}
- ];
- // M1 is only supported for Java 16 & 17
- if (process.platform !== 'darwin' || this.architecture !== 'aarch64') {
- jdkVersions.push({
- version: [11, 0, 13, 8, 1]
- });
}
- return jdkVersions;
+ catch (err) {
+ core.debug(`Http request for microsoft-openjdk-versions.json failed with status code: ${response === null || response === void 0 ? void 0 : response.statusCode}`);
+ return null;
+ }
+ if (response.result) {
+ releases = response.result;
+ }
+ return releases;
});
}
- getPlatformOption(platform = process.platform /* for testing */) {
- switch (platform) {
- case 'darwin':
- return { archive: 'tar.gz', os: 'macos' };
- case 'win32':
- return { archive: 'zip', os: 'windows' };
- case 'linux':
- return { archive: 'tar.gz', os: 'linux' };
- default:
- throw new Error(`Platform '${platform}' is not supported. Supported platforms: 'darwin', 'linux', 'win32'`);
- }
- }
- convertVersionToSemver(version) {
- const major = version.version[0];
- const minor = version.version[1];
- const patch = version.version[2];
- return `${major}.${minor}.${patch}`;
- }
}
exports.MicrosoftDistributions = MicrosoftDistributions;
@@ -104807,7 +104870,7 @@ class TemurinDistribution extends base_installer_1.JavaBase {
getAvailableVersions() {
return __awaiter(this, void 0, void 0, function* () {
const platform = this.getPlatformOption();
- const arch = this.architecture;
+ 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';
@@ -105011,17 +105074,17 @@ class ZuluDistribution extends base_installer_1.JavaBase {
});
}
getArchitectureOptions() {
- if (this.architecture == 'x64') {
- return { arch: 'x86', hw_bitness: '64', abi: '' };
- }
- else if (this.architecture == 'x86') {
- return { arch: 'x86', hw_bitness: '32', abi: '' };
- }
- else if (this.architecture == 'arm64') {
- return { arch: 'arm', hw_bitness: '64', abi: '' };
- }
- else {
- return { arch: this.architecture, hw_bitness: '', abi: '' };
+ const arch = this.distributionArchitecture();
+ switch (arch) {
+ case 'x64':
+ return { arch: 'x86', hw_bitness: '64', abi: '' };
+ case 'x86':
+ return { arch: 'x86', hw_bitness: '32', abi: '' };
+ case 'aarch64':
+ case 'arm64':
+ return { arch: 'arm', hw_bitness: '64', abi: '' };
+ default:
+ return { arch: arch, hw_bitness: '', abi: '' };
}
}
getPlatformOption() {
@@ -105163,6 +105226,7 @@ Object.defineProperty(exports, "__esModule", ({ value: true }));
const core = __importStar(__nccwpck_require__(2186));
const auth = __importStar(__nccwpck_require__(3497));
const util_1 = __nccwpck_require__(2629);
+const toolchains = __importStar(__nccwpck_require__(9322));
const constants = __importStar(__nccwpck_require__(9042));
const cache_1 = __nccwpck_require__(4810);
const path = __importStar(__nccwpck_require__(1017));
@@ -105177,8 +105241,12 @@ function run() {
const jdkFile = core.getInput(constants.INPUT_JDK_FILE);
const cache = core.getInput(constants.INPUT_CACHE);
const checkLatest = util_1.getBooleanInput(constants.INPUT_CHECK_LATEST, false);
+ let toolchainIds = core.getMultilineInput(constants.INPUT_MVN_TOOLCHAIN_ID);
+ if (versions.length !== toolchainIds.length) {
+ toolchainIds = [];
+ }
core.startGroup('Installed distributions');
- for (const version of versions) {
+ for (const [index, version] of versions.entries()) {
const installerOptions = {
architecture,
packageType,
@@ -105190,6 +105258,7 @@ function run() {
throw new Error(`No supported distribution was found for input ${distributionName}`);
}
const result = yield distribution.setupJava();
+ yield toolchains.configureToolchains(version, distributionName, result.path, toolchainIds[index]);
core.info('');
core.info('Java configuration:');
core.info(` Distribution: ${distributionName}`);
@@ -105213,6 +105282,166 @@ function run() {
run();
+/***/ }),
+
+/***/ 9322:
+/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) {
+
+"use strict";
+
+var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
+ if (k2 === undefined) k2 = k;
+ Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
+}) : (function(o, m, k, k2) {
+ if (k2 === undefined) k2 = k;
+ o[k2] = m[k];
+}));
+var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
+}) : function(o, v) {
+ o["default"] = v;
+});
+var __importStar = (this && this.__importStar) || function (mod) {
+ if (mod && mod.__esModule) return mod;
+ var result = {};
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
+ __setModuleDefault(result, mod);
+ return result;
+};
+var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
+ return new (P || (P = Promise))(function (resolve, reject) {
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
+ });
+};
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.generateToolchainDefinition = exports.createToolchainsSettings = exports.configureToolchains = void 0;
+const fs = __importStar(__nccwpck_require__(7147));
+const os = __importStar(__nccwpck_require__(2037));
+const path = __importStar(__nccwpck_require__(1017));
+const core = __importStar(__nccwpck_require__(2186));
+const io = __importStar(__nccwpck_require__(7436));
+const constants = __importStar(__nccwpck_require__(9042));
+const util_1 = __nccwpck_require__(2629);
+const xmlbuilder2_1 = __nccwpck_require__(151);
+function configureToolchains(version, distributionName, jdkHome, toolchainId) {
+ return __awaiter(this, void 0, void 0, function* () {
+ const vendor = core.getInput(constants.INPUT_MVN_TOOLCHAIN_VENDOR) || distributionName;
+ const id = toolchainId || `${vendor}_${version}`;
+ const settingsDirectory = core.getInput(constants.INPUT_SETTINGS_PATH) || path.join(os.homedir(), constants.M2_DIR);
+ const overwriteSettings = util_1.getBooleanInput(constants.INPUT_OVERWRITE_SETTINGS, true);
+ yield createToolchainsSettings({
+ jdkInfo: {
+ version,
+ vendor,
+ id,
+ jdkHome
+ },
+ settingsDirectory,
+ overwriteSettings
+ });
+ });
+}
+exports.configureToolchains = configureToolchains;
+function createToolchainsSettings({ jdkInfo, settingsDirectory, overwriteSettings }) {
+ return __awaiter(this, void 0, void 0, function* () {
+ core.info(`Creating ${constants.MVN_TOOLCHAINS_FILE} for JDK version ${jdkInfo.version} from ${jdkInfo.vendor}`);
+ // when an alternate m2 location is specified use only that location (no .m2 directory)
+ // otherwise use the home/.m2/ path
+ yield io.mkdirP(settingsDirectory);
+ const originalToolchains = yield readExistingToolchainsFile(settingsDirectory);
+ const updatedToolchains = generateToolchainDefinition(originalToolchains, jdkInfo.version, jdkInfo.vendor, jdkInfo.id, jdkInfo.jdkHome);
+ yield writeToolchainsFileToDisk(settingsDirectory, updatedToolchains, overwriteSettings);
+ });
+}
+exports.createToolchainsSettings = createToolchainsSettings;
+// only exported for testing purposes
+function generateToolchainDefinition(original, version, vendor, id, jdkHome) {
+ let xmlObj;
+ if (original === null || original === void 0 ? void 0 : original.length) {
+ xmlObj = xmlbuilder2_1.create(original)
+ .root()
+ .ele({
+ toolchain: {
+ type: 'jdk',
+ provides: {
+ version: `${version}`,
+ vendor: `${vendor}`,
+ id: `${id}`
+ },
+ configuration: {
+ jdkHome: `${jdkHome}`
+ }
+ }
+ });
+ }
+ else
+ xmlObj = xmlbuilder2_1.create({
+ toolchains: {
+ '@xmlns': 'https://maven.apache.org/TOOLCHAINS/1.1.0',
+ '@xmlns:xsi': 'https://www.w3.org/2001/XMLSchema-instance',
+ '@xsi:schemaLocation': 'https://maven.apache.org/TOOLCHAINS/1.1.0 https://maven.apache.org/xsd/toolchains-1.1.0.xsd',
+ toolchain: [
+ {
+ type: 'jdk',
+ provides: {
+ version: `${version}`,
+ vendor: `${vendor}`,
+ id: `${id}`
+ },
+ configuration: {
+ jdkHome: `${jdkHome}`
+ }
+ }
+ ]
+ }
+ });
+ return xmlObj.end({
+ format: 'xml',
+ wellFormed: false,
+ headless: false,
+ prettyPrint: true,
+ width: 80
+ });
+}
+exports.generateToolchainDefinition = generateToolchainDefinition;
+function readExistingToolchainsFile(directory) {
+ return __awaiter(this, void 0, void 0, function* () {
+ const location = path.join(directory, constants.MVN_TOOLCHAINS_FILE);
+ if (fs.existsSync(location)) {
+ return fs.readFileSync(location, {
+ encoding: 'utf-8',
+ flag: 'r'
+ });
+ }
+ return '';
+ });
+}
+function writeToolchainsFileToDisk(directory, settings, overwriteSettings) {
+ return __awaiter(this, void 0, void 0, function* () {
+ const location = path.join(directory, constants.MVN_TOOLCHAINS_FILE);
+ const settingsExists = fs.existsSync(location);
+ if (settingsExists && overwriteSettings) {
+ core.info(`Overwriting existing file ${location}`);
+ }
+ else if (!settingsExists) {
+ core.info(`Writing to ${location}`);
+ }
+ else {
+ core.info(`Skipping generation of ${location} because file already exists and overwriting is not enabled`);
+ return;
+ }
+ return fs.writeFileSync(location, settings, {
+ encoding: 'utf-8',
+ flag: 'w'
+ });
+ });
+}
+
+
/***/ }),
/***/ 2629:
diff --git a/docs/advanced-usage.md b/docs/advanced-usage.md
index befe52d..93ebd85 100644
--- a/docs/advanced-usage.md
+++ b/docs/advanced-usage.md
@@ -14,6 +14,7 @@
- [Publishing using Apache Maven](#Publishing-using-Apache-Maven)
- [Publishing using Gradle](#Publishing-using-Gradle)
- [Hosted Tool Cache](#Hosted-Tool-Cache)
+- [Modifying Maven Toolchains](#Modifying-Maven-Toolchains)
See [action.yml](../action.yml) for more details on task inputs.
@@ -350,3 +351,100 @@ GitHub Hosted Runners have a tool cache that comes with some Java versions pre-i
Currently, LTS versions of Adopt OpenJDK (`adopt`) are cached on the GitHub Hosted Runners.
The tools cache gets updated on a weekly basis. For information regarding locally cached versions of Java on GitHub hosted runners, check out [GitHub Actions Virtual Environments](https://github.com/actions/virtual-environments).
+
+## Modifying Maven Toolchains
+The `setup-java` action generates a basic [Maven Toolchains declaration](https://maven.apache.org/guides/mini/guide-using-toolchains.html) for specified Java versions by either creating a minimal toolchains file or extending an existing declaration with the additional JDKs.
+
+### Installing Multiple JDKs With Toolchains
+Subsequent calls to `setup-java` with distinct distribution and version parameters will continue to extend the toolchains declaration and make all specified Java versions available.
+
+```yaml
+steps:
+- uses: actions/setup-java@v3
+ with:
+ distribution: ''
+ java-version: |
+ 8
+ 11
+
+- uses: actions/setup-java@v3
+ with:
+ distribution: ''
+ java-version: 15
+```
+
+The result is a Toolchain with entries for JDKs 8, 11 and 15. You can even combine this with custom JDKs of arbitrary versions:
+
+```yaml
+- run: |
+ download_url="https://example.com/java/jdk/6u45-b06/jdk-6u45-linux-x64.tar.gz"
+ wget -O $RUNNER_TEMP/java_package.tar.gz $download_url
+- uses: actions/setup-java@v3
+ with:
+ distribution: 'jdkfile'
+ jdkFile: ${{ runner.temp }}/java_package.tar.gz
+ java-version: '1.6'
+ architecture: x64
+```
+
+This will generate a Toolchains entry with the following values: `version: 1.6`, `vendor: jkdfile`, `id: Oracle_1.6`.
+
+### Modifying The Toolchain Vendor For JDKs
+Each JDK provider will receive a default `vendor` using the `distribution` input value but this can be overridden with the `mvn-toolchain-vendor` parameter as follows.
+
+```yaml
+- run: |
+ download_url="https://example.com/java/jdk/6u45-b06/jdk-6u45-linux-x64.tar.gz"
+ wget -O $RUNNER_TEMP/java_package.tar.gz $download_url
+- uses: actions/setup-java@v3
+ with:
+ distribution: 'jdkfile'
+ jdkFile: ${{ runner.temp }}/java_package.tar.gz
+ java-version: '1.6'
+ architecture: x64
+ mvn-toolchain-vendor: 'Oracle'
+```
+
+This will generate a Toolchains entry with the following values: `version: 1.6`, `vendor: Oracle`, `id: Oracle_1.6`.
+
+In case you install multiple versions of Java at once with multi-line `java-version` input setting the `mvn-toolchain-vendor` still only accepts one value and will use this value for installed JDKs as expected when installing multiple versions of the same `distribution`.
+
+```yaml
+steps:
+- uses: actions/setup-java@v3
+ with:
+ distribution: ''
+ java-version: |
+ 8
+ 11
+ mvn-toolchain-vendor: Eclipse Temurin
+```
+
+### Modifying The Toolchain ID For JDKs
+Each JDK provider will receive a default `id` based on the combination of `distribution` and `java-version` in the format of `distribution_java-version` (e.g. `temurin_11`) but this can be overridden with the `mvn-toolchain-id` parameter as follows.
+
+```yaml
+steps:
+- uses: actions/checkout@v3
+- uses: actions/setup-java@v3
+ with:
+ distribution: 'temurin'
+ java-version: '11'
+ mvn-toolchain-id: 'some_other_id'
+- run: java -cp java HelloWorldApp
+```
+
+In case you install multiple versions of Java at once you can use the same syntax as used in `java-versions`. Please note that you have to declare an ID for all Java versions that will be installed or the `mvn-toolchain-id` instruction will be skipped wholesale due to mapping ambiguities.
+
+```yaml
+steps:
+- uses: actions/setup-java@v3
+ with:
+ distribution: ''
+ java-version: |
+ 8
+ 11
+ mvn-toolchain-id: |
+ something_else
+ something_other
+```
diff --git a/package-lock.json b/package-lock.json
index cf6aba8..351da99 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -9,8 +9,8 @@
"version": "3.4.1",
"license": "MIT",
"dependencies": {
- "@actions/cache": "^3.0.0",
- "@actions/core": "^1.9.0",
+ "@actions/cache": "^3.0.4",
+ "@actions/core": "^1.10.0",
"@actions/exec": "^1.0.4",
"@actions/glob": "^0.2.0",
"@actions/http-client": "^1.0.11",
@@ -32,9 +32,9 @@
}
},
"node_modules/@actions/cache": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/@actions/cache/-/cache-3.0.0.tgz",
- "integrity": "sha512-GL9CT1Fnu+pqs8TTB621q8Xa8Cilw2n9MwvbgMedetH7L1q2n6jY61gzbwGbKgtVbp3gVJ12aNMi4osSGXx3KQ==",
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/@actions/cache/-/cache-3.0.4.tgz",
+ "integrity": "sha512-9RwVL8/ISJoYWFNH1wR/C26E+M3HDkGPWmbFJMMCKwTkjbNZJreMT4XaR/EB1bheIvN4PREQxEQQVJ18IPnf/Q==",
"dependencies": {
"@actions/core": "^1.2.6",
"@actions/exec": "^1.0.1",
@@ -73,9 +73,9 @@
}
},
"node_modules/@actions/core": {
- "version": "1.9.1",
- "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.9.1.tgz",
- "integrity": "sha512-5ad+U2YGrmmiw6du20AQW5XuWo7UKN2052FjSV7MX+Wfjf8sCqcsZe62NfgHys4QI4/Y+vQvLKYL8jWtA1ZBTA==",
+ "version": "1.10.0",
+ "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.10.0.tgz",
+ "integrity": "sha512-2aZDDa3zrrZbP5ZYg159sNoLRb61nQ7awl5pSvIq5Qpj81vwDzdMRKzkWJGJuwVvWpvZKx7vspJALyvaaIQyug==",
"dependencies": {
"@actions/http-client": "^2.0.1",
"uuid": "^8.3.2"
@@ -4790,9 +4790,9 @@
},
"dependencies": {
"@actions/cache": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/@actions/cache/-/cache-3.0.0.tgz",
- "integrity": "sha512-GL9CT1Fnu+pqs8TTB621q8Xa8Cilw2n9MwvbgMedetH7L1q2n6jY61gzbwGbKgtVbp3gVJ12aNMi4osSGXx3KQ==",
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/@actions/cache/-/cache-3.0.4.tgz",
+ "integrity": "sha512-9RwVL8/ISJoYWFNH1wR/C26E+M3HDkGPWmbFJMMCKwTkjbNZJreMT4XaR/EB1bheIvN4PREQxEQQVJ18IPnf/Q==",
"requires": {
"@actions/core": "^1.2.6",
"@actions/exec": "^1.0.1",
@@ -4830,9 +4830,9 @@
}
},
"@actions/core": {
- "version": "1.9.1",
- "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.9.1.tgz",
- "integrity": "sha512-5ad+U2YGrmmiw6du20AQW5XuWo7UKN2052FjSV7MX+Wfjf8sCqcsZe62NfgHys4QI4/Y+vQvLKYL8jWtA1ZBTA==",
+ "version": "1.10.0",
+ "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.10.0.tgz",
+ "integrity": "sha512-2aZDDa3zrrZbP5ZYg159sNoLRb61nQ7awl5pSvIq5Qpj81vwDzdMRKzkWJGJuwVvWpvZKx7vspJALyvaaIQyug==",
"requires": {
"@actions/http-client": "^2.0.1",
"uuid": "^8.3.2"
diff --git a/package.json b/package.json
index 0360bb9..9cb00e1 100644
--- a/package.json
+++ b/package.json
@@ -24,8 +24,8 @@
"author": "GitHub",
"license": "MIT",
"dependencies": {
- "@actions/cache": "^3.0.0",
- "@actions/core": "^1.9.0",
+ "@actions/cache": "^3.0.4",
+ "@actions/core": "^1.10.0",
"@actions/exec": "^1.0.4",
"@actions/glob": "^0.2.0",
"@actions/http-client": "^1.0.11",
diff --git a/src/auth.ts b/src/auth.ts
index a52306b..f697ddc 100644
--- a/src/auth.ts
+++ b/src/auth.ts
@@ -10,15 +10,12 @@ import * as constants from './constants';
import * as gpg from './gpg';
import { getBooleanInput } from './util';
-export const M2_DIR = '.m2';
-export const SETTINGS_FILE = 'settings.xml';
-
export async function configureAuthentication() {
const id = core.getInput(constants.INPUT_SERVER_ID);
const username = core.getInput(constants.INPUT_SERVER_USERNAME);
const password = core.getInput(constants.INPUT_SERVER_PASSWORD);
const settingsDirectory =
- core.getInput(constants.INPUT_SETTINGS_PATH) || path.join(os.homedir(), M2_DIR);
+ core.getInput(constants.INPUT_SETTINGS_PATH) || path.join(os.homedir(), constants.M2_DIR);
const overwriteSettings = getBooleanInput(constants.INPUT_OVERWRITE_SETTINGS, true);
const gpgPrivateKey =
core.getInput(constants.INPUT_GPG_PRIVATE_KEY) || constants.INPUT_DEFAULT_GPG_PRIVATE_KEY;
@@ -54,7 +51,7 @@ export async function createAuthenticationSettings(
overwriteSettings: boolean,
gpgPassphrase: string | undefined = undefined
) {
- core.info(`Creating ${SETTINGS_FILE} with server-id: ${id}`);
+ core.info(`Creating ${constants.MVN_SETTINGS_FILE} with server-id: ${id}`);
// when an alternate m2 location is specified use only that location (no .m2 directory)
// otherwise use the home/.m2/ path
await io.mkdirP(settingsDirectory);
@@ -106,7 +103,7 @@ export function generate(
}
async function write(directory: string, settings: string, overwriteSettings: boolean) {
- const location = path.join(directory, SETTINGS_FILE);
+ const location = path.join(directory, constants.MVN_SETTINGS_FILE);
const settingsExists = fs.existsSync(location);
if (settingsExists && overwriteSettings) {
core.info(`Overwriting existing file ${location}`);
diff --git a/src/cache.ts b/src/cache.ts
index 1533ed0..20b553e 100644
--- a/src/cache.ts
+++ b/src/cache.ts
@@ -35,7 +35,8 @@ const supportedPackageManager: PackageManager[] = [
'**/*.gradle*',
'**/gradle-wrapper.properties',
'buildSrc/**/Versions.kt',
- 'buildSrc/**/Dependencies.kt'
+ 'buildSrc/**/Dependencies.kt',
+ 'gradle/*.versions.toml'
]
},
{
diff --git a/src/constants.ts b/src/constants.ts
index 94d7667..ad8709e 100644
--- a/src/constants.ts
+++ b/src/constants.ts
@@ -20,3 +20,9 @@ export const INPUT_CACHE = 'cache';
export const INPUT_JOB_STATUS = 'job-status';
export const STATE_GPG_PRIVATE_KEY_FINGERPRINT = 'gpg-private-key-fingerprint';
+
+export const M2_DIR = '.m2';
+export const MVN_SETTINGS_FILE = 'settings.xml';
+export const MVN_TOOLCHAINS_FILE = 'toolchains.xml';
+export const INPUT_MVN_TOOLCHAIN_ID = 'mvn-toolchain-id';
+export const INPUT_MVN_TOOLCHAIN_VENDOR = 'mvn-toolchain-vendor';
diff --git a/src/distributions/adopt/installer.ts b/src/distributions/adopt/installer.ts
index e106c4b..52b64c6 100644
--- a/src/distributions/adopt/installer.ts
+++ b/src/distributions/adopt/installer.ts
@@ -88,7 +88,7 @@ export class AdoptDistribution extends JavaBase {
private async getAvailableVersions(): Promise {
const platform = this.getPlatformOption();
- const arch = this.architecture;
+ 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';
diff --git a/src/distributions/base-installer.ts b/src/distributions/base-installer.ts
index e25ed34..1a31ffa 100644
--- a/src/distributions/base-installer.ts
+++ b/src/distributions/base-installer.ts
@@ -7,6 +7,7 @@ import * as httpm from '@actions/http-client';
import { getToolcachePath, isVersionSatisfies } from '../util';
import { JavaDownloadRelease, JavaInstallerOptions, JavaInstallerResults } from './base-models';
import { MACOS_JAVA_CONTENT_POSTFIX } from '../constants';
+import os from 'os';
export abstract class JavaBase {
protected http: httpm.HttpClient;
@@ -25,7 +26,7 @@ export abstract class JavaBase {
({ version: this.version, stable: this.stable } = this.normalizeVersion(
installerOptions.version
));
- this.architecture = installerOptions.architecture;
+ this.architecture = installerOptions.architecture || os.arch();
this.packageType = installerOptions.packageType;
this.checkLatest = installerOptions.checkLatest;
}
@@ -150,4 +151,24 @@ export abstract class JavaBase {
core.setOutput('version', version);
core.exportVariable(`JAVA_HOME_${majorVersion}_${this.architecture.toUpperCase()}`, toolPath);
}
+
+ 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;
+ }
+ }
}
diff --git a/src/distributions/corretto/installer.ts b/src/distributions/corretto/installer.ts
index cc0cad0..6b4872d 100644
--- a/src/distributions/corretto/installer.ts
+++ b/src/distributions/corretto/installer.ts
@@ -68,7 +68,7 @@ export class CorrettoDistribution extends JavaBase {
private async getAvailableVersions(): Promise {
const platform = this.getPlatformOption();
- const arch = this.architecture;
+ const arch = this.distributionArchitecture();
const imageType = this.packageType;
if (core.isDebug()) {
diff --git a/src/distributions/liberica/installer.ts b/src/distributions/liberica/installer.ts
index d177db9..f06e56e 100644
--- a/src/distributions/liberica/installer.ts
+++ b/src/distributions/liberica/installer.ts
@@ -10,7 +10,7 @@ import path from 'path';
const supportedPlatform = `'linux', 'linux-musl', 'macos', 'solaris', 'windows'`;
-const supportedArchitecture = `'x86', 'x64', 'armv7', 'aarch64', 'ppc64le'`;
+const supportedArchitectures = `'x86', 'x64', 'armv7', 'aarch64', 'ppc64le'`;
export class LibericaDistributions extends JavaBase {
constructor(installerOptions: JavaInstallerOptions) {
@@ -112,7 +112,8 @@ export class LibericaDistributions extends JavaBase {
}
private getArchitectureOptions(): ArchitectureOptions {
- switch (this.architecture) {
+ const arch = this.distributionArchitecture();
+ switch (arch) {
case 'x86':
return { bitness: '32', arch: 'x86' };
case 'x64':
@@ -125,7 +126,7 @@ export class LibericaDistributions extends JavaBase {
return { bitness: '64', arch: 'ppc' };
default:
throw new Error(
- `Architecture '${this.architecture}' is not supported. Supported architectures: ${supportedArchitecture}`
+ `Architecture '${this.architecture}' is not supported. Supported architectures: ${supportedArchitectures}`
);
}
}
@@ -156,4 +157,14 @@ export class LibericaDistributions extends JavaBase {
}
return mainVersion;
}
+
+ protected distributionArchitecture(): string {
+ let arch = super.distributionArchitecture();
+ switch (arch) {
+ case 'arm':
+ return 'armv7';
+ default:
+ return arch;
+ }
+ }
}
diff --git a/src/distributions/microsoft/installer.ts b/src/distributions/microsoft/installer.ts
index 4ceb428..6284f96 100644
--- a/src/distributions/microsoft/installer.ts
+++ b/src/distributions/microsoft/installer.ts
@@ -1,12 +1,12 @@
import { JavaBase } from '../base-installer';
import { JavaDownloadRelease, JavaInstallerOptions, JavaInstallerResults } from '../base-models';
-import semver from 'semver';
-import { extractJdkFile, getDownloadArchiveExtension, isVersionSatisfies } from '../../util';
+import { extractJdkFile, getDownloadArchiveExtension } from '../../util';
import * as core from '@actions/core';
-import { MicrosoftVersion, PlatformOptions } from './models';
import * as tc from '@actions/tool-cache';
+import { OutgoingHttpHeaders } from 'http';
import fs from 'fs';
import path from 'path';
+import { ITypedResponse } from '@actions/http-client/interfaces';
export class MicrosoftDistributions extends JavaBase {
constructor(installerOptions: JavaInstallerOptions) {
@@ -37,7 +37,8 @@ export class MicrosoftDistributions extends JavaBase {
}
protected async findPackageForDownload(range: string): Promise {
- if (this.architecture !== 'x64' && this.architecture !== 'aarch64') {
+ const arch = this.distributionArchitecture();
+ if (arch !== 'x64' && arch !== 'aarch64') {
throw new Error(`Unsupported architecture: ${this.architecture}`);
}
@@ -49,82 +50,60 @@ export class MicrosoftDistributions extends JavaBase {
throw new Error('Microsoft Build of OpenJDK provides only the `jdk` package type');
}
- const availableVersionsRaw = await this.getAvailableVersions();
+ const manifest = await this.getAvailableVersions();
- const opts = this.getPlatformOption();
- const availableVersions = availableVersionsRaw.map(item => ({
- url: `https://aka.ms/download-jdk/microsoft-jdk-${item.version.join('.')}-${opts.os}-${
- this.architecture
- }.${opts.archive}`,
- version: this.convertVersionToSemver(item)
- }));
+ if (!manifest) {
+ throw new Error('Could not load manifest for Microsoft Build of OpenJDK');
+ }
- const satisfiedVersion = availableVersions
- .filter(item => isVersionSatisfies(range, item.version))
- .sort((a, b) => -semver.compareBuild(a.version, b.version))[0];
+ const foundRelease = await tc.findFromManifest(range, true, manifest, arch);
- if (!satisfiedVersion) {
- const availableOptions = availableVersions.map(item => item.version).join(', ');
- const availableOptionsMessage = availableOptions
- ? `\nAvailable versions: ${availableOptions}`
- : '';
+ if (!foundRelease) {
throw new Error(
- `Could not find satisfied version for SemVer ${range}. ${availableOptionsMessage}`
+ `Could not find satisfied version for SemVer ${range}. ${manifest
+ .map(item => item.version)
+ .join(', ')}`
);
}
- return satisfiedVersion;
+ return { url: foundRelease.files[0].download_url, version: foundRelease.version };
}
- private async getAvailableVersions(): Promise {
+ private async getAvailableVersions(): Promise {
// TODO get these dynamically!
// We will need Microsoft to add an endpoint where we can query for versions.
- const jdkVersions = [
- {
- version: [17, 0, 3]
- },
- {
- version: [17, 0, 1, 12, 1]
- },
- {
- version: [16, 0, 2, 7, 1]
- },
- {
- version: [11, 0, 15]
+ const token = core.getInput('token');
+ const owner = 'actions';
+ const repository = 'setup-java';
+ const branch = 'main';
+ const filePath = 'src/distributions/microsoft/microsoft-openjdk-versions.json';
+
+ let releases: tc.IToolRelease[] | null = null;
+ const fileUrl = `https://api.github.com/repos/${owner}/${repository}/contents/${filePath}?ref=${branch}`;
+
+ const headers: OutgoingHttpHeaders = {
+ authorization: token,
+ accept: 'application/vnd.github.VERSION.raw'
+ };
+
+ let response: ITypedResponse | null = null;
+
+ try {
+ response = await this.http.getJson(fileUrl, headers);
+ if (!response.result) {
+ return null;
}
- ];
-
- // M1 is only supported for Java 16 & 17
- if (process.platform !== 'darwin' || this.architecture !== 'aarch64') {
- jdkVersions.push({
- version: [11, 0, 13, 8, 1]
- });
+ } catch (err) {
+ core.debug(
+ `Http request for microsoft-openjdk-versions.json failed with status code: ${response?.statusCode}`
+ );
+ return null;
}
- return jdkVersions;
- }
-
- private getPlatformOption(
- platform: NodeJS.Platform = process.platform /* for testing */
- ): PlatformOptions {
- switch (platform) {
- case 'darwin':
- return { archive: 'tar.gz', os: 'macos' };
- case 'win32':
- return { archive: 'zip', os: 'windows' };
- case 'linux':
- return { archive: 'tar.gz', os: 'linux' };
- default:
- throw new Error(
- `Platform '${platform}' is not supported. Supported platforms: 'darwin', 'linux', 'win32'`
- );
+ if (response.result) {
+ releases = response.result;
}
- }
- private convertVersionToSemver(version: MicrosoftVersion): string {
- const major = version.version[0];
- const minor = version.version[1];
- const patch = version.version[2];
- return `${major}.${minor}.${patch}`;
+ return releases;
}
}
diff --git a/src/distributions/microsoft/microsoft-openjdk-versions.json b/src/distributions/microsoft/microsoft-openjdk-versions.json
new file mode 100644
index 0000000..b729619
--- /dev/null
+++ b/src/distributions/microsoft/microsoft-openjdk-versions.json
@@ -0,0 +1,181 @@
+[
+ {
+ "version": "17.0.3",
+ "stable": true,
+ "release_url": "https://aka.ms/download-jdk",
+ "files": [
+ {
+ "filename": "microsoft-jdk-17.0.3-macos-x64.tar.gz",
+ "arch": "x64",
+ "platform": "darwin",
+ "download_url": "https://aka.ms/download-jdk/microsoft-jdk-17.0.3-macos-x64.tar.gz"
+ },
+ {
+ "filename": "microsoft-jdk-17.0.3-linux-x64.tar.gz",
+ "arch": "x64",
+ "platform": "linux",
+ "download_url": "https://aka.ms/download-jdk/microsoft-jdk-17.0.3-linux-x64.tar.gz"
+ },
+ {
+ "filename": "microsoft-jdk-17.0.3-windows-x64.zip",
+ "arch": "x64",
+ "platform": "win32",
+ "download_url": "https://aka.ms/download-jdk/microsoft-jdk-17.0.3-windows-x64.zip"
+ },
+ {
+ "filename": "microsoft-jdk-17.0.3-macos-aarch64.tar.gz",
+ "arch": "aarch64",
+ "platform": "darwin",
+ "download_url": "https://aka.ms/download-jdk/microsoft-jdk-17.0.3-macos-aarch64.tar.gz"
+ },
+ {
+ "filename": "microsoft-jdk-17.0.3-linux-aarch64.tar.gz",
+ "arch": "aarch64",
+ "platform": "linux",
+ "download_url": "https://aka.ms/download-jdk/microsoft-jdk-17.0.3-linux-aarch64.tar.gz"
+ }
+ ]
+ },
+ {
+ "version": "17.0.1+12.1",
+ "stable": true,
+ "release_url": "https://aka.ms/download-jdk",
+ "files": [
+ {
+ "filename": "microsoft-jdk-17.0.1.12.1-macos-x64.tar.gz",
+ "arch": "x64",
+ "platform": "darwin",
+ "download_url": "https://aka.ms/download-jdk/microsoft-jdk-17.0.1.12.1-macos-x64.tar.gz"
+ },
+ {
+ "filename": "microsoft-jdk-17.0.1.12.1-linux-x64.tar.gz",
+ "arch": "x64",
+ "platform": "linux",
+ "download_url": "https://aka.ms/download-jdk/microsoft-jdk-17.0.1.12.1-linux-x64.tar.gz"
+ },
+ {
+ "filename": "microsoft-jdk-17.0.1.12.1-windows-x64.zip",
+ "arch": "x64",
+ "platform": "win32",
+ "download_url": "https://aka.ms/download-jdk/microsoft-jdk-17.0.1.12.1-windows-x64.zip"
+ },
+ {
+ "filename": "microsoft-jdk-17.0.1.12.1-macos-aarch64.tar.gz",
+ "arch": "aarch64",
+ "platform": "darwin",
+ "download_url": "https://aka.ms/download-jdk/microsoft-jdk-17.0.1.12.1-macos-aarch64.tar.gz"
+ },
+ {
+ "filename": "microsoft-jdk-17.0.1.12.1-linux-aarch64.tar.gz",
+ "arch": "aarch64",
+ "platform": "linux",
+ "download_url": "https://aka.ms/download-jdk/microsoft-jdk-17.0.1.12.1-linux-aarch64.tar.gz"
+ }
+ ]
+ },
+ {
+ "version": "16.0.2+7.1",
+ "stable": true,
+ "release_url": "https://aka.ms/download-jdk",
+ "files": [
+ {
+ "filename": "microsoft-jdk-16.0.2.7.1-macos-x64.tar.gz",
+ "arch": "x64",
+ "platform": "darwin",
+ "download_url": "https://aka.ms/download-jdk/microsoft-jdk-16.0.2.7.1-macos-x64.tar.gz"
+ },
+ {
+ "filename": "microsoft-jdk-16.0.2.7.1-linux-x64.tar.gz",
+ "arch": "x64",
+ "platform": "linux",
+ "download_url": "https://aka.ms/download-jdk/microsoft-jdk-16.0.2.7.1-linux-x64.tar.gz"
+ },
+ {
+ "filename": "microsoft-jdk-16.0.2.7.1-windows-x64.zip",
+ "arch": "x64",
+ "platform": "win32",
+ "download_url": "https://aka.ms/download-jdk/microsoft-jdk-16.0.2.7.1-windows-x64.zip"
+ },
+ {
+ "filename": "microsoft-jdk-16.0.2.7.1-macos-aarch64.tar.gz",
+ "arch": "aarch64",
+ "platform": "darwin",
+ "download_url": "https://aka.ms/download-jdk/microsoft-jdk-16.0.2.7.1-macos-aarch64.tar.gz"
+ },
+ {
+ "filename": "microsoft-jdk-16.0.2.7.1-linux-aarch64.tar.gz",
+ "arch": "aarch64",
+ "platform": "linux",
+ "download_url": "https://aka.ms/download-jdk/microsoft-jdk-16.0.2.7.1-linux-aarch64.tar.gz"
+ }
+ ]
+ },
+ {
+ "version": "11.0.15",
+ "stable": true,
+ "release_url": "https://aka.ms/download-jdk",
+ "files": [
+ {
+ "filename": "microsoft-jdk-11.0.15-macos-x64.tar.gz",
+ "arch": "x64",
+ "platform": "darwin",
+ "download_url": "https://aka.ms/download-jdk/microsoft-jdk-11.0.15-macos-x64.tar.gz"
+ },
+ {
+ "filename": "microsoft-jdk-11.0.15-linux-x64.tar.gz",
+ "arch": "x64",
+ "platform": "linux",
+ "download_url": "https://aka.ms/download-jdk/microsoft-jdk-11.0.15-linux-x64.tar.gz"
+ },
+ {
+ "filename": "microsoft-jdk-11.0.15-windows-x64.zip",
+ "arch": "x64",
+ "platform": "win32",
+ "download_url": "https://aka.ms/download-jdk/microsoft-jdk-11.0.15-windows-x64.zip"
+ },
+ {
+ "filename": "microsoft-jdk-11.0.15-macos-aarch64.tar.gz",
+ "arch": "aarch64",
+ "platform": "darwin",
+ "download_url": "https://aka.ms/download-jdk/microsoft-jdk-11.0.15-macos-aarch64.tar.gz"
+ },
+ {
+ "filename": "microsoft-jdk-11.0.15-linux-aarch64.tar.gz",
+ "arch": "aarch64",
+ "platform": "linux",
+ "download_url": "https://aka.ms/download-jdk/microsoft-jdk-11.0.15-linux-aarch64.tar.gz"
+ }
+ ]
+ },
+ {
+ "version": "11.0.13+8.1",
+ "stable": true,
+ "release_url": "https://aka.ms/download-jdk",
+ "files": [
+ {
+ "filename": "microsoft-jdk-11.0.13.8.1-macos-x64.tar.gz",
+ "arch": "x64",
+ "platform": "darwin",
+ "download_url": "https://aka.ms/download-jdk/microsoft-jdk-11.0.13.8.1-macos-x64.tar.gz"
+ },
+ {
+ "filename": "microsoft-jdk-11.0.13.8.1-linux-x64.tar.gz",
+ "arch": "x64",
+ "platform": "linux",
+ "download_url": "https://aka.ms/download-jdk/microsoft-jdk-11.0.13.8.1-linux-x64.tar.gz"
+ },
+ {
+ "filename": "microsoft-jdk-11.0.13.8.1-windows-x64.zip",
+ "arch": "x64",
+ "platform": "win32",
+ "download_url": "https://aka.ms/download-jdk/microsoft-jdk-11.0.13.8.1-windows-x64.zip"
+ },
+ {
+ "filename": "microsoft-jdk-11.0.13.8.1-linux-aarch64.tar.gz",
+ "arch": "aarch64",
+ "platform": "linux",
+ "download_url": "https://aka.ms/download-jdk/microsoft-jdk-11.0.13.8.1-linux-aarch64.tar.gz"
+ }
+ ]
+ }
+]
\ No newline at end of file
diff --git a/src/distributions/microsoft/models.ts b/src/distributions/microsoft/models.ts
index 361c7db..c012bc7 100644
--- a/src/distributions/microsoft/models.ts
+++ b/src/distributions/microsoft/models.ts
@@ -1,12 +1,2 @@
type OsVersions = 'linux' | 'macos' | 'windows';
type ArchiveType = 'tar.gz' | 'zip';
-
-export interface PlatformOptions {
- archive: ArchiveType;
- os: OsVersions;
-}
-
-export interface MicrosoftVersion {
- downloadUrl?: string;
- version: Array;
-}
diff --git a/src/distributions/temurin/installer.ts b/src/distributions/temurin/installer.ts
index b30caa3..4cd3e66 100644
--- a/src/distributions/temurin/installer.ts
+++ b/src/distributions/temurin/installer.ts
@@ -86,7 +86,7 @@ export class TemurinDistribution extends JavaBase {
private async getAvailableVersions(): Promise {
const platform = this.getPlatformOption();
- const arch = this.architecture;
+ 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';
diff --git a/src/distributions/zulu/installer.ts b/src/distributions/zulu/installer.ts
index 42a9661..0ca6571 100644
--- a/src/distributions/zulu/installer.ts
+++ b/src/distributions/zulu/installer.ts
@@ -131,14 +131,17 @@ export class ZuluDistribution extends JavaBase {
hw_bitness: string;
abi: string;
} {
- if (this.architecture == 'x64') {
- return { arch: 'x86', hw_bitness: '64', abi: '' };
- } else if (this.architecture == 'x86') {
- return { arch: 'x86', hw_bitness: '32', abi: '' };
- } else if (this.architecture == 'arm64') {
- return { arch: 'arm', hw_bitness: '64', abi: '' };
- } else {
- return { arch: this.architecture, hw_bitness: '', abi: '' };
+ const arch = this.distributionArchitecture();
+ switch (arch) {
+ case 'x64':
+ return { arch: 'x86', hw_bitness: '64', abi: '' };
+ case 'x86':
+ return { arch: 'x86', hw_bitness: '32', abi: '' };
+ case 'aarch64':
+ case 'arm64':
+ return { arch: 'arm', hw_bitness: '64', abi: '' };
+ default:
+ return { arch: arch, hw_bitness: '', abi: '' };
}
}
diff --git a/src/setup-java.ts b/src/setup-java.ts
index 621883a..048c5dd 100644
--- a/src/setup-java.ts
+++ b/src/setup-java.ts
@@ -1,6 +1,7 @@
import * as core from '@actions/core';
import * as auth from './auth';
import { getBooleanInput, isCacheFeatureAvailable } from './util';
+import * as toolchains from './toolchains';
import * as constants from './constants';
import { restore } from './cache';
import * as path from 'path';
@@ -16,9 +17,14 @@ async function run() {
const jdkFile = core.getInput(constants.INPUT_JDK_FILE);
const cache = core.getInput(constants.INPUT_CACHE);
const checkLatest = getBooleanInput(constants.INPUT_CHECK_LATEST, false);
+ let toolchainIds = core.getMultilineInput(constants.INPUT_MVN_TOOLCHAIN_ID);
+
+ if (versions.length !== toolchainIds.length) {
+ toolchainIds = [];
+ }
core.startGroup('Installed distributions');
- for (const version of versions) {
+ for (const [index, version] of versions.entries()) {
const installerOptions: JavaInstallerOptions = {
architecture,
packageType,
@@ -32,6 +38,12 @@ async function run() {
}
const result = await distribution.setupJava();
+ await toolchains.configureToolchains(
+ version,
+ distributionName,
+ result.path,
+ toolchainIds[index]
+ );
core.info('');
core.info('Java configuration:');
diff --git a/src/toolchains.ts b/src/toolchains.ts
new file mode 100644
index 0000000..8c7d72c
--- /dev/null
+++ b/src/toolchains.ts
@@ -0,0 +1,158 @@
+import * as fs from 'fs';
+import * as os from 'os';
+import * as path from 'path';
+import * as core from '@actions/core';
+import * as io from '@actions/io';
+import * as constants from './constants';
+
+import { getBooleanInput } from './util';
+import { create as xmlCreate } from 'xmlbuilder2';
+
+interface JdkInfo {
+ version: string;
+ vendor: string;
+ id: string;
+ jdkHome: string;
+}
+
+export async function configureToolchains(
+ version: string,
+ distributionName: string,
+ jdkHome: string,
+ toolchainId?: string
+) {
+ const vendor = core.getInput(constants.INPUT_MVN_TOOLCHAIN_VENDOR) || distributionName;
+ const id = toolchainId || `${vendor}_${version}`;
+ const settingsDirectory =
+ core.getInput(constants.INPUT_SETTINGS_PATH) || path.join(os.homedir(), constants.M2_DIR);
+ const overwriteSettings = getBooleanInput(constants.INPUT_OVERWRITE_SETTINGS, true);
+
+ await createToolchainsSettings({
+ jdkInfo: {
+ version,
+ vendor,
+ id,
+ jdkHome
+ },
+ settingsDirectory,
+ overwriteSettings
+ });
+}
+
+export async function createToolchainsSettings({
+ jdkInfo,
+ settingsDirectory,
+ overwriteSettings
+}: {
+ jdkInfo: JdkInfo;
+ settingsDirectory: string;
+ overwriteSettings: boolean;
+}) {
+ core.info(
+ `Creating ${constants.MVN_TOOLCHAINS_FILE} for JDK version ${jdkInfo.version} from ${jdkInfo.vendor}`
+ );
+ // when an alternate m2 location is specified use only that location (no .m2 directory)
+ // otherwise use the home/.m2/ path
+ await io.mkdirP(settingsDirectory);
+ const originalToolchains = await readExistingToolchainsFile(settingsDirectory);
+ const updatedToolchains = generateToolchainDefinition(
+ originalToolchains,
+ jdkInfo.version,
+ jdkInfo.vendor,
+ jdkInfo.id,
+ jdkInfo.jdkHome
+ );
+ await writeToolchainsFileToDisk(settingsDirectory, updatedToolchains, overwriteSettings);
+}
+
+// only exported for testing purposes
+export function generateToolchainDefinition(
+ original: string,
+ version: string,
+ vendor: string,
+ id: string,
+ jdkHome: string
+) {
+ let xmlObj;
+ if (original?.length) {
+ xmlObj = xmlCreate(original)
+ .root()
+ .ele({
+ toolchain: {
+ type: 'jdk',
+ provides: {
+ version: `${version}`,
+ vendor: `${vendor}`,
+ id: `${id}`
+ },
+ configuration: {
+ jdkHome: `${jdkHome}`
+ }
+ }
+ });
+ } else
+ xmlObj = xmlCreate({
+ toolchains: {
+ '@xmlns': 'https://maven.apache.org/TOOLCHAINS/1.1.0',
+ '@xmlns:xsi': 'https://www.w3.org/2001/XMLSchema-instance',
+ '@xsi:schemaLocation':
+ 'https://maven.apache.org/TOOLCHAINS/1.1.0 https://maven.apache.org/xsd/toolchains-1.1.0.xsd',
+ toolchain: [
+ {
+ type: 'jdk',
+ provides: {
+ version: `${version}`,
+ vendor: `${vendor}`,
+ id: `${id}`
+ },
+ configuration: {
+ jdkHome: `${jdkHome}`
+ }
+ }
+ ]
+ }
+ });
+
+ return xmlObj.end({
+ format: 'xml',
+ wellFormed: false,
+ headless: false,
+ prettyPrint: true,
+ width: 80
+ });
+}
+
+async function readExistingToolchainsFile(directory: string) {
+ const location = path.join(directory, constants.MVN_TOOLCHAINS_FILE);
+ if (fs.existsSync(location)) {
+ return fs.readFileSync(location, {
+ encoding: 'utf-8',
+ flag: 'r'
+ });
+ }
+ return '';
+}
+
+async function writeToolchainsFileToDisk(
+ directory: string,
+ settings: string,
+ overwriteSettings: boolean
+) {
+ const location = path.join(directory, constants.MVN_TOOLCHAINS_FILE);
+ const settingsExists = fs.existsSync(location);
+ if (settingsExists && overwriteSettings) {
+ core.info(`Overwriting existing file ${location}`);
+ } else if (!settingsExists) {
+ core.info(`Writing to ${location}`);
+ } else {
+ core.info(
+ `Skipping generation of ${location} because file already exists and overwriting is not enabled`
+ );
+ return;
+ }
+
+ return fs.writeFileSync(location, settings, {
+ encoding: 'utf-8',
+ flag: 'w'
+ });
+}
diff --git a/tsconfig.json b/tsconfig.json
index 9ecff86..5621158 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -6,6 +6,7 @@
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
// "allowJs": true, /* Allow javascript files to be compiled. */
// "checkJs": true, /* Report errors in .js files. */
+ "resolveJsonModule": true,
// "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
// "declaration": true, /* Generates corresponding '.d.ts' file. */
// "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */