Skip to content

Commit 1ee08f4

Browse files
committed
chore: use Gradle toolchains for JDK provisioning
It enables automatic JDK provisioning (e.g. download), and it enables using different JDKs for executing Gradle and for building JMeter Java version can be specified when building with -PjdkVersion=11 You could use ./gradlew -q javaToolchains to list the detected toolchains. See https://docs.gradle.org/8.0/userguide/toolchains.html#sec:consuming Fixes apache#5986
1 parent 3670413 commit 1ee08f4

21 files changed

+274
-52
lines changed

Diff for: .github/workflows/main.yml

+16-2
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,19 @@ jobs:
4646
- uses: actions/checkout@v3
4747
with:
4848
fetch-depth: 50
49-
- name: Set up Java ${{ matrix.java_version }}, ${{ matrix.java_distribution }}
49+
- name: Set up Java ${{ matrix.java_version }}, oracle
50+
if: ${{ matrix.oracle_java_website != '' }}
51+
uses: oracle-actions/setup-java@1611a647972adb8b04779be3529a044d650fd510 # v1
52+
with:
53+
website: ${{ matrix.oracle_java_website }}
54+
release: ${{ matrix.java_version }}
55+
- name: Set up Java 17 and ${{ matrix.non_ea_java_version }}, ${{ matrix.java_distribution }}
5056
uses: actions/setup-java@v3
5157
with:
52-
java-version: ${{ matrix.java_version }}
58+
# The latest one will be the default, so we use Java 17 for launching Gradle
59+
java-version: |
60+
${{ matrix.non_ea_java_version }}
61+
17
5362
distribution: ${{ matrix.java_distribution }}
5463
architecture: x64
5564
- name: Steps to reproduce
@@ -68,6 +77,11 @@ jobs:
6877
properties: |
6978
testExtraJvmArgs=${{ matrix.testExtraJvmArgs }}
7079
testDisableCaching=${{ matrix.testDisableCaching }}
80+
jdkBuildVersion=17
81+
jdkTestVersion=${{ matrix.java_version }}
82+
jdkTestVendor=${{ matrix.java_vendor }}
83+
# We provision JDKs with GitHub Actions for caching purposes, so Gradle should rather fail in case JDK is not found
84+
org.gradle.java.installations.auto-download=false
7185
env:
7286
_JAVA_OPTIONS: ${{ matrix.extraJvmArgs }}
7387
GRADLE_ENTERPRISE_ACCESS_KEY: ${{ secrets.GE_ACCESS_TOKEN }}

Diff for: .github/workflows/matrix.js

+21-8
Original file line numberDiff line numberDiff line change
@@ -8,23 +8,26 @@ const matrix = new MatrixBuilder();
88
matrix.addAxis({
99
name: 'java_distribution',
1010
values: [
11-
{value: 'corretto', weight: 1},
12-
{value: 'liberica', weight: 1},
13-
{value: 'microsoft', weight: 1},
14-
{value: 'oracle', weight: 1},
15-
{value: 'semeru', weight: 4},
16-
{value: 'temurin', weight: 1},
17-
{value: 'zulu', weight: 1},
11+
{value: 'corretto', vendor: 'amazon', weight: 1},
12+
{value: 'liberica', vendor: 'bellsoft', weight: 1},
13+
{value: 'microsoft', vendor: 'microsoft', weight: 1},
14+
{value: 'oracle', vendor: 'oracle', weight: 1},
15+
{value: 'semeru', vendor: 'ibm', weight: 4},
16+
{value: 'temurin', vendor: 'eclipse', weight: 1},
17+
{value: 'zulu', vendor: 'azul', weight: 1},
1818
]
1919
});
2020

21+
const eaJava = '21';
22+
2123
matrix.addAxis({
2224
name: 'java_version',
2325
// Strings allow versions like 18-ea
2426
values: [
2527
'8',
2628
'11',
2729
'17',
30+
eaJava,
2831
]
2932
});
3033

