Skip to content

Commit b318250

Browse files
authored
[8.19] Fix reproducability of builds against Java EA versions (elastic#132847) (elastic#132977)
* Fix reproducability of builds against Java EA versions (elastic#132847) * 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 # build-tools-internal/src/integTest/groovy/org/elasticsearch/gradle/internal/JdkDownloadPluginFuncTest.groovy * Fix jdkdownload tests
1 parent 08c7804 commit b318250

File tree

21 files changed

+426
-141
lines changed

21 files changed

+426
-141
lines changed

BUILDING.md

Lines changed: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -92,10 +92,10 @@ uses the changed dependencies. In most cases, `precommit` or `check` are good ca
9292
We prefer sha256 checksums as md5 and sha1 are not considered safe anymore these days. The generated entry
9393
will have the `origin` attribute been set to `Generated by Gradle`.
9494

95-
>A manual confirmation of the Gradle generated checksums is currently not mandatory.
96-
>If you want to add a level of verification you can manually confirm the checksum (e.g. by looking it up on the website of the library)
97-
>Please replace the content of the `origin` attribute by `official site` in that case.
98-
>
95+
> [!Tip]
96+
> A manual confirmation of the Gradle generated checksums is currently not mandatory.
97+
> If you want to add a level of verification you can manually confirm the checksum (e.g. by looking it up on the website of the library)
98+
> Please replace the content of the `origin` attribute by `official site` in that case.
9999
100100
#### Custom plugin and task implementations
101101

@@ -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: 37 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -33,17 +33,20 @@ class JdkDownloadPluginFuncTest extends AbstractGradleFuncTest {
3333
private static final String ADOPT_JDK_VERSION = "12.0.2+10"
3434
private static final String ADOPT_JDK_VERSION_11 = "11.0.10+9"
3535
private static final String ADOPT_JDK_VERSION_15 = "15.0.2+7"
36+
private static final String AZUL_JDK_VERSION_8 = "8u302+b08"
37+
private static final String AZUL_8_DISTRO_VERSION = "8.56.0.23"
38+
private static final String CATALOG_EA_VERSION = "25-ea+30"
3639
private static final String OPEN_JDK_VERSION = "12.0.1+99@123456789123456789123456789abcde"
3740
private static final Pattern JDK_HOME_LOGLINE = Pattern.compile("JDK HOME: (.*)")
3841

3942
def setup() {
40-
configurationCacheCompatible = false
43+
configurationCacheCompatible = false // JDK class references configurations which break configuration cache
4144
}
4245

4346
@Unroll
44-
def "jdk #jdkVendor for #platform#suffix are downloaded and extracted"() {
47+
def "jdk #distributionVersion #jdkVendor for #platform#suffix are downloaded and extracted"() {
4548
given:
46-
def mockRepoUrl = urlPath(jdkVendor, jdkVersion, platform, arch);
49+
def mockRepoUrl = urlPath(jdkVendor, jdkVersion, platform, arch, distributionVersion);
4750
def mockedContent = filebytes(jdkVendor, platform)
4851
buildFile.text = """
4952
plugins {
@@ -56,6 +59,7 @@ class JdkDownloadPluginFuncTest extends AbstractGradleFuncTest {
5659
version = '$jdkVersion'
5760
platform = "$platform"
5861
architecture = '$arch'
62+
distributionVersion = '$distributionVersion'
5963
}
6064
}
6165
@@ -78,22 +82,27 @@ class JdkDownloadPluginFuncTest extends AbstractGradleFuncTest {
7882
assertExtraction(result.output, expectedJavaBin);
7983

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

99108
def "transforms are reused across projects"() {
@@ -211,13 +220,19 @@ class JdkDownloadPluginFuncTest extends AbstractGradleFuncTest {
211220
private static String urlPath(final String vendor,
212221
final String version,
213222
final String platform,
214-
final String arch = 'x64') {
215-
if (vendor.equals(VENDOR_ADOPTIUM)) {
223+
final String arch = 'x64',
224+
final String distributedVersion = '') {
225+
final boolean isOld = version.equals(OPENJDK_VERSION_OLD)
226+
227+
if (distributedVersion.equals("ea")) {
228+
def effectivePlatform = isMac(platform) ? "macos" : platform;
229+
def fileExtension = platform.toLowerCase().equals("windows") ? "zip" : "tar.gz";
230+
return "/jdks/openjdk/25/openjdk-${version}/openjdk-${version}_$effectivePlatform-${arch}_bin.$fileExtension";
231+
} else if (vendor.equals(VENDOR_ADOPTIUM)) {
216232
final String module = isMac(platform) ? "mac" : platform;
217233
return "/jdk-" + version + "/" + module + "/${arch}/jdk/hotspot/normal/adoptium";
218234
} else if (vendor.equals(VENDOR_OPENJDK)) {
219235
final String effectivePlatform = isMac(platform) ? "macos" : platform;
220-
final boolean isOld = version.equals(OPENJDK_VERSION_OLD);
221236
final String versionPath = isOld ? "jdk1/99" : "jdk12.0.1/123456789123456789123456789abcde/99";
222237
final String filename = "openjdk-" + (isOld ? "1" : "12.0.1") + "_" + effectivePlatform + "-x64_bin." + extension(platform);
223238
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
@@ -31,6 +31,7 @@ public class Jdk implements Buildable, Iterable<File> {
3131
"(\\d+)(\\.\\d+\\.\\d+(?:\\.\\d+)?)?\\+(\\d+(?:\\.\\d+)?)(@([a-f0-9]{32}))?"
3232
);
3333
private static final Pattern LEGACY_VERSION_PATTERN = Pattern.compile("(\\d)(u\\d+)\\+(b\\d+?)(@([a-f0-9]{32}))?");
34+
private static final Pattern EA_VERSION_PATTERN = Pattern.compile("(\\d+)-ea\\+(\\d+)(@([a-f0-9]{32}))?");
3435

3536
private final String name;
3637
private final Configuration configuration;
@@ -75,7 +76,9 @@ public String getVersion() {
7576
}
7677

7778
public void setVersion(String version) {
78-
if (VERSION_PATTERN.matcher(version).matches() == false && LEGACY_VERSION_PATTERN.matcher(version).matches() == false) {
79+
if (VERSION_PATTERN.matcher(version).matches() == false
80+
&& LEGACY_VERSION_PATTERN.matcher(version).matches() == false
81+
&& EA_VERSION_PATTERN.matcher(version).matches() == false) {
7982
throw new IllegalArgumentException("malformed version [" + version + "] for jdk [" + name + "]");
8083
}
8184
parseVersion(version);
@@ -109,7 +112,7 @@ public void setArchitecture(final String architecture) {
109112
}
110113

111114
public String getDistributionVersion() {
112-
return distributionVersion.get();
115+
return distributionVersion.getOrNull();
113116
}
114117

115118
public void setDistributionVersion(String distributionVersion) {
@@ -215,9 +218,17 @@ private void parseVersion(String version) {
215218
if (jdkVersionMatcher.matches() == false) {
216219
// Try again with the pre-Java9 version format
217220
jdkVersionMatcher = LEGACY_VERSION_PATTERN.matcher(version);
218-
219221
if (jdkVersionMatcher.matches() == false) {
220-
throw new IllegalArgumentException("Malformed jdk version [" + version + "]");
222+
// Try again with the pre-Java9 version format
223+
jdkVersionMatcher = EA_VERSION_PATTERN.matcher(version);
224+
if (jdkVersionMatcher.matches() == false) {
225+
throw new IllegalArgumentException("Malformed jdk version [" + version + "]");
226+
}
227+
baseVersion = version;
228+
major = jdkVersionMatcher.group(1);
229+
build = jdkVersionMatcher.group(2);
230+
hash = null;
231+
return;
221232
}
222233
}
223234

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
@@ -115,6 +115,15 @@ private void setupRepository(Project project, Jdk jdk) {
115115
+ jdk.getBuild()
116116
+ "/[module]/[classifier]/jdk/hotspot/normal/adoptium";
117117
}
118+
} else if (jdk.getVendor().equals(VENDOR_OPENJDK) && "ea".equals(jdk.getDistributionVersion())) {
119+
repoUrl = "https://builds.es-jdk-archive.com/";
120+
// current pattern since 12.0.1
121+
artifactPattern = "jdks/openjdk/"
122+
+ jdk.getMajor()
123+
+ "/openjdk-"
124+
+ jdk.getBaseVersion()
125+
+ "/"
126+
+ "openjdk-[revision]_[module]-[classifier]_bin.[ext]";
118127
} else if (jdk.getVendor().equals(VENDOR_OPENJDK)) {
119128
repoUrl = "https://download.oracle.com";
120129
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);
@@ -277,7 +285,9 @@ private JavaVersion determineJavaVersion(String description, File javaHome, Java
277285
private InstallationLocation getJavaInstallation(File javaHome) {
278286
return getAvailableJavaInstallationLocationSteam().filter(installationLocation -> isSameFile(javaHome, installationLocation))
279287
.findFirst()
280-
.orElseThrow(() -> new GradleException("Could not locate available Java installation in Gradle registry at: " + javaHome));
288+
.orElse(
289+
InstallationLocation.userDefined(javaHome, "Manually resolved JavaHome (not auto-detected by Gradle toolchain service)")
290+
);
281291
}
282292

283293
private boolean isSameFile(File javaHome, InstallationLocation installationLocation) {
@@ -345,7 +355,14 @@ private Provider<File> findRuntimeJavaHome() {
345355
String runtimeJavaProperty = System.getProperty("runtime.java");
346356

347357
if (runtimeJavaProperty != null) {
348-
return resolveJavaHomeFromToolChainService(runtimeJavaProperty);
358+
if (runtimeJavaProperty.toLowerCase().endsWith("-ea")) {
359+
// handle EA builds differently due to lack of support in Gradle toolchain service
360+
// we resolve them using JdkDownloadPlugin for now.
361+
Integer major = Integer.parseInt(runtimeJavaProperty.substring(0, runtimeJavaProperty.length() - 3));
362+
return resolveEarlyAccessJavaHome(major);
363+
} else {
364+
return resolveJavaHomeFromToolChainService(runtimeJavaProperty);
365+
}
349366
}
350367
if (System.getenv("RUNTIME_JAVA_HOME") != null) {
351368
return providers.provider(() -> new File(System.getenv("RUNTIME_JAVA_HOME")));
@@ -360,6 +377,23 @@ private Provider<File> findRuntimeJavaHome() {
360377
});
361378
}
362379

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

0 commit comments

Comments
 (0)