Skip to content

Commit e150063

Browse files
Merge pull request actions#282 from Okeanos/maven-toolchains-support
Add Maven Toolchains Declaration (actions#276)
2 parents 499ae9c + eb1418a commit e150063

File tree

11 files changed

+774
-20
lines changed

11 files changed

+774
-20
lines changed

README.md

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ The `setup-java` action provides the following functionality for GitHub Actions
1212
- Caching dependencies managed by Apache Maven
1313
- Caching dependencies managed by Gradle
1414
- Caching dependencies managed by sbt
15+
- [Maven Toolchains declaration](https://maven.apache.org/guides/mini/guide-using-toolchains.html) for specified JDK versions
1516

1617
This action allows you to work with Java and Scala projects.
1718

@@ -37,7 +38,7 @@ This action allows you to work with Java and Scala projects.
3738
- `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".
3839

3940
#### Maven options
40-
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. See [advanced usage](docs/advanced-usage.md) for more.
41+
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.
4142

4243
- `overwrite-settings`: By default action overwrites the settings.xml. In order to skip generation of file if it exists set this to `false`.
4344

@@ -53,6 +54,10 @@ This action allows you to work with Java and Scala projects.
5354

5455
- `gpg-passphrase`: description: 'Environment variable name for the GPG private key passphrase. Default is GPG_PASSPHRASE.
5556

57+
- `mvn-toolchain-id`: Name of Maven Toolchain ID if the default name of `${distribution}_${java-version}` is not wanted.
58+
59+
- `mvn-toolchain-vendor`: Name of Maven Toolchain Vendor if the default name of `${distribution}` is not wanted.
60+
5661
### Basic Configuration
5762

5863
#### Eclipse Temurin
@@ -203,7 +208,11 @@ All versions are added to the PATH. The last version will be used and available
203208
15
204209
```
205210

211+
### Using Maven Toolchains
212+
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.
213+
206214
### Advanced Configuration
215+
207216
- [Selecting a Java distribution](docs/advanced-usage.md#Selecting-a-Java-distribution)
208217
- [Eclipse Temurin](docs/advanced-usage.md#Eclipse-Temurin)
209218
- [Adopt](docs/advanced-usage.md#Adopt)
@@ -219,6 +228,7 @@ All versions are added to the PATH. The last version will be used and available
219228
- [Publishing using Apache Maven](docs/advanced-usage.md#Publishing-using-Apache-Maven)
220229
- [Publishing using Gradle](docs/advanced-usage.md#Publishing-using-Gradle)
221230
- [Hosted Tool Cache](docs/advanced-usage.md#Hosted-Tool-Cache)
231+
- [Modifying Maven Toolchains](docs/advanced-usage.md#Modifying-Maven-Toolchains)
222232

223233
## License
224234

__tests__/auth.test.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,10 @@ import * as core from '@actions/core';
55
import os from 'os';
66

77
import * as auth from '../src/auth';
8+
import { M2_DIR, MVN_SETTINGS_FILE } from '../src/constants';
89

9-
const m2Dir = path.join(__dirname, auth.M2_DIR);
10-
const settingsFile = path.join(m2Dir, auth.SETTINGS_FILE);
10+
const m2Dir = path.join(__dirname, M2_DIR);
11+
const settingsFile = path.join(m2Dir, MVN_SETTINGS_FILE);
1112

1213
describe('auth tests', () => {
1314
let spyOSHomedir: jest.SpyInstance;
@@ -38,7 +39,7 @@ describe('auth tests', () => {
3839
const password = 'TOLKIEN';
3940

4041
const altHome = path.join(__dirname, 'runner', 'settings');
41-
const altSettingsFile = path.join(altHome, auth.SETTINGS_FILE);
42+
const altSettingsFile = path.join(altHome, MVN_SETTINGS_FILE);
4243
await io.rmRF(altHome); // ensure it doesn't already exist
4344

4445
await auth.createAuthenticationSettings(id, username, password, altHome, true);

__tests__/toolchains.test.ts

Lines changed: 292 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,292 @@
1+
import * as fs from 'fs';
2+
import os from 'os';
3+
import * as path from 'path';
4+
import * as core from '@actions/core';
5+
import * as io from '@actions/io';
6+
import * as toolchains from '../src/toolchains';
7+
import { M2_DIR, MVN_TOOLCHAINS_FILE } from '../src/constants';
8+
9+
const m2Dir = path.join(__dirname, M2_DIR);
10+
const toolchainsFile = path.join(m2Dir, MVN_TOOLCHAINS_FILE);
11+
12+
describe('toolchains tests', () => {
13+
let spyOSHomedir: jest.SpyInstance;
14+
let spyInfo: jest.SpyInstance;
15+
16+
beforeEach(async () => {
17+
await io.rmRF(m2Dir);
18+
spyOSHomedir = jest.spyOn(os, 'homedir');
19+
spyOSHomedir.mockReturnValue(__dirname);
20+
spyInfo = jest.spyOn(core, 'info');
21+
spyInfo.mockImplementation(() => null);
22+
}, 300000);
23+
24+
afterAll(async () => {
25+
try {
26+
await io.rmRF(m2Dir);
27+
} catch {
28+
console.log('Failed to remove test directories');
29+
}
30+
jest.resetAllMocks();
31+
jest.clearAllMocks();
32+
jest.restoreAllMocks();
33+
}, 100000);
34+
35+
it('creates toolchains.xml in alternate locations', async () => {
36+
const jdkInfo = {
37+
version: '17',
38+
vendor: 'Eclipse Temurin',
39+
id: 'temurin_17',
40+
jdkHome: '/opt/hostedtoolcache/Java_Temurin-Hotspot_jdk/17.0.1-12/x64'
41+
};
42+
43+
const altHome = path.join(__dirname, 'runner', 'toolchains');
44+
const altToolchainsFile = path.join(altHome, MVN_TOOLCHAINS_FILE);
45+
await io.rmRF(altHome); // ensure it doesn't already exist
46+
47+
await toolchains.createToolchainsSettings({
48+
jdkInfo,
49+
settingsDirectory: altHome,
50+
overwriteSettings: true
51+
});
52+
53+
expect(fs.existsSync(m2Dir)).toBe(false);
54+
expect(fs.existsSync(toolchainsFile)).toBe(false);
55+
56+
expect(fs.existsSync(altHome)).toBe(true);
57+
expect(fs.existsSync(altToolchainsFile)).toBe(true);
58+
expect(fs.readFileSync(altToolchainsFile, 'utf-8')).toEqual(
59+
toolchains.generateToolchainDefinition(
60+
'',
61+
jdkInfo.version,
62+
jdkInfo.vendor,
63+
jdkInfo.id,
64+
jdkInfo.jdkHome
65+
)
66+
);
67+
68+
await io.rmRF(altHome);
69+
}, 100000);
70+
71+
it('creates toolchains.xml with minimal configuration', async () => {
72+
const jdkInfo = {
73+
version: '17',
74+
vendor: 'Eclipse Temurin',
75+
id: 'temurin_17',
76+
jdkHome: '/opt/hostedtoolcache/Java_Temurin-Hotspot_jdk/17.0.1-12/x64'
77+
};
78+
79+
const result = `<?xml version="1.0"?>
80+
<toolchains xmlns="https://maven.apache.org/TOOLCHAINS/1.1.0"
81+
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
82+
xsi:schemaLocation="https://maven.apache.org/TOOLCHAINS/1.1.0 https://maven.apache.org/xsd/toolchains-1.1.0.xsd">
83+
<toolchain>
84+
<type>jdk</type>
85+
<provides>
86+
<version>17</version>
87+
<vendor>Eclipse Temurin</vendor>
88+
<id>temurin_17</id>
89+
</provides>
90+
<configuration>
91+
<jdkHome>/opt/hostedtoolcache/Java_Temurin-Hotspot_jdk/17.0.1-12/x64</jdkHome>
92+
</configuration>
93+
</toolchain>
94+
</toolchains>`;
95+
96+
await toolchains.createToolchainsSettings({
97+
jdkInfo,
98+
settingsDirectory: m2Dir,
99+
overwriteSettings: true
100+
});
101+
102+
expect(fs.existsSync(m2Dir)).toBe(true);
103+
expect(fs.existsSync(toolchainsFile)).toBe(true);
104+
expect(fs.readFileSync(toolchainsFile, 'utf-8')).toEqual(
105+
toolchains.generateToolchainDefinition(
106+
'',
107+
jdkInfo.version,
108+
jdkInfo.vendor,
109+
jdkInfo.id,
110+
jdkInfo.jdkHome
111+
)
112+
);
113+
expect(
114+
toolchains.generateToolchainDefinition(
115+
'',
116+
jdkInfo.version,
117+
jdkInfo.vendor,
118+
jdkInfo.id,
119+
jdkInfo.jdkHome
120+
)
121+
).toEqual(result);
122+
}, 100000);
123+
124+
it('reuses existing toolchains.xml files', async () => {
125+
const jdkInfo = {
126+
version: '17',
127+
vendor: 'Eclipse Temurin',
128+
id: 'temurin_17',
129+
jdkHome: '/opt/hostedtoolcache/Java_Temurin-Hotspot_jdk/17.0.1-12/x64'
130+
};
131+
132+
const originalFile = `<toolchains>
133+
<toolchain>
134+
<type>jdk</type>
135+
<provides>
136+
<version>1.6</version>
137+
<vendor>Sun</vendor>
138+
<id>sun_1.6</id>
139+
</provides>
140+
<configuration>
141+
<jdkHome>/opt/jdk/sun/1.6</jdkHome>
142+
</configuration>
143+
</toolchain>
144+
</toolchains>`;
145+
const result = `<?xml version="1.0"?>
146+
<toolchains>
147+
<toolchain>
148+
<type>jdk</type>
149+
<provides>
150+
<version>1.6</version>
151+
<vendor>Sun</vendor>
152+
<id>sun_1.6</id>
153+
</provides>
154+
<configuration>
155+
<jdkHome>/opt/jdk/sun/1.6</jdkHome>
156+
</configuration>
157+
</toolchain>
158+
<toolchain>
159+
<type>jdk</type>
160+
<provides>
161+
<version>17</version>
162+
<vendor>Eclipse Temurin</vendor>
163+
<id>temurin_17</id>
164+
</provides>
165+
<configuration>
166+
<jdkHome>/opt/hostedtoolcache/Java_Temurin-Hotspot_jdk/17.0.1-12/x64</jdkHome>
167+
</configuration>
168+
</toolchain>
169+
</toolchains>`;
170+
171+
fs.mkdirSync(m2Dir, { recursive: true });
172+
fs.writeFileSync(toolchainsFile, originalFile);
173+
expect(fs.existsSync(m2Dir)).toBe(true);
174+
expect(fs.existsSync(toolchainsFile)).toBe(true);
175+
176+
await toolchains.createToolchainsSettings({
177+
jdkInfo,
178+
settingsDirectory: m2Dir,
179+
overwriteSettings: true
180+
});
181+
182+
expect(fs.existsSync(m2Dir)).toBe(true);
183+
expect(fs.existsSync(toolchainsFile)).toBe(true);
184+
expect(fs.readFileSync(toolchainsFile, 'utf-8')).toEqual(
185+
toolchains.generateToolchainDefinition(
186+
originalFile,
187+
jdkInfo.version,
188+
jdkInfo.vendor,
189+
jdkInfo.id,
190+
jdkInfo.jdkHome
191+
)
192+
);
193+
expect(
194+
toolchains.generateToolchainDefinition(
195+
originalFile,
196+
jdkInfo.version,
197+
jdkInfo.vendor,
198+
jdkInfo.id,
199+
jdkInfo.jdkHome
200+
)
201+
).toEqual(result);
202+
}, 100000);
203+
204+
it('does not overwrite existing toolchains.xml files', async () => {
205+
const jdkInfo = {
206+
version: '17',
207+
vendor: 'Eclipse Temurin',
208+
id: 'temurin_17',
209+
jdkHome: '/opt/hostedtoolcache/Java_Temurin-Hotspot_jdk/17.0.1-12/x64'
210+
};
211+
212+
const originalFile = `<toolchains>
213+
<toolchain>
214+
<type>jdk</type>
215+
<provides>
216+
<version>1.6</version>
217+
<vendor>Sun</vendor>
218+
<id>sun_1.6</id>
219+
</provides>
220+
<configuration>
221+
<jdkHome>/opt/jdk/sun/1.6</jdkHome>
222+
</configuration>
223+
</toolchain>
224+
</toolchains>`;
225+
226+
fs.mkdirSync(m2Dir, { recursive: true });
227+
fs.writeFileSync(toolchainsFile, originalFile);
228+
expect(fs.existsSync(m2Dir)).toBe(true);
229+
expect(fs.existsSync(toolchainsFile)).toBe(true);
230+
231+
await toolchains.createToolchainsSettings({
232+
jdkInfo,
233+
settingsDirectory: m2Dir,
234+
overwriteSettings: false
235+
});
236+
237+
expect(fs.existsSync(m2Dir)).toBe(true);
238+
expect(fs.existsSync(toolchainsFile)).toBe(true);
239+
expect(fs.readFileSync(toolchainsFile, 'utf-8')).toEqual(originalFile);
240+
}, 100000);
241+
242+
it('generates valid toolchains.xml with minimal configuration', () => {
243+
const jdkInfo = {
244+
version: 'JAVA_VERSION',
245+
vendor: 'JAVA_VENDOR',
246+
id: 'VENDOR_VERSION',
247+
jdkHome: 'JAVA_HOME'
248+
};
249+
250+
const expectedToolchains = `<?xml version="1.0"?>
251+
<toolchains xmlns="https://maven.apache.org/TOOLCHAINS/1.1.0"
252+
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
253+
xsi:schemaLocation="https://maven.apache.org/TOOLCHAINS/1.1.0 https://maven.apache.org/xsd/toolchains-1.1.0.xsd">
254+
<toolchain>
255+
<type>jdk</type>
256+
<provides>
257+
<version>${jdkInfo.version}</version>
258+
<vendor>${jdkInfo.vendor}</vendor>
259+
<id>${jdkInfo.id}</id>
260+
</provides>
261+
<configuration>
262+
<jdkHome>${jdkInfo.jdkHome}</jdkHome>
263+
</configuration>
264+
</toolchain>
265+
</toolchains>`;
266+
267+
expect(
268+
toolchains.generateToolchainDefinition(
269+
'',
270+
jdkInfo.version,
271+
jdkInfo.vendor,
272+
jdkInfo.id,
273+
jdkInfo.jdkHome
274+
)
275+
).toEqual(expectedToolchains);
276+
}, 100000);
277+
278+
it('creates toolchains.xml with correct id when none is supplied', async () => {
279+
const version = '17';
280+
const distributionName = 'temurin';
281+
const id = 'temurin_17';
282+
const jdkHome = '/opt/hostedtoolcache/Java_Temurin-Hotspot_jdk/17.0.1-12/x64';
283+
284+
await toolchains.configureToolchains(version, distributionName, jdkHome, undefined);
285+
286+
expect(fs.existsSync(m2Dir)).toBe(true);
287+
expect(fs.existsSync(toolchainsFile)).toBe(true);
288+
expect(fs.readFileSync(toolchainsFile, 'utf-8')).toEqual(
289+
toolchains.generateToolchainDefinition('', version, distributionName, id, jdkHome)
290+
);
291+
}, 100000);
292+
});

action.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,12 @@ inputs:
6262
token:
6363
description: Used to pull java versions from setup-java. Since there is a default value, token is typically not supplied by the user.
6464
default: ${{ github.token }}
65+
mvn-toolchain-id:
66+
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'
67+
required: false
68+
mvn-toolchain-vendor:
69+
description: 'Name of Maven Toolchain Vendor if the default name of "${distribution}" is not wanted. See examples of supported syntax in Advanced Usage file'
70+
required: false
6571
outputs:
6672
distribution:
6773
description: 'Distribution of Java that has been installed'

dist/cleanup/index.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68406,7 +68406,7 @@ else {
6840668406
"use strict";
6840768407

6840868408
Object.defineProperty(exports, "__esModule", ({ value: true }));
68409-
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;
68409+
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;
6841068410
exports.MACOS_JAVA_CONTENT_POSTFIX = 'Contents/Home';
6841168411
exports.INPUT_JAVA_VERSION = 'java-version';
6841268412
exports.INPUT_ARCHITECTURE = 'architecture';
@@ -68426,6 +68426,11 @@ exports.INPUT_DEFAULT_GPG_PASSPHRASE = 'GPG_PASSPHRASE';
6842668426
exports.INPUT_CACHE = 'cache';
6842768427
exports.INPUT_JOB_STATUS = 'job-status';
6842868428
exports.STATE_GPG_PRIVATE_KEY_FINGERPRINT = 'gpg-private-key-fingerprint';
68429+
exports.M2_DIR = '.m2';
68430+
exports.MVN_SETTINGS_FILE = 'settings.xml';
68431+
exports.MVN_TOOLCHAINS_FILE = 'toolchains.xml';
68432+
exports.INPUT_MVN_TOOLCHAIN_ID = 'mvn-toolchain-id';
68433+
exports.INPUT_MVN_TOOLCHAIN_VENDOR = 'mvn-toolchain-vendor';
6842968434

6843068435

6843168436
/***/ }),

0 commit comments

Comments
 (0)