@@ -74,10 +77,13 @@ matrix.setNamePattern(['java_version', 'java_distribution', 'hash', 'os', 'tz',
7477

7578
// Semeru uses OpenJ9 jit which has no option for making hash codes the same
7679
matrix.exclude({java_distribution: {value: 'semeru'}, hash: {value: 'same'}});
80+
// Semeru 8 fails when Semeru 17 is on the PATH (we use 17 for build)
81+
matrix.exclude({java_distribution: {value: 'semeru'}, java_version: '8'});
7782
// Microsoft Java has no distribution for 8
7883
matrix.exclude({java_distribution: {value: 'microsoft'}, java_version: '8'});
7984
// Oracle JDK is only supported for JDK 17 and later
8085
matrix.exclude({java_distribution: {value: 'oracle'}, java_version: ['8', '11']});
86+
matrix.imply({java_version: eaJava}, {java_distribution: {value: 'oracle'}})
8187
// Ensure at least one job with "same" hashcode exists
8288
matrix.generateRow({hash: {value: 'same'}});
8389
// Ensure at least one Windows and at least one Linux job is present (macOS is almost the same as Linux)
@@ -90,6 +96,8 @@ matrix.generateRow({java_version: "8"});
9096
matrix.generateRow({java_version: "11"});
9197
// Ensure there will be at least one job with Java 17
9298
matrix.generateRow({java_version: "17"});
99+
// Ensure there will be at least one job with Java EA
100+
matrix.generateRow({java_version: eaJava});
93101
const include = matrix.generateRows(process.env.MATRIX_JOBS || 5);
94102
if (include.length === 0) {
95103
throw new Error('Matrix list is empty');
@@ -124,9 +132,14 @@ include.forEach(v => {
124132
jvmArgs.push(`-Duser.country=${v.locale.country}`);
125133
jvmArgs.push(`-Duser.language=${v.locale.language}`);
126134
v.java_distribution = v.java_distribution.value;
135+
v.java_vendor = v.java_distribution.vendor;
136+
if (v.java_distribution === 'oracle') {
137+
v.oracle_java_website = v.java_version === eaJava ? 'jdk.java.net' : 'oracle.com';
138+
}
139+
v.non_ea_java_version = v.java_version === eaJava ? '' : v.java_version;
127140
if (v.java_distribution !== 'semeru' && Math.random() > 0.5) {
128141
// The following options randomize instruction selection in JIT compiler
129-
// so it might reveal missing synchronization in TestNG code
142+
// so it might reveal missing synchronization
130143
v.name += ', stress JIT';
131144
v.testDisableCaching = 'JIT randomization should not be cached';
132145
jvmArgs.push('-XX:+UnlockDiagnosticVMOptions');

Diff for: .github/workflows/matrix_builder.js

+18-5
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ class Axis {
1818
}
1919
if (Array.isArray(filter)) {
2020
// e.g. row={os: 'windows'}; filter=[{os: 'linux'}, {os: 'linux'}]
21-
return filter.find(v => Axis.matches(row, v));
21+
return filter.some(v => Axis.matches(row, v));
2222
}
2323
if (typeof filter === 'object') {
2424
// e.g. row={jdk: {name: 'openjdk', version: 8}}; filter={jdk: {version: 8}}
@@ -68,6 +68,7 @@ class MatrixBuilder {
6868
this.duplicates = {};
6969
this.excludes = [];
7070
this.includes = [];
71+
this.implications = [];
7172
this.failOnUnsatisfiableFilters = false;
7273
}
7374

@@ -80,13 +81,23 @@ class MatrixBuilder {
8081
}
8182

8283
/**
83-
* Specifies exclude filter (e.g. exclude a forbidden combination)
84+
* Specifies exclude filter (e.g. exclude a forbidden combination).
8485
* @param filter
8586
*/
8687
exclude(filter) {
8788
this.excludes.push(filter);
8889
}
8990

91+
/**
92+
* Adds implication like `antecedent -> consequent`.
93+
* In other words, if `antecedent` holds, then `consequent` must also hold.
94+
* @param antecedent
95+
* @param consequent
96+
*/
97+
imply(antecedent, consequent) {
98+
this.implications.push({antecedent: antecedent, consequent: consequent});
99+
}
100+
90101
addAxis({name, title, values}) {
91102
const axis = new Axis({name, title, values});
92103
this.axes.push(axis);
@@ -104,8 +115,10 @@ class MatrixBuilder {
104115
* @returns {boolean}
105116
*/
106117
matches(row) {
107-
return (this.excludes.length === 0 || !this.excludes.find(f => Axis.matches(row, f))) &&
108-
(this.includes.length === 0 || this.includes.find(f => Axis.matches(row, f)));
118+
return (this.excludes.length === 0 || !this.excludes.some(f => Axis.matches(row, f))) &&
119+
(this.includes.length === 0 || this.includes.some(f => Axis.matches(row, f))) &&
120+
(this.implications.length === 0 || (
121+
this.implications.every(i => !Axis.matches(row, i.antecedent) || Axis.matches(row, i.consequent))));
109122
}
110123

111124
failOnUnsatisfiableFilters(value) {
@@ -125,7 +138,7 @@ class MatrixBuilder {
125138
let res;
126139
if (filter) {
127140
// If matching row already exists, no need to generate more
128-
res = this.rows.find(v => Axis.matches(v, filter));
141+
res = this.rows.some(v => Axis.matches(v, filter));
129142
if (res) {
130143
return res;
131144
}

Diff for: README.md

+16-2
Original file line numberDiff line numberDiff line change
@@ -175,14 +175,28 @@ systemProp.https.proxyPassword=your_password
175175

176176
### Test builds
177177

178-
JMeter is built using Gradle.
178+
JMeter is built using Gradle, and it uses [Gradle's Toolchains for JVM projects](https://docs.gradle.org/current/userguide/toolchains.html)
179+
for provisioning JDKs. It means the code would search for the needed JDKs locally, or download them
180+
if they are not found.
181+
182+
By default, the code would use JDK 17 for build purposes, however it would set the target release to 8,
183+
so the resulting artifacts would be compatible with Java 8.
179184

180185
The following command builds and tests JMeter:
181186

182187
```sh
183188
./gradlew build
184189
```
185190

191+
If you want to use a custom JDK for building you can set `-PjdkBuildVersion=11`,
192+
and you can select `-PjdkTestVersion=21` if you want to use a different JDK for testing.
193+
194+
You can list the available build parameters by executing
195+
196+
```sh
197+
./gradlew parameters
198+
```
199+
186200
If the system does not have a GUI display then:
187201

188202
```sh
@@ -196,7 +210,7 @@ The following command would compile the application and enable you to run `jmete
196210
from the `bin` directory.
197211

198212
> **Note** that it completely refreshes `lib/` contents,
199-
so it would remove custom plugins should you have them installed.
213+
so it would remove custom plugins should you have them installed to `lib/`. However, it would keep `lib/ext/` plugins intact.
200214

201215
```sh
202216
./gradlew createDist

Diff for: build-logic/basics/build.gradle.kts

+4
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,7 @@
1818
plugins {
1919
id("build-logic.kotlin-dsl-gradle-plugin")
2020
}
21+
22+
dependencies {
23+
api(projects.buildParameters)
24+
}
+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to you under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
import buildparameters.BuildParametersExtension
19+
import org.gradle.api.JavaVersion
20+
21+
class ToolchainProperties(
22+
val version: Int,
23+
val vendor: String?,
24+
val implementation: String?,
25+
)
26+
27+
val BuildParametersExtension.buildJdk: ToolchainProperties?
28+
get() = jdkBuildVersion.takeIf { it != 0 }
29+
?.let { ToolchainProperties(it, jdkBuildVendor.orNull, jdkBuildImplementation.orNull) }
30+
31+
val BuildParametersExtension.buildJdkVersion: Int
32+
get() = buildJdk?.version ?: JavaVersion.current().majorVersion.toInt()
33+
34+
val BuildParametersExtension.testJdk: ToolchainProperties?
35+
get() = jdkTestVersion.orNull?.takeIf { it != 0 }
36+
?.let { ToolchainProperties(it, jdkTestVendor.orNull, jdkTestImplementation.orNull) }
37+
?: buildJdk
+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to you under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
import org.gradle.api.provider.Provider
19+
import org.gradle.jvm.toolchain.JavaLanguageVersion
20+
import org.gradle.jvm.toolchain.JavaLauncher
21+
import org.gradle.jvm.toolchain.JavaToolchainService
22+
import org.gradle.jvm.toolchain.JavaToolchainSpec
23+
import org.gradle.jvm.toolchain.JvmImplementation
24+
import org.gradle.jvm.toolchain.JvmVendorSpec
25+
26+
fun JavaToolchainService.launcherFor(jdk: ToolchainProperties): Provider<JavaLauncher> = launcherFor {
27+
configureToolchain(jdk)
28+
}
29+
30+
fun JavaToolchainSpec.configureToolchain(jdk: ToolchainProperties?) {
31+
if (jdk == null) {
32+
return
33+
}
34+
languageVersion.set(JavaLanguageVersion.of(jdk.version))
35+
jdk.vendor?.let {
36+
vendor.set(JvmVendorSpec.matching(it))
37+
}
38+
if (jdk.implementation.equals("J9", ignoreCase = true)) {
39+
implementation.set(JvmImplementation.J9)
40+
}
41+
}

Diff for: build-logic/build-parameters/build.gradle.kts

+29
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,39 @@ buildParameters {
2929
defaultValue.set(true)
3030
description.set("Add mavenLocal() to repositories")
3131
}
32+
bool("enableJavaFx") {
33+
defaultValue.set(false)
34+
description.set("Build and include classes that depend on JavaFX. Disabled by default since JavaFX is not included in the default Java distributions")
35+
}
3236
bool("coverage") {
3337
defaultValue.set(false)
3438
description.set("Collect test coverage")
3539
}
40+
integer("targetJavaVersion") {
41+
defaultValue.set(8)
42+
mandatory.set(true)
43+
description.set("Java version for source and target compatibility")
44+
}
45+
integer("jdkBuildVersion") {
46+
defaultValue.set(17)
47+
mandatory.set(true)
48+
description.set("JDK version to use for building JMeter. If the value is 0, then the current Java is used. (see https://docs.gradle.org/8.0/userguide/toolchains.html#sec:consuming)")
49+
}
50+
string("jdkBuildVendor") {
51+
description.set("JDK vendor to use building JMeter (see https://docs.gradle.org/8.0/userguide/toolchains.html#sec:vendors)")
52+
}
53+
string("jdkBuildImplementation") {
54+
description.set("Vendor-specific virtual machine implementation to use building JMeter (see https://docs.gradle.org/8.0/userguide/toolchains.html#selecting_toolchains_by_virtual_machine_implementation)")
55+
}
56+
integer("jdkTestVersion") {
57+
description.set("JDK version to use for testing JMeter. If the value is 0, then the current Java is used. (see https://docs.gradle.org/8.0/userguide/toolchains.html#sec:consuming)")
58+
}
59+
string("jdkTestVendor") {
60+
description.set("JDK vendor to use testing JMeter (see https://docs.gradle.org/8.0/userguide/toolchains.html#sec:vendors)")
61+
}
62+
string("jdkTestImplementation") {
63+
description.set("Vendor-specific virtual machine implementation to use testing JMeter (see https://docs.gradle.org/8.0/userguide/toolchains.html#selecting_toolchains_by_virtual_machine_implementation)")
64+
}
3665
bool("spotbugs") {
3766
defaultValue.set(false)
3867
description.set("Run SpotBugs verifications")

Diff for: build-logic/jvm/src/main/kotlin/build-logic.groovy.gradle.kts

+12
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,20 @@
1515
* limitations under the License.
1616
*/
1717

18+
import com.github.vlsi.gradle.dsl.configureEach
19+
1820
plugins {
1921
id("java")
2022
id("groovy")
2123
id("build-logic.test-spock")
24+
id("com.github.vlsi.gradle-extensions")
25+
id("build-logic.build-params")
26+
}
27+
28+
tasks.configureEach<GroovyCompile> {
29+
buildParameters.testJdk?.let {
30+
javaLauncher.convention(javaToolchains.launcherFor(it))
31+
}
32+
// Support jdk-release to configure the target Java release when compiling the bytecode
33+
// See https://issues.apache.org/jira/browse/GROOVY-11105
2234
}

0 commit comments

Comments
 (0)