Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package datadog.buildlogic.smoketest

import java.net.URI

internal const val MASS_READ_URL_ENV = "MASS_READ_URL"

internal fun gradleDistributionUri(massReadUrl: String, gradleVersion: String): URI {
val baseUrl = if (massReadUrl.endsWith("/")) massReadUrl else "$massReadUrl/"
return URI.create(
"${baseUrl}internal/artifact/services.gradle.org/distributions/gradle-$gradleVersion-bin.zip",
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import org.gradle.api.tasks.InputFiles
import org.gradle.api.tasks.Internal
import org.gradle.api.tasks.CacheableTask
import org.gradle.api.tasks.Nested
import org.gradle.api.tasks.Optional
import org.gradle.api.tasks.OutputDirectory
import org.gradle.api.tasks.PathSensitive
import org.gradle.api.tasks.PathSensitivity
Expand Down Expand Up @@ -47,6 +48,9 @@ abstract class NestedGradleBuild @Inject constructor(

init {
gradleVersion.convention(DEFAULT_NESTED_GRADLE_VERSION)
gradleDistributionBaseUrl.convention(
project.providers.environmentVariable(MASS_READ_URL_ENV),
)
javaLauncher.convention(
javaToolchains.launcherFor {
languageVersion.set(JavaLanguageVersion.of(DEFAULT_NESTED_JAVA_VERSION))
Expand All @@ -69,6 +73,14 @@ abstract class NestedGradleBuild @Inject constructor(
@get:Input
abstract val gradleVersion: Property<String>

/**
* Optional base URL for Gradle distribution downloads. CI sets this to MASS so nested builds
* download through the pull-through cache instead of directly from services.gradle.org.
*/
@get:Input
@get:Optional
abstract val gradleDistributionBaseUrl: Property<String>

@get:Nested
abstract val javaLauncher: Property<JavaLauncher>

Expand Down Expand Up @@ -137,8 +149,17 @@ abstract class NestedGradleBuild @Inject constructor(
}

val connector = GradleConnector.newConnector()
.useGradleVersion(gradleVersion.get())
.forProjectDirectory(appDir)
.apply {
val distributionBaseUrl = gradleDistributionBaseUrl.orNull
if (distributionBaseUrl.isNullOrBlank()) {
useGradleVersion(gradleVersion.get())
} else {
useDistribution(
gradleDistributionUri(distributionBaseUrl, gradleVersion.get()),
)
}
}

val extraEnv = environment.get()
val mergedEnv: Map<String, String>? =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,12 @@ abstract class SmokeTestAppExtension @Inject constructor(
*/
abstract val gradleVersion: Property<String>

/**
* Optional base URL for Gradle distribution downloads. Defaults to the CI-provided MASS read
* URL when present, so Tooling API downloads go through the pull-through cache.
*/
abstract val gradleDistributionBaseUrl: Property<String>

/**
* JDK used by the nested daemon. Defaults to a [DEFAULT_NESTED_JAVA_VERSION] toolchain;
* override to pin a different JDK if the nested application's plugin chain requires it.
Expand All @@ -63,6 +69,9 @@ abstract class SmokeTestAppExtension @Inject constructor(
applicationDir.convention(project.layout.projectDirectory.dir("application"))
applicationBuildDir.convention(project.layout.buildDirectory.dir("application"))
gradleVersion.convention(DEFAULT_NESTED_GRADLE_VERSION)
gradleDistributionBaseUrl.convention(
project.providers.environmentVariable(MASS_READ_URL_ENV),
)
javaLauncher.convention(
javaToolchains.launcherFor {
languageVersion.set(JavaLanguageVersion.of(DEFAULT_NESTED_JAVA_VERSION))
Expand Down Expand Up @@ -94,6 +103,7 @@ abstract class SmokeTestAppExtension @Inject constructor(
applicationDir.set(this@SmokeTestAppExtension.applicationDir)
applicationBuildDir.set(this@SmokeTestAppExtension.applicationBuildDir)
gradleVersion.set(this@SmokeTestAppExtension.gradleVersion)
gradleDistributionBaseUrl.set(this@SmokeTestAppExtension.gradleDistributionBaseUrl)
javaLauncher.set(this@SmokeTestAppExtension.javaLauncher)
tasksToRun.set(nestedTasks)
buildArguments.set(spec.buildArguments)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,37 @@ class SmokeTestAppPluginTest {
assertThat(extension.gradleVersion.get()).isEqualTo(DEFAULT_NESTED_GRADLE_VERSION)
}

@Test
fun `application task receives configured Gradle distribution base URL`() {
val project = ProjectBuilder.builder().build()
project.apply<JavaPlugin>()
project.plugins.apply("dd-trace-java.smoke-test-app")

val extension = project.extensions.getByType<SmokeTestAppExtension>()
extension.gradleDistributionBaseUrl.set("https://mass.example")
extension.application {
taskName.set("packageApp")
artifactPath.set("libs/test.jar")
sysProperty.set("test.path")
}

val task = project.tasks.getByName("packageApp") as NestedGradleBuild

assertThat(task.gradleDistributionBaseUrl.get()).isEqualTo("https://mass.example")
}

@Test
fun `Gradle distribution URI routes through MASS artifact path`() {
assertThat(gradleDistributionUri("https://mass.example", "8.14.5").toString())
.isEqualTo(
"https://mass.example/internal/artifact/services.gradle.org/distributions/gradle-8.14.5-bin.zip",
)
assertThat(gradleDistributionUri("https://mass.example/", "8.14.5").toString())
.isEqualTo(
"https://mass.example/internal/artifact/services.gradle.org/distributions/gradle-8.14.5-bin.zip",
)
}

@Test
fun `extension defaults javaLauncher to a JDK 21 toolchain`() {
// JavaToolchainService is contributed by the `java-base` plugin; apply something that
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
import org.gradle.testkit.runner.TaskOutcome;
import org.gradle.tooling.internal.consumer.DefaultGradleConnector;
import org.gradle.util.GradleVersion;
import org.gradle.util.internal.DistributionLocator;
import org.gradle.wrapper.Download;
import org.gradle.wrapper.GradleUserHomeLookup;
import org.gradle.wrapper.Install;
Expand Down Expand Up @@ -275,8 +274,7 @@ private void ensureDependenciesDownloaded(String gradleVersion) {
Install install = new Install(logger, download, new PathAssembler(userHomeDir, projectDir));

WrapperConfiguration configuration = new WrapperConfiguration();
configuration.setDistribution(
new DistributionLocator().getDistributionFor(GradleVersion.version(gradleVersion)));
configuration.setDistribution(GradleDistribution.uriFor(gradleVersion));
configuration.setNetworkTimeout(GRADLE_DISTRIBUTION_NETWORK_TIMEOUT);

// This will download distribution (if not downloaded yet to userHomeDir) and verify its SHA.
Expand All @@ -292,17 +290,22 @@ private BuildResult runGradle(
String gradleVersion, List<String> arguments, boolean successExpected) throws IOException {
Map<String, String> buildEnv = new HashMap<>();
buildEnv.put("GRADLE_VERSION", gradleVersion);
buildEnv.put(
GradleDistribution.GRADLE_DISTRIBUTION_URL_ENV,
GradleDistribution.uriFor(gradleVersion).toString());

String mavenRepositoryProxy = System.getenv("MAVEN_REPOSITORY_PROXY");
if (mavenRepositoryProxy != null) {
buildEnv.put("MAVEN_REPOSITORY_PROXY", mavenRepositoryProxy);
}
GradleDistribution.propagateMassReadUrl(buildEnv);

GradleRunner gradleRunner =
GradleRunner.create()
.withTestKitDir(testKitFolder.toFile())
.withProjectDir(projectFolder.toFile())
.withGradleVersion(gradleVersion)
GradleDistribution.withDistribution(
GradleRunner.create()
.withTestKitDir(testKitFolder.toFile())
.withProjectDir(projectFolder.toFile()),
gradleVersion)
.withArguments(arguments)
.withEnvironment(buildEnv)
.forwardOutput();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package datadog.smoketest;

import java.io.IOException;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.gradle.testkit.runner.GradleRunner;
import org.gradle.util.GradleVersion;
import org.gradle.util.internal.DistributionLocator;

final class GradleDistribution {

static final String GRADLE_DISTRIBUTION_URL_ENV = "GRADLE_DISTRIBUTION_URL";

private static final String MASS_READ_URL_ENV = "MASS_READ_URL";
private static final Pattern DISTRIBUTION_URL_LINE = Pattern.compile("(?m)^distributionUrl=.*$");

private GradleDistribution() {}

static URI uriFor(String gradleVersion) {
String massReadUrl = System.getenv(MASS_READ_URL_ENV);
if (massReadUrl == null || massReadUrl.trim().isEmpty()) {
return new DistributionLocator().getDistributionFor(GradleVersion.version(gradleVersion));
}
return massUriFor(massReadUrl, gradleVersion);
}

static GradleRunner withDistribution(GradleRunner runner, String gradleVersion) {
String massReadUrl = System.getenv(MASS_READ_URL_ENV);
if (massReadUrl == null || massReadUrl.trim().isEmpty()) {
return runner.withGradleVersion(gradleVersion);
}
return runner.withGradleDistribution(massUriFor(massReadUrl, gradleVersion));
}

static void propagateMassReadUrl(Map<String, String> environment) {
String massReadUrl = System.getenv(MASS_READ_URL_ENV);
if (massReadUrl != null && !massReadUrl.trim().isEmpty()) {
environment.put(MASS_READ_URL_ENV, massReadUrl);
}
}

static String uriPropertiesValueFor(String gradleVersion) {
return uriFor(gradleVersion).toString().replace(":", "\\:");
}

static void rewriteWrapperDistributionUrl(Path projectFolder, String gradleVersion)
throws IOException {
Path wrapperProperties = projectFolder.resolve("gradle/wrapper/gradle-wrapper.properties");
String contents = new String(Files.readAllBytes(wrapperProperties), StandardCharsets.UTF_8);
String replacement = "distributionUrl=" + uriPropertiesValueFor(gradleVersion);
String updated =
DISTRIBUTION_URL_LINE.matcher(contents).replaceFirst(Matcher.quoteReplacement(replacement));
Files.write(wrapperProperties, updated.getBytes(StandardCharsets.UTF_8));
}

private static URI massUriFor(String massReadUrl, String gradleVersion) {
String baseUrl = massReadUrl.endsWith("/") ? massReadUrl : massReadUrl + "/";
return URI.create(
baseUrl
+ "internal/artifact/services.gradle.org/distributions/gradle-"
+ gradleVersion
+ "-bin.zip");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ void testGradleLauncherInjectsTracerIntoGradleDaemon(
Map<String, Map<String, String>> replacements = new HashMap<>();
Map<String, String> versionMap = new HashMap<>();
versionMap.put("gradle-version", resolvedGradleVersion);
versionMap.put(
"gradle-distribution-url", GradleDistribution.uriPropertiesValueFor(resolvedGradleVersion));
replacements.put("gradle-wrapper.properties", versionMap);
givenGradleProjectFiles("test-gradle-wrapper", replacements);
// we want to check that instrumentation works with different wrapper versions too
Expand Down Expand Up @@ -84,6 +86,7 @@ private void givenGradleWrapper(String gradleVersion) throws Exception {
try {
shellCommandExecutor.executeCommand(
IOUtils::readFully, "./gradlew", "wrapper", "--gradle-version", gradleVersion);
GradleDistribution.rewriteWrapperDistributionUrl(projectFolder, gradleVersion);
return;
} catch (ShellCommandExecutor.ShellCommandFailedException e) {
LOGGER.warn("Failed gradle wrapper resolution with exception: ", e);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-${gradle-version}-bin.zip
distributionUrl=${gradle-distribution-url}
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
[ {
"files" : [ {
"bitmap" : "AAAAx+EN",
"bitmap" : "AAAAfOxv",
"filename" : "src/test/java/datadog/smoke/HelloPluginFunctionalTest.java"
} ],
"span_id" : ${content_span_id_4},
"test_session_id" : ${content_test_session_id},
"test_suite_id" : ${content_test_suite_id}
} ]
} ]
Original file line number Diff line number Diff line change
Expand Up @@ -216,8 +216,8 @@
"_dd.profiling.enabled" : 0,
"_dd.trace_span_attribute_schema" : 0,
"process_id" : ${content_metrics_process_id_2},
"test.source.end" : 44,
"test.source.start" : 16
"test.source.end" : 47,
"test.source.start" : 18
},
"name" : "junit5.test_suite",
"resource" : "datadog.smoke.HelloPluginFunctionalTest",
Expand Down Expand Up @@ -278,8 +278,8 @@
"_dd.profiling.enabled" : 0,
"_dd.trace_span_attribute_schema" : 0,
"process_id" : ${content_metrics_process_id_2},
"test.source.end" : 43,
"test.source.start" : 30
"test.source.end" : 46,
"test.source.start" : 34
},
"name" : "junit5.test",
"parent_id" : ${content_parent_id},
Expand Down Expand Up @@ -469,4 +469,4 @@
},
"type" : "span",
"version" : 1
} ]
} ]
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
package datadog.smoke;

import static java.util.Objects.requireNonNull;
import static org.junit.jupiter.api.Assertions.assertTrue;

import org.gradle.testkit.runner.BuildResult;
import org.gradle.testkit.runner.GradleRunner;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import org.gradle.testkit.runner.BuildResult;
import org.gradle.testkit.runner.GradleRunner;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;

class HelloPluginFunctionalTest {

Expand All @@ -22,22 +24,23 @@ class HelloPluginFunctionalTest {
@BeforeEach
void setUp() throws IOException {
buildFile = testProjectDir.resolve("build.gradle").toFile();
Files.write(buildFile.toPath(), "plugins { id 'datadog.smoke.helloplugin' }".getBytes(StandardCharsets.UTF_8));
Files.write(
buildFile.toPath(),
"plugins { id 'datadog.smoke.helloplugin' }".getBytes(StandardCharsets.UTF_8));
}

@Test
void pluginPrintsHelloMessageOnGradle85() {
BuildResult result = GradleRunner.create()
.withProjectDir(testProjectDir.toFile())
.withPluginClasspath()
// Use the same Gradle version as of the actual smoke test that builds this project.
// This is to ensure Gradle is already downloaded and available in the environment.
// Gradle Test Kit can download a Gradle distribution by itself,
// but sometimes these downloads fail, making the test flaky.
.withGradleVersion(System.getenv("GRADLE_VERSION"))
.withArguments("hello", "--stacktrace")
.forwardOutput()
.build();
String gradleDistributionUrl =
requireNonNull(System.getenv("GRADLE_DISTRIBUTION_URL"), "GRADLE_DISTRIBUTION_URL");
BuildResult result =
GradleRunner.create()
.withProjectDir(testProjectDir.toFile())
.withPluginClasspath()
.withGradleDistribution(URI.create(gradleDistributionUrl))
.withArguments("hello", "--stacktrace")
.forwardOutput()
.build();

assertTrue(result.getOutput().contains("Hello from my plugin!"));
}
Expand Down