Skip to content

Commit 763390a

Browse files
authored
Fix reproducability of builds against Java EA versions (#132847) (#132975)
* Introduce dedicated toolchain resolver for EA java versions * Fix reproducability of builds against Java EA versions This fixes a reproducability issue when using the gradle javaToolChain api. There is no way to test toolchain candidates reliable against the build number in use. This meant that ones you e.g. have resolved some version of java 25, gradle toolchain detection does not detect the difference between certain builds (or even ea vs. released version) Therefore we fallback to rely on our custom JDKDownloadPlugin for now here. Syncing with the gradle team, they want to fix this somewhen in 9.x. We will revisit our solution ones something is available. Ultimately we want to get rid of usages of the JDK download plugin. * Minor cleanup and fixing non set distribution type in jdk * Fix ea jdk selection not just based on major version explicitly requires to add a ea postfix to the runtime sys property * Fix test reproduce linies when using java ea version * Apply review feedback * Use runtime jdk when patching * More cleanup (cherry picked from commit 16fe7db) # Conflicts: # BUILDING.md
1 parent d807aa6 commit 763390a

File tree

21 files changed

+421
-135
lines changed

21 files changed

+421
-135
lines changed

BUILDING.md

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,25 @@ dependencies {
186186

187187
To test an unreleased development version of a third party dependency you have several options.
188188

189+
### How do I test against java early access (ea) versions?
190+
191+
Currently only openjdk EA builds by oracle are supported.
192+
To test against an early access version java version you can pass the major
193+
java version appended with `-ea` as a system property (e.g. -Druntime.java=26-ea) to the Gradle build:
194+
195+
```
196+
./gradlew clean test -Druntime.java=26-ea
197+
```
198+
199+
This will run the tests using the JDK 26 EA version and pick the latest available build of the matching JDK EA version we expose
200+
in our custom jdk catalogue at `https://storage.googleapis.com/elasticsearch-jdk-archive/jdks/openjdk/latest.json`.
201+
202+
To run against a specific build number of the EA build you can pass a second system property (e.g. `-Druntime.java.build=6`):
203+
204+
```
205+
./gradlew clean test -Druntime.java=26-ea -Druntime.java.build=6
206+
```
207+
189208
#### How to use a Maven based third party dependency via `mavenlocal`?
190209

191210
1. Clone the third party repository locally
@@ -229,11 +248,8 @@ In addition to snapshot builds JitPack supports building Pull Requests. Simply u
229248
3. Run the Gradle build as needed. Keep in mind the initial resolution might take a bit longer as this needs to be built
230249
by JitPack in the background before we can resolve the adhoc built dependency.
231250

232-
---
233-
234-
**NOTE**
235-
236-
You should only use that approach locally or on a developer branch for production dependencies as we do
251+
> [!Note]
252+
> You should only use that approach locally or on a developer branch for production dependencies as we do
237253
not want to ship unreleased libraries into our releases.
238254
---
239255

@@ -265,10 +281,8 @@ allprojects {
265281
```
266282
4. Run the Gradle build as needed with `--write-verification-metadata` to ensure the Gradle dependency verification does not fail on your custom dependency.
267283

268-
---
269-
**NOTE**
270-
271-
As Gradle prefers to use modules whose descriptor has been created from real meta-data rather than being generated,
284+
> [!Note]
285+
> As Gradle prefers to use modules whose descriptor has been created from real meta-data rather than being generated,
272286
flat directory repositories cannot be used to override artifacts with real meta-data from other repositories declared in the build.
273287
For example, if Gradle finds only `jmxri-1.2.1.jar` in a flat directory repository, but `jmxri-1.2.1.pom` in another repository
274288
that supports meta-data, it will use the second repository to provide the module.

build-tools-internal/src/integTest/groovy/org/elasticsearch/gradle/fixtures/AbstractGitAwareGradleFuncTest.groovy

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
package org.elasticsearch.gradle.fixtures
1111

1212
import org.apache.commons.io.FileUtils
13-
import org.elasticsearch.gradle.internal.test.InternalAwareGradleRunner
1413
import org.gradle.testkit.runner.GradleRunner
1514
import org.junit.Rule
1615
import org.junit.rules.TemporaryFolder

build-tools-internal/src/integTest/groovy/org/elasticsearch/gradle/internal/JdkDownloadPluginFuncTest.groovy

Lines changed: 36 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,18 @@ class JdkDownloadPluginFuncTest extends AbstractGradleFuncTest {
3333
private static final String ADOPT_JDK_VERSION_15 = "15.0.2+7"
3434
private static final String AZUL_JDK_VERSION_8 = "8u302+b08"
3535
private static final String AZUL_8_DISTRO_VERSION = "8.56.0.23"
36+
private static final String CATALOG_EA_VERSION = "25-ea+30"
3637
private static final String OPEN_JDK_VERSION = "12.0.1+99@123456789123456789123456789abcde"
3738
private static final Pattern JDK_HOME_LOGLINE = Pattern.compile("JDK HOME: (.*)")
3839

40+
def setup() {
41+
configurationCacheCompatible = false // JDK class references configurations which break configuration cache
42+
}
43+
3944
@Unroll
40-
def "jdk #jdkVendor for #platform#suffix are downloaded and extracted"() {
45+
def "jdk #distributionVersion #jdkVendor for #platform#suffix are downloaded and extracted"() {
4146
given:
42-
def mockRepoUrl = urlPath(jdkVendor, jdkVersion, platform, arch);
47+
def mockRepoUrl = urlPath(jdkVendor, jdkVersion, platform, arch, distributionVersion);
4348
def mockedContent = filebytes(jdkVendor, platform)
4449
buildFile.text = """
4550
plugins {
@@ -77,21 +82,26 @@ class JdkDownloadPluginFuncTest extends AbstractGradleFuncTest {
7782

7883
where:
7984
platform | arch | jdkVendor | jdkVersion | distributionVersion | expectedJavaBin | suffix
80-
"linux" | "x64" | VENDOR_ADOPTIUM | ADOPT_JDK_VERSION | null | "bin/java" | ""
81-
"linux" | "x64" | VENDOR_OPENJDK | OPEN_JDK_VERSION | null | "bin/java" | ""
82-
"linux" | "x64" | VENDOR_OPENJDK | OPENJDK_VERSION_OLD | null | "bin/java" | "(old version)"
83-
"windows" | "x64" | VENDOR_ADOPTIUM | ADOPT_JDK_VERSION | null | "bin/java" | ""
84-
"windows" | "x64" | VENDOR_OPENJDK | OPEN_JDK_VERSION | null | "bin/java" | ""
85-
"windows" | "x64" | VENDOR_OPENJDK | OPENJDK_VERSION_OLD | null | "bin/java" | "(old version)"
86-
"darwin" | "x64" | VENDOR_ADOPTIUM | ADOPT_JDK_VERSION | null | "Contents/Home/bin/java" | ""
87-
"darwin" | "x64" | VENDOR_OPENJDK | OPEN_JDK_VERSION | null | "Contents/Home/bin/java" | ""
88-
"darwin" | "x64" | VENDOR_OPENJDK | OPENJDK_VERSION_OLD | null | "Contents/Home/bin/java" | "(old version)"
89-
"mac" | "x64" | VENDOR_OPENJDK | OPEN_JDK_VERSION | null | "Contents/Home/bin/java" | ""
90-
"mac" | "x64" | VENDOR_OPENJDK | OPENJDK_VERSION_OLD | null | "Contents/Home/bin/java" | "(old version)"
91-
"darwin" | "aarch64" | VENDOR_ADOPTIUM | ADOPT_JDK_VERSION | null | "Contents/Home/bin/java" | ""
92-
"linux" | "aarch64" | VENDOR_ADOPTIUM | ADOPT_JDK_VERSION | null | "bin/java" | ""
93-
"linux" | "aarch64" | VENDOR_ADOPTIUM | ADOPT_JDK_VERSION_11 | null | "bin/java" | "(jdk 11)"
94-
"linux" | "aarch64" | VENDOR_ADOPTIUM | ADOPT_JDK_VERSION_15 | null | "bin/java" | "(jdk 15)"
85+
"linux" | "aarch64" | VENDOR_OPENJDK | CATALOG_EA_VERSION | "ea" | "bin/java" | ""
86+
"linux" | "x64" | VENDOR_OPENJDK | CATALOG_EA_VERSION | "ea" | "bin/java" | ""
87+
"darwin" | "aarch64" | VENDOR_OPENJDK | CATALOG_EA_VERSION | "ea" | "Contents/Home/bin/java" | ""
88+
"darwin" | "x64" | VENDOR_OPENJDK | CATALOG_EA_VERSION | "ea" | "Contents/Home/bin/java" | ""
89+
"windows" | "x64" | VENDOR_OPENJDK | CATALOG_EA_VERSION | "ea" | "bin/java" | ""
90+
"linux" | "x64" | VENDOR_ADOPTIUM | ADOPT_JDK_VERSION | "" | "bin/java" | ""
91+
"linux" | "x64" | VENDOR_OPENJDK | OPEN_JDK_VERSION | "" | "bin/java" | ""
92+
"linux" | "x64" | VENDOR_OPENJDK | OPENJDK_VERSION_OLD | "" | "bin/java" | "(old version)"
93+
"windows" | "x64" | VENDOR_ADOPTIUM | ADOPT_JDK_VERSION | "" | "bin/java" | ""
94+
"windows" | "x64" | VENDOR_OPENJDK | OPEN_JDK_VERSION | "" | "bin/java" | ""
95+
"windows" | "x64" | VENDOR_OPENJDK | OPENJDK_VERSION_OLD | "" | "bin/java" | "(old version)"
96+
"darwin" | "x64" | VENDOR_ADOPTIUM | ADOPT_JDK_VERSION | "" | "Contents/Home/bin/java" | ""
97+
"darwin" | "x64" | VENDOR_OPENJDK | OPEN_JDK_VERSION | "" | "Contents/Home/bin/java" | ""
98+
"darwin" | "x64" | VENDOR_OPENJDK | OPENJDK_VERSION_OLD | "" | "Contents/Home/bin/java" | "(old version)"
99+
"mac" | "x64" | VENDOR_OPENJDK | OPEN_JDK_VERSION | "" | "Contents/Home/bin/java" | ""
100+
"mac" | "x64" | VENDOR_OPENJDK | OPENJDK_VERSION_OLD | "" | "Contents/Home/bin/java" | "(old version)"
101+
"darwin" | "aarch64" | VENDOR_ADOPTIUM | ADOPT_JDK_VERSION | "" | "Contents/Home/bin/java" | ""
102+
"linux" | "aarch64" | VENDOR_ADOPTIUM | ADOPT_JDK_VERSION | "" | "bin/java" | ""
103+
"linux" | "aarch64" | VENDOR_ADOPTIUM | ADOPT_JDK_VERSION_11 | "" | "bin/java" | "(jdk 11)"
104+
"linux" | "aarch64" | VENDOR_ADOPTIUM | ADOPT_JDK_VERSION_15 | "" | "bin/java" | "(jdk 15)"
95105
"darwin" | "aarch64" | VENDOR_ZULU | AZUL_JDK_VERSION_8 | AZUL_8_DISTRO_VERSION | "Contents/Home/bin/java" | "(jdk 8)"
96106
}
97107

@@ -214,13 +224,19 @@ class JdkDownloadPluginFuncTest extends AbstractGradleFuncTest {
214224
private static String urlPath(final String vendor,
215225
final String version,
216226
final String platform,
217-
final String arch = 'x64') {
218-
if (vendor.equals(VENDOR_ADOPTIUM)) {
227+
final String arch = 'x64',
228+
final String distributedVersion = '') {
229+
final boolean isOld = version.equals(OPENJDK_VERSION_OLD);
230+
231+
if (distributedVersion.equals("ea")) {
232+
def effectivePlatform = isMac(platform) ? "macos" : platform;
233+
def fileExtension = platform.toLowerCase().equals("windows") ? "zip" : "tar.gz";
234+
return "/jdks/openjdk/25/openjdk-${version}/openjdk-${version}_$effectivePlatform-${arch}_bin.$fileExtension";
235+
} else if (vendor.equals(VENDOR_ADOPTIUM)) {
219236
final String module = isMac(platform) ? "mac" : platform;
220237
return "/jdk-" + version + "/" + module + "/${arch}/jdk/hotspot/normal/adoptium";
221238
} else if (vendor.equals(VENDOR_OPENJDK)) {
222239
final String effectivePlatform = isMac(platform) ? "macos" : platform;
223-
final boolean isOld = version.equals(OPENJDK_VERSION_OLD);
224240
final String versionPath = isOld ? "jdk1/99" : "jdk12.0.1/123456789123456789123456789abcde/99";
225241
final String filename = "openjdk-" + (isOld ? "1" : "12.0.1") + "_" + effectivePlatform + "-x64_bin." + extension(platform);
226242
return "/java/GA/" + versionPath + "/GPL/" + filename;

build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/Jdk.java

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ public class Jdk implements Buildable, Iterable<File> {
3232
"(\\d+)(\\.\\d+\\.\\d+(?:\\.\\d+)?)?\\+(\\d+(?:\\.\\d+)?)(@([a-f0-9]{32}))?"
3333
);
3434
private static final Pattern LEGACY_VERSION_PATTERN = Pattern.compile("(\\d)(u\\d+)\\+(b\\d+?)(@([a-f0-9]{32}))?");
35+
private static final Pattern EA_VERSION_PATTERN = Pattern.compile("(\\d+)-ea\\+(\\d+)(@([a-f0-9]{32}))?");
3536

3637
private final String name;
3738
private final FileCollection configuration;
@@ -78,7 +79,9 @@ public String getVersion() {
7879
}
7980

8081
public void setVersion(String version) {
81-
if (VERSION_PATTERN.matcher(version).matches() == false && LEGACY_VERSION_PATTERN.matcher(version).matches() == false) {
82+
if (VERSION_PATTERN.matcher(version).matches() == false
83+
&& LEGACY_VERSION_PATTERN.matcher(version).matches() == false
84+
&& EA_VERSION_PATTERN.matcher(version).matches() == false) {
8285
throw new IllegalArgumentException("malformed version [" + version + "] for jdk [" + name + "]");
8386
}
8487
parseVersion(version);
@@ -112,7 +115,7 @@ public void setArchitecture(final String architecture) {
112115
}
113116

114117
public String getDistributionVersion() {
115-
return distributionVersion.get();
118+
return distributionVersion.getOrNull();
116119
}
117120

118121
public void setDistributionVersion(String distributionVersion) {
@@ -218,9 +221,17 @@ private void parseVersion(String version) {
218221
if (jdkVersionMatcher.matches() == false) {
219222
// Try again with the pre-Java9 version format
220223
jdkVersionMatcher = LEGACY_VERSION_PATTERN.matcher(version);
221-
222224
if (jdkVersionMatcher.matches() == false) {
223-
throw new IllegalArgumentException("Malformed jdk version [" + version + "]");
225+
// Try again with the pre-Java9 version format
226+
jdkVersionMatcher = EA_VERSION_PATTERN.matcher(version);
227+
if (jdkVersionMatcher.matches() == false) {
228+
throw new IllegalArgumentException("Malformed jdk version [" + version + "]");
229+
}
230+
baseVersion = version;
231+
major = jdkVersionMatcher.group(1);
232+
build = jdkVersionMatcher.group(2);
233+
hash = null;
234+
return;
224235
}
225236
}
226237

build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/JdkDownloadPlugin.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,15 @@ private void setupRepository(Project project, Jdk jdk) {
114114
+ jdk.getBuild()
115115
+ "/[module]/[classifier]/jdk/hotspot/normal/adoptium";
116116
}
117+
} else if (jdk.getVendor().equals(VENDOR_OPENJDK) && "ea".equals(jdk.getDistributionVersion())) {
118+
repoUrl = "https://builds.es-jdk-archive.com/";
119+
// current pattern since 12.0.1
120+
artifactPattern = "jdks/openjdk/"
121+
+ jdk.getMajor()
122+
+ "/openjdk-"
123+
+ jdk.getBaseVersion()
124+
+ "/"
125+
+ "openjdk-[revision]_[module]-[classifier]_bin.[ext]";
117126
} else if (jdk.getVendor().equals(VENDOR_OPENJDK)) {
118127
repoUrl = "https://download.oracle.com";
119128
if (jdk.getHash() != null) {

build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/info/GlobalBuildInfoPlugin.java

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,12 @@
1212
import com.fasterxml.jackson.databind.ObjectMapper;
1313

1414
import org.apache.commons.io.IOUtils;
15+
import org.elasticsearch.gradle.Architecture;
16+
import org.elasticsearch.gradle.OS;
1517
import org.elasticsearch.gradle.VersionProperties;
1618
import org.elasticsearch.gradle.internal.BwcVersions;
19+
import org.elasticsearch.gradle.internal.Jdk;
20+
import org.elasticsearch.gradle.internal.JdkDownloadPlugin;
1721
import org.elasticsearch.gradle.internal.conventions.GitInfoPlugin;
1822
import org.elasticsearch.gradle.internal.conventions.info.GitInfo;
1923
import org.elasticsearch.gradle.internal.conventions.info.ParallelDetector;
@@ -22,6 +26,7 @@
2226
import org.gradle.api.Action;
2327
import org.gradle.api.GradleException;
2428
import org.gradle.api.JavaVersion;
29+
import org.gradle.api.NamedDomainObjectContainer;
2530
import org.gradle.api.Plugin;
2631
import org.gradle.api.Project;
2732
import org.gradle.api.logging.Logger;
@@ -63,6 +68,7 @@
6368
import javax.inject.Inject;
6469

6570
import static org.elasticsearch.gradle.internal.conventions.GUtils.elvis;
71+
import static org.elasticsearch.gradle.internal.toolchain.EarlyAccessCatalogJdkToolchainResolver.findLatestEABuildNumber;
6672

6773
public class GlobalBuildInfoPlugin implements Plugin<Project> {
6874
private static final Logger LOGGER = Logging.getLogger(GlobalBuildInfoPlugin.class);
@@ -92,11 +98,13 @@ public GlobalBuildInfoPlugin(
9298

9399
@Override
94100
public void apply(Project project) {
101+
95102
if (project != project.getRootProject()) {
96103
throw new IllegalStateException(this.getClass().getName() + " can only be applied to the root project.");
97104
}
98105
this.project = project;
99106
project.getPlugins().apply(JvmToolchainsPlugin.class);
107+
project.getPlugins().apply(JdkDownloadPlugin.class);
100108
Provider<GitInfo> gitInfo = project.getPlugins().apply(GitInfoPlugin.class).getGitInfo();
101109

102110
toolChainService = project.getExtensions().getByType(JavaToolchainService.class);
@@ -270,7 +278,9 @@ private JavaVersion determineJavaVersion(String description, File javaHome, Java
270278
private InstallationLocation getJavaInstallation(File javaHome) {
271279
return getAvailableJavaInstallationLocationSteam().filter(installationLocation -> isSameFile(javaHome, installationLocation))
272280
.findFirst()
273-
.orElseThrow(() -> new GradleException("Could not locate available Java installation in Gradle registry at: " + javaHome));
281+
.orElse(
282+
InstallationLocation.userDefined(javaHome, "Manually resolved JavaHome (not auto-detected by Gradle toolchain service)")
283+
);
274284
}
275285

276286
private boolean isSameFile(File javaHome, InstallationLocation installationLocation) {
@@ -338,7 +348,14 @@ private Provider<File> findRuntimeJavaHome() {
338348
String runtimeJavaProperty = System.getProperty("runtime.java");
339349

340350
if (runtimeJavaProperty != null) {
341-
return resolveJavaHomeFromToolChainService(runtimeJavaProperty);
351+
if (runtimeJavaProperty.toLowerCase().endsWith("-ea")) {
352+
// handle EA builds differently due to lack of support in Gradle toolchain service
353+
// we resolve them using JdkDownloadPlugin for now.
354+
Integer major = Integer.parseInt(runtimeJavaProperty.substring(0, runtimeJavaProperty.length() - 3));
355+
return resolveEarlyAccessJavaHome(major);
356+
} else {
357+
return resolveJavaHomeFromToolChainService(runtimeJavaProperty);
358+
}
342359
}
343360
if (System.getenv("RUNTIME_JAVA_HOME") != null) {
344361
return providers.provider(() -> new File(System.getenv("RUNTIME_JAVA_HOME")));
@@ -353,6 +370,23 @@ private Provider<File> findRuntimeJavaHome() {
353370
});
354371
}
355372

373+
private Provider<File> resolveEarlyAccessJavaHome(Integer runtimeJavaProperty) {
374+
NamedDomainObjectContainer<Jdk> container = (NamedDomainObjectContainer<Jdk>) project.getExtensions().getByName("jdks");
375+
Integer buildNumber = Integer.getInteger("runtime.java.build");
376+
if (buildNumber == null) {
377+
buildNumber = findLatestEABuildNumber(runtimeJavaProperty);
378+
}
379+
String eaVersionString = String.format("%d-ea+%d", runtimeJavaProperty, buildNumber);
380+
Jdk jdk = container.create("ea_jdk_" + runtimeJavaProperty, j -> {
381+
j.setVersion(eaVersionString);
382+
j.setVendor("openjdk");
383+
j.setPlatform(OS.current().javaOsReference);
384+
j.setArchitecture(Architecture.current().javaClassifier);
385+
j.setDistributionVersion("ea");
386+
});
387+
return providers.provider(() -> new File(jdk.getJavaHomePath().toString()));
388+
}
389+
356390
@NotNull
357391
private Provider<File> resolveJavaHomeFromToolChainService(String version) {
358392
Property<JavaLanguageVersion> value = objectFactory.property(JavaLanguageVersion.class).value(JavaLanguageVersion.of(version));

0 commit comments

Comments
 (0)