From 28df80b0112af2eee9364158c09173ac2201e7ac Mon Sep 17 00:00:00 2001 From: Brice Dutheil Date: Thu, 4 Jun 2026 14:27:11 +0200 Subject: [PATCH 1/8] ci(gitlab): enable Gradle colored console Gradle 9.1.0 introduced the colored console mode for color highlighting in plain logs without rich progress bars: https://docs.gradle.org/9.1.0/release-notes.html#plain-console-with-colors Use that mode through GRADLE_OPTS so GitLab jobs can render ANSI color while keeping the existing JVM argument configuration. --- .gitlab-ci.yml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 6b29a12668b..87a6bd39de1 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -50,6 +50,7 @@ variables: DEPENDENCY_CACHE_POLICY: pull BUILD_CACHE_POLICY: pull GRADLE_VERSION: "9.5.1" # must match gradle-wrapper.properties + GRADLE_CONSOLE_OPTS: "-Dorg.gradle.console=colored" MASS_READ_URL: "https://mass-read.us1.ddbuild.io" MAVEN_REPOSITORY_PROXY: "https://depot-read-api-java.us1.ddbuild.io/magicmirror/magicmirror/@current/" GRADLE_PLUGIN_PROXY: "https://depot-read-api-java.us1.ddbuild.io/magicmirror/magicmirror/@current/" @@ -243,7 +244,7 @@ default: rm -rf "$HOME/.m2/repository/dev/equo" ln -s "$(pwd)/.mvn/caches/equo" "$HOME/.m2/repository/dev/equo" fi - - export GRADLE_OPTS="-Dorg.gradle.jvmargs='-Xms$GRADLE_MEMORY_MIN -Xmx$GRADLE_MEMORY_MAX -XX:ErrorFile=/tmp/hs_err_pid%p.log -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp'" + - export GRADLE_OPTS="$GRADLE_CONSOLE_OPTS -Dorg.gradle.jvmargs='-Xms$GRADLE_MEMORY_MIN -Xmx$GRADLE_MEMORY_MAX -XX:ErrorFile=/tmp/hs_err_pid%p.log -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp'" - export GRADLE_ARGS=" --build-cache --stacktrace --no-daemon --parallel --max-workers=$GRADLE_WORKERS" - *normalize_node_index # GitLab's cache helper restores .gradle as root, but we run as non-root-user (uid 1001), @@ -458,10 +459,10 @@ test_published_artifacts: - rm -rf "${mvn_local_repo}/com/datadoghq" - export GPG_PRIVATE_KEY=$(aws ssm get-parameter --region us-east-1 --name ci.dd-trace-java.signing.gpg_private_key --with-decryption --query "Parameter.Value" --out text) - export GPG_PASSWORD=$(aws ssm get-parameter --region us-east-1 --name ci.dd-trace-java.signing.gpg_passphrase --with-decryption --query "Parameter.Value" --out text) - - export GRADLE_OPTS="-Dorg.gradle.jvmargs='-Xms2G -Xmx2G -XX:ErrorFile=/tmp/hs_err_pid%p.log -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp'" + - export GRADLE_OPTS="$GRADLE_CONSOLE_OPTS -Dorg.gradle.jvmargs='-Xms2G -Xmx2G -XX:ErrorFile=/tmp/hs_err_pid%p.log -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp'" - ./gradlew publishToMavenLocal $GRADLE_ARGS - cd test-published-dependencies - - export GRADLE_OPTS="-Dorg.gradle.jvmargs='-Xms1G -Xmx1G -XX:ErrorFile=/tmp/hs_err_pid%p.log -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp'" + - export GRADLE_OPTS="$GRADLE_CONSOLE_OPTS -Dorg.gradle.jvmargs='-Xms1G -Xmx1G -XX:ErrorFile=/tmp/hs_err_pid%p.log -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp'" - ./gradlew --version - ./gradlew check --info $GRADLE_ARGS after_script: @@ -669,7 +670,7 @@ muzzle-dep-report: export PROFILER_COMMAND="-XX:StartFlightRecording=settings=profile,filename=/tmp/${CI_JOB_NAME_SLUG}.jfr,dumponexit=true"; fi - *prepare_test_env - - export GRADLE_OPTS="-Dorg.gradle.jvmargs='-Xms$GRADLE_MEMORY_MIN -Xmx$GRADLE_MEMORY_MAX $PROFILER_COMMAND -XX:ErrorFile=/tmp/hs_err_pid%p.log -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp -Djava.util.prefs.userRoot=/tmp/.java/.userPrefs-${CI_JOB_ID}' -Ddatadog.forkedMinHeapSize=128M -Ddatadog.forkedMaxHeapSize=1024M" + - export GRADLE_OPTS="$GRADLE_CONSOLE_OPTS -Dorg.gradle.jvmargs='-Xms$GRADLE_MEMORY_MIN -Xmx$GRADLE_MEMORY_MAX $PROFILER_COMMAND -XX:ErrorFile=/tmp/hs_err_pid%p.log -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp -Djava.util.prefs.userRoot=/tmp/.java/.userPrefs-${CI_JOB_ID}' -Ddatadog.forkedMinHeapSize=128M -Ddatadog.forkedMaxHeapSize=1024M" - ./gradlew --version - ./gradlew $GRADLE_TARGET $GRADLE_PARAMS -PtestJvm=$testJvm -Pslot=$CI_NODE_INDEX/$CI_NODE_TOTAL $GRADLE_ARGS --continue || $CONTINUE_ON_FAILURE after_script: From bae116412b053e1c53f67abc9064e5181c23993b Mon Sep 17 00:00:00 2001 From: Brice Dutheil Date: Thu, 4 Jun 2026 14:48:02 +0200 Subject: [PATCH 2/8] ci(gitlab): avoid leaking Gradle console mode Keep --console=colored as an explicit argument for direct GitLab Gradle invocations instead of putting org.gradle.console in GRADLE_OPTS. Nested smoke-test application builds run through the Gradle Tooling API with Gradle 8.14.5, where the colored console value is not valid and fails before the nested build can run. --- .gitlab-ci.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 87a6bd39de1..55b850c1633 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -50,7 +50,7 @@ variables: DEPENDENCY_CACHE_POLICY: pull BUILD_CACHE_POLICY: pull GRADLE_VERSION: "9.5.1" # must match gradle-wrapper.properties - GRADLE_CONSOLE_OPTS: "-Dorg.gradle.console=colored" + GRADLE_CONSOLE_ARGS: "--console=colored" MASS_READ_URL: "https://mass-read.us1.ddbuild.io" MAVEN_REPOSITORY_PROXY: "https://depot-read-api-java.us1.ddbuild.io/magicmirror/magicmirror/@current/" GRADLE_PLUGIN_PROXY: "https://depot-read-api-java.us1.ddbuild.io/magicmirror/magicmirror/@current/" @@ -244,8 +244,8 @@ default: rm -rf "$HOME/.m2/repository/dev/equo" ln -s "$(pwd)/.mvn/caches/equo" "$HOME/.m2/repository/dev/equo" fi - - export GRADLE_OPTS="$GRADLE_CONSOLE_OPTS -Dorg.gradle.jvmargs='-Xms$GRADLE_MEMORY_MIN -Xmx$GRADLE_MEMORY_MAX -XX:ErrorFile=/tmp/hs_err_pid%p.log -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp'" - - export GRADLE_ARGS=" --build-cache --stacktrace --no-daemon --parallel --max-workers=$GRADLE_WORKERS" + - export GRADLE_OPTS="-Dorg.gradle.jvmargs='-Xms$GRADLE_MEMORY_MIN -Xmx$GRADLE_MEMORY_MAX -XX:ErrorFile=/tmp/hs_err_pid%p.log -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp'" + - export GRADLE_ARGS=" $GRADLE_CONSOLE_ARGS --build-cache --stacktrace --no-daemon --parallel --max-workers=$GRADLE_WORKERS" - *normalize_node_index # GitLab's cache helper restores .gradle as root, but we run as non-root-user (uid 1001), # and Gradle does `chmod 700 .gradle` on startup which requires user ownership. @@ -437,7 +437,7 @@ check-instrumentation-naming: needs: [ ] script: - ./gradlew --version - - ./gradlew checkInstrumentationNaming + - ./gradlew checkInstrumentationNaming $GRADLE_CONSOLE_ARGS config-inversion-linter: extends: .gradle_build @@ -445,7 +445,7 @@ config-inversion-linter: needs: [] script: - ./gradlew --version - - ./gradlew checkConfigurations + - ./gradlew checkConfigurations $GRADLE_CONSOLE_ARGS test_published_artifacts: extends: .gradle_build @@ -459,10 +459,10 @@ test_published_artifacts: - rm -rf "${mvn_local_repo}/com/datadoghq" - export GPG_PRIVATE_KEY=$(aws ssm get-parameter --region us-east-1 --name ci.dd-trace-java.signing.gpg_private_key --with-decryption --query "Parameter.Value" --out text) - export GPG_PASSWORD=$(aws ssm get-parameter --region us-east-1 --name ci.dd-trace-java.signing.gpg_passphrase --with-decryption --query "Parameter.Value" --out text) - - export GRADLE_OPTS="$GRADLE_CONSOLE_OPTS -Dorg.gradle.jvmargs='-Xms2G -Xmx2G -XX:ErrorFile=/tmp/hs_err_pid%p.log -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp'" + - export GRADLE_OPTS="-Dorg.gradle.jvmargs='-Xms2G -Xmx2G -XX:ErrorFile=/tmp/hs_err_pid%p.log -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp'" - ./gradlew publishToMavenLocal $GRADLE_ARGS - cd test-published-dependencies - - export GRADLE_OPTS="$GRADLE_CONSOLE_OPTS -Dorg.gradle.jvmargs='-Xms1G -Xmx1G -XX:ErrorFile=/tmp/hs_err_pid%p.log -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp'" + - export GRADLE_OPTS="-Dorg.gradle.jvmargs='-Xms1G -Xmx1G -XX:ErrorFile=/tmp/hs_err_pid%p.log -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp'" - ./gradlew --version - ./gradlew check --info $GRADLE_ARGS after_script: @@ -670,7 +670,7 @@ muzzle-dep-report: export PROFILER_COMMAND="-XX:StartFlightRecording=settings=profile,filename=/tmp/${CI_JOB_NAME_SLUG}.jfr,dumponexit=true"; fi - *prepare_test_env - - export GRADLE_OPTS="$GRADLE_CONSOLE_OPTS -Dorg.gradle.jvmargs='-Xms$GRADLE_MEMORY_MIN -Xmx$GRADLE_MEMORY_MAX $PROFILER_COMMAND -XX:ErrorFile=/tmp/hs_err_pid%p.log -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp -Djava.util.prefs.userRoot=/tmp/.java/.userPrefs-${CI_JOB_ID}' -Ddatadog.forkedMinHeapSize=128M -Ddatadog.forkedMaxHeapSize=1024M" + - export GRADLE_OPTS="-Dorg.gradle.jvmargs='-Xms$GRADLE_MEMORY_MIN -Xmx$GRADLE_MEMORY_MAX $PROFILER_COMMAND -XX:ErrorFile=/tmp/hs_err_pid%p.log -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp -Djava.util.prefs.userRoot=/tmp/.java/.userPrefs-${CI_JOB_ID}' -Ddatadog.forkedMinHeapSize=128M -Ddatadog.forkedMaxHeapSize=1024M" - ./gradlew --version - ./gradlew $GRADLE_TARGET $GRADLE_PARAMS -PtestJvm=$testJvm -Pslot=$CI_NODE_INDEX/$CI_NODE_TOTAL $GRADLE_ARGS --continue || $CONTINUE_ON_FAILURE after_script: From 4a06da200f9e64b2588a4728d8dc4a7855ce8d54 Mon Sep 17 00:00:00 2001 From: Brice Dutheil Date: Thu, 4 Jun 2026 15:09:26 +0200 Subject: [PATCH 3/8] fix(smoke-test): clear nested Gradle launcher env Nested smoke-test application builds run through the Gradle Tooling API and can otherwise inherit CI launcher variables from the outer build. Clear GRADLE_OPTS and GRADLE_ARGS by default before starting the nested Gradle build, while still allowing explicit smokeTestApp environment overrides. --- .../buildlogic/smoketest/NestedGradleBuild.kt | 17 +++-- .../smoketest/SmokeTestAppExtension.kt | 5 +- .../smoketest/SmokeTestAppEndToEndTest.kt | 63 ++++++++++++++++++- 3 files changed, 76 insertions(+), 9 deletions(-) diff --git a/build-logic/smoke-test/src/main/kotlin/datadog/buildlogic/smoketest/NestedGradleBuild.kt b/build-logic/smoke-test/src/main/kotlin/datadog/buildlogic/smoketest/NestedGradleBuild.kt index ffdefe82f35..4e30ac64baa 100644 --- a/build-logic/smoke-test/src/main/kotlin/datadog/buildlogic/smoketest/NestedGradleBuild.kt +++ b/build-logic/smoke-test/src/main/kotlin/datadog/buildlogic/smoketest/NestedGradleBuild.kt @@ -104,8 +104,9 @@ abstract class NestedGradleBuild @Inject constructor( /** * Extra environment variables for the nested Gradle daemon. Merged on top of the outer - * process environment — set a key to override an inherited value. The nested build script - * sees these via `System.getenv()` like any normal environment variable. + * process environment after clearing Gradle launcher variables — set a key to override an + * inherited value. The nested build script sees these via `System.getenv()` like any normal + * environment variable. */ @get:Input abstract val environment: MapProperty @@ -161,16 +162,20 @@ abstract class NestedGradleBuild @Inject constructor( } } - val extraEnv = environment.get() - val mergedEnv: Map? = - if (extraEnv.isEmpty()) null else System.getenv() + extraEnv + val mergedEnv = + System.getenv() + + mapOf( + "GRADLE_ARGS" to "", + "GRADLE_OPTS" to "", + ) + + environment.get() connector.connect().use { connection -> connection.newBuild() .forTasks(*tasksToRun.get().toTypedArray()) .withArguments(args) .setJavaHome(daemonJavaHome) - .apply { if (mergedEnv != null) setEnvironmentVariables(mergedEnv) } + .setEnvironmentVariables(mergedEnv) .setStandardOutput(System.out) .setStandardError(System.err) .run() diff --git a/build-logic/smoke-test/src/main/kotlin/datadog/buildlogic/smoketest/SmokeTestAppExtension.kt b/build-logic/smoke-test/src/main/kotlin/datadog/buildlogic/smoketest/SmokeTestAppExtension.kt index 7e49d1f4ba9..507a678c5a0 100644 --- a/build-logic/smoke-test/src/main/kotlin/datadog/buildlogic/smoketest/SmokeTestAppExtension.kt +++ b/build-logic/smoke-test/src/main/kotlin/datadog/buildlogic/smoketest/SmokeTestAppExtension.kt @@ -215,8 +215,9 @@ abstract class ApplicationSpec @Inject constructor() { /** * Extra environment variables exposed to the nested Gradle daemon. Merged on top of the - * outer process environment — entries here override any inherited values with the same key. - * Use this for nested tooling that reads `JAVA_HOME`, `GRAALVM_HOME`, etc. from the env. + * outer process environment after clearing Gradle launcher variables — entries here override + * any inherited values with the same key. Use this for nested tooling that reads `JAVA_HOME`, + * `GRAALVM_HOME`, etc. from the env. */ abstract val environment: MapProperty diff --git a/build-logic/smoke-test/src/test/kotlin/datadog/buildlogic/smoketest/SmokeTestAppEndToEndTest.kt b/build-logic/smoke-test/src/test/kotlin/datadog/buildlogic/smoketest/SmokeTestAppEndToEndTest.kt index b3ae23cf52e..28d36bbd74e 100644 --- a/build-logic/smoke-test/src/test/kotlin/datadog/buildlogic/smoketest/SmokeTestAppEndToEndTest.kt +++ b/build-logic/smoke-test/src/test/kotlin/datadog/buildlogic/smoketest/SmokeTestAppEndToEndTest.kt @@ -163,6 +163,63 @@ class SmokeTestAppEndToEndTest { assertThat(result.task(":customBuild")?.outcome).isEqualTo(TaskOutcome.SUCCESS) } + @Test + fun `nested build clears inherited Gradle launcher environment`() { + writeOuterSettings() + outerBuild.writeText( + """ + plugins { + java + id("dd-trace-java.smoke-test-app") + } + + smokeTestApp { + javaLauncher.set( + javaToolchains.launcherFor { languageVersion.set(JavaLanguageVersion.of(${currentMajorJdk()})) } + ) + application { + taskName.set("recordGradleEnvironment") + artifactPath.set("gradle-env.txt") + sysProperty.set("gradle.env.path") + } + } + """.trimIndent(), + ) + writeInnerSettings() + writeInnerBuild( + """ + tasks.register("recordGradleEnvironment") { + val out = layout.buildDirectory.file("gradle-env.txt") + outputs.file(out) + doLast { + out.get().asFile.writeText( + listOf("GRADLE_ARGS", "GRADLE_OPTS") + .joinToString(System.lineSeparator()) { key -> + "${'$'}key=${'$'}{System.getenv(key) ?: ""}" + } + ) + } + } + """.trimIndent(), + ) + + val result = runner( + "recordGradleEnvironment", + environment = mapOf( + "GRADLE_ARGS" to "--console=colored", + "GRADLE_OPTS" to "-Dorg.gradle.console=colored", + ), + ).build() + + assertThat(result.task(":recordGradleEnvironment")?.outcome).isEqualTo(TaskOutcome.SUCCESS) + val envFile = File(projectDir.toFile(), "build/application/gradle-env.txt") + assertThat(envFile).exists() + assertThat(envFile.readLines()).containsExactly( + "GRADLE_ARGS=", + "GRADLE_OPTS=", + ) + } + /** * `buildCacheEnabled` defaults to `false` and is plumbed through to the nested daemon as * an explicit `--no-build-cache` / `--build-cache` argument. The inner build records @@ -336,11 +393,15 @@ class SmokeTestAppEndToEndTest { ) } - private fun runner(vararg args: String): GradleRunner = + private fun runner( + vararg args: String, + environment: Map? = null, + ): GradleRunner = GradleRunner.create() .withProjectDir(projectDir.toFile()) .withPluginClasspath() .withArguments(*args, "--stacktrace") + .apply { if (environment != null) withEnvironment(System.getenv() + environment) } .forwardOutput() private fun currentMajorJdk(): Int = From 65db5bf677f3d3c314dcaf4c989e9df899f67519 Mon Sep 17 00:00:00 2001 From: Brice Dutheil Date: Thu, 4 Jun 2026 15:22:11 +0200 Subject: [PATCH 4/8] fix(gradle): sanitize TestKit launcher env Inline the GitLab colored console flag as --console=colored and keep it out of Gradle properties. Clear GRADLE_OPTS and GRADLE_ARGS for GradleRunner and wrapper helper invocations so nested Gradle builds do not inherit incompatible CI launcher settings. --- .gitlab-ci.yml | 7 +++---- .../smoketest/SmokeTestAppEndToEndTest.kt | 14 ++++++++++++-- .../datadog/smoketest/GradleDaemonSmokeTest.java | 2 ++ .../datadog/smoketest/GradleLauncherSmokeTest.java | 5 ++++- .../datadog/smoke/HelloPluginFunctionalTest.java | 10 ++++++++++ 5 files changed, 31 insertions(+), 7 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 55b850c1633..b92cc8dc043 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -50,7 +50,6 @@ variables: DEPENDENCY_CACHE_POLICY: pull BUILD_CACHE_POLICY: pull GRADLE_VERSION: "9.5.1" # must match gradle-wrapper.properties - GRADLE_CONSOLE_ARGS: "--console=colored" MASS_READ_URL: "https://mass-read.us1.ddbuild.io" MAVEN_REPOSITORY_PROXY: "https://depot-read-api-java.us1.ddbuild.io/magicmirror/magicmirror/@current/" GRADLE_PLUGIN_PROXY: "https://depot-read-api-java.us1.ddbuild.io/magicmirror/magicmirror/@current/" @@ -245,7 +244,7 @@ default: ln -s "$(pwd)/.mvn/caches/equo" "$HOME/.m2/repository/dev/equo" fi - export GRADLE_OPTS="-Dorg.gradle.jvmargs='-Xms$GRADLE_MEMORY_MIN -Xmx$GRADLE_MEMORY_MAX -XX:ErrorFile=/tmp/hs_err_pid%p.log -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp'" - - export GRADLE_ARGS=" $GRADLE_CONSOLE_ARGS --build-cache --stacktrace --no-daemon --parallel --max-workers=$GRADLE_WORKERS" + - export GRADLE_ARGS=" --console=colored --build-cache --stacktrace --no-daemon --parallel --max-workers=$GRADLE_WORKERS" - *normalize_node_index # GitLab's cache helper restores .gradle as root, but we run as non-root-user (uid 1001), # and Gradle does `chmod 700 .gradle` on startup which requires user ownership. @@ -437,7 +436,7 @@ check-instrumentation-naming: needs: [ ] script: - ./gradlew --version - - ./gradlew checkInstrumentationNaming $GRADLE_CONSOLE_ARGS + - ./gradlew checkInstrumentationNaming --console=colored config-inversion-linter: extends: .gradle_build @@ -445,7 +444,7 @@ config-inversion-linter: needs: [] script: - ./gradlew --version - - ./gradlew checkConfigurations $GRADLE_CONSOLE_ARGS + - ./gradlew checkConfigurations --console=colored test_published_artifacts: extends: .gradle_build diff --git a/build-logic/smoke-test/src/test/kotlin/datadog/buildlogic/smoketest/SmokeTestAppEndToEndTest.kt b/build-logic/smoke-test/src/test/kotlin/datadog/buildlogic/smoketest/SmokeTestAppEndToEndTest.kt index 28d36bbd74e..44b5584ae3d 100644 --- a/build-logic/smoke-test/src/test/kotlin/datadog/buildlogic/smoketest/SmokeTestAppEndToEndTest.kt +++ b/build-logic/smoke-test/src/test/kotlin/datadog/buildlogic/smoketest/SmokeTestAppEndToEndTest.kt @@ -207,7 +207,7 @@ class SmokeTestAppEndToEndTest { "recordGradleEnvironment", environment = mapOf( "GRADLE_ARGS" to "--console=colored", - "GRADLE_OPTS" to "-Dorg.gradle.console=colored", + "GRADLE_OPTS" to "-Ddd.test.gradle.opts=inherited", ), ).build() @@ -401,9 +401,19 @@ class SmokeTestAppEndToEndTest { .withProjectDir(projectDir.toFile()) .withPluginClasspath() .withArguments(*args, "--stacktrace") - .apply { if (environment != null) withEnvironment(System.getenv() + environment) } + .withEnvironment(sanitizedGradleEnvironment(environment)) .forwardOutput() + private fun sanitizedGradleEnvironment( + overrides: Map? = null, + ): Map = + System.getenv() + + mapOf( + "GRADLE_ARGS" to "", + "GRADLE_OPTS" to "", + ) + + (overrides ?: emptyMap()) + private fun currentMajorJdk(): Int = System.getProperty("java.specification.version").let { if (it.startsWith("1.")) it.substring(2).toInt() else it.toInt() diff --git a/dd-smoke-tests/gradle/src/test/java/datadog/smoketest/GradleDaemonSmokeTest.java b/dd-smoke-tests/gradle/src/test/java/datadog/smoketest/GradleDaemonSmokeTest.java index add663ebaa8..4a8666337d0 100644 --- a/dd-smoke-tests/gradle/src/test/java/datadog/smoketest/GradleDaemonSmokeTest.java +++ b/dd-smoke-tests/gradle/src/test/java/datadog/smoketest/GradleDaemonSmokeTest.java @@ -306,6 +306,8 @@ private void ensureDependenciesDownloaded(String gradleVersion) { private BuildResult runGradle( String gradleVersion, List arguments, boolean successExpected) throws IOException { Map buildEnv = new HashMap<>(); + buildEnv.put("GRADLE_ARGS", ""); + buildEnv.put("GRADLE_OPTS", ""); buildEnv.put("GRADLE_VERSION", gradleVersion); buildEnv.put( GradleDistribution.GRADLE_DISTRIBUTION_URL_ENV, diff --git a/dd-smoke-tests/gradle/src/test/java/datadog/smoketest/GradleLauncherSmokeTest.java b/dd-smoke-tests/gradle/src/test/java/datadog/smoketest/GradleLauncherSmokeTest.java index 63a0295e0ff..199e21bfe70 100644 --- a/dd-smoke-tests/gradle/src/test/java/datadog/smoketest/GradleLauncherSmokeTest.java +++ b/dd-smoke-tests/gradle/src/test/java/datadog/smoketest/GradleLauncherSmokeTest.java @@ -99,6 +99,7 @@ void stopGradleBuildDaemon() { Map env = new HashMap<>(); env.put("JAVA_HOME", JAVA_HOME); env.put("GRADLE_USER_HOME", gradleUserHome.toString()); + env.put("GRADLE_ARGS", ""); env.put("GRADLE_OPTS", ""); ShellCommandExecutor shellCommandExecutor = new ShellCommandExecutor(projectFolder.toFile(), GRADLE_STOP_TIMEOUT_MILLIS, env); @@ -114,7 +115,8 @@ private void givenGradleWrapper(String gradleVersion) throws Exception { Map env = new HashMap<>(); env.put("JAVA_HOME", JAVA_HOME); env.put("GRADLE_USER_HOME", gradleUserHome.toString()); - // Avoid inheriting CI's GRADLE_OPTS which might be incompatible with the tested JVM. + // Avoid inheriting CI Gradle launcher settings that might be incompatible with this wrapper. + env.put("GRADLE_ARGS", ""); env.put("GRADLE_OPTS", ""); ShellCommandExecutor shellCommandExecutor = new ShellCommandExecutor(projectFolder.toFile(), GRADLE_BUILD_TIMEOUT_MILLIS, env); @@ -139,6 +141,7 @@ private String whenRunningGradleLauncherWithJavaTracerInjected(String gradleDaem Map env = new HashMap<>(); env.put("JAVA_HOME", JAVA_HOME); env.put("GRADLE_USER_HOME", gradleUserHome.toString()); + env.put("GRADLE_ARGS", ""); env.put("GRADLE_OPTS", "-javaagent:" + AGENT_JAR); env.put("DD_CIVISIBILITY_ENABLED", "true"); env.put("DD_CIVISIBILITY_AGENTLESS_ENABLED", "true"); diff --git a/dd-smoke-tests/gradle/src/test/resources/test-succeed-gradle-plugin-test/src/test/java/datadog/smoke/HelloPluginFunctionalTest.java b/dd-smoke-tests/gradle/src/test/resources/test-succeed-gradle-plugin-test/src/test/java/datadog/smoke/HelloPluginFunctionalTest.java index bc71633bd91..f4d9b30414d 100644 --- a/dd-smoke-tests/gradle/src/test/resources/test-succeed-gradle-plugin-test/src/test/java/datadog/smoke/HelloPluginFunctionalTest.java +++ b/dd-smoke-tests/gradle/src/test/resources/test-succeed-gradle-plugin-test/src/test/java/datadog/smoke/HelloPluginFunctionalTest.java @@ -9,6 +9,8 @@ import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; +import java.util.HashMap; +import java.util.Map; import org.gradle.testkit.runner.BuildResult; import org.gradle.testkit.runner.GradleRunner; import org.junit.jupiter.api.BeforeEach; @@ -39,9 +41,17 @@ void pluginPrintsHelloMessageOnGradle85() { .withPluginClasspath() .withGradleDistribution(URI.create(gradleDistributionUrl)) .withArguments("hello", "--stacktrace") + .withEnvironment(sanitizedGradleEnvironment()) .forwardOutput() .build(); assertTrue(result.getOutput().contains("Hello from my plugin!")); } + + private static Map sanitizedGradleEnvironment() { + Map environment = new HashMap<>(System.getenv()); + environment.put("GRADLE_ARGS", ""); + environment.put("GRADLE_OPTS", ""); + return environment; + } } From 409c0953acc5ea29486090000215fb1b55c9d38e Mon Sep 17 00:00:00 2001 From: Brice Dutheil Date: Thu, 4 Jun 2026 15:38:06 +0200 Subject: [PATCH 5/8] fix(smoke-test): isolate nested Gradle user home Run nested smoke-test application builds with a task-local Gradle user home and delete it after the Tooling API build finishes. This prevents inherited CI Gradle user-home state from leaking into pinned nested Gradle versions alongside GRADLE_OPTS and GRADLE_ARGS. --- .../buildlogic/smoketest/NestedGradleBuild.kt | 58 ++++++++++++++----- .../smoketest/SmokeTestAppExtension.kt | 8 +-- .../smoketest/SmokeTestAppEndToEndTest.kt | 23 ++++++-- 3 files changed, 64 insertions(+), 25 deletions(-) diff --git a/build-logic/smoke-test/src/main/kotlin/datadog/buildlogic/smoketest/NestedGradleBuild.kt b/build-logic/smoke-test/src/main/kotlin/datadog/buildlogic/smoketest/NestedGradleBuild.kt index 4e30ac64baa..69f2db90f54 100644 --- a/build-logic/smoke-test/src/main/kotlin/datadog/buildlogic/smoketest/NestedGradleBuild.kt +++ b/build-logic/smoke-test/src/main/kotlin/datadog/buildlogic/smoketest/NestedGradleBuild.kt @@ -2,6 +2,7 @@ package datadog.buildlogic.smoketest import org.gradle.api.Action import org.gradle.api.DefaultTask +import org.gradle.api.GradleException import org.gradle.api.file.DirectoryProperty import org.gradle.api.file.FileTree import org.gradle.api.file.RegularFile @@ -26,6 +27,7 @@ import org.gradle.jvm.toolchain.JavaLauncher import org.gradle.jvm.toolchain.JavaToolchainService import org.gradle.kotlin.dsl.newInstance import org.gradle.tooling.GradleConnector +import java.io.File import javax.inject.Inject /** @@ -103,10 +105,10 @@ abstract class NestedGradleBuild @Inject constructor( abstract val buildCacheEnabled: Property /** - * Extra environment variables for the nested Gradle daemon. Merged on top of the outer - * process environment after clearing Gradle launcher variables — set a key to override an - * inherited value. The nested build script sees these via `System.getenv()` like any normal - * environment variable. + * Extra environment variables for the nested Gradle daemon. Merged on top of the outer process + * environment; Gradle launcher variables are reserved by this task so nested builds do not + * inherit incompatible outer-build settings. The nested build script sees these via + * `System.getenv()` like any normal environment variable. */ @get:Input abstract val environment: MapProperty @@ -139,6 +141,7 @@ abstract class NestedGradleBuild @Inject constructor( val appDir = applicationDir.get().asFile val appBuildDirFile = applicationBuildDir.get().asFile val daemonJavaHome = javaLauncher.get().metadata.installationPath.asFile + val gradleUserHomeDir = createGradleUserHome() val args = buildList { add(if (buildCacheEnabled.get()) "--build-cache" else "--no-build-cache") @@ -151,6 +154,7 @@ abstract class NestedGradleBuild @Inject constructor( val connector = GradleConnector.newConnector() .forProjectDirectory(appDir) + .useGradleUserHomeDir(gradleUserHomeDir) .apply { val distributionBaseUrl = gradleDistributionBaseUrl.orNull if (distributionBaseUrl.isNullOrBlank()) { @@ -164,21 +168,43 @@ abstract class NestedGradleBuild @Inject constructor( val mergedEnv = System.getenv() + + environment.get() + mapOf( "GRADLE_ARGS" to "", "GRADLE_OPTS" to "", - ) + - environment.get() - - connector.connect().use { connection -> - connection.newBuild() - .forTasks(*tasksToRun.get().toTypedArray()) - .withArguments(args) - .setJavaHome(daemonJavaHome) - .setEnvironmentVariables(mergedEnv) - .setStandardOutput(System.out) - .setStandardError(System.err) - .run() + "GRADLE_USER_HOME" to gradleUserHomeDir.absolutePath, + ) + + try { + connector.connect().use { connection -> + connection.newBuild() + .forTasks(*tasksToRun.get().toTypedArray()) + .withArguments(args) + .setJavaHome(daemonJavaHome) + .setEnvironmentVariables(mergedEnv) + .setStandardOutput(System.out) + .setStandardError(System.err) + .run() + } + } finally { + deleteGradleUserHome(gradleUserHomeDir) + } + } + + private fun createGradleUserHome(): File { + val directory = temporaryDir.resolve("gradle-user-home") + deleteGradleUserHome(directory) + if (!directory.mkdirs()) { + throw GradleException( + "Could not create nested Gradle user home: ${directory.absolutePath}", + ) + } + return directory + } + + private fun deleteGradleUserHome(directory: File) { + if (directory.exists() && !directory.deleteRecursively()) { + logger.warn("Could not delete nested Gradle user home: {}", directory.absolutePath) } } } diff --git a/build-logic/smoke-test/src/main/kotlin/datadog/buildlogic/smoketest/SmokeTestAppExtension.kt b/build-logic/smoke-test/src/main/kotlin/datadog/buildlogic/smoketest/SmokeTestAppExtension.kt index 507a678c5a0..e999d1020ad 100644 --- a/build-logic/smoke-test/src/main/kotlin/datadog/buildlogic/smoketest/SmokeTestAppExtension.kt +++ b/build-logic/smoke-test/src/main/kotlin/datadog/buildlogic/smoketest/SmokeTestAppExtension.kt @@ -214,10 +214,10 @@ abstract class ApplicationSpec @Inject constructor() { abstract val buildArguments: ListProperty /** - * Extra environment variables exposed to the nested Gradle daemon. Merged on top of the - * outer process environment after clearing Gradle launcher variables — entries here override - * any inherited values with the same key. Use this for nested tooling that reads `JAVA_HOME`, - * `GRAALVM_HOME`, etc. from the env. + * Extra environment variables exposed to the nested Gradle daemon. Merged on top of the outer + * process environment; Gradle launcher variables are reserved by the nested build task so CI + * settings do not leak into pinned Gradle versions. Use this for nested tooling that reads + * `JAVA_HOME`, `GRAALVM_HOME`, etc. from the env. */ abstract val environment: MapProperty diff --git a/build-logic/smoke-test/src/test/kotlin/datadog/buildlogic/smoketest/SmokeTestAppEndToEndTest.kt b/build-logic/smoke-test/src/test/kotlin/datadog/buildlogic/smoketest/SmokeTestAppEndToEndTest.kt index 44b5584ae3d..e69abd4a826 100644 --- a/build-logic/smoke-test/src/test/kotlin/datadog/buildlogic/smoketest/SmokeTestAppEndToEndTest.kt +++ b/build-logic/smoke-test/src/test/kotlin/datadog/buildlogic/smoketest/SmokeTestAppEndToEndTest.kt @@ -166,6 +166,8 @@ class SmokeTestAppEndToEndTest { @Test fun `nested build clears inherited Gradle launcher environment`() { writeOuterSettings() + val inheritedGradleUserHome = projectDir.resolve("inherited-gradle-user-home").toFile() + inheritedGradleUserHome.mkdirs() outerBuild.writeText( """ plugins { @@ -193,10 +195,12 @@ class SmokeTestAppEndToEndTest { outputs.file(out) doLast { out.get().asFile.writeText( - listOf("GRADLE_ARGS", "GRADLE_OPTS") - .joinToString(System.lineSeparator()) { key -> - "${'$'}key=${'$'}{System.getenv(key) ?: ""}" - } + listOf( + "GRADLE_ARGS=${'$'}{System.getenv("GRADLE_ARGS") ?: ""}", + "GRADLE_OPTS=${'$'}{System.getenv("GRADLE_OPTS") ?: ""}", + "GRADLE_USER_HOME=${'$'}{System.getenv("GRADLE_USER_HOME") ?: ""}", + "gradleUserHomeDir=${'$'}{gradle.gradleUserHomeDir.absolutePath}", + ).joinToString(System.lineSeparator()) ) } } @@ -208,16 +212,25 @@ class SmokeTestAppEndToEndTest { environment = mapOf( "GRADLE_ARGS" to "--console=colored", "GRADLE_OPTS" to "-Ddd.test.gradle.opts=inherited", + "GRADLE_USER_HOME" to inheritedGradleUserHome.absolutePath, ), ).build() assertThat(result.task(":recordGradleEnvironment")?.outcome).isEqualTo(TaskOutcome.SUCCESS) val envFile = File(projectDir.toFile(), "build/application/gradle-env.txt") assertThat(envFile).exists() - assertThat(envFile.readLines()).containsExactly( + val lines = envFile.readLines() + assertThat(lines).contains( "GRADLE_ARGS=", "GRADLE_OPTS=", ) + val gradleUserHomeEnv = lines.single { it.startsWith("GRADLE_USER_HOME=") } + .substringAfter("=") + val gradleUserHomeDir = lines.single { it.startsWith("gradleUserHomeDir=") } + .substringAfter("=") + assertThat(gradleUserHomeEnv).isEqualTo(gradleUserHomeDir) + assertThat(gradleUserHomeDir).isNotEqualTo(inheritedGradleUserHome.absolutePath) + assertThat(File(gradleUserHomeDir)).doesNotExist() } /** From 6b78f6fb1cf26b6ae171c78f9c481a844ec10351 Mon Sep 17 00:00:00 2001 From: Brice Dutheil Date: Thu, 4 Jun 2026 15:58:31 +0200 Subject: [PATCH 6/8] ci(gitlab): configure Gradle console in properties Write org.gradle.console=colored into the CI-generated root gradle.properties instead of passing --console=colored on Gradle command lines. Keep the nested smoke-test GradleRunner regression focused on clearing inherited launcher arguments without using the console flag as the sentinel. --- .gitlab-ci.yml | 7 ++++--- .../buildlogic/smoketest/SmokeTestAppEndToEndTest.kt | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index b92cc8dc043..4bca29a11f1 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -224,6 +224,7 @@ default: org.gradle.java.installations.auto-detect=false org.gradle.java.installations.auto-download=false org.gradle.java.installations.fromEnv=$JAVA_HOMES + org.gradle.console=colored EOF - mkdir -p .gradle - export GRADLE_USER_HOME=$(pwd)/.gradle @@ -244,7 +245,7 @@ default: ln -s "$(pwd)/.mvn/caches/equo" "$HOME/.m2/repository/dev/equo" fi - export GRADLE_OPTS="-Dorg.gradle.jvmargs='-Xms$GRADLE_MEMORY_MIN -Xmx$GRADLE_MEMORY_MAX -XX:ErrorFile=/tmp/hs_err_pid%p.log -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp'" - - export GRADLE_ARGS=" --console=colored --build-cache --stacktrace --no-daemon --parallel --max-workers=$GRADLE_WORKERS" + - export GRADLE_ARGS=" --build-cache --stacktrace --no-daemon --parallel --max-workers=$GRADLE_WORKERS" - *normalize_node_index # GitLab's cache helper restores .gradle as root, but we run as non-root-user (uid 1001), # and Gradle does `chmod 700 .gradle` on startup which requires user ownership. @@ -436,7 +437,7 @@ check-instrumentation-naming: needs: [ ] script: - ./gradlew --version - - ./gradlew checkInstrumentationNaming --console=colored + - ./gradlew checkInstrumentationNaming config-inversion-linter: extends: .gradle_build @@ -444,7 +445,7 @@ config-inversion-linter: needs: [] script: - ./gradlew --version - - ./gradlew checkConfigurations --console=colored + - ./gradlew checkConfigurations test_published_artifacts: extends: .gradle_build diff --git a/build-logic/smoke-test/src/test/kotlin/datadog/buildlogic/smoketest/SmokeTestAppEndToEndTest.kt b/build-logic/smoke-test/src/test/kotlin/datadog/buildlogic/smoketest/SmokeTestAppEndToEndTest.kt index e69abd4a826..8b0c6ae81ee 100644 --- a/build-logic/smoke-test/src/test/kotlin/datadog/buildlogic/smoketest/SmokeTestAppEndToEndTest.kt +++ b/build-logic/smoke-test/src/test/kotlin/datadog/buildlogic/smoketest/SmokeTestAppEndToEndTest.kt @@ -210,7 +210,7 @@ class SmokeTestAppEndToEndTest { val result = runner( "recordGradleEnvironment", environment = mapOf( - "GRADLE_ARGS" to "--console=colored", + "GRADLE_ARGS" to "--info", "GRADLE_OPTS" to "-Ddd.test.gradle.opts=inherited", "GRADLE_USER_HOME" to inheritedGradleUserHome.absolutePath, ), From 0a4627d355681569104233741c792609c7e005c0 Mon Sep 17 00:00:00 2001 From: Brice Dutheil Date: Thu, 4 Jun 2026 16:19:06 +0200 Subject: [PATCH 7/8] fix(smoke-test): stop nested Gradle daemons Stop the nested Gradle daemon with the downloaded Gradle distribution before deleting the task-local Gradle user home. Also configure colored console output for the test-published-dependencies Gradle root. --- .gitlab-ci.yml | 1 + .../buildlogic/smoketest/NestedGradleBuild.kt | 67 +++++++++++++++++++ 2 files changed, 68 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 4bca29a11f1..291a6e631eb 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -462,6 +462,7 @@ test_published_artifacts: - export GRADLE_OPTS="-Dorg.gradle.jvmargs='-Xms2G -Xmx2G -XX:ErrorFile=/tmp/hs_err_pid%p.log -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp'" - ./gradlew publishToMavenLocal $GRADLE_ARGS - cd test-published-dependencies + - printf '\norg.gradle.console=colored\n' >> gradle.properties - export GRADLE_OPTS="-Dorg.gradle.jvmargs='-Xms1G -Xmx1G -XX:ErrorFile=/tmp/hs_err_pid%p.log -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp'" - ./gradlew --version - ./gradlew check --info $GRADLE_ARGS diff --git a/build-logic/smoke-test/src/main/kotlin/datadog/buildlogic/smoketest/NestedGradleBuild.kt b/build-logic/smoke-test/src/main/kotlin/datadog/buildlogic/smoketest/NestedGradleBuild.kt index 69f2db90f54..7500e8dfdf2 100644 --- a/build-logic/smoke-test/src/main/kotlin/datadog/buildlogic/smoketest/NestedGradleBuild.kt +++ b/build-logic/smoke-test/src/main/kotlin/datadog/buildlogic/smoketest/NestedGradleBuild.kt @@ -28,6 +28,7 @@ import org.gradle.jvm.toolchain.JavaToolchainService import org.gradle.kotlin.dsl.newInstance import org.gradle.tooling.GradleConnector import java.io.File +import java.util.concurrent.TimeUnit import javax.inject.Inject /** @@ -187,10 +188,72 @@ abstract class NestedGradleBuild @Inject constructor( .run() } } finally { + stopGradleDaemon(appDir, gradleUserHomeDir, daemonJavaHome, mergedEnv) deleteGradleUserHome(gradleUserHomeDir) } } + private fun stopGradleDaemon( + appDir: File, + gradleUserHomeDir: File, + daemonJavaHome: File, + environment: Map, + ) { + val gradleExecutable = findGradleExecutable(gradleUserHomeDir) + if (gradleExecutable == null) { + logger.warn( + "Could not find nested Gradle executable under {} to stop its daemon", + gradleUserHomeDir.absolutePath, + ) + return + } + + try { + val processBuilder = ProcessBuilder(gradleExecutable.absolutePath, "--stop") + .directory(appDir) + .redirectOutput(ProcessBuilder.Redirect.INHERIT) + .redirectError(ProcessBuilder.Redirect.INHERIT) + processBuilder.environment().apply { + clear() + putAll(environment) + put("JAVA_HOME", daemonJavaHome.absolutePath) + } + + val process = processBuilder.start() + if (!process.waitFor(GRADLE_STOP_TIMEOUT_SECONDS, TimeUnit.SECONDS)) { + process.destroyForcibly() + logger.warn("Timed out while stopping nested Gradle daemon") + return + } + val exitCode = process.exitValue() + if (exitCode != 0) { + logger.warn("Nested Gradle daemon stop exited with code {}", exitCode) + } + } catch (e: InterruptedException) { + Thread.currentThread().interrupt() + logger.warn( + "Interrupted while stopping nested Gradle daemon before deleting its user home", + e, + ) + } catch (e: Exception) { + logger.warn("Could not stop nested Gradle daemon before deleting its user home", e) + } + } + + private fun findGradleExecutable(gradleUserHomeDir: File): File? = + gradleUserHomeDir.walkTopDown().firstOrNull { file -> + file.isFile && + file.name == gradleExecutableName() && + file.parentFile?.name == "bin" + } + + private fun gradleExecutableName(): String = + if (System.getProperty("os.name").lowercase().contains("windows")) { + "gradle.bat" + } else { + "gradle" + } + private fun createGradleUserHome(): File { val directory = temporaryDir.resolve("gradle-user-home") deleteGradleUserHome(directory) @@ -207,4 +270,8 @@ abstract class NestedGradleBuild @Inject constructor( logger.warn("Could not delete nested Gradle user home: {}", directory.absolutePath) } } + + private companion object { + const val GRADLE_STOP_TIMEOUT_SECONDS = 30L + } } From a90a324d9dc5c773cc9ee88a50593512a4b63205 Mon Sep 17 00:00:00 2001 From: Brice Dutheil Date: Thu, 4 Jun 2026 17:54:00 +0200 Subject: [PATCH 8/8] fix(smoke-test): sanitize nested Gradle user home Clear inherited Gradle user-home state from TestKit and build-logic smoke runs, and align the Gradle plugin smoke fixture expectations after adding the sanitized environment. --- .../smoketest/SmokeTestAppEndToEndTest.kt | 16 ++++++++++++++++ .../datadog/smoketest/GradleDaemonSmokeTest.java | 4 ++-- .../coverages.ftl | 2 +- .../test-succeed-gradle-plugin-test/events.ftl | 8 ++++---- .../datadog/smoke/HelloPluginFunctionalTest.java | 5 +++-- 5 files changed, 26 insertions(+), 9 deletions(-) diff --git a/build-logic/smoke-test/src/test/kotlin/datadog/buildlogic/smoketest/SmokeTestAppEndToEndTest.kt b/build-logic/smoke-test/src/test/kotlin/datadog/buildlogic/smoketest/SmokeTestAppEndToEndTest.kt index 8b0c6ae81ee..a0966107f44 100644 --- a/build-logic/smoke-test/src/test/kotlin/datadog/buildlogic/smoketest/SmokeTestAppEndToEndTest.kt +++ b/build-logic/smoke-test/src/test/kotlin/datadog/buildlogic/smoketest/SmokeTestAppEndToEndTest.kt @@ -3,6 +3,7 @@ package datadog.buildlogic.smoketest import org.assertj.core.api.Assertions.assertThat import org.gradle.testkit.runner.GradleRunner import org.gradle.testkit.runner.TaskOutcome +import org.gradle.tooling.internal.consumer.DefaultGradleConnector import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test import org.junit.jupiter.api.io.TempDir @@ -10,6 +11,7 @@ import org.junit.jupiter.params.ParameterizedTest import org.junit.jupiter.params.provider.Arguments import org.junit.jupiter.params.provider.MethodSource import java.io.File +import java.nio.file.Files import java.nio.file.Path /** @@ -424,6 +426,7 @@ class SmokeTestAppEndToEndTest { mapOf( "GRADLE_ARGS" to "", "GRADLE_OPTS" to "", + "GRADLE_USER_HOME" to outerGradleUserHome.absolutePath, ) + (overrides ?: emptyMap()) @@ -433,6 +436,19 @@ class SmokeTestAppEndToEndTest { } companion object { + private val outerGradleUserHome: File by lazy { + Files.createTempDirectory("smoke-test-app-gradle-user-home-").toFile().also { dir -> + Runtime.getRuntime().addShutdownHook(Thread { + try { + DefaultGradleConnector.close() + } catch (_: Exception) { + // best effort + } + dir.deleteRecursively() + }) + } + } + @JvmStatic fun buildCacheFlagCases(): List = listOf( // (scenario name, DSL line added to the `application { … }` block, expected diff --git a/dd-smoke-tests/gradle/src/test/java/datadog/smoketest/GradleDaemonSmokeTest.java b/dd-smoke-tests/gradle/src/test/java/datadog/smoketest/GradleDaemonSmokeTest.java index 4a8666337d0..7983e85282e 100644 --- a/dd-smoke-tests/gradle/src/test/java/datadog/smoketest/GradleDaemonSmokeTest.java +++ b/dd-smoke-tests/gradle/src/test/java/datadog/smoketest/GradleDaemonSmokeTest.java @@ -25,7 +25,6 @@ import org.gradle.tooling.internal.consumer.DefaultGradleConnector; import org.gradle.util.GradleVersion; import org.gradle.wrapper.Download; -import org.gradle.wrapper.GradleUserHomeLookup; import org.gradle.wrapper.Install; import org.gradle.wrapper.PathAssembler; import org.gradle.wrapper.WrapperConfiguration; @@ -286,7 +285,7 @@ private void ensureDependenciesDownloaded(String gradleVersion) { GradleVersion.current().getVersion(), GRADLE_DISTRIBUTION_NETWORK_TIMEOUT); - java.io.File userHomeDir = GradleUserHomeLookup.gradleUserHome(); + java.io.File userHomeDir = testKitFolder.toFile(); java.io.File projectDir = projectFolder.toFile(); Install install = new Install(logger, download, new PathAssembler(userHomeDir, projectDir)); @@ -308,6 +307,7 @@ private BuildResult runGradle( Map buildEnv = new HashMap<>(); buildEnv.put("GRADLE_ARGS", ""); buildEnv.put("GRADLE_OPTS", ""); + buildEnv.put("GRADLE_USER_HOME", testKitFolder.toString()); buildEnv.put("GRADLE_VERSION", gradleVersion); buildEnv.put( GradleDistribution.GRADLE_DISTRIBUTION_URL_ENV, diff --git a/dd-smoke-tests/gradle/src/test/resources/test-succeed-gradle-plugin-test/coverages.ftl b/dd-smoke-tests/gradle/src/test/resources/test-succeed-gradle-plugin-test/coverages.ftl index 482b6832e98..6be477ce51c 100644 --- a/dd-smoke-tests/gradle/src/test/resources/test-succeed-gradle-plugin-test/coverages.ftl +++ b/dd-smoke-tests/gradle/src/test/resources/test-succeed-gradle-plugin-test/coverages.ftl @@ -1,6 +1,6 @@ [ { "files" : [ { - "bitmap" : "AAAAfOxv", + "bitmap" : "AAAA8LF/8wE=", "filename" : "src/test/java/datadog/smoke/HelloPluginFunctionalTest.java" } ], "span_id" : ${content_span_id_4}, diff --git a/dd-smoke-tests/gradle/src/test/resources/test-succeed-gradle-plugin-test/events.ftl b/dd-smoke-tests/gradle/src/test/resources/test-succeed-gradle-plugin-test/events.ftl index dce4865bfc1..66ded4c6a4f 100644 --- a/dd-smoke-tests/gradle/src/test/resources/test-succeed-gradle-plugin-test/events.ftl +++ b/dd-smoke-tests/gradle/src/test/resources/test-succeed-gradle-plugin-test/events.ftl @@ -216,8 +216,8 @@ "_dd.profiling.enabled" : 0, "_dd.trace_span_attribute_schema" : 0, "process_id" : ${content_metrics_process_id_2}, - "test.source.end" : 47, - "test.source.start" : 18 + "test.source.end" : 58, + "test.source.start" : 20 }, "name" : "junit5.test_suite", "resource" : "datadog.smoke.HelloPluginFunctionalTest", @@ -278,8 +278,8 @@ "_dd.profiling.enabled" : 0, "_dd.trace_span_attribute_schema" : 0, "process_id" : ${content_metrics_process_id_2}, - "test.source.end" : 46, - "test.source.start" : 34 + "test.source.end" : 49, + "test.source.start" : 36 }, "name" : "junit5.test", "parent_id" : ${content_parent_id}, diff --git a/dd-smoke-tests/gradle/src/test/resources/test-succeed-gradle-plugin-test/src/test/java/datadog/smoke/HelloPluginFunctionalTest.java b/dd-smoke-tests/gradle/src/test/resources/test-succeed-gradle-plugin-test/src/test/java/datadog/smoke/HelloPluginFunctionalTest.java index f4d9b30414d..e0cf8189e54 100644 --- a/dd-smoke-tests/gradle/src/test/resources/test-succeed-gradle-plugin-test/src/test/java/datadog/smoke/HelloPluginFunctionalTest.java +++ b/dd-smoke-tests/gradle/src/test/resources/test-succeed-gradle-plugin-test/src/test/java/datadog/smoke/HelloPluginFunctionalTest.java @@ -41,17 +41,18 @@ void pluginPrintsHelloMessageOnGradle85() { .withPluginClasspath() .withGradleDistribution(URI.create(gradleDistributionUrl)) .withArguments("hello", "--stacktrace") - .withEnvironment(sanitizedGradleEnvironment()) + .withEnvironment(sanitizedGradleEnvironment(testProjectDir.resolve("gradle-user-home"))) .forwardOutput() .build(); assertTrue(result.getOutput().contains("Hello from my plugin!")); } - private static Map sanitizedGradleEnvironment() { + private static Map sanitizedGradleEnvironment(Path gradleUserHomeDir) { Map environment = new HashMap<>(System.getenv()); environment.put("GRADLE_ARGS", ""); environment.put("GRADLE_OPTS", ""); + environment.put("GRADLE_USER_HOME", gradleUserHomeDir.toString()); return environment; } }