From a5824d8024199099a23c94b82fe1082d44a009aa Mon Sep 17 00:00:00 2001 From: Brice Dutheil Date: Mon, 18 May 2026 18:06:24 +0200 Subject: [PATCH 1/5] chore(build-logic): add smoke-test plugin for nested Gradle builds Adds a new included build `build-logic/` hosting a single subproject `smoke-test` that exposes the `dd-trace-java.smoke-test-app` plugin. The plugin contributes: - `NestedGradleBuild` task type that runs a nested Gradle build via the Gradle Tooling API. It pins the nested Gradle version (no committed per-application wrappers), uses the configured Java toolchain for the nested daemon, forwards artifact paths from the root build as `-P=`, and redirects the nested `buildDir` via `-PappBuildDir=` so outputs land under the outer project's build directory. - `smokeTestApp` project extension with an `application { ... }` block that registers the `NestedGradleBuild` task, wires it into every `Test` task via `dependsOn` + a `jvmArgumentProvider` for the produced artifact's system property. Consumers can also register `NestedGradleBuild` directly when they need more control; the plugin is a no-op until `application` or a manual registration is done. - `projectJar(name, project)` helper that forwards a sibling project's jar to the nested build through a resolvable `Configuration` (avoids `evaluationDependsOn` and the cross-project access ordering issues). The plugin is verified with JUnit 5 unit tests (`ProjectBuilder`) and end-to-end tests that drive the Tooling API path through the Gradle Test Kit with a temporary Kotlin-DSL test project. `build-logic/settings.gradle.kts` references the existing `gradle/libs.versions.toml` catalog (mirroring `buildSrc/`) so the plugin can use the same library coordinates as the rest of the repo. The Gradle libs Maven repository (`https://repo.gradle.org/gradle/libs-releases`, scoped to `org.gradle:`) is added to the root build's `pluginManagement` and to `gradle/repositories.gradle` so the Tooling API jar resolves. Smoke-test modules with Spring Boot plugin versions incompatible with Gradle 9 will use this plugin in follow-up PRs instead of a committed Gradle 8 wrapper. Co-Authored-By: Claude Opus 4.7 (1M context) --- build-logic/settings.gradle.kts | 50 +++++ build-logic/smoke-test/build.gradle.kts | 56 +++++ .../smoketest/NestedBuildProjectJar.kt | 24 +++ .../buildlogic/smoketest/NestedGradleBuild.kt | 112 ++++++++++ .../smoketest/SmokeTestAppExtension.kt | 182 ++++++++++++++++ .../smoketest/SmokeTestAppPlugin.kt | 20 ++ .../smoketest/SmokeTestAppEndToEndTest.kt | 204 ++++++++++++++++++ .../smoketest/SmokeTestAppPluginTest.kt | 65 ++++++ gradle/libs.versions.toml | 2 + gradle/repositories.gradle | 8 + settings.gradle.kts | 9 + 11 files changed, 732 insertions(+) create mode 100644 build-logic/settings.gradle.kts create mode 100644 build-logic/smoke-test/build.gradle.kts create mode 100644 build-logic/smoke-test/src/main/kotlin/datadog/buildlogic/smoketest/NestedBuildProjectJar.kt create mode 100644 build-logic/smoke-test/src/main/kotlin/datadog/buildlogic/smoketest/NestedGradleBuild.kt create mode 100644 build-logic/smoke-test/src/main/kotlin/datadog/buildlogic/smoketest/SmokeTestAppExtension.kt create mode 100644 build-logic/smoke-test/src/main/kotlin/datadog/buildlogic/smoketest/SmokeTestAppPlugin.kt create mode 100644 build-logic/smoke-test/src/test/kotlin/datadog/buildlogic/smoketest/SmokeTestAppEndToEndTest.kt create mode 100644 build-logic/smoke-test/src/test/kotlin/datadog/buildlogic/smoketest/SmokeTestAppPluginTest.kt diff --git a/build-logic/settings.gradle.kts b/build-logic/settings.gradle.kts new file mode 100644 index 00000000000..612ae4b8fdd --- /dev/null +++ b/build-logic/settings.gradle.kts @@ -0,0 +1,50 @@ +pluginManagement { + repositories { + mavenLocal() + if (settings.extra.has("gradlePluginProxy")) { + maven { + url = uri(settings.extra["gradlePluginProxy"] as String) + isAllowInsecureProtocol = true + } + } + if (settings.extra.has("mavenRepositoryProxy")) { + maven { + url = uri(settings.extra["mavenRepositoryProxy"] as String) + isAllowInsecureProtocol = true + } + } + gradlePluginPortal() + mavenCentral() + } +} + +dependencyResolutionManagement { + versionCatalogs { + create("libs") { + from(files("../gradle/libs.versions.toml")) + } + } + repositories { + mavenLocal() + if (settings.extra.has("mavenRepositoryProxy")) { + maven { + url = uri(settings.extra["mavenRepositoryProxy"] as String) + isAllowInsecureProtocol = true + } + } + gradlePluginPortal() + mavenCentral() + // Hosts gradle-tooling-api; used by the smoke-test plugin to run nested Gradle builds + // pinned to older Gradle versions. + maven { + url = uri("https://repo.gradle.org/gradle/libs-releases") + content { + includeGroup("org.gradle") + } + } + } +} + +rootProject.name = "build-logic" + +include(":smoke-test") diff --git a/build-logic/smoke-test/build.gradle.kts b/build-logic/smoke-test/build.gradle.kts new file mode 100644 index 00000000000..2581025425e --- /dev/null +++ b/build-logic/smoke-test/build.gradle.kts @@ -0,0 +1,56 @@ +plugins { + `java-gradle-plugin` + `kotlin-dsl` + `jvm-test-suite` +} + +java { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 +} + +kotlin { + compilerOptions { + jvmTarget.set(org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_1_8) + } +} + +dependencies { + implementation(libs.gradle.tooling.api) + runtimeOnly("org.slf4j:slf4j-simple:1.7.36") +} + +gradlePlugin { + plugins { + create("smoke-test-app") { + id = "dd-trace-java.smoke-test-app" + implementationClass = "datadog.buildlogic.smoketest.SmokeTestAppPlugin" + } + } +} + +@Suppress("UnstableApiUsage") +testing { + suites { + val test by getting(JvmTestSuite::class) { + useJUnitJupiter(libs.versions.junit5) + dependencies { + implementation(libs.junit.jupiter) + implementation(libs.junit.jupiter.params) + implementation(libs.junit.jupiter.engine) + implementation(libs.assertj.core) + implementation(gradleTestKit()) + } + targets.configureEach { + testTask.configure { + // The gradle-test-kit runner shells out to a Gradle daemon, which can be slow on a + // cold cache. Surface stdout/stderr to make CI failures debuggable. + testLogging { + showStandardStreams = true + events("failed", "skipped") + } + } + } + } + } +} diff --git a/build-logic/smoke-test/src/main/kotlin/datadog/buildlogic/smoketest/NestedBuildProjectJar.kt b/build-logic/smoke-test/src/main/kotlin/datadog/buildlogic/smoketest/NestedBuildProjectJar.kt new file mode 100644 index 00000000000..503f78c47b4 --- /dev/null +++ b/build-logic/smoke-test/src/main/kotlin/datadog/buildlogic/smoketest/NestedBuildProjectJar.kt @@ -0,0 +1,24 @@ +package datadog.buildlogic.smoketest + +import org.gradle.api.file.RegularFileProperty +import org.gradle.api.provider.Property +import org.gradle.api.tasks.Input +import org.gradle.api.tasks.InputFile +import org.gradle.api.tasks.PathSensitive +import org.gradle.api.tasks.PathSensitivity + +/** + * A jar produced by the root build that needs to be forwarded into a [NestedGradleBuild]. + * + * At execution time the task adds `-P${propertyName}=` to the nested + * Gradle invocation, so the inner build script can pick it up via `findProperty(...)`. + */ +abstract class NestedBuildProjectJar { + + @get:Input + abstract val propertyName: Property + + @get:InputFile + @get:PathSensitive(PathSensitivity.NONE) + abstract val file: RegularFileProperty +} 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 new file mode 100644 index 00000000000..bb8a269c4d0 --- /dev/null +++ b/build-logic/smoke-test/src/main/kotlin/datadog/buildlogic/smoketest/NestedGradleBuild.kt @@ -0,0 +1,112 @@ +package datadog.buildlogic.smoketest + +import org.gradle.api.Action +import org.gradle.api.DefaultTask +import org.gradle.api.file.DirectoryProperty +import org.gradle.api.file.FileTree +import org.gradle.api.file.RegularFile +import org.gradle.api.model.ObjectFactory +import org.gradle.api.provider.ListProperty +import org.gradle.api.provider.Property +import org.gradle.api.provider.Provider +import org.gradle.api.tasks.IgnoreEmptyDirectories +import org.gradle.api.tasks.Input +import org.gradle.api.tasks.InputFiles +import org.gradle.api.tasks.Internal +import org.gradle.api.tasks.Nested +import org.gradle.api.tasks.OutputDirectory +import org.gradle.api.tasks.PathSensitive +import org.gradle.api.tasks.PathSensitivity +import org.gradle.api.tasks.TaskAction +import org.gradle.jvm.toolchain.JavaLauncher +import org.gradle.tooling.GradleConnector +import javax.inject.Inject + +/** + * Runs a nested Gradle build inside [applicationDir] via the Gradle Tooling API. + * + * Lets a smoke test pin a Gradle version (typically older than the root build) and a Java + * toolchain for the nested daemon, without committing per-application `gradlew` wrappers. + * + * The nested build script is expected to honour `-PappBuildDir=` and redirect its + * `buildDir` to that path so the artifact lands in [applicationBuildDir]. Project artifacts + * from the root build can be forwarded via [projectJar]; each entry is passed as + * `-P=` and tracked as a task input so the nested build re-runs + * when the upstream jar changes. + */ +abstract class NestedGradleBuild @Inject constructor(private val objects: ObjectFactory) : + DefaultTask() { + + @get:Internal + abstract val applicationDir: DirectoryProperty + + @get:InputFiles + @get:IgnoreEmptyDirectories + @get:PathSensitive(PathSensitivity.RELATIVE) + val applicationSources: FileTree = + objects.fileTree().from(applicationDir).matching { + exclude(".gradle/**", "build/**") + } + + @get:Input + abstract val gradleVersion: Property + + @get:Nested + abstract val javaLauncher: Property + + @get:Input + abstract val tasksToRun: ListProperty + + @get:Input + abstract val buildArguments: ListProperty + + @get:Nested + abstract val projectJars: ListProperty + + @get:OutputDirectory + abstract val applicationBuildDir: DirectoryProperty + + /** Forward a root-build jar as `-P=` into the nested build. */ + fun projectJar(name: String, file: Provider) { + val entry = objects.newInstance(NestedBuildProjectJar::class.java) + entry.propertyName.set(name) + entry.file.set(file) + projectJars.add(entry) + } + + /** Configure additional aspects of the nested build via a typed action. */ + fun projectJar(action: Action) { + val entry = objects.newInstance(NestedBuildProjectJar::class.java) + action.execute(entry) + projectJars.add(entry) + } + + @TaskAction + fun runNestedBuild() { + val appDir = applicationDir.get().asFile + val appBuildDirFile = applicationBuildDir.get().asFile + val daemonJavaHome = javaLauncher.get().metadata.installationPath.asFile + + val args = buildList { + add("-PappBuildDir=${appBuildDirFile.absolutePath}") + projectJars.get().forEach { entry -> + add("-P${entry.propertyName.get()}=${entry.file.get().asFile.absolutePath}") + } + addAll(buildArguments.get()) + } + + val connector = GradleConnector.newConnector() + .useGradleVersion(gradleVersion.get()) + .forProjectDirectory(appDir) + + connector.connect().use { connection -> + connection.newBuild() + .forTasks(*tasksToRun.get().toTypedArray()) + .withArguments(args) + .setJavaHome(daemonJavaHome) + .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 new file mode 100644 index 00000000000..c6a9b926bbc --- /dev/null +++ b/build-logic/smoke-test/src/main/kotlin/datadog/buildlogic/smoketest/SmokeTestAppExtension.kt @@ -0,0 +1,182 @@ +package datadog.buildlogic.smoketest + +import org.gradle.api.Action +import org.gradle.api.Project +import org.gradle.api.artifacts.Configuration +import org.gradle.api.file.DirectoryProperty +import org.gradle.api.file.RegularFile +import org.gradle.api.provider.ListProperty +import org.gradle.api.provider.MapProperty +import org.gradle.api.provider.Property +import org.gradle.api.provider.Provider +import org.gradle.api.tasks.TaskProvider +import org.gradle.api.tasks.testing.Test +import org.gradle.jvm.toolchain.JavaLauncher +import org.gradle.process.CommandLineArgumentProvider +import java.util.Locale +import javax.inject.Inject + +/** + * Project extension that wires a [NestedGradleBuild] task for a smoke-test application. + * + * The plugin only contributes a task when the consumer calls [application]; if the extension + * stays unconfigured, the plugin is a no-op and consumers can register [NestedGradleBuild] + * directly. + */ +abstract class SmokeTestAppExtension @Inject constructor(private val project: Project) { + + /** Gradle version used by the nested daemon. Defaults to the root build's version. */ + abstract val gradleVersion: Property + + /** JDK used by the nested daemon. Required when calling [application]. */ + abstract val javaLauncher: Property + + /** Directory containing the nested project's `settings.gradle` + sources. */ + abstract val applicationDir: DirectoryProperty + + /** + * Directory the nested build writes its outputs to. The nested build script is expected to + * honour `-PappBuildDir=`; see the existing smoke-test inner builds for the pattern. + */ + abstract val applicationBuildDir: DirectoryProperty + + internal abstract val projectJars: ListProperty + + init { + applicationDir.convention(project.layout.projectDirectory.dir("application")) + applicationBuildDir.convention(project.layout.buildDirectory.dir("application")) + gradleVersion.convention(project.gradle.gradleVersion) + } + + /** + * Register the nested-build task and wire the produced artifact into every `Test` task as + * a system property. Calling this triggers task registration; consumers that prefer to + * register [NestedGradleBuild] manually can leave [application] uncalled. + */ + fun application(action: Action) { + require(javaLauncher.isPresent) { + "smokeTestApp.javaLauncher must be set before configuring application { ... }" + } + val spec = project.objects.newInstance(ApplicationSpec::class.java) + action.execute(spec) + val taskName = requireNotNull(spec.taskName.orNull) { + "smokeTestApp.application { taskName = ... } is required" + } + val artifactPath = requireNotNull(spec.artifactPath.orNull) { + "smokeTestApp.application { artifactPath = ... } is required" + } + val sysProperty = requireNotNull(spec.sysProperty.orNull) { + "smokeTestApp.application { sysProperty = ... } is required" + } + val nestedTasks = spec.nestedTasks.orNull?.takeIf { it.isNotEmpty() } ?: listOf(taskName) + + val capturedJars = projectJars + val capturedAppDir = applicationDir + val capturedAppBuildDir = applicationBuildDir + val capturedGradleVersion = gradleVersion + val capturedJavaLauncher = javaLauncher + val capturedBuildArguments = spec.buildArguments + + val taskProvider: TaskProvider = + project.tasks.register(taskName, NestedGradleBuild::class.java) { + applicationDir.set(capturedAppDir) + applicationBuildDir.set(capturedAppBuildDir) + gradleVersion.set(capturedGradleVersion) + javaLauncher.set(capturedJavaLauncher) + tasksToRun.set(nestedTasks) + buildArguments.set(capturedBuildArguments) + projectJars.set(capturedJars) + } + + val artifactProvider: Provider = applicationBuildDir.file(artifactPath) + val extras = spec.additionalSystemProperties.get().mapValues { (_, relativePath) -> + applicationBuildDir.file(relativePath) + } + project.tasks.withType(Test::class.java).configureEach { + dependsOn(taskProvider) + jvmArgumentProviders.add(SmokeTestArgProvider(sysProperty, artifactProvider, extras)) + } + } + + /** + * Forward the default `jar` artifact from [sourceProject] into the nested build as + * `-P=`. The jar is consumed via a resolvable [Configuration], + * which both establishes the correct task dependency and lets Gradle resolve the artifact + * lazily — no `evaluationDependsOn` is needed. + */ + fun projectJar(propertyName: String, sourceProject: Project) { + val configurationName = "smokeTestAppExtraJar" + + propertyName.replaceFirstChar { it.titlecase(Locale.ROOT) } + val cfg = project.configurations.maybeCreate(configurationName).apply { + isCanBeConsumed = false + isCanBeResolved = true + isTransitive = false + description = "Jar artifact forwarded as -P$propertyName into the smoke-test nested build" + } + project.dependencies.add(configurationName, sourceProject) + addProjectJarFromConfiguration(propertyName, cfg) + } + + /** + * Lower-level overload for the rare case where the caller already has a provider of the + * file. The caller is responsible for the upstream task dependency. + */ + fun projectJar(propertyName: String, file: Provider) { + val entry = project.objects.newInstance(NestedBuildProjectJar::class.java) + entry.propertyName.set(propertyName) + entry.file.set(file) + projectJars.add(entry) + } + + private fun addProjectJarFromConfiguration(propertyName: String, cfg: Configuration) { + val entry = project.objects.newInstance(NestedBuildProjectJar::class.java) + entry.propertyName.set(propertyName) + // Configuration.elements yields a Provider that carries the producing task dependency, so + // wiring it into the task's @InputFile both tracks file contents and arranges build order. + entry.file.set( + cfg.elements.map { files -> + project.objects.fileProperty().fileValue(files.single().asFile).get() + } + ) + projectJars.add(entry) + } +} + +/** DSL describing the nested-build invocation for one smoke-test application. */ +abstract class ApplicationSpec @Inject constructor() { + /** Outer task name; the nested daemon runs the same task by default. */ + abstract val taskName: Property + + /** Path to the produced artifact, relative to `applicationBuildDir`. */ + abstract val artifactPath: Property + + /** System property name set on Test tasks to point them at the produced artifact. */ + abstract val sysProperty: Property + + /** Tasks run inside the nested build. Defaults to `[taskName]`. */ + abstract val nestedTasks: ListProperty + + /** Extra arguments passed to the nested Gradle invocation. */ + abstract val buildArguments: ListProperty + + /** + * Additional system properties to forward to every `Test` task, keyed by property name with + * values resolved against `applicationBuildDir`. Use this for smoke tests that need more + * than the single primary artifact path (e.g. a separately unpacked server install). + */ + abstract val additionalSystemProperties: MapProperty +} + +private class SmokeTestArgProvider( + private val sysProperty: String, + private val artifact: Provider, + private val extras: Map>, +) : CommandLineArgumentProvider { + override fun asArguments(): Iterable = + buildList { + add("-D$sysProperty=${artifact.get().asFile.absolutePath}") + extras.forEach { (key, value) -> + add("-D$key=${value.get().asFile.absolutePath}") + } + } +} diff --git a/build-logic/smoke-test/src/main/kotlin/datadog/buildlogic/smoketest/SmokeTestAppPlugin.kt b/build-logic/smoke-test/src/main/kotlin/datadog/buildlogic/smoketest/SmokeTestAppPlugin.kt new file mode 100644 index 00000000000..a3bb337eaac --- /dev/null +++ b/build-logic/smoke-test/src/main/kotlin/datadog/buildlogic/smoketest/SmokeTestAppPlugin.kt @@ -0,0 +1,20 @@ +package datadog.buildlogic.smoketest + +import org.gradle.api.Plugin +import org.gradle.api.Project + +/** + * Exposes the [NestedGradleBuild] task type plus a `smokeTestApp` extension that wires the + * nested-build task and Test-side system properties for a smoke-test application. + * + * Consumers can either: + * - configure `smokeTestApp { application { ... } }` to let the plugin register the task and + * wire it into every `Test` task, or + * - leave the extension untouched and register a [NestedGradleBuild] task manually (for cases + * that need more control, e.g. additional `Exec`-like task wiring). + */ +class SmokeTestAppPlugin : Plugin { + override fun apply(project: Project) { + project.extensions.create("smokeTestApp", SmokeTestAppExtension::class.java) + } +} 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 new file mode 100644 index 00000000000..b3ad87bbaf3 --- /dev/null +++ b/build-logic/smoke-test/src/test/kotlin/datadog/buildlogic/smoketest/SmokeTestAppEndToEndTest.kt @@ -0,0 +1,204 @@ +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.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.io.TempDir +import java.io.File +import java.nio.file.Path + +/** + * End-to-end tests that drive the plugin through the Gradle Test Kit and a temporary, + * self-contained Kotlin-DSL test project. The inner "smoke-test application" is itself a + * minimal Kotlin-DSL Gradle build; the outer build wires it through the `smokeTestApp` DSL. + * + * These tests are slow (each test spins up a Gradle daemon) but they are the only way to + * exercise the Tooling API path end-to-end. + */ +class SmokeTestAppEndToEndTest { + + @TempDir + lateinit var projectDir: Path + + private val outerSettings get() = projectDir.resolve("settings.gradle.kts").toFile() + private val outerBuild get() = projectDir.resolve("build.gradle.kts").toFile() + private val applicationDir get() = projectDir.resolve("application").toFile() + + @BeforeEach + fun setUp() { + applicationDir.mkdirs() + } + + @Test + fun `application block registers a NestedGradleBuild task with the configured name`() { + 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("packageApp") + artifactPath.set("libs/test.jar") + sysProperty.set("test.path") + } + } + """.trimIndent(), + ) + + val result = runner("tasks", "--all").build() + + assertThat(result.output).contains("packageApp") + } + + @Test + fun `nested build produces the configured artifact`() { + 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("buildJar") + artifactPath.set("libs/sample.jar") + sysProperty.set("sample.path") + } + } + """.trimIndent(), + ) + writeInnerSettings() + writeInnerBuild( + """ + tasks.register("buildJar") { + archiveFileName.set("sample.jar") + from(file("src")) + } + """.trimIndent(), + ) + File(applicationDir, "src").mkdir() + File(applicationDir, "src/hello.txt").writeText("hi") + + val result = runner("buildJar").build() + + assertThat(result.task(":buildJar")?.outcome).isEqualTo(TaskOutcome.SUCCESS) + assertThat(File(projectDir.toFile(), "build/application/libs/sample.jar")).exists() + } + + @Test + fun `plugin is a no-op when the application block is never called`() { + writeOuterSettings() + outerBuild.writeText( + """ + plugins { + java + id("dd-trace-java.smoke-test-app") + } + + smokeTestApp { + // No application block, no javaLauncher — should not blow up. + } + """.trimIndent(), + ) + + val result = runner("help").build() + + assertThat(result.output).contains("BUILD SUCCESSFUL") + } + + @Test + fun `manual NestedGradleBuild task registration works without the application block`() { + writeOuterSettings() + outerBuild.writeText( + """ + import datadog.buildlogic.smoketest.NestedGradleBuild + + plugins { + java + id("dd-trace-java.smoke-test-app") + } + + tasks.register("customBuild") { + applicationDir.set(layout.projectDirectory.dir("application")) + applicationBuildDir.set(layout.buildDirectory.dir("application")) + gradleVersion.set(gradle.gradleVersion) + javaLauncher.set( + javaToolchains.launcherFor { languageVersion.set(JavaLanguageVersion.of(${currentMajorJdk()})) } + ) + tasksToRun.set(listOf("buildJar")) + } + """.trimIndent(), + ) + writeInnerSettings() + writeInnerBuild( + """ + tasks.register("buildJar") { + archiveFileName.set("custom.jar") + from(file("src")) + } + """.trimIndent(), + ) + File(applicationDir, "src").mkdir() + File(applicationDir, "src/hello.txt").writeText("hi") + + val result = runner("customBuild").build() + + assertThat(result.task(":customBuild")?.outcome).isEqualTo(TaskOutcome.SUCCESS) + } + + private fun writeOuterSettings() { + outerSettings.writeText( + """ + rootProject.name = "smoke-test-app-fixture" + """.trimIndent(), + ) + } + + private fun writeInnerSettings() { + File(applicationDir, "settings.gradle.kts").writeText( + """ + rootProject.name = "smoke-test-app-fixture-application" + """.trimIndent(), + ) + } + + private fun writeInnerBuild(taskBlock: String) { + File(applicationDir, "build.gradle.kts").writeText( + """ + plugins { + java + } + if (hasProperty("appBuildDir")) { + layout.buildDirectory.set(file(property("appBuildDir") as String)) + } + $taskBlock + """.trimIndent(), + ) + } + + private fun runner(vararg args: String): GradleRunner = + GradleRunner.create() + .withProjectDir(projectDir.toFile()) + .withPluginClasspath() + .withArguments(*args, "--stacktrace") + .forwardOutput() + + private fun currentMajorJdk(): Int = + System.getProperty("java.specification.version").let { + if (it.startsWith("1.")) it.substring(2).toInt() else it.toInt() + } +} diff --git a/build-logic/smoke-test/src/test/kotlin/datadog/buildlogic/smoketest/SmokeTestAppPluginTest.kt b/build-logic/smoke-test/src/test/kotlin/datadog/buildlogic/smoketest/SmokeTestAppPluginTest.kt new file mode 100644 index 00000000000..a082444d733 --- /dev/null +++ b/build-logic/smoke-test/src/test/kotlin/datadog/buildlogic/smoketest/SmokeTestAppPluginTest.kt @@ -0,0 +1,65 @@ +package datadog.buildlogic.smoketest + +import org.assertj.core.api.Assertions.assertThat +import org.gradle.testfixtures.ProjectBuilder +import org.junit.jupiter.api.Test + +/** + * Fast in-process tests that exercise plugin application and extension wiring through + * [ProjectBuilder]. End-to-end task execution lives in [SmokeTestAppEndToEndTest]. + */ +class SmokeTestAppPluginTest { + + @Test + fun `applying the plugin creates the smokeTestApp extension`() { + val project = ProjectBuilder.builder().build() + + project.plugins.apply("dd-trace-java.smoke-test-app") + + val extension = project.extensions.findByName("smokeTestApp") + assertThat(extension).isInstanceOf(SmokeTestAppExtension::class.java) + } + + @Test + fun `plugin is a no-op when smokeTestApp_application is never called`() { + val project = ProjectBuilder.builder().build() + + project.plugins.apply("dd-trace-java.smoke-test-app") + + // No task of our type should be registered until `application { }` is invoked. + val nestedBuildTasks = project.tasks.withType(NestedGradleBuild::class.java) + assertThat(nestedBuildTasks).isEmpty() + } + + @Test + fun `extension defaults applicationDir to projectDir slash application`() { + val project = ProjectBuilder.builder().build() + project.plugins.apply("dd-trace-java.smoke-test-app") + + val extension = project.extensions.getByType(SmokeTestAppExtension::class.java) + + assertThat(extension.applicationDir.get().asFile) + .isEqualTo(project.layout.projectDirectory.dir("application").asFile) + } + + @Test + fun `extension defaults applicationBuildDir to buildDir slash application`() { + val project = ProjectBuilder.builder().build() + project.plugins.apply("dd-trace-java.smoke-test-app") + + val extension = project.extensions.getByType(SmokeTestAppExtension::class.java) + + assertThat(extension.applicationBuildDir.get().asFile) + .isEqualTo(project.layout.buildDirectory.dir("application").get().asFile) + } + + @Test + fun `extension defaults gradleVersion to the host build's version`() { + val project = ProjectBuilder.builder().build() + project.plugins.apply("dd-trace-java.smoke-test-app") + + val extension = project.extensions.getByType(SmokeTestAppExtension::class.java) + + assertThat(extension.gradleVersion.get()).isEqualTo(project.gradle.gradleVersion) + } +} diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 6b1916a456f..6abe7896aab 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -4,6 +4,7 @@ # Build develocity = "4.4.1" forbiddenapis = "3.10" +gradle-tooling-api = "8.14.5" spotbugs_annotations = "4.9.8" # DataDog libs and forks @@ -78,6 +79,7 @@ testcontainers = "1.21.4" # Build develocity = { module = "com.gradle:develocity-gradle-plugin", version.ref = "develocity" } forbiddenapis = { module = "de.thetaphi:forbiddenapis", version.ref = "forbiddenapis" } +gradle-tooling-api = { module = "org.gradle:gradle-tooling-api", version.ref = "gradle-tooling-api" } spotbugs-annotations = { module = "com.github.spotbugs:spotbugs-annotations", version.ref = "spotbugs_annotations" } # DataDog libs and forks diff --git a/gradle/repositories.gradle b/gradle/repositories.gradle index 98085e93c50..e7d4824b4c6 100644 --- a/gradle/repositories.gradle +++ b/gradle/repositories.gradle @@ -35,4 +35,12 @@ repositories { includeGroupAndSubgroups "org.springframework" } } + // Hosts gradle-tooling-api, used by build-logic:smoke-test to run nested + // Gradle builds for smoke-test applications pinned to older Gradle versions. + maven { + url = 'https://repo.gradle.org/gradle/libs-releases' + content { + includeGroup "org.gradle" + } + } } diff --git a/settings.gradle.kts b/settings.gradle.kts index bd5aaceffaa..e6c9469b9c6 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -16,7 +16,16 @@ pluginManagement { } gradlePluginPortal() mavenCentral() + // Hosts gradle-tooling-api, a transitive dep of the build-logic:smoke-test plugin used + // to run nested Gradle builds for smoke-test applications pinned to older Gradle versions. + maven { + url = uri("https://repo.gradle.org/gradle/libs-releases") + content { + includeGroup("org.gradle") + } + } } + includeBuild("build-logic") } plugins { From 156219263174f984957431724c4728edd4d87b35 Mon Sep 17 00:00:00 2001 From: Brice Dutheil Date: Tue, 19 May 2026 16:00:39 +0200 Subject: [PATCH 2/5] chore(build-logic): default smokeTestApp to JDK 21 daemon + Gradle 8.14.5 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Set conventions on `smokeTestApp`: - `gradleVersion` defaults to `"8.14.5"` (Gradle 8 last release; pinned because Spring Boot plugin pre-3.5 calls `Configuration.getUploadTaskName()`, removed in Gradle 9). - `javaLauncher` defaults to a JDK 21 toolchain (the version the root build requires for its own Gradle 9 migration; standardising the nested daemon on the same JDK avoids requiring an extra toolchain on dev machines and CI runners). Consumers that need a different JDK or Gradle version still override explicitly. The inner build script is responsible for pinning the produced bytecode level (`java { sourceCompatibility = JavaVersion.VERSION_1_8 }` or similar) — Gradle adds `--release N` automatically when source/target differs from the daemon JVM. `JavaToolchainService` is now injected into the extension; this works in any project where a `java*` (or related) plugin is applied. Smoke-test modules already apply `gradle/java.gradle`, which applies `java`, so the convention resolves on first read. Public defaults exposed as `DEFAULT_NESTED_GRADLE_VERSION` and `DEFAULT_NESTED_JAVA_VERSION` constants so the values are discoverable. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../buildlogic/smoketest/NestedGradleBuild.kt | 17 ++++++- .../smoketest/SmokeTestAppExtension.kt | 45 ++++++++++++++++--- .../smoketest/SmokeTestAppPluginTest.kt | 20 ++++++++- 3 files changed, 71 insertions(+), 11 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 bb8a269c4d0..d31aaaa5cc9 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 @@ -18,7 +18,9 @@ import org.gradle.api.tasks.OutputDirectory import org.gradle.api.tasks.PathSensitive import org.gradle.api.tasks.PathSensitivity import org.gradle.api.tasks.TaskAction +import org.gradle.jvm.toolchain.JavaLanguageVersion import org.gradle.jvm.toolchain.JavaLauncher +import org.gradle.jvm.toolchain.JavaToolchainService import org.gradle.tooling.GradleConnector import javax.inject.Inject @@ -34,8 +36,19 @@ import javax.inject.Inject * `-P=` and tracked as a task input so the nested build re-runs * when the upstream jar changes. */ -abstract class NestedGradleBuild @Inject constructor(private val objects: ObjectFactory) : - DefaultTask() { +abstract class NestedGradleBuild @Inject constructor( + private val objects: ObjectFactory, + javaToolchains: JavaToolchainService, +) : DefaultTask() { + + init { + gradleVersion.convention(DEFAULT_NESTED_GRADLE_VERSION) + javaLauncher.convention( + javaToolchains.launcherFor { + languageVersion.set(JavaLanguageVersion.of(DEFAULT_NESTED_JAVA_VERSION)) + }, + ) + } @get:Internal abstract val applicationDir: DirectoryProperty 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 c6a9b926bbc..1efc51d4e9e 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 @@ -11,7 +11,9 @@ import org.gradle.api.provider.Property import org.gradle.api.provider.Provider import org.gradle.api.tasks.TaskProvider import org.gradle.api.tasks.testing.Test +import org.gradle.jvm.toolchain.JavaLanguageVersion import org.gradle.jvm.toolchain.JavaLauncher +import org.gradle.jvm.toolchain.JavaToolchainService import org.gradle.process.CommandLineArgumentProvider import java.util.Locale import javax.inject.Inject @@ -23,12 +25,24 @@ import javax.inject.Inject * stays unconfigured, the plugin is a no-op and consumers can register [NestedGradleBuild] * directly. */ -abstract class SmokeTestAppExtension @Inject constructor(private val project: Project) { +abstract class SmokeTestAppExtension @Inject constructor( + private val project: Project, + javaToolchains: JavaToolchainService, +) { - /** Gradle version used by the nested daemon. Defaults to the root build's version. */ + /** + * Gradle version used by the nested daemon. Defaults to [DEFAULT_NESTED_GRADLE_VERSION] — + * the version pinned for smoke-test applications whose Spring Boot plugin is incompatible + * with Gradle 9. + */ abstract val gradleVersion: Property - /** JDK used by the nested daemon. Required when calling [application]. */ + /** + * 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. + * The inner build script is responsible for pinning the produced bytecode level (e.g. + * `java { sourceCompatibility = JavaVersion.VERSION_1_8 }`). + */ abstract val javaLauncher: Property /** Directory containing the nested project's `settings.gradle` + sources. */ @@ -45,7 +59,12 @@ abstract class SmokeTestAppExtension @Inject constructor(private val project: Pr init { applicationDir.convention(project.layout.projectDirectory.dir("application")) applicationBuildDir.convention(project.layout.buildDirectory.dir("application")) - gradleVersion.convention(project.gradle.gradleVersion) + gradleVersion.convention(DEFAULT_NESTED_GRADLE_VERSION) + javaLauncher.convention( + javaToolchains.launcherFor { + languageVersion.set(JavaLanguageVersion.of(DEFAULT_NESTED_JAVA_VERSION)) + }, + ) } /** @@ -54,9 +73,6 @@ abstract class SmokeTestAppExtension @Inject constructor(private val project: Pr * register [NestedGradleBuild] manually can leave [application] uncalled. */ fun application(action: Action) { - require(javaLauncher.isPresent) { - "smokeTestApp.javaLauncher must be set before configuring application { ... }" - } val spec = project.objects.newInstance(ApplicationSpec::class.java) action.execute(spec) val taskName = requireNotNull(spec.taskName.orNull) { @@ -167,6 +183,21 @@ abstract class ApplicationSpec @Inject constructor() { abstract val additionalSystemProperties: MapProperty } +/** + * Default Gradle distribution version for the nested daemon. Pinned to a Gradle 8 release + * because the Spring Boot Gradle plugin pre-3.5.0 calls `Configuration.getUploadTaskName()`, + * removed in Gradle 9. + */ +const val DEFAULT_NESTED_GRADLE_VERSION = "8.14.5" + +/** + * Default JDK language version for the nested daemon. JDK 21 is the version the root build + * requires for Gradle 9; standardising the nested daemon on the same JDK avoids pulling a + * second toolchain onto dev machines and CI runners. Inner build scripts cross-compile down + * to their actual bytecode target via `java { sourceCompatibility = ... }`. + */ +const val DEFAULT_NESTED_JAVA_VERSION = 21 + private class SmokeTestArgProvider( private val sysProperty: String, private val artifact: Provider, diff --git a/build-logic/smoke-test/src/test/kotlin/datadog/buildlogic/smoketest/SmokeTestAppPluginTest.kt b/build-logic/smoke-test/src/test/kotlin/datadog/buildlogic/smoketest/SmokeTestAppPluginTest.kt index a082444d733..9d0d14b2727 100644 --- a/build-logic/smoke-test/src/test/kotlin/datadog/buildlogic/smoketest/SmokeTestAppPluginTest.kt +++ b/build-logic/smoke-test/src/test/kotlin/datadog/buildlogic/smoketest/SmokeTestAppPluginTest.kt @@ -1,6 +1,8 @@ package datadog.buildlogic.smoketest import org.assertj.core.api.Assertions.assertThat +import org.gradle.api.plugins.JavaPlugin +import org.gradle.jvm.toolchain.JavaLanguageVersion import org.gradle.testfixtures.ProjectBuilder import org.junit.jupiter.api.Test @@ -54,12 +56,26 @@ class SmokeTestAppPluginTest { } @Test - fun `extension defaults gradleVersion to the host build's version`() { + fun `extension defaults gradleVersion to the smoke-test pinned version`() { val project = ProjectBuilder.builder().build() project.plugins.apply("dd-trace-java.smoke-test-app") val extension = project.extensions.getByType(SmokeTestAppExtension::class.java) - assertThat(extension.gradleVersion.get()).isEqualTo(project.gradle.gradleVersion) + assertThat(extension.gradleVersion.get()).isEqualTo(DEFAULT_NESTED_GRADLE_VERSION) + } + + @Test + fun `extension defaults javaLauncher to a JDK 21 toolchain`() { + // JavaToolchainService is contributed by the `java-base` plugin; apply something that + // pulls it in so ProjectBuilder can resolve the convention. + val project = ProjectBuilder.builder().build() + project.plugins.apply(JavaPlugin::class.java) + project.plugins.apply("dd-trace-java.smoke-test-app") + + val extension = project.extensions.getByType(SmokeTestAppExtension::class.java) + + assertThat(extension.javaLauncher.get().metadata.languageVersion) + .isEqualTo(JavaLanguageVersion.of(DEFAULT_NESTED_JAVA_VERSION)) } } From 0139443cfc6cb9e08a196ae24f8aeb5dad6c2485 Mon Sep 17 00:00:00 2001 From: Brice Dutheil Date: Tue, 19 May 2026 18:59:46 +0200 Subject: [PATCH 3/5] chore(build-logic): use org.gradle.kotlin.dsl idioms in smoke-test plugin MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Switch the plugin sources and unit tests over to the typed `org.gradle.kotlin.dsl` extension functions where they replace `::class.java` boilerplate: - `tasks.register(name, Type::class.java) { … }` → `tasks.register(name) { … }` - `tasks.withType(Type::class.java).configureEach { … }` → `tasks.withType().configureEach { … }` - `extensions.create("name", Type::class.java)` → `extensions.create("name")` - `extensions.getByType(Type::class.java)` → `extensions.getByType()` - `extensions.findByName("name")` (followed by `isInstanceOf`) → `extensions.findByType()` - `project.plugins.apply(Plugin::class.java)` → `project.apply()` (PluginAware) - `objects.newInstance(Type::class.java)` → `objects.newInstance()` Also drop the six `captured*` local variables in `SmokeTestAppExtension.application` — inside `tasks.register(taskName) { … }` the outer extension's properties are now reached via `this@SmokeTestAppExtension.` directly. No behavioural change; the 9 plugin tests still pass. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../buildlogic/smoketest/NestedGradleBuild.kt | 17 +++--- .../smoketest/SmokeTestAppExtension.kt | 59 ++++++++++--------- .../smoketest/SmokeTestAppPlugin.kt | 3 +- .../smoketest/SmokeTestAppPluginTest.kt | 20 ++++--- 4 files changed, 53 insertions(+), 46 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 d31aaaa5cc9..e2c1c34f09f 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 @@ -21,6 +21,7 @@ import org.gradle.api.tasks.TaskAction import org.gradle.jvm.toolchain.JavaLanguageVersion import org.gradle.jvm.toolchain.JavaLauncher import org.gradle.jvm.toolchain.JavaToolchainService +import org.gradle.kotlin.dsl.newInstance import org.gradle.tooling.GradleConnector import javax.inject.Inject @@ -81,17 +82,19 @@ abstract class NestedGradleBuild @Inject constructor( /** Forward a root-build jar as `-P=` into the nested build. */ fun projectJar(name: String, file: Provider) { - val entry = objects.newInstance(NestedBuildProjectJar::class.java) - entry.propertyName.set(name) - entry.file.set(file) - projectJars.add(entry) + projectJars.add( + objects.newInstance().apply { + propertyName.set(name) + this.file.set(file) + }, + ) } /** Configure additional aspects of the nested build via a typed action. */ fun projectJar(action: Action) { - val entry = objects.newInstance(NestedBuildProjectJar::class.java) - action.execute(entry) - projectJars.add(entry) + projectJars.add( + objects.newInstance().also(action::execute), + ) } @TaskAction 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 1efc51d4e9e..ccb5ee838db 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 @@ -14,6 +14,9 @@ import org.gradle.api.tasks.testing.Test import org.gradle.jvm.toolchain.JavaLanguageVersion import org.gradle.jvm.toolchain.JavaLauncher import org.gradle.jvm.toolchain.JavaToolchainService +import org.gradle.kotlin.dsl.newInstance +import org.gradle.kotlin.dsl.register +import org.gradle.kotlin.dsl.withType import org.gradle.process.CommandLineArgumentProvider import java.util.Locale import javax.inject.Inject @@ -73,7 +76,7 @@ abstract class SmokeTestAppExtension @Inject constructor( * register [NestedGradleBuild] manually can leave [application] uncalled. */ fun application(action: Action) { - val spec = project.objects.newInstance(ApplicationSpec::class.java) + val spec = project.objects.newInstance() action.execute(spec) val taskName = requireNotNull(spec.taskName.orNull) { "smokeTestApp.application { taskName = ... } is required" @@ -86,29 +89,22 @@ abstract class SmokeTestAppExtension @Inject constructor( } val nestedTasks = spec.nestedTasks.orNull?.takeIf { it.isNotEmpty() } ?: listOf(taskName) - val capturedJars = projectJars - val capturedAppDir = applicationDir - val capturedAppBuildDir = applicationBuildDir - val capturedGradleVersion = gradleVersion - val capturedJavaLauncher = javaLauncher - val capturedBuildArguments = spec.buildArguments - val taskProvider: TaskProvider = - project.tasks.register(taskName, NestedGradleBuild::class.java) { - applicationDir.set(capturedAppDir) - applicationBuildDir.set(capturedAppBuildDir) - gradleVersion.set(capturedGradleVersion) - javaLauncher.set(capturedJavaLauncher) + project.tasks.register(taskName) { + applicationDir.set(this@SmokeTestAppExtension.applicationDir) + applicationBuildDir.set(this@SmokeTestAppExtension.applicationBuildDir) + gradleVersion.set(this@SmokeTestAppExtension.gradleVersion) + javaLauncher.set(this@SmokeTestAppExtension.javaLauncher) tasksToRun.set(nestedTasks) - buildArguments.set(capturedBuildArguments) - projectJars.set(capturedJars) + buildArguments.set(spec.buildArguments) + projectJars.set(this@SmokeTestAppExtension.projectJars) } val artifactProvider: Provider = applicationBuildDir.file(artifactPath) val extras = spec.additionalSystemProperties.get().mapValues { (_, relativePath) -> applicationBuildDir.file(relativePath) } - project.tasks.withType(Test::class.java).configureEach { + project.tasks.withType().configureEach { dependsOn(taskProvider) jvmArgumentProviders.add(SmokeTestArgProvider(sysProperty, artifactProvider, extras)) } @@ -138,23 +134,28 @@ abstract class SmokeTestAppExtension @Inject constructor( * file. The caller is responsible for the upstream task dependency. */ fun projectJar(propertyName: String, file: Provider) { - val entry = project.objects.newInstance(NestedBuildProjectJar::class.java) - entry.propertyName.set(propertyName) - entry.file.set(file) - projectJars.add(entry) + projectJars.add( + project.objects.newInstance().apply { + this.propertyName.set(propertyName) + this.file.set(file) + }, + ) } private fun addProjectJarFromConfiguration(propertyName: String, cfg: Configuration) { - val entry = project.objects.newInstance(NestedBuildProjectJar::class.java) - entry.propertyName.set(propertyName) - // Configuration.elements yields a Provider that carries the producing task dependency, so - // wiring it into the task's @InputFile both tracks file contents and arranges build order. - entry.file.set( - cfg.elements.map { files -> - project.objects.fileProperty().fileValue(files.single().asFile).get() - } + projectJars.add( + project.objects.newInstance().apply { + this.propertyName.set(propertyName) + // Configuration.elements yields a Provider that carries the producing task dependency, + // so wiring it into the task's @InputFile both tracks file contents and arranges build + // order. + this.file.set( + cfg.elements.map { files -> + project.objects.fileProperty().fileValue(files.single().asFile).get() + }, + ) + }, ) - projectJars.add(entry) } } diff --git a/build-logic/smoke-test/src/main/kotlin/datadog/buildlogic/smoketest/SmokeTestAppPlugin.kt b/build-logic/smoke-test/src/main/kotlin/datadog/buildlogic/smoketest/SmokeTestAppPlugin.kt index a3bb337eaac..b6d6fe6b7ba 100644 --- a/build-logic/smoke-test/src/main/kotlin/datadog/buildlogic/smoketest/SmokeTestAppPlugin.kt +++ b/build-logic/smoke-test/src/main/kotlin/datadog/buildlogic/smoketest/SmokeTestAppPlugin.kt @@ -2,6 +2,7 @@ package datadog.buildlogic.smoketest import org.gradle.api.Plugin import org.gradle.api.Project +import org.gradle.kotlin.dsl.create /** * Exposes the [NestedGradleBuild] task type plus a `smokeTestApp` extension that wires the @@ -15,6 +16,6 @@ import org.gradle.api.Project */ class SmokeTestAppPlugin : Plugin { override fun apply(project: Project) { - project.extensions.create("smokeTestApp", SmokeTestAppExtension::class.java) + project.extensions.create("smokeTestApp") } } diff --git a/build-logic/smoke-test/src/test/kotlin/datadog/buildlogic/smoketest/SmokeTestAppPluginTest.kt b/build-logic/smoke-test/src/test/kotlin/datadog/buildlogic/smoketest/SmokeTestAppPluginTest.kt index 9d0d14b2727..22fd1ce93fe 100644 --- a/build-logic/smoke-test/src/test/kotlin/datadog/buildlogic/smoketest/SmokeTestAppPluginTest.kt +++ b/build-logic/smoke-test/src/test/kotlin/datadog/buildlogic/smoketest/SmokeTestAppPluginTest.kt @@ -3,6 +3,10 @@ package datadog.buildlogic.smoketest import org.assertj.core.api.Assertions.assertThat import org.gradle.api.plugins.JavaPlugin import org.gradle.jvm.toolchain.JavaLanguageVersion +import org.gradle.kotlin.dsl.apply +import org.gradle.kotlin.dsl.findByType +import org.gradle.kotlin.dsl.getByType +import org.gradle.kotlin.dsl.withType import org.gradle.testfixtures.ProjectBuilder import org.junit.jupiter.api.Test @@ -18,8 +22,7 @@ class SmokeTestAppPluginTest { project.plugins.apply("dd-trace-java.smoke-test-app") - val extension = project.extensions.findByName("smokeTestApp") - assertThat(extension).isInstanceOf(SmokeTestAppExtension::class.java) + assertThat(project.extensions.findByType()).isNotNull } @Test @@ -29,8 +32,7 @@ class SmokeTestAppPluginTest { project.plugins.apply("dd-trace-java.smoke-test-app") // No task of our type should be registered until `application { }` is invoked. - val nestedBuildTasks = project.tasks.withType(NestedGradleBuild::class.java) - assertThat(nestedBuildTasks).isEmpty() + assertThat(project.tasks.withType()).isEmpty() } @Test @@ -38,7 +40,7 @@ class SmokeTestAppPluginTest { val project = ProjectBuilder.builder().build() project.plugins.apply("dd-trace-java.smoke-test-app") - val extension = project.extensions.getByType(SmokeTestAppExtension::class.java) + val extension = project.extensions.getByType() assertThat(extension.applicationDir.get().asFile) .isEqualTo(project.layout.projectDirectory.dir("application").asFile) @@ -49,7 +51,7 @@ class SmokeTestAppPluginTest { val project = ProjectBuilder.builder().build() project.plugins.apply("dd-trace-java.smoke-test-app") - val extension = project.extensions.getByType(SmokeTestAppExtension::class.java) + val extension = project.extensions.getByType() assertThat(extension.applicationBuildDir.get().asFile) .isEqualTo(project.layout.buildDirectory.dir("application").get().asFile) @@ -60,7 +62,7 @@ class SmokeTestAppPluginTest { val project = ProjectBuilder.builder().build() project.plugins.apply("dd-trace-java.smoke-test-app") - val extension = project.extensions.getByType(SmokeTestAppExtension::class.java) + val extension = project.extensions.getByType() assertThat(extension.gradleVersion.get()).isEqualTo(DEFAULT_NESTED_GRADLE_VERSION) } @@ -70,10 +72,10 @@ class SmokeTestAppPluginTest { // JavaToolchainService is contributed by the `java-base` plugin; apply something that // pulls it in so ProjectBuilder can resolve the convention. val project = ProjectBuilder.builder().build() - project.plugins.apply(JavaPlugin::class.java) + project.apply() project.plugins.apply("dd-trace-java.smoke-test-app") - val extension = project.extensions.getByType(SmokeTestAppExtension::class.java) + val extension = project.extensions.getByType() assertThat(extension.javaLauncher.get().metadata.languageVersion) .isEqualTo(JavaLanguageVersion.of(DEFAULT_NESTED_JAVA_VERSION)) From 6b7e87c4fc3cf98ed4c1e731c4912c4309c1cbd0 Mon Sep 17 00:00:00 2001 From: Brice Dutheil Date: Mon, 18 May 2026 18:16:28 +0200 Subject: [PATCH 4/5] chore(smoke-tests): extract Spring Boot 2.x app source into nested-build subprojects MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Spring Boot Gradle plugin is incompatible with Gradle 9 for all versions before 3.5.0 because it calls `Configuration.getUploadTaskName()`, a method removed in Gradle 9. Twelve smoke-test modules were direct Gradle subprojects that applied the Spring Boot plugin to build their bootJar / bootWar artefact. They cannot stay as subprojects of the Gradle 9 root build. For each of these modules, the application source is extracted into a new `application/` subdirectory that is a fully self-contained Gradle project (`settings.gradle` + `build.gradle`). The outer module keeps the test source and delegates the application build to the `dd-trace-java.smoke-test-app` plugin from `build-logic/` (added in the parent infrastructure PR), which runs the nested build via the Gradle Tooling API pinned to Gradle 8.14.5 — no committed `gradlew` wrapper. Modules converted (bootJar): - springboot-thymeleaf (Spring Boot 2.7.15, Java 8) - springboot-freemarker (Spring Boot 2.7.15 plugin / 1.5.18 starter, Java 8) - springboot-velocity (Spring Boot 2.7.15 plugin / 1.5.18 starter, Java 8) - springboot-java-11 (Spring Boot 2.7.15, Java 11; passes iast-util-11 jar) - springboot-java-17 (Spring Boot 2.7.15, Java 17; passes iast-util-17 jar) - openfeature (Spring Boot 2.7.15, Java 11; passes feature-flagging-api jar) - kafka-2 (Spring Boot 2.7.15, Java 8; passes iast-util jar) - apm-tracing-disabled (Spring Boot 2.7.15, Java 8; passes dd-trace-api jar) Modules converted (bootWar): - springboot-jpa (Spring Boot 2.6.0, Java 8; Lombok) - springboot-tomcat-jsp (Spring Boot 2.7.15, Java 8; JSP webapp) - springboot-jetty-jsp (Spring Boot 2.7.15, Java 8; JSP webapp) - springboot-tomcat (Spring Boot 2.5.12, Java 8; Ivy Tomcat download + unzip) Where an application module depends on a project artifact from the main build (e.g. iast-util-11, dd-trace-api), the jar is forwarded via the plugin's `projectJar(name, project)` helper — a resolvable `Configuration` that establishes the upstream task dependency automatically. The inner build picks it up via `findProperty(name)` and adds it as `implementation files(...)`. The `spring-kafka-test` test dependency in kafka-2 is pinned to 2.8.11 (the version previously resolved from the Spring Boot BOM) since the outer test module no longer applies that BOM. For springboot-freemarker and springboot-velocity, the `XssController` loads templates from `resources/main/templates` relative to the test JVM's working directory. After moving sources into `application/`, those files land at `build/application/resources/main/templates/` instead of `build/resources/main/templates/`. Each affected outer build registers a `copyAppResources` Copy task that mirrors the inner build's processed resources into the outer build dir so the runtime path still resolves. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../application/build.gradle | 38 ++++++ .../application/settings.gradle | 32 +++++ .../apmtracingdisabled/AppConfig.java | 0 .../apmtracingdisabled/Controller.java | 0 .../SpringbootApplication.java | 0 .../apm-tracing-disabled/build.gradle | 38 +++--- .../kafka-2/application/build.gradle | 35 +++++ .../kafka-2/application/settings.gradle | 32 +++++ .../smoketest/kafka/KafkaApplication.java | 0 .../kafka/iast/IastConfiguration.java | 0 .../smoketest/kafka/iast/IastController.java | 0 .../smoketest/kafka/iast/IastMessage.java | 0 dd-smoke-tests/kafka-2/build.gradle | 44 +++--- .../openfeature/application/build.gradle | 35 +++++ .../openfeature/application/settings.gradle | 32 +++++ .../springboot/SpringbootApplication.java | 0 .../openfeature/OpenFeatureConfiguration.java | 0 .../openfeature/OpenFeatureController.java | 0 dd-smoke-tests/openfeature/build.gradle | 37 +++-- .../application/build.gradle | 26 ++++ .../application/settings.gradle | 32 +++++ .../springboot/SpringbootApplication.java | 0 .../smoketest/springboot/XssController.java | 0 .../templates/freemarker-2.3.24-insecure.ftlh | 0 .../templates/freemarker-2.3.24-secure.ftlh | 0 .../templates/freemarker-2.3.9-insecure.ftlh | 0 .../templates/freemarker-2.3.9-secure.ftlh | 0 .../springboot-freemarker/build.gradle | 55 +++++--- .../application/build.gradle | 31 +++++ .../application/settings.gradle | 32 +++++ .../springboot/SpringbootApplication.java | 0 .../springboot-java-11/build.gradle | 41 +++--- .../application/build.gradle | 31 +++++ .../application/settings.gradle | 32 +++++ .../springboot/SpringbootApplication.java | 0 .../springboot-java-17/build.gradle | 41 +++--- .../application/build.gradle | 37 +++++ .../application/settings.gradle | 32 +++++ .../springboot/SpringbootApplication.java | 0 .../smoketest/springboot/ViewController.java | 0 .../src/main/resources/application.properties | 0 .../src/main/webapp/WEB-INF/jsp/test_xss.jsp | 0 .../springboot-jetty-jsp/build.gradle | 44 ++---- .../springboot-jpa/application/build.gradle | 36 +++++ .../application/settings.gradle | 32 +++++ .../springboot/SpringbootApplication.java | 0 .../controller/LibraryController.java | 0 .../smoketest/springboot/entity/Author.java | 0 .../smoketest/springboot/entity/Book.java | 0 .../smoketest/springboot/entity/Library.java | 0 .../smoketest/springboot/entity/Owner.java | 0 .../filter/SessionVisitorFilter.java | 0 .../springboot/service/LibraryService.java | 0 .../src/main/resources/application.yml | 0 .../src/main/webapp/WEB-INF/jsp/update.jsp | 0 dd-smoke-tests/springboot-jpa/build.gradle | 49 +++---- .../application/build.gradle | 26 ++++ .../application/settings.gradle | 32 +++++ .../springboot/SpringbootApplication.java | 0 .../smoketest/springboot/XssController.java | 0 .../src/main/resources/templates/utext.html | 0 .../springboot-thymeleaf/build.gradle | 36 +++-- .../application/build.gradle | 37 +++++ .../application/settings.gradle | 32 +++++ .../springboot/SpringbootApplication.java | 0 .../smoketest/springboot/ViewController.java | 0 .../src/main/resources/application.properties | 0 .../src/main/webapp/WEB-INF/jsp/test_xss.jsp | 0 .../springboot-tomcat-jsp/build.gradle | 44 ++---- .../application/build.gradle | 89 +++++++++++++ .../application/settings.gradle | 32 +++++ .../SpringbootTomcatApplication.java | 0 .../springboot/controller/TestSuite.java | 0 .../springboot/controller/ViewController.java | 0 .../src/main/resources/application.properties | 0 dd-smoke-tests/springboot-tomcat/build.gradle | 126 +++--------------- .../application/build.gradle | 31 +++++ .../application/settings.gradle | 32 +++++ .../springboot/SpringbootApplication.java | 0 .../smoketest/springboot/XssController.java | 0 .../resources/templates/velocity-insecure.vm | 0 .../resources/templates/velocity-secure.vm | 0 .../springboot-velocity/build.gradle | 56 +++++--- 83 files changed, 1080 insertions(+), 367 deletions(-) create mode 100644 dd-smoke-tests/apm-tracing-disabled/application/build.gradle create mode 100644 dd-smoke-tests/apm-tracing-disabled/application/settings.gradle rename dd-smoke-tests/apm-tracing-disabled/{ => application}/src/main/java/datadog/smoketest/apmtracingdisabled/AppConfig.java (100%) rename dd-smoke-tests/apm-tracing-disabled/{ => application}/src/main/java/datadog/smoketest/apmtracingdisabled/Controller.java (100%) rename dd-smoke-tests/apm-tracing-disabled/{ => application}/src/main/java/datadog/smoketest/apmtracingdisabled/SpringbootApplication.java (100%) create mode 100644 dd-smoke-tests/kafka-2/application/build.gradle create mode 100644 dd-smoke-tests/kafka-2/application/settings.gradle rename dd-smoke-tests/kafka-2/{ => application}/src/main/java/datadog/smoketest/kafka/KafkaApplication.java (100%) rename dd-smoke-tests/kafka-2/{ => application}/src/main/java/datadog/smoketest/kafka/iast/IastConfiguration.java (100%) rename dd-smoke-tests/kafka-2/{ => application}/src/main/java/datadog/smoketest/kafka/iast/IastController.java (100%) rename dd-smoke-tests/kafka-2/{ => application}/src/main/java/datadog/smoketest/kafka/iast/IastMessage.java (100%) create mode 100644 dd-smoke-tests/openfeature/application/build.gradle create mode 100644 dd-smoke-tests/openfeature/application/settings.gradle rename dd-smoke-tests/openfeature/{ => application}/src/main/java/datadog/smoketest/springboot/SpringbootApplication.java (100%) rename dd-smoke-tests/openfeature/{ => application}/src/main/java/datadog/smoketest/springboot/openfeature/OpenFeatureConfiguration.java (100%) rename dd-smoke-tests/openfeature/{ => application}/src/main/java/datadog/smoketest/springboot/openfeature/OpenFeatureController.java (100%) create mode 100644 dd-smoke-tests/springboot-freemarker/application/build.gradle create mode 100644 dd-smoke-tests/springboot-freemarker/application/settings.gradle rename dd-smoke-tests/springboot-freemarker/{ => application}/src/main/java/datadog/smoketest/springboot/SpringbootApplication.java (100%) rename dd-smoke-tests/springboot-freemarker/{ => application}/src/main/java/datadog/smoketest/springboot/XssController.java (100%) rename dd-smoke-tests/springboot-freemarker/{ => application}/src/main/resources/templates/freemarker-2.3.24-insecure.ftlh (100%) rename dd-smoke-tests/springboot-freemarker/{ => application}/src/main/resources/templates/freemarker-2.3.24-secure.ftlh (100%) rename dd-smoke-tests/springboot-freemarker/{ => application}/src/main/resources/templates/freemarker-2.3.9-insecure.ftlh (100%) rename dd-smoke-tests/springboot-freemarker/{ => application}/src/main/resources/templates/freemarker-2.3.9-secure.ftlh (100%) create mode 100644 dd-smoke-tests/springboot-java-11/application/build.gradle create mode 100644 dd-smoke-tests/springboot-java-11/application/settings.gradle rename dd-smoke-tests/springboot-java-11/{ => application}/src/main/java/datadog/smoketest/springboot/SpringbootApplication.java (100%) create mode 100644 dd-smoke-tests/springboot-java-17/application/build.gradle create mode 100644 dd-smoke-tests/springboot-java-17/application/settings.gradle rename dd-smoke-tests/springboot-java-17/{ => application}/src/main/java/datadog/smoketest/springboot/SpringbootApplication.java (100%) create mode 100644 dd-smoke-tests/springboot-jetty-jsp/application/build.gradle create mode 100644 dd-smoke-tests/springboot-jetty-jsp/application/settings.gradle rename dd-smoke-tests/springboot-jetty-jsp/{ => application}/src/main/java/datadog/smoketest/springboot/SpringbootApplication.java (100%) rename dd-smoke-tests/springboot-jetty-jsp/{ => application}/src/main/java/datadog/smoketest/springboot/ViewController.java (100%) rename dd-smoke-tests/springboot-jetty-jsp/{ => application}/src/main/resources/application.properties (100%) rename dd-smoke-tests/springboot-jetty-jsp/{ => application}/src/main/webapp/WEB-INF/jsp/test_xss.jsp (100%) create mode 100644 dd-smoke-tests/springboot-jpa/application/build.gradle create mode 100644 dd-smoke-tests/springboot-jpa/application/settings.gradle rename dd-smoke-tests/springboot-jpa/{ => application}/src/main/java/datadog/smoketest/springboot/SpringbootApplication.java (100%) rename dd-smoke-tests/springboot-jpa/{ => application}/src/main/java/datadog/smoketest/springboot/controller/LibraryController.java (100%) rename dd-smoke-tests/springboot-jpa/{ => application}/src/main/java/datadog/smoketest/springboot/entity/Author.java (100%) rename dd-smoke-tests/springboot-jpa/{ => application}/src/main/java/datadog/smoketest/springboot/entity/Book.java (100%) rename dd-smoke-tests/springboot-jpa/{ => application}/src/main/java/datadog/smoketest/springboot/entity/Library.java (100%) rename dd-smoke-tests/springboot-jpa/{ => application}/src/main/java/datadog/smoketest/springboot/entity/Owner.java (100%) rename dd-smoke-tests/springboot-jpa/{ => application}/src/main/java/datadog/smoketest/springboot/filter/SessionVisitorFilter.java (100%) rename dd-smoke-tests/springboot-jpa/{ => application}/src/main/java/datadog/smoketest/springboot/service/LibraryService.java (100%) rename dd-smoke-tests/springboot-jpa/{ => application}/src/main/resources/application.yml (100%) rename dd-smoke-tests/springboot-jpa/{ => application}/src/main/webapp/WEB-INF/jsp/update.jsp (100%) create mode 100644 dd-smoke-tests/springboot-thymeleaf/application/build.gradle create mode 100644 dd-smoke-tests/springboot-thymeleaf/application/settings.gradle rename dd-smoke-tests/springboot-thymeleaf/{ => application}/src/main/java/datadog/smoketest/springboot/SpringbootApplication.java (100%) rename dd-smoke-tests/springboot-thymeleaf/{ => application}/src/main/java/datadog/smoketest/springboot/XssController.java (100%) rename dd-smoke-tests/springboot-thymeleaf/{ => application}/src/main/resources/templates/utext.html (100%) create mode 100644 dd-smoke-tests/springboot-tomcat-jsp/application/build.gradle create mode 100644 dd-smoke-tests/springboot-tomcat-jsp/application/settings.gradle rename dd-smoke-tests/springboot-tomcat-jsp/{ => application}/src/main/java/datadog/smoketest/springboot/SpringbootApplication.java (100%) rename dd-smoke-tests/springboot-tomcat-jsp/{ => application}/src/main/java/datadog/smoketest/springboot/ViewController.java (100%) rename dd-smoke-tests/springboot-tomcat-jsp/{ => application}/src/main/resources/application.properties (100%) rename dd-smoke-tests/springboot-tomcat-jsp/{ => application}/src/main/webapp/WEB-INF/jsp/test_xss.jsp (100%) create mode 100644 dd-smoke-tests/springboot-tomcat/application/build.gradle create mode 100644 dd-smoke-tests/springboot-tomcat/application/settings.gradle rename dd-smoke-tests/springboot-tomcat/{ => application}/src/main/java/datadog/smoketest/springboot/SpringbootTomcatApplication.java (100%) rename dd-smoke-tests/springboot-tomcat/{ => application}/src/main/java/datadog/smoketest/springboot/controller/TestSuite.java (100%) rename dd-smoke-tests/springboot-tomcat/{ => application}/src/main/java/datadog/smoketest/springboot/controller/ViewController.java (100%) rename dd-smoke-tests/springboot-tomcat/{ => application}/src/main/resources/application.properties (100%) create mode 100644 dd-smoke-tests/springboot-velocity/application/build.gradle create mode 100644 dd-smoke-tests/springboot-velocity/application/settings.gradle rename dd-smoke-tests/springboot-velocity/{ => application}/src/main/java/datadog/smoketest/springboot/SpringbootApplication.java (100%) rename dd-smoke-tests/springboot-velocity/{ => application}/src/main/java/datadog/smoketest/springboot/XssController.java (100%) rename dd-smoke-tests/springboot-velocity/{ => application}/src/main/resources/templates/velocity-insecure.vm (100%) rename dd-smoke-tests/springboot-velocity/{ => application}/src/main/resources/templates/velocity-secure.vm (100%) diff --git a/dd-smoke-tests/apm-tracing-disabled/application/build.gradle b/dd-smoke-tests/apm-tracing-disabled/application/build.gradle new file mode 100644 index 00000000000..3f5c868f46a --- /dev/null +++ b/dd-smoke-tests/apm-tracing-disabled/application/build.gradle @@ -0,0 +1,38 @@ +plugins { + id 'java' + id 'org.springframework.boot' version '2.7.15' + id 'io.spring.dependency-management' version '1.0.15.RELEASE' +} + +def sharedRootDir = "$rootDir/../../../" +def sharedConfigDirectory = "$sharedRootDir/gradle" +rootProject.ext.sharedConfigDirectory = sharedConfigDirectory + +apply from: "$sharedConfigDirectory/repositories.gradle" + +if (hasProperty('appBuildDir')) { + buildDir = property('appBuildDir') +} + +version = "" + +java { + sourceCompatibility = '1.8' +} + +if (hasProperty('apiJar')) { + dependencies { + implementation files(property('apiJar')) + } +} else { + dependencies { + implementation "com.datadoghq:dd-trace-api:+" + } +} + +dependencies { + compileOnly 'com.github.spotbugs:spotbugs-annotations:4.9.8' + implementation 'org.springframework.boot:spring-boot-starter-web' + implementation group: 'io.opentracing', name: 'opentracing-api', version: '0.32.0' + implementation group: 'io.opentracing', name: 'opentracing-util', version: '0.32.0' +} diff --git a/dd-smoke-tests/apm-tracing-disabled/application/settings.gradle b/dd-smoke-tests/apm-tracing-disabled/application/settings.gradle new file mode 100644 index 00000000000..aac1278eba5 --- /dev/null +++ b/dd-smoke-tests/apm-tracing-disabled/application/settings.gradle @@ -0,0 +1,32 @@ +pluginManagement { + repositories { + mavenLocal() + if (settings.hasProperty("gradlePluginProxy")) { + maven { + url settings["gradlePluginProxy"] + allowInsecureProtocol = true + } + } + if (settings.hasProperty("mavenRepositoryProxy")) { + maven { + url settings["mavenRepositoryProxy"] + allowInsecureProtocol = true + } + } + gradlePluginPortal() + mavenCentral() + } +} + +def isCI = providers.environmentVariable("CI").isPresent() + +if (isCI) { + def sharedRootDir = "$rootDir/../../../" + buildCache { + local { + directory = "$sharedRootDir/workspace/build-cache" + } + } +} + +rootProject.name = 'apm-tracing-disabled-smoketest' diff --git a/dd-smoke-tests/apm-tracing-disabled/src/main/java/datadog/smoketest/apmtracingdisabled/AppConfig.java b/dd-smoke-tests/apm-tracing-disabled/application/src/main/java/datadog/smoketest/apmtracingdisabled/AppConfig.java similarity index 100% rename from dd-smoke-tests/apm-tracing-disabled/src/main/java/datadog/smoketest/apmtracingdisabled/AppConfig.java rename to dd-smoke-tests/apm-tracing-disabled/application/src/main/java/datadog/smoketest/apmtracingdisabled/AppConfig.java diff --git a/dd-smoke-tests/apm-tracing-disabled/src/main/java/datadog/smoketest/apmtracingdisabled/Controller.java b/dd-smoke-tests/apm-tracing-disabled/application/src/main/java/datadog/smoketest/apmtracingdisabled/Controller.java similarity index 100% rename from dd-smoke-tests/apm-tracing-disabled/src/main/java/datadog/smoketest/apmtracingdisabled/Controller.java rename to dd-smoke-tests/apm-tracing-disabled/application/src/main/java/datadog/smoketest/apmtracingdisabled/Controller.java diff --git a/dd-smoke-tests/apm-tracing-disabled/src/main/java/datadog/smoketest/apmtracingdisabled/SpringbootApplication.java b/dd-smoke-tests/apm-tracing-disabled/application/src/main/java/datadog/smoketest/apmtracingdisabled/SpringbootApplication.java similarity index 100% rename from dd-smoke-tests/apm-tracing-disabled/src/main/java/datadog/smoketest/apmtracingdisabled/SpringbootApplication.java rename to dd-smoke-tests/apm-tracing-disabled/application/src/main/java/datadog/smoketest/apmtracingdisabled/SpringbootApplication.java diff --git a/dd-smoke-tests/apm-tracing-disabled/build.gradle b/dd-smoke-tests/apm-tracing-disabled/build.gradle index 638260752db..7b5d43b11db 100644 --- a/dd-smoke-tests/apm-tracing-disabled/build.gradle +++ b/dd-smoke-tests/apm-tracing-disabled/build.gradle @@ -1,36 +1,32 @@ -import org.springframework.boot.gradle.tasks.bundling.BootJar - plugins { - id 'java' - id 'org.springframework.boot' version '2.7.15' - id 'io.spring.dependency-management' version '1.0.15.RELEASE' + id 'dd-trace-java.smoke-test-app' id 'java-test-fixtures' } apply from: "$rootDir/gradle/java.gradle" -apply from: "$rootDir/gradle/spring-boot-plugin.gradle" + description = 'ASM Standalone Billing Tests.' -java { - sourceCompatibility = '1.8' +smokeTestApp { + application { + taskName = 'bootJar' + artifactPath = 'libs/apm-tracing-disabled-smoketest.jar' + sysProperty = 'datadog.smoketest.springboot.shadowJar.path' + } + projectJar('apiJar', project(':dd-trace-api')) } dependencies { - implementation 'org.springframework.boot:spring-boot-starter-web' - implementation group: 'io.opentracing', name: 'opentracing-api', version: '0.32.0' - implementation group: 'io.opentracing', name: 'opentracing-util', version: '0.32.0' - implementation project(':dd-trace-api') testImplementation project(':dd-smoke-tests') testImplementation(testFixtures(project(":dd-smoke-tests:iast-util"))) } -tasks.withType(Test).configureEach { - def bootJarTask = tasks.named('bootJar', BootJar) - dependsOn bootJarTask - jvmArgumentProviders.add(new CommandLineArgumentProvider() { - @Override - Iterable asArguments() { - return bootJarTask.map { ["-Ddatadog.smoketest.springboot.shadowJar.path=${it.archiveFile.get()}"] }.get() - } - }) +spotless { + java { + target "**/*.java" + } + + groovyGradle { + target '*.gradle', "**/*.gradle" + } } diff --git a/dd-smoke-tests/kafka-2/application/build.gradle b/dd-smoke-tests/kafka-2/application/build.gradle new file mode 100644 index 00000000000..9304c311ebe --- /dev/null +++ b/dd-smoke-tests/kafka-2/application/build.gradle @@ -0,0 +1,35 @@ +plugins { + id 'java' + id 'org.springframework.boot' version '2.7.15' + id 'io.spring.dependency-management' version '1.0.15.RELEASE' +} + +def sharedRootDir = "$rootDir/../../../" +def sharedConfigDirectory = "$sharedRootDir/gradle" +rootProject.ext.sharedConfigDirectory = sharedConfigDirectory + +apply from: "$sharedConfigDirectory/repositories.gradle" + +if (hasProperty('appBuildDir')) { + buildDir = property('appBuildDir') +} + +version = "" + +// Pin bytecode target: the nested daemon now runs on JDK 21, but the smoke test launches +// the produced jar on Java 8. +java { + sourceCompatibility = JavaVersion.VERSION_1_8 +} + +if (hasProperty('iastUtilJar')) { + dependencies { + implementation files(property('iastUtilJar')) + } +} + +dependencies { + implementation('org.springframework.boot:spring-boot-starter-web') + implementation('org.springframework.boot:spring-boot-starter-actuator') + implementation('org.springframework.kafka:spring-kafka') +} diff --git a/dd-smoke-tests/kafka-2/application/settings.gradle b/dd-smoke-tests/kafka-2/application/settings.gradle new file mode 100644 index 00000000000..f5d4088d9b5 --- /dev/null +++ b/dd-smoke-tests/kafka-2/application/settings.gradle @@ -0,0 +1,32 @@ +pluginManagement { + repositories { + mavenLocal() + if (settings.hasProperty("gradlePluginProxy")) { + maven { + url settings["gradlePluginProxy"] + allowInsecureProtocol = true + } + } + if (settings.hasProperty("mavenRepositoryProxy")) { + maven { + url settings["mavenRepositoryProxy"] + allowInsecureProtocol = true + } + } + gradlePluginPortal() + mavenCentral() + } +} + +def isCI = providers.environmentVariable("CI").isPresent() + +if (isCI) { + def sharedRootDir = "$rootDir/../../../" + buildCache { + local { + directory = "$sharedRootDir/workspace/build-cache" + } + } +} + +rootProject.name = 'kafka-2-smoketest' diff --git a/dd-smoke-tests/kafka-2/src/main/java/datadog/smoketest/kafka/KafkaApplication.java b/dd-smoke-tests/kafka-2/application/src/main/java/datadog/smoketest/kafka/KafkaApplication.java similarity index 100% rename from dd-smoke-tests/kafka-2/src/main/java/datadog/smoketest/kafka/KafkaApplication.java rename to dd-smoke-tests/kafka-2/application/src/main/java/datadog/smoketest/kafka/KafkaApplication.java diff --git a/dd-smoke-tests/kafka-2/src/main/java/datadog/smoketest/kafka/iast/IastConfiguration.java b/dd-smoke-tests/kafka-2/application/src/main/java/datadog/smoketest/kafka/iast/IastConfiguration.java similarity index 100% rename from dd-smoke-tests/kafka-2/src/main/java/datadog/smoketest/kafka/iast/IastConfiguration.java rename to dd-smoke-tests/kafka-2/application/src/main/java/datadog/smoketest/kafka/iast/IastConfiguration.java diff --git a/dd-smoke-tests/kafka-2/src/main/java/datadog/smoketest/kafka/iast/IastController.java b/dd-smoke-tests/kafka-2/application/src/main/java/datadog/smoketest/kafka/iast/IastController.java similarity index 100% rename from dd-smoke-tests/kafka-2/src/main/java/datadog/smoketest/kafka/iast/IastController.java rename to dd-smoke-tests/kafka-2/application/src/main/java/datadog/smoketest/kafka/iast/IastController.java diff --git a/dd-smoke-tests/kafka-2/src/main/java/datadog/smoketest/kafka/iast/IastMessage.java b/dd-smoke-tests/kafka-2/application/src/main/java/datadog/smoketest/kafka/iast/IastMessage.java similarity index 100% rename from dd-smoke-tests/kafka-2/src/main/java/datadog/smoketest/kafka/iast/IastMessage.java rename to dd-smoke-tests/kafka-2/application/src/main/java/datadog/smoketest/kafka/iast/IastMessage.java diff --git a/dd-smoke-tests/kafka-2/build.gradle b/dd-smoke-tests/kafka-2/build.gradle index c947425a4ba..29a18a59f20 100644 --- a/dd-smoke-tests/kafka-2/build.gradle +++ b/dd-smoke-tests/kafka-2/build.gradle @@ -1,34 +1,36 @@ -import org.springframework.boot.gradle.tasks.bundling.BootJar - plugins { - id 'org.springframework.boot' version '2.7.15' - id 'io.spring.dependency-management' version '1.0.15.RELEASE' + id 'dd-trace-java.smoke-test-app' id 'java-test-fixtures' } apply from: "$rootDir/gradle/java.gradle" -apply from: "$rootDir/gradle/spring-boot-plugin.gradle" -description = 'Kafka 2.x Smoke Tests.' -dependencies { - implementation('org.springframework.boot:spring-boot-starter-web') - implementation('org.springframework.boot:spring-boot-starter-actuator') - implementation('org.springframework.kafka:spring-kafka') +description = 'Kafka 2.x Smoke Tests.' - testImplementation('org.springframework.kafka:spring-kafka-test') +smokeTestApp { + application { + taskName = 'bootJar' + artifactPath = 'libs/kafka-2-smoketest.jar' + sysProperty = 'datadog.smoketest.springboot.shadowJar.path' + } + projectJar('iastUtilJar', project(':dd-smoke-tests:iast-util')) +} +dependencies { + // Pinned: this version was previously resolved transitively from the Spring Boot BOM in + // the outer build. Now that the application is in a nested build, the BOM is no longer + // available here. + testImplementation('org.springframework.kafka:spring-kafka-test:2.8.11') testImplementation project(':dd-smoke-tests') - implementation project(':dd-smoke-tests:iast-util') testImplementation(testFixtures(project(":dd-smoke-tests:iast-util"))) } -tasks.withType(Test).configureEach { - def bootJarTask = tasks.named('bootJar', BootJar) - dependsOn bootJarTask - jvmArgumentProviders.add(new CommandLineArgumentProvider() { - @Override - Iterable asArguments() { - return bootJarTask.map { ["-Ddatadog.smoketest.springboot.shadowJar.path=${it.archiveFile.get()}"] }.get() - } - }) +spotless { + java { + target "**/*.java" + } + + groovyGradle { + target '*.gradle', "**/*.gradle" + } } diff --git a/dd-smoke-tests/openfeature/application/build.gradle b/dd-smoke-tests/openfeature/application/build.gradle new file mode 100644 index 00000000000..a74020164f9 --- /dev/null +++ b/dd-smoke-tests/openfeature/application/build.gradle @@ -0,0 +1,35 @@ +plugins { + id 'java' + id 'org.springframework.boot' version '2.7.15' + id 'io.spring.dependency-management' version '1.0.15.RELEASE' +} + +def sharedRootDir = "$rootDir/../../../" +def sharedConfigDirectory = "$sharedRootDir/gradle" +rootProject.ext.sharedConfigDirectory = sharedConfigDirectory + +apply from: "$sharedConfigDirectory/repositories.gradle" + +if (hasProperty('appBuildDir')) { + buildDir = property('appBuildDir') +} + +version = "" + +java { + sourceCompatibility = 11 + targetCompatibility = 11 +} + +if (hasProperty('featureFlaggingApiJar')) { + dependencies { + implementation files(property('featureFlaggingApiJar')) + } +} + +dependencies { + // OpenFeature SDK is an API dependency of feature-flagging-api but is not + // transitively resolved when the jar is passed as a files() dependency. + implementation 'dev.openfeature:sdk:1.20.1' + implementation 'org.springframework.boot:spring-boot-starter-web' +} diff --git a/dd-smoke-tests/openfeature/application/settings.gradle b/dd-smoke-tests/openfeature/application/settings.gradle new file mode 100644 index 00000000000..cd52c32ced8 --- /dev/null +++ b/dd-smoke-tests/openfeature/application/settings.gradle @@ -0,0 +1,32 @@ +pluginManagement { + repositories { + mavenLocal() + if (settings.hasProperty("gradlePluginProxy")) { + maven { + url settings["gradlePluginProxy"] + allowInsecureProtocol = true + } + } + if (settings.hasProperty("mavenRepositoryProxy")) { + maven { + url settings["mavenRepositoryProxy"] + allowInsecureProtocol = true + } + } + gradlePluginPortal() + mavenCentral() + } +} + +def isCI = providers.environmentVariable("CI").isPresent() + +if (isCI) { + def sharedRootDir = "$rootDir/../../../" + buildCache { + local { + directory = "$sharedRootDir/workspace/build-cache" + } + } +} + +rootProject.name = 'openfeature-smoketest' diff --git a/dd-smoke-tests/openfeature/src/main/java/datadog/smoketest/springboot/SpringbootApplication.java b/dd-smoke-tests/openfeature/application/src/main/java/datadog/smoketest/springboot/SpringbootApplication.java similarity index 100% rename from dd-smoke-tests/openfeature/src/main/java/datadog/smoketest/springboot/SpringbootApplication.java rename to dd-smoke-tests/openfeature/application/src/main/java/datadog/smoketest/springboot/SpringbootApplication.java diff --git a/dd-smoke-tests/openfeature/src/main/java/datadog/smoketest/springboot/openfeature/OpenFeatureConfiguration.java b/dd-smoke-tests/openfeature/application/src/main/java/datadog/smoketest/springboot/openfeature/OpenFeatureConfiguration.java similarity index 100% rename from dd-smoke-tests/openfeature/src/main/java/datadog/smoketest/springboot/openfeature/OpenFeatureConfiguration.java rename to dd-smoke-tests/openfeature/application/src/main/java/datadog/smoketest/springboot/openfeature/OpenFeatureConfiguration.java diff --git a/dd-smoke-tests/openfeature/src/main/java/datadog/smoketest/springboot/openfeature/OpenFeatureController.java b/dd-smoke-tests/openfeature/application/src/main/java/datadog/smoketest/springboot/openfeature/OpenFeatureController.java similarity index 100% rename from dd-smoke-tests/openfeature/src/main/java/datadog/smoketest/springboot/openfeature/OpenFeatureController.java rename to dd-smoke-tests/openfeature/application/src/main/java/datadog/smoketest/springboot/openfeature/OpenFeatureController.java diff --git a/dd-smoke-tests/openfeature/build.gradle b/dd-smoke-tests/openfeature/build.gradle index a38696418ef..cb2c83d112d 100644 --- a/dd-smoke-tests/openfeature/build.gradle +++ b/dd-smoke-tests/openfeature/build.gradle @@ -1,38 +1,35 @@ -import org.springframework.boot.gradle.tasks.bundling.BootJar - plugins { - id 'java' - id 'org.springframework.boot' version '2.7.15' - id 'io.spring.dependency-management' version '1.0.15.RELEASE' + id 'dd-trace-java.smoke-test-app' } apply from: "$rootDir/gradle/java.gradle" -apply from: "$rootDir/gradle/spring-boot-plugin.gradle" + description = 'Open Feature provider Smoke Tests.' testJvmConstraints { minJavaVersion = JavaVersion.VERSION_11 } -tasks.named("compileJava", JavaCompile) { - configureCompiler(it, 11, JavaVersion.VERSION_11) +smokeTestApp { + application { + taskName = 'bootJar' + artifactPath = 'libs/openfeature-smoketest.jar' + sysProperty = 'datadog.smoketest.springboot.shadowJar.path' + } + projectJar('featureFlaggingApiJar', project(':products:feature-flagging:feature-flagging-api')) } dependencies { - implementation project(':products:feature-flagging:feature-flagging-api') - implementation 'org.springframework.boot:spring-boot-starter-web' - testImplementation project(':dd-smoke-tests') testImplementation project(':products:feature-flagging:feature-flagging-lib') } -tasks.withType(Test).configureEach { - dependsOn "bootJar" - def bootJarTask = tasks.named('bootJar', BootJar) - jvmArgumentProviders.add(new CommandLineArgumentProvider() { - @Override - Iterable asArguments() { - return bootJarTask.map { ["-Ddatadog.smoketest.springboot.shadowJar.path=${it.archiveFile.get()}"] }.get() - } - }) +spotless { + java { + target "**/*.java" + } + + groovyGradle { + target '*.gradle', "**/*.gradle" + } } diff --git a/dd-smoke-tests/springboot-freemarker/application/build.gradle b/dd-smoke-tests/springboot-freemarker/application/build.gradle new file mode 100644 index 00000000000..3a0220c4ca8 --- /dev/null +++ b/dd-smoke-tests/springboot-freemarker/application/build.gradle @@ -0,0 +1,26 @@ +plugins { + id 'java' + id 'org.springframework.boot' version '2.7.15' + id 'io.spring.dependency-management' version '1.0.15.RELEASE' +} + +def sharedRootDir = "$rootDir/../../../" +def sharedConfigDirectory = "$sharedRootDir/gradle" +rootProject.ext.sharedConfigDirectory = sharedConfigDirectory + +apply from: "$sharedConfigDirectory/repositories.gradle" + +if (hasProperty('appBuildDir')) { + buildDir = property('appBuildDir') +} + +version = "" + +java { + sourceCompatibility = '1.8' +} + +dependencies { + implementation group: 'org.springframework.boot', name: 'spring-boot-starter-web', version: '1.5.18.RELEASE' + implementation group: 'org.freemarker', name: 'freemarker', version: '2.3.24-incubating' +} diff --git a/dd-smoke-tests/springboot-freemarker/application/settings.gradle b/dd-smoke-tests/springboot-freemarker/application/settings.gradle new file mode 100644 index 00000000000..c35041e5d73 --- /dev/null +++ b/dd-smoke-tests/springboot-freemarker/application/settings.gradle @@ -0,0 +1,32 @@ +pluginManagement { + repositories { + mavenLocal() + if (settings.hasProperty("gradlePluginProxy")) { + maven { + url settings["gradlePluginProxy"] + allowInsecureProtocol = true + } + } + if (settings.hasProperty("mavenRepositoryProxy")) { + maven { + url settings["mavenRepositoryProxy"] + allowInsecureProtocol = true + } + } + gradlePluginPortal() + mavenCentral() + } +} + +def isCI = providers.environmentVariable("CI").isPresent() + +if (isCI) { + def sharedRootDir = "$rootDir/../../../" + buildCache { + local { + directory = "$sharedRootDir/workspace/build-cache" + } + } +} + +rootProject.name = 'springboot-freemarker-smoketest' diff --git a/dd-smoke-tests/springboot-freemarker/src/main/java/datadog/smoketest/springboot/SpringbootApplication.java b/dd-smoke-tests/springboot-freemarker/application/src/main/java/datadog/smoketest/springboot/SpringbootApplication.java similarity index 100% rename from dd-smoke-tests/springboot-freemarker/src/main/java/datadog/smoketest/springboot/SpringbootApplication.java rename to dd-smoke-tests/springboot-freemarker/application/src/main/java/datadog/smoketest/springboot/SpringbootApplication.java diff --git a/dd-smoke-tests/springboot-freemarker/src/main/java/datadog/smoketest/springboot/XssController.java b/dd-smoke-tests/springboot-freemarker/application/src/main/java/datadog/smoketest/springboot/XssController.java similarity index 100% rename from dd-smoke-tests/springboot-freemarker/src/main/java/datadog/smoketest/springboot/XssController.java rename to dd-smoke-tests/springboot-freemarker/application/src/main/java/datadog/smoketest/springboot/XssController.java diff --git a/dd-smoke-tests/springboot-freemarker/src/main/resources/templates/freemarker-2.3.24-insecure.ftlh b/dd-smoke-tests/springboot-freemarker/application/src/main/resources/templates/freemarker-2.3.24-insecure.ftlh similarity index 100% rename from dd-smoke-tests/springboot-freemarker/src/main/resources/templates/freemarker-2.3.24-insecure.ftlh rename to dd-smoke-tests/springboot-freemarker/application/src/main/resources/templates/freemarker-2.3.24-insecure.ftlh diff --git a/dd-smoke-tests/springboot-freemarker/src/main/resources/templates/freemarker-2.3.24-secure.ftlh b/dd-smoke-tests/springboot-freemarker/application/src/main/resources/templates/freemarker-2.3.24-secure.ftlh similarity index 100% rename from dd-smoke-tests/springboot-freemarker/src/main/resources/templates/freemarker-2.3.24-secure.ftlh rename to dd-smoke-tests/springboot-freemarker/application/src/main/resources/templates/freemarker-2.3.24-secure.ftlh diff --git a/dd-smoke-tests/springboot-freemarker/src/main/resources/templates/freemarker-2.3.9-insecure.ftlh b/dd-smoke-tests/springboot-freemarker/application/src/main/resources/templates/freemarker-2.3.9-insecure.ftlh similarity index 100% rename from dd-smoke-tests/springboot-freemarker/src/main/resources/templates/freemarker-2.3.9-insecure.ftlh rename to dd-smoke-tests/springboot-freemarker/application/src/main/resources/templates/freemarker-2.3.9-insecure.ftlh diff --git a/dd-smoke-tests/springboot-freemarker/src/main/resources/templates/freemarker-2.3.9-secure.ftlh b/dd-smoke-tests/springboot-freemarker/application/src/main/resources/templates/freemarker-2.3.9-secure.ftlh similarity index 100% rename from dd-smoke-tests/springboot-freemarker/src/main/resources/templates/freemarker-2.3.9-secure.ftlh rename to dd-smoke-tests/springboot-freemarker/application/src/main/resources/templates/freemarker-2.3.9-secure.ftlh diff --git a/dd-smoke-tests/springboot-freemarker/build.gradle b/dd-smoke-tests/springboot-freemarker/build.gradle index 57c7a4e9eb1..ca3fd1c8991 100644 --- a/dd-smoke-tests/springboot-freemarker/build.gradle +++ b/dd-smoke-tests/springboot-freemarker/build.gradle @@ -1,35 +1,52 @@ -import org.springframework.boot.gradle.tasks.bundling.BootJar - plugins { - id 'java' - id 'org.springframework.boot' version '2.7.15' - id 'io.spring.dependency-management' version '1.0.15.RELEASE' + id 'dd-trace-java.smoke-test-app' id 'java-test-fixtures' } apply from: "$rootDir/gradle/java.gradle" -apply from: "$rootDir/gradle/spring-boot-plugin.gradle" + description = 'SpringBoot Freemarker Smoke Tests.' -java { - sourceCompatibility = '1.8' +smokeTestApp { + application { + taskName = 'bootJar' + artifactPath = 'libs/springboot-freemarker-smoketest.jar' + sysProperty = 'datadog.smoketest.springboot.shadowJar.path' + } } dependencies { - implementation group: 'org.springframework.boot', name: 'spring-boot-starter-web', version: '1.5.18.RELEASE' - implementation group: 'org.freemarker', name: 'freemarker', version: '2.3.24-incubating' - testImplementation project(':dd-smoke-tests') testImplementation(testFixtures(project(":dd-smoke-tests:iast-util"))) } +// XssController loads templates from the filesystem at "resources/main/templates" relative to +// the test JVM's working directory (this module's build dir). Mirror the nested app's +// processed resources so that path resolves at runtime. +def applicationResourcesProvider = layout.buildDirectory.dir("application/resources/main") +tasks.register('copyAppResources', Copy) { + dependsOn 'bootJar' + from applicationResourcesProvider + into layout.buildDirectory.dir("resources/main") +} + +// `java.gradle` applies the `java` plugin so an empty `jar` task is created with +// `build/resources/main` as one of its inputs. Wire the dependency so Gradle knows +// `copyAppResources` writes there. +tasks.named('jar') { + dependsOn 'copyAppResources' +} + tasks.withType(Test).configureEach { - dependsOn "bootJar" - def bootJarTask = tasks.named('bootJar', BootJar) - jvmArgumentProviders.add(new CommandLineArgumentProvider() { - @Override - Iterable asArguments() { - return bootJarTask.map { ["-Ddatadog.smoketest.springboot.shadowJar.path=${it.archiveFile.get()}"] }.get() - } - }) + dependsOn 'copyAppResources' +} + +spotless { + java { + target "**/*.java" + } + + groovyGradle { + target '*.gradle', "**/*.gradle" + } } diff --git a/dd-smoke-tests/springboot-java-11/application/build.gradle b/dd-smoke-tests/springboot-java-11/application/build.gradle new file mode 100644 index 00000000000..ea12bb0cdc4 --- /dev/null +++ b/dd-smoke-tests/springboot-java-11/application/build.gradle @@ -0,0 +1,31 @@ +plugins { + id 'java' + id 'org.springframework.boot' version '2.7.15' + id 'io.spring.dependency-management' version '1.0.15.RELEASE' +} + +def sharedRootDir = "$rootDir/../../../" +def sharedConfigDirectory = "$sharedRootDir/gradle" +rootProject.ext.sharedConfigDirectory = sharedConfigDirectory + +apply from: "$sharedConfigDirectory/repositories.gradle" + +if (hasProperty('appBuildDir')) { + buildDir = property('appBuildDir') +} + +version = "" + +java { + sourceCompatibility = 11 +} + +if (hasProperty('iastUtil11Jar')) { + dependencies { + implementation files(property('iastUtil11Jar')) + } +} + +dependencies { + implementation group: 'org.springframework.boot', name: 'spring-boot-starter-web', version: '2.2.0.RELEASE' +} diff --git a/dd-smoke-tests/springboot-java-11/application/settings.gradle b/dd-smoke-tests/springboot-java-11/application/settings.gradle new file mode 100644 index 00000000000..d2356e2b0b3 --- /dev/null +++ b/dd-smoke-tests/springboot-java-11/application/settings.gradle @@ -0,0 +1,32 @@ +pluginManagement { + repositories { + mavenLocal() + if (settings.hasProperty("gradlePluginProxy")) { + maven { + url settings["gradlePluginProxy"] + allowInsecureProtocol = true + } + } + if (settings.hasProperty("mavenRepositoryProxy")) { + maven { + url settings["mavenRepositoryProxy"] + allowInsecureProtocol = true + } + } + gradlePluginPortal() + mavenCentral() + } +} + +def isCI = providers.environmentVariable("CI").isPresent() + +if (isCI) { + def sharedRootDir = "$rootDir/../../../" + buildCache { + local { + directory = "$sharedRootDir/workspace/build-cache" + } + } +} + +rootProject.name = 'springboot-java-11-smoketest' diff --git a/dd-smoke-tests/springboot-java-11/src/main/java/datadog/smoketest/springboot/SpringbootApplication.java b/dd-smoke-tests/springboot-java-11/application/src/main/java/datadog/smoketest/springboot/SpringbootApplication.java similarity index 100% rename from dd-smoke-tests/springboot-java-11/src/main/java/datadog/smoketest/springboot/SpringbootApplication.java rename to dd-smoke-tests/springboot-java-11/application/src/main/java/datadog/smoketest/springboot/SpringbootApplication.java diff --git a/dd-smoke-tests/springboot-java-11/build.gradle b/dd-smoke-tests/springboot-java-11/build.gradle index 029df98dbd8..142199fc645 100644 --- a/dd-smoke-tests/springboot-java-11/build.gradle +++ b/dd-smoke-tests/springboot-java-11/build.gradle @@ -1,42 +1,37 @@ -import org.springframework.boot.gradle.tasks.bundling.BootJar - plugins { - id 'java' - id 'org.springframework.boot' version '2.7.15' - id 'io.spring.dependency-management' version '1.0.15.RELEASE' + id 'dd-trace-java.smoke-test-app' id 'java-test-fixtures' } apply from: "$rootDir/gradle/java.gradle" +description = 'SpringBoot Java 11 Smoke Tests.' + testJvmConstraints { minJavaVersion = JavaVersion.VERSION_11 } -apply from: "$rootDir/gradle/spring-boot-plugin.gradle" -description = 'SpringBoot Java 11 Smoke Tests.' +smokeTestApp { + application { + taskName = 'bootJar' + artifactPath = 'libs/springboot-java-11-smoketest.jar' + sysProperty = 'datadog.smoketest.springboot.shadowJar.path' + } + projectJar('iastUtil11Jar', project(':dd-smoke-tests:iast-util:iast-util-11')) +} dependencies { - implementation group: 'org.springframework.boot', name: 'spring-boot-starter-web', version: '2.2.0.RELEASE' - testImplementation project(':dd-smoke-tests') testImplementation testFixtures(project(":dd-smoke-tests:iast-util:iast-util-11")) testImplementation testFixtures(project(':dd-smoke-tests:iast-util')) - - implementation project(':dd-smoke-tests:iast-util:iast-util-11') } -tasks.named("compileJava", JavaCompile) { - configureCompiler(it, 11, JavaVersion.VERSION_11) -} +spotless { + java { + target "**/*.java" + } -tasks.withType(Test).configureEach { - dependsOn "bootJar" - def bootJarTask = tasks.named('bootJar', BootJar) - jvmArgumentProviders.add(new CommandLineArgumentProvider() { - @Override - Iterable asArguments() { - return bootJarTask.map { ["-Ddatadog.smoketest.springboot.shadowJar.path=${it.archiveFile.get()}"] }.get() - } - }) + groovyGradle { + target '*.gradle', "**/*.gradle" + } } diff --git a/dd-smoke-tests/springboot-java-17/application/build.gradle b/dd-smoke-tests/springboot-java-17/application/build.gradle new file mode 100644 index 00000000000..413f24ce06d --- /dev/null +++ b/dd-smoke-tests/springboot-java-17/application/build.gradle @@ -0,0 +1,31 @@ +plugins { + id 'java' + id 'org.springframework.boot' version '2.7.15' + id 'io.spring.dependency-management' version '1.0.15.RELEASE' +} + +def sharedRootDir = "$rootDir/../../../" +def sharedConfigDirectory = "$sharedRootDir/gradle" +rootProject.ext.sharedConfigDirectory = sharedConfigDirectory + +apply from: "$sharedConfigDirectory/repositories.gradle" + +if (hasProperty('appBuildDir')) { + buildDir = property('appBuildDir') +} + +version = "" + +java { + sourceCompatibility = 17 +} + +if (hasProperty('iastUtil17Jar')) { + dependencies { + implementation files(property('iastUtil17Jar')) + } +} + +dependencies { + implementation group: 'org.springframework.boot', name: 'spring-boot-starter-web', version: '2.2.0.RELEASE' +} diff --git a/dd-smoke-tests/springboot-java-17/application/settings.gradle b/dd-smoke-tests/springboot-java-17/application/settings.gradle new file mode 100644 index 00000000000..83e3c7f2135 --- /dev/null +++ b/dd-smoke-tests/springboot-java-17/application/settings.gradle @@ -0,0 +1,32 @@ +pluginManagement { + repositories { + mavenLocal() + if (settings.hasProperty("gradlePluginProxy")) { + maven { + url settings["gradlePluginProxy"] + allowInsecureProtocol = true + } + } + if (settings.hasProperty("mavenRepositoryProxy")) { + maven { + url settings["mavenRepositoryProxy"] + allowInsecureProtocol = true + } + } + gradlePluginPortal() + mavenCentral() + } +} + +def isCI = providers.environmentVariable("CI").isPresent() + +if (isCI) { + def sharedRootDir = "$rootDir/../../../" + buildCache { + local { + directory = "$sharedRootDir/workspace/build-cache" + } + } +} + +rootProject.name = 'springboot-java-17-smoketest' diff --git a/dd-smoke-tests/springboot-java-17/src/main/java/datadog/smoketest/springboot/SpringbootApplication.java b/dd-smoke-tests/springboot-java-17/application/src/main/java/datadog/smoketest/springboot/SpringbootApplication.java similarity index 100% rename from dd-smoke-tests/springboot-java-17/src/main/java/datadog/smoketest/springboot/SpringbootApplication.java rename to dd-smoke-tests/springboot-java-17/application/src/main/java/datadog/smoketest/springboot/SpringbootApplication.java diff --git a/dd-smoke-tests/springboot-java-17/build.gradle b/dd-smoke-tests/springboot-java-17/build.gradle index cb878a92c7f..c896ee5efee 100644 --- a/dd-smoke-tests/springboot-java-17/build.gradle +++ b/dd-smoke-tests/springboot-java-17/build.gradle @@ -1,42 +1,37 @@ -import org.springframework.boot.gradle.tasks.bundling.BootJar - plugins { - id 'java' - id 'org.springframework.boot' version '2.7.15' - id 'io.spring.dependency-management' version '1.0.15.RELEASE' + id 'dd-trace-java.smoke-test-app' id 'java-test-fixtures' } apply from: "$rootDir/gradle/java.gradle" +description = 'SpringBoot Java 17 Smoke Tests.' + testJvmConstraints { minJavaVersion = JavaVersion.VERSION_17 } -apply from: "$rootDir/gradle/spring-boot-plugin.gradle" -description = 'SpringBoot Java 17 Smoke Tests.' +smokeTestApp { + application { + taskName = 'bootJar' + artifactPath = 'libs/springboot-java-17-smoketest.jar' + sysProperty = 'datadog.smoketest.springboot.shadowJar.path' + } + projectJar('iastUtil17Jar', project(':dd-smoke-tests:iast-util:iast-util-17')) +} dependencies { - implementation group: 'org.springframework.boot', name: 'spring-boot-starter-web', version: '2.2.0.RELEASE' - testImplementation project(':dd-smoke-tests') testImplementation testFixtures(project(":dd-smoke-tests:iast-util:iast-util-17")) testImplementation testFixtures(project(':dd-smoke-tests:iast-util')) - - implementation project(':dd-smoke-tests:iast-util:iast-util-17') } -tasks.named("compileJava", JavaCompile) { - configureCompiler(it, 17, JavaVersion.VERSION_17) -} +spotless { + java { + target "**/*.java" + } -tasks.withType(Test).configureEach { - dependsOn "bootJar" - def bootJarTask = tasks.named('bootJar', BootJar) - jvmArgumentProviders.add(new CommandLineArgumentProvider() { - @Override - Iterable asArguments() { - return bootJarTask.map { ["-Ddatadog.smoketest.springboot.shadowJar.path=${it.archiveFile.get()}"] }.get() - } - }) + groovyGradle { + target '*.gradle', "**/*.gradle" + } } diff --git a/dd-smoke-tests/springboot-jetty-jsp/application/build.gradle b/dd-smoke-tests/springboot-jetty-jsp/application/build.gradle new file mode 100644 index 00000000000..4c68c426f93 --- /dev/null +++ b/dd-smoke-tests/springboot-jetty-jsp/application/build.gradle @@ -0,0 +1,37 @@ +plugins { + id 'java' + id 'war' + id 'org.springframework.boot' version '2.7.15' + id 'io.spring.dependency-management' version '1.0.15.RELEASE' +} + +def sharedRootDir = "$rootDir/../../../" +def sharedConfigDirectory = "$sharedRootDir/gradle" +rootProject.ext.sharedConfigDirectory = sharedConfigDirectory + +apply from: "$sharedConfigDirectory/repositories.gradle" + +if (hasProperty('appBuildDir')) { + buildDir = property('appBuildDir') +} + +version = "" + +java { + sourceCompatibility = '1.8' +} + +sourceSets { + main { + resources.srcDir("src/main/webapp") + } +} + +dependencies { + implementation 'org.springframework.boot:spring-boot-starter-web' + + runtimeOnly("javax.servlet:jstl") + runtimeOnly("org.apache.tomcat.embed:tomcat-embed-jasper") + + providedRuntime("org.springframework.boot:spring-boot-starter-jetty") +} diff --git a/dd-smoke-tests/springboot-jetty-jsp/application/settings.gradle b/dd-smoke-tests/springboot-jetty-jsp/application/settings.gradle new file mode 100644 index 00000000000..dad60537f79 --- /dev/null +++ b/dd-smoke-tests/springboot-jetty-jsp/application/settings.gradle @@ -0,0 +1,32 @@ +pluginManagement { + repositories { + mavenLocal() + if (settings.hasProperty("gradlePluginProxy")) { + maven { + url settings["gradlePluginProxy"] + allowInsecureProtocol = true + } + } + if (settings.hasProperty("mavenRepositoryProxy")) { + maven { + url settings["mavenRepositoryProxy"] + allowInsecureProtocol = true + } + } + gradlePluginPortal() + mavenCentral() + } +} + +def isCI = providers.environmentVariable("CI").isPresent() + +if (isCI) { + def sharedRootDir = "$rootDir/../../../" + buildCache { + local { + directory = "$sharedRootDir/workspace/build-cache" + } + } +} + +rootProject.name = 'springboot-jetty-jsp-smoketest' diff --git a/dd-smoke-tests/springboot-jetty-jsp/src/main/java/datadog/smoketest/springboot/SpringbootApplication.java b/dd-smoke-tests/springboot-jetty-jsp/application/src/main/java/datadog/smoketest/springboot/SpringbootApplication.java similarity index 100% rename from dd-smoke-tests/springboot-jetty-jsp/src/main/java/datadog/smoketest/springboot/SpringbootApplication.java rename to dd-smoke-tests/springboot-jetty-jsp/application/src/main/java/datadog/smoketest/springboot/SpringbootApplication.java diff --git a/dd-smoke-tests/springboot-jetty-jsp/src/main/java/datadog/smoketest/springboot/ViewController.java b/dd-smoke-tests/springboot-jetty-jsp/application/src/main/java/datadog/smoketest/springboot/ViewController.java similarity index 100% rename from dd-smoke-tests/springboot-jetty-jsp/src/main/java/datadog/smoketest/springboot/ViewController.java rename to dd-smoke-tests/springboot-jetty-jsp/application/src/main/java/datadog/smoketest/springboot/ViewController.java diff --git a/dd-smoke-tests/springboot-jetty-jsp/src/main/resources/application.properties b/dd-smoke-tests/springboot-jetty-jsp/application/src/main/resources/application.properties similarity index 100% rename from dd-smoke-tests/springboot-jetty-jsp/src/main/resources/application.properties rename to dd-smoke-tests/springboot-jetty-jsp/application/src/main/resources/application.properties diff --git a/dd-smoke-tests/springboot-jetty-jsp/src/main/webapp/WEB-INF/jsp/test_xss.jsp b/dd-smoke-tests/springboot-jetty-jsp/application/src/main/webapp/WEB-INF/jsp/test_xss.jsp similarity index 100% rename from dd-smoke-tests/springboot-jetty-jsp/src/main/webapp/WEB-INF/jsp/test_xss.jsp rename to dd-smoke-tests/springboot-jetty-jsp/application/src/main/webapp/WEB-INF/jsp/test_xss.jsp diff --git a/dd-smoke-tests/springboot-jetty-jsp/build.gradle b/dd-smoke-tests/springboot-jetty-jsp/build.gradle index d8fdc4fbab4..29abca9fab9 100644 --- a/dd-smoke-tests/springboot-jetty-jsp/build.gradle +++ b/dd-smoke-tests/springboot-jetty-jsp/build.gradle @@ -1,47 +1,31 @@ -import org.springframework.boot.gradle.tasks.bundling.BootWar - plugins { - id 'java' - id 'war' - id 'org.springframework.boot' version '2.7.15' - id 'io.spring.dependency-management' version '1.0.15.RELEASE' + id 'dd-trace-java.smoke-test-app' id 'java-test-fixtures' } apply from: "$rootDir/gradle/java.gradle" -apply from: "$rootDir/gradle/spring-boot-plugin.gradle" -description = 'SpringBoot Jetty JSP Smoke Tests.' -java { - sourceCompatibility = '1.8' -} +description = 'SpringBoot Jetty JSP Smoke Tests.' -sourceSets { - main { - resources.srcDir("src/main/webapp") +smokeTestApp { + application { + taskName = 'bootWar' + artifactPath = 'libs/springboot-jetty-jsp-smoketest.war' + sysProperty = 'datadog.smoketest.springboot.war.path' } } dependencies { - implementation 'org.springframework.boot:spring-boot-starter-web' - - runtimeOnly("javax.servlet:jstl") - runtimeOnly("org.apache.tomcat.embed:tomcat-embed-jasper") - - providedRuntime("org.springframework.boot:spring-boot-starter-jetty") - testImplementation project(':dd-smoke-tests') testImplementation(testFixtures(project(":dd-smoke-tests:iast-util"))) } -tasks.withType(Test).configureEach { - dependsOn "war", "bootWar" +spotless { + java { + target "**/*.java" + } - jvmArgumentProviders.add(new CommandLineArgumentProvider() { - @Override - Iterable asArguments() { - def bootWarTask = tasks.named('bootWar', BootWar).get() - return ["-Ddatadog.smoketest.springboot.war.path=${bootWarTask.archiveFile.get().getAsFile()}"] - } - }) + groovyGradle { + target '*.gradle', "**/*.gradle" + } } diff --git a/dd-smoke-tests/springboot-jpa/application/build.gradle b/dd-smoke-tests/springboot-jpa/application/build.gradle new file mode 100644 index 00000000000..73438253bb8 --- /dev/null +++ b/dd-smoke-tests/springboot-jpa/application/build.gradle @@ -0,0 +1,36 @@ +plugins { + id 'java' + id 'war' + id 'org.springframework.boot' version '2.6.0' +} + +apply plugin: 'io.spring.dependency-management' + +def sharedRootDir = "$rootDir/../../../" +def sharedConfigDirectory = "$sharedRootDir/gradle" +rootProject.ext.sharedConfigDirectory = sharedConfigDirectory + +apply from: "$sharedConfigDirectory/repositories.gradle" + +if (hasProperty('appBuildDir')) { + buildDir = property('appBuildDir') +} + +version = "" + +// Pin bytecode target: the nested daemon now runs on JDK 21, but the smoke test launches +// the produced jar/war on Java 8. +java { + sourceCompatibility = JavaVersion.VERSION_1_8 +} + +dependencies { + implementation 'org.springframework.boot:spring-boot-starter-web' + implementation 'org.springframework.boot:spring-boot-starter-data-jpa' + implementation 'org.apache.tomcat.embed:tomcat-embed-jasper' + implementation 'javax.servlet:jstl:1.2' + implementation 'com.h2database:h2:2.1.214' + + compileOnly 'org.projectlombok:lombok:1.18.34' + annotationProcessor 'org.projectlombok:lombok:1.18.34' +} diff --git a/dd-smoke-tests/springboot-jpa/application/settings.gradle b/dd-smoke-tests/springboot-jpa/application/settings.gradle new file mode 100644 index 00000000000..ff156736e67 --- /dev/null +++ b/dd-smoke-tests/springboot-jpa/application/settings.gradle @@ -0,0 +1,32 @@ +pluginManagement { + repositories { + mavenLocal() + if (settings.hasProperty("gradlePluginProxy")) { + maven { + url settings["gradlePluginProxy"] + allowInsecureProtocol = true + } + } + if (settings.hasProperty("mavenRepositoryProxy")) { + maven { + url settings["mavenRepositoryProxy"] + allowInsecureProtocol = true + } + } + gradlePluginPortal() + mavenCentral() + } +} + +def isCI = providers.environmentVariable("CI").isPresent() + +if (isCI) { + def sharedRootDir = "$rootDir/../../../" + buildCache { + local { + directory = "$sharedRootDir/workspace/build-cache" + } + } +} + +rootProject.name = 'springboot-jpa-smoketest' diff --git a/dd-smoke-tests/springboot-jpa/src/main/java/datadog/smoketest/springboot/SpringbootApplication.java b/dd-smoke-tests/springboot-jpa/application/src/main/java/datadog/smoketest/springboot/SpringbootApplication.java similarity index 100% rename from dd-smoke-tests/springboot-jpa/src/main/java/datadog/smoketest/springboot/SpringbootApplication.java rename to dd-smoke-tests/springboot-jpa/application/src/main/java/datadog/smoketest/springboot/SpringbootApplication.java diff --git a/dd-smoke-tests/springboot-jpa/src/main/java/datadog/smoketest/springboot/controller/LibraryController.java b/dd-smoke-tests/springboot-jpa/application/src/main/java/datadog/smoketest/springboot/controller/LibraryController.java similarity index 100% rename from dd-smoke-tests/springboot-jpa/src/main/java/datadog/smoketest/springboot/controller/LibraryController.java rename to dd-smoke-tests/springboot-jpa/application/src/main/java/datadog/smoketest/springboot/controller/LibraryController.java diff --git a/dd-smoke-tests/springboot-jpa/src/main/java/datadog/smoketest/springboot/entity/Author.java b/dd-smoke-tests/springboot-jpa/application/src/main/java/datadog/smoketest/springboot/entity/Author.java similarity index 100% rename from dd-smoke-tests/springboot-jpa/src/main/java/datadog/smoketest/springboot/entity/Author.java rename to dd-smoke-tests/springboot-jpa/application/src/main/java/datadog/smoketest/springboot/entity/Author.java diff --git a/dd-smoke-tests/springboot-jpa/src/main/java/datadog/smoketest/springboot/entity/Book.java b/dd-smoke-tests/springboot-jpa/application/src/main/java/datadog/smoketest/springboot/entity/Book.java similarity index 100% rename from dd-smoke-tests/springboot-jpa/src/main/java/datadog/smoketest/springboot/entity/Book.java rename to dd-smoke-tests/springboot-jpa/application/src/main/java/datadog/smoketest/springboot/entity/Book.java diff --git a/dd-smoke-tests/springboot-jpa/src/main/java/datadog/smoketest/springboot/entity/Library.java b/dd-smoke-tests/springboot-jpa/application/src/main/java/datadog/smoketest/springboot/entity/Library.java similarity index 100% rename from dd-smoke-tests/springboot-jpa/src/main/java/datadog/smoketest/springboot/entity/Library.java rename to dd-smoke-tests/springboot-jpa/application/src/main/java/datadog/smoketest/springboot/entity/Library.java diff --git a/dd-smoke-tests/springboot-jpa/src/main/java/datadog/smoketest/springboot/entity/Owner.java b/dd-smoke-tests/springboot-jpa/application/src/main/java/datadog/smoketest/springboot/entity/Owner.java similarity index 100% rename from dd-smoke-tests/springboot-jpa/src/main/java/datadog/smoketest/springboot/entity/Owner.java rename to dd-smoke-tests/springboot-jpa/application/src/main/java/datadog/smoketest/springboot/entity/Owner.java diff --git a/dd-smoke-tests/springboot-jpa/src/main/java/datadog/smoketest/springboot/filter/SessionVisitorFilter.java b/dd-smoke-tests/springboot-jpa/application/src/main/java/datadog/smoketest/springboot/filter/SessionVisitorFilter.java similarity index 100% rename from dd-smoke-tests/springboot-jpa/src/main/java/datadog/smoketest/springboot/filter/SessionVisitorFilter.java rename to dd-smoke-tests/springboot-jpa/application/src/main/java/datadog/smoketest/springboot/filter/SessionVisitorFilter.java diff --git a/dd-smoke-tests/springboot-jpa/src/main/java/datadog/smoketest/springboot/service/LibraryService.java b/dd-smoke-tests/springboot-jpa/application/src/main/java/datadog/smoketest/springboot/service/LibraryService.java similarity index 100% rename from dd-smoke-tests/springboot-jpa/src/main/java/datadog/smoketest/springboot/service/LibraryService.java rename to dd-smoke-tests/springboot-jpa/application/src/main/java/datadog/smoketest/springboot/service/LibraryService.java diff --git a/dd-smoke-tests/springboot-jpa/src/main/resources/application.yml b/dd-smoke-tests/springboot-jpa/application/src/main/resources/application.yml similarity index 100% rename from dd-smoke-tests/springboot-jpa/src/main/resources/application.yml rename to dd-smoke-tests/springboot-jpa/application/src/main/resources/application.yml diff --git a/dd-smoke-tests/springboot-jpa/src/main/webapp/WEB-INF/jsp/update.jsp b/dd-smoke-tests/springboot-jpa/application/src/main/webapp/WEB-INF/jsp/update.jsp similarity index 100% rename from dd-smoke-tests/springboot-jpa/src/main/webapp/WEB-INF/jsp/update.jsp rename to dd-smoke-tests/springboot-jpa/application/src/main/webapp/WEB-INF/jsp/update.jsp diff --git a/dd-smoke-tests/springboot-jpa/build.gradle b/dd-smoke-tests/springboot-jpa/build.gradle index af9c22ff235..b70934ee101 100644 --- a/dd-smoke-tests/springboot-jpa/build.gradle +++ b/dd-smoke-tests/springboot-jpa/build.gradle @@ -1,44 +1,29 @@ -import org.springframework.boot.gradle.tasks.bundling.BootWar - plugins { - id 'java' - id 'war' - id 'org.springframework.boot' version '2.6.0' + id 'dd-trace-java.smoke-test-app' } -apply plugin: 'io.spring.dependency-management' apply from: "$rootDir/gradle/java.gradle" -apply from: "$rootDir/gradle/spring-boot-plugin.gradle" + description = 'SpringBoot JPA Smoke Tests.' -dependencies { - implementation 'org.springframework.boot:spring-boot-starter-web' - implementation 'org.springframework.boot:spring-boot-starter-data-jpa' - implementation 'org.apache.tomcat.embed:tomcat-embed-jasper' - implementation 'javax.servlet:jstl:1.2' - implementation 'com.h2database:h2:2.1.214' +smokeTestApp { + application { + taskName = 'bootWar' + artifactPath = 'libs/springboot-jpa-smoketest.war' + sysProperty = 'datadog.smoketest.springboot.bootWar.path' + } +} +dependencies { testImplementation project(':dd-smoke-tests') - - compileOnly 'org.projectlombok:lombok:1.18.34' - annotationProcessor 'org.projectlombok:lombok:1.18.34' - - testCompileOnly 'org.projectlombok:lombok:1.18.34' - testAnnotationProcessor 'org.projectlombok:lombok:1.18.34' } -tasks.withType(Test).configureEach { - dependsOn "bootWar" - - jvmArgumentProviders.add(new CommandLineArgumentProvider() { - @Override - Iterable asArguments() { - def bootWarTask = tasks.named('bootWar', BootWar).get() - return ["-Ddatadog.smoketest.springboot.bootWar.path=${bootWarTask.archiveFile.get()}"] - } - }) -} +spotless { + java { + target "**/*.java" + } -tasks.withType(GroovyCompile).configureEach { - configureCompiler(it, 8) + groovyGradle { + target '*.gradle', "**/*.gradle" + } } diff --git a/dd-smoke-tests/springboot-thymeleaf/application/build.gradle b/dd-smoke-tests/springboot-thymeleaf/application/build.gradle new file mode 100644 index 00000000000..77f8e57d848 --- /dev/null +++ b/dd-smoke-tests/springboot-thymeleaf/application/build.gradle @@ -0,0 +1,26 @@ +plugins { + id 'java' + id 'org.springframework.boot' version '2.7.15' + id 'io.spring.dependency-management' version '1.0.15.RELEASE' +} + +def sharedRootDir = "$rootDir/../../../" +def sharedConfigDirectory = "$sharedRootDir/gradle" +rootProject.ext.sharedConfigDirectory = sharedConfigDirectory + +apply from: "$sharedConfigDirectory/repositories.gradle" + +if (hasProperty('appBuildDir')) { + buildDir = property('appBuildDir') +} + +version = "" + +java { + sourceCompatibility = '1.8' +} + +dependencies { + implementation 'org.springframework.boot:spring-boot-starter-web' + implementation 'org.springframework.boot:spring-boot-starter-thymeleaf' +} diff --git a/dd-smoke-tests/springboot-thymeleaf/application/settings.gradle b/dd-smoke-tests/springboot-thymeleaf/application/settings.gradle new file mode 100644 index 00000000000..0dbff5f340e --- /dev/null +++ b/dd-smoke-tests/springboot-thymeleaf/application/settings.gradle @@ -0,0 +1,32 @@ +pluginManagement { + repositories { + mavenLocal() + if (settings.hasProperty("gradlePluginProxy")) { + maven { + url settings["gradlePluginProxy"] + allowInsecureProtocol = true + } + } + if (settings.hasProperty("mavenRepositoryProxy")) { + maven { + url settings["mavenRepositoryProxy"] + allowInsecureProtocol = true + } + } + gradlePluginPortal() + mavenCentral() + } +} + +def isCI = providers.environmentVariable("CI").isPresent() + +if (isCI) { + def sharedRootDir = "$rootDir/../../../" + buildCache { + local { + directory = "$sharedRootDir/workspace/build-cache" + } + } +} + +rootProject.name = 'springboot-thymeleaf-smoketest' diff --git a/dd-smoke-tests/springboot-thymeleaf/src/main/java/datadog/smoketest/springboot/SpringbootApplication.java b/dd-smoke-tests/springboot-thymeleaf/application/src/main/java/datadog/smoketest/springboot/SpringbootApplication.java similarity index 100% rename from dd-smoke-tests/springboot-thymeleaf/src/main/java/datadog/smoketest/springboot/SpringbootApplication.java rename to dd-smoke-tests/springboot-thymeleaf/application/src/main/java/datadog/smoketest/springboot/SpringbootApplication.java diff --git a/dd-smoke-tests/springboot-thymeleaf/src/main/java/datadog/smoketest/springboot/XssController.java b/dd-smoke-tests/springboot-thymeleaf/application/src/main/java/datadog/smoketest/springboot/XssController.java similarity index 100% rename from dd-smoke-tests/springboot-thymeleaf/src/main/java/datadog/smoketest/springboot/XssController.java rename to dd-smoke-tests/springboot-thymeleaf/application/src/main/java/datadog/smoketest/springboot/XssController.java diff --git a/dd-smoke-tests/springboot-thymeleaf/src/main/resources/templates/utext.html b/dd-smoke-tests/springboot-thymeleaf/application/src/main/resources/templates/utext.html similarity index 100% rename from dd-smoke-tests/springboot-thymeleaf/src/main/resources/templates/utext.html rename to dd-smoke-tests/springboot-thymeleaf/application/src/main/resources/templates/utext.html diff --git a/dd-smoke-tests/springboot-thymeleaf/build.gradle b/dd-smoke-tests/springboot-thymeleaf/build.gradle index 7de0a0833e5..4cd0d533f81 100644 --- a/dd-smoke-tests/springboot-thymeleaf/build.gradle +++ b/dd-smoke-tests/springboot-thymeleaf/build.gradle @@ -1,35 +1,31 @@ -import org.springframework.boot.gradle.tasks.bundling.BootJar - plugins { - id 'java' - id 'org.springframework.boot' version '2.7.15' - id 'io.spring.dependency-management' version '1.0.15.RELEASE' + id 'dd-trace-java.smoke-test-app' id 'java-test-fixtures' } apply from: "$rootDir/gradle/java.gradle" -apply from: "$rootDir/gradle/spring-boot-plugin.gradle" + description = 'SpringBoot thymeleaf 3 Smoke Tests.' -java { - sourceCompatibility = '1.8' +smokeTestApp { + application { + taskName = 'bootJar' + artifactPath = 'libs/springboot-thymeleaf-smoketest.jar' + sysProperty = 'datadog.smoketest.springboot.shadowJar.path' + } } dependencies { - implementation 'org.springframework.boot:spring-boot-starter-web' - implementation 'org.springframework.boot:spring-boot-starter-thymeleaf' - testImplementation project(':dd-smoke-tests') testImplementation(testFixtures(project(":dd-smoke-tests:iast-util"))) } -tasks.withType(Test).configureEach { - dependsOn "bootJar" - def bootJarTask = tasks.named('bootJar', BootJar) - jvmArgumentProviders.add(new CommandLineArgumentProvider() { - @Override - Iterable asArguments() { - return bootJarTask.map { ["-Ddatadog.smoketest.springboot.shadowJar.path=${it.archiveFile.get()}"] }.get() - } - }) +spotless { + java { + target "**/*.java" + } + + groovyGradle { + target '*.gradle', "**/*.gradle" + } } diff --git a/dd-smoke-tests/springboot-tomcat-jsp/application/build.gradle b/dd-smoke-tests/springboot-tomcat-jsp/application/build.gradle new file mode 100644 index 00000000000..8632e7afc64 --- /dev/null +++ b/dd-smoke-tests/springboot-tomcat-jsp/application/build.gradle @@ -0,0 +1,37 @@ +plugins { + id 'java' + id 'war' + id 'org.springframework.boot' version '2.7.15' + id 'io.spring.dependency-management' version '1.0.15.RELEASE' +} + +def sharedRootDir = "$rootDir/../../../" +def sharedConfigDirectory = "$sharedRootDir/gradle" +rootProject.ext.sharedConfigDirectory = sharedConfigDirectory + +apply from: "$sharedConfigDirectory/repositories.gradle" + +if (hasProperty('appBuildDir')) { + buildDir = property('appBuildDir') +} + +version = "" + +java { + sourceCompatibility = '1.8' +} + +sourceSets { + main { + resources.srcDir("src/main/webapp") + } +} + +dependencies { + implementation 'org.springframework.boot:spring-boot-starter-web' + + runtimeOnly("javax.servlet:jstl") + runtimeOnly("org.apache.tomcat.embed:tomcat-embed-jasper") + + providedRuntime("org.springframework.boot:spring-boot-starter-tomcat") +} diff --git a/dd-smoke-tests/springboot-tomcat-jsp/application/settings.gradle b/dd-smoke-tests/springboot-tomcat-jsp/application/settings.gradle new file mode 100644 index 00000000000..1c31089a007 --- /dev/null +++ b/dd-smoke-tests/springboot-tomcat-jsp/application/settings.gradle @@ -0,0 +1,32 @@ +pluginManagement { + repositories { + mavenLocal() + if (settings.hasProperty("gradlePluginProxy")) { + maven { + url settings["gradlePluginProxy"] + allowInsecureProtocol = true + } + } + if (settings.hasProperty("mavenRepositoryProxy")) { + maven { + url settings["mavenRepositoryProxy"] + allowInsecureProtocol = true + } + } + gradlePluginPortal() + mavenCentral() + } +} + +def isCI = providers.environmentVariable("CI").isPresent() + +if (isCI) { + def sharedRootDir = "$rootDir/../../../" + buildCache { + local { + directory = "$sharedRootDir/workspace/build-cache" + } + } +} + +rootProject.name = 'springboot-tomcat-jsp-smoketest' diff --git a/dd-smoke-tests/springboot-tomcat-jsp/src/main/java/datadog/smoketest/springboot/SpringbootApplication.java b/dd-smoke-tests/springboot-tomcat-jsp/application/src/main/java/datadog/smoketest/springboot/SpringbootApplication.java similarity index 100% rename from dd-smoke-tests/springboot-tomcat-jsp/src/main/java/datadog/smoketest/springboot/SpringbootApplication.java rename to dd-smoke-tests/springboot-tomcat-jsp/application/src/main/java/datadog/smoketest/springboot/SpringbootApplication.java diff --git a/dd-smoke-tests/springboot-tomcat-jsp/src/main/java/datadog/smoketest/springboot/ViewController.java b/dd-smoke-tests/springboot-tomcat-jsp/application/src/main/java/datadog/smoketest/springboot/ViewController.java similarity index 100% rename from dd-smoke-tests/springboot-tomcat-jsp/src/main/java/datadog/smoketest/springboot/ViewController.java rename to dd-smoke-tests/springboot-tomcat-jsp/application/src/main/java/datadog/smoketest/springboot/ViewController.java diff --git a/dd-smoke-tests/springboot-tomcat-jsp/src/main/resources/application.properties b/dd-smoke-tests/springboot-tomcat-jsp/application/src/main/resources/application.properties similarity index 100% rename from dd-smoke-tests/springboot-tomcat-jsp/src/main/resources/application.properties rename to dd-smoke-tests/springboot-tomcat-jsp/application/src/main/resources/application.properties diff --git a/dd-smoke-tests/springboot-tomcat-jsp/src/main/webapp/WEB-INF/jsp/test_xss.jsp b/dd-smoke-tests/springboot-tomcat-jsp/application/src/main/webapp/WEB-INF/jsp/test_xss.jsp similarity index 100% rename from dd-smoke-tests/springboot-tomcat-jsp/src/main/webapp/WEB-INF/jsp/test_xss.jsp rename to dd-smoke-tests/springboot-tomcat-jsp/application/src/main/webapp/WEB-INF/jsp/test_xss.jsp diff --git a/dd-smoke-tests/springboot-tomcat-jsp/build.gradle b/dd-smoke-tests/springboot-tomcat-jsp/build.gradle index 224274ece2a..0cf65d39298 100644 --- a/dd-smoke-tests/springboot-tomcat-jsp/build.gradle +++ b/dd-smoke-tests/springboot-tomcat-jsp/build.gradle @@ -1,47 +1,31 @@ -import org.springframework.boot.gradle.tasks.bundling.BootWar - plugins { - id 'java' - id 'war' - id 'org.springframework.boot' version '2.7.15' - id 'io.spring.dependency-management' version '1.0.15.RELEASE' + id 'dd-trace-java.smoke-test-app' id 'java-test-fixtures' } apply from: "$rootDir/gradle/java.gradle" -apply from: "$rootDir/gradle/spring-boot-plugin.gradle" -description = 'SpringBoot Tomcat JSP Smoke Tests.' -java { - sourceCompatibility = '1.8' -} +description = 'SpringBoot Tomcat JSP Smoke Tests.' -sourceSets { - main { - resources.srcDir("src/main/webapp") +smokeTestApp { + application { + taskName = 'bootWar' + artifactPath = 'libs/springboot-tomcat-jsp-smoketest.war' + sysProperty = 'datadog.smoketest.springboot.war.path' } } dependencies { - implementation 'org.springframework.boot:spring-boot-starter-web' - - runtimeOnly("javax.servlet:jstl") - runtimeOnly("org.apache.tomcat.embed:tomcat-embed-jasper") - - providedRuntime("org.springframework.boot:spring-boot-starter-tomcat") - testImplementation project(':dd-smoke-tests') testImplementation(testFixtures(project(":dd-smoke-tests:iast-util"))) } -tasks.withType(Test).configureEach { - dependsOn "war", "bootWar" +spotless { + java { + target "**/*.java" + } - jvmArgumentProviders.add(new CommandLineArgumentProvider() { - @Override - Iterable asArguments() { - def bootWarTask = tasks.named('bootWar', BootWar).get() - return ["-Ddatadog.smoketest.springboot.war.path=${bootWarTask.archiveFile.get().getAsFile()}"] - } - }) + groovyGradle { + target '*.gradle', "**/*.gradle" + } } diff --git a/dd-smoke-tests/springboot-tomcat/application/build.gradle b/dd-smoke-tests/springboot-tomcat/application/build.gradle new file mode 100644 index 00000000000..923b5d34006 --- /dev/null +++ b/dd-smoke-tests/springboot-tomcat/application/build.gradle @@ -0,0 +1,89 @@ +plugins { + id 'war' + id 'org.springframework.boot' version '2.5.12' +} + +def sharedRootDir = "$rootDir/../../../" +def sharedConfigDirectory = "$sharedRootDir/gradle" +rootProject.ext.sharedConfigDirectory = sharedConfigDirectory + +apply from: "$sharedConfigDirectory/repositories.gradle" + +if (hasProperty('appBuildDir')) { + buildDir = property('appBuildDir') +} + +version = "" + +// Pin bytecode target: the nested daemon now runs on JDK 21, but the smoke test launches +// the produced war on Java 8. +java { + sourceCompatibility = JavaVersion.VERSION_1_8 +} + +ext { + serverName = 'tomcat' + serverModule = 'tomcat-9' + serverVersion = '9.0.117' + serverExtension = 'zip' +} + +repositories { + ivy { + url = 'https://dlcdn.apache.org' + patternLayout { + artifact '/[organisation]/[module]/v[revision]/bin/apache-[organisation]-[revision].[ext]' + } + metadataSources { + it.artifact() + } + } +} + +configurations { + serverFile { + extendsFrom implementation + canBeResolved = true + } +} + +dependencies { + // uses the ivy repository url to download the tomcat server + // organisation = serverName, revision = serverVersion, module = serverModule, ext = serverExtension + serverFile "${serverName}:${serverModule}:${serverVersion}@${serverExtension}" + + implementation group: 'org.springframework.boot', name: 'spring-boot-starter-web', version: '2.5.12' + providedRuntime group: 'org.springframework.boot', name: 'spring-boot-starter-tomcat', version: '2.5.12' +} + +tasks.register("unzip", Copy) { + def zipFileNamePrefix = "tomcat" + def serverZipTree = providers.provider { + // eager access + def zipPath = project.configurations.serverFile.find { + it.name.startsWith(zipFileNamePrefix) + } + if (zipPath == null) { + throw new GradleException("Can't find server zip file that starts with: " + zipFileNamePrefix) + } + zipTree(zipPath) + } + + from serverZipTree + into layout.buildDirectory + + // When tests are disabled this would still be run, so disable this manually + onlyIf { !project.rootProject.hasProperty("skipTests") } +} + +tasks.named('bootWar') { + dependsOn 'unzip' +} + +tasks.named('bootWarMainClassName') { + dependsOn 'unzip' +} + +tasks.named('war') { + dependsOn 'unzip' +} diff --git a/dd-smoke-tests/springboot-tomcat/application/settings.gradle b/dd-smoke-tests/springboot-tomcat/application/settings.gradle new file mode 100644 index 00000000000..c526fe40384 --- /dev/null +++ b/dd-smoke-tests/springboot-tomcat/application/settings.gradle @@ -0,0 +1,32 @@ +pluginManagement { + repositories { + mavenLocal() + if (settings.hasProperty("gradlePluginProxy")) { + maven { + url settings["gradlePluginProxy"] + allowInsecureProtocol = true + } + } + if (settings.hasProperty("mavenRepositoryProxy")) { + maven { + url settings["mavenRepositoryProxy"] + allowInsecureProtocol = true + } + } + gradlePluginPortal() + mavenCentral() + } +} + +def isCI = providers.environmentVariable("CI").isPresent() + +if (isCI) { + def sharedRootDir = "$rootDir/../../../" + buildCache { + local { + directory = "$sharedRootDir/workspace/build-cache" + } + } +} + +rootProject.name = 'springboot-tomcat-smoketest' diff --git a/dd-smoke-tests/springboot-tomcat/src/main/java/datadog/smoketest/springboot/SpringbootTomcatApplication.java b/dd-smoke-tests/springboot-tomcat/application/src/main/java/datadog/smoketest/springboot/SpringbootTomcatApplication.java similarity index 100% rename from dd-smoke-tests/springboot-tomcat/src/main/java/datadog/smoketest/springboot/SpringbootTomcatApplication.java rename to dd-smoke-tests/springboot-tomcat/application/src/main/java/datadog/smoketest/springboot/SpringbootTomcatApplication.java diff --git a/dd-smoke-tests/springboot-tomcat/src/main/java/datadog/smoketest/springboot/controller/TestSuite.java b/dd-smoke-tests/springboot-tomcat/application/src/main/java/datadog/smoketest/springboot/controller/TestSuite.java similarity index 100% rename from dd-smoke-tests/springboot-tomcat/src/main/java/datadog/smoketest/springboot/controller/TestSuite.java rename to dd-smoke-tests/springboot-tomcat/application/src/main/java/datadog/smoketest/springboot/controller/TestSuite.java diff --git a/dd-smoke-tests/springboot-tomcat/src/main/java/datadog/smoketest/springboot/controller/ViewController.java b/dd-smoke-tests/springboot-tomcat/application/src/main/java/datadog/smoketest/springboot/controller/ViewController.java similarity index 100% rename from dd-smoke-tests/springboot-tomcat/src/main/java/datadog/smoketest/springboot/controller/ViewController.java rename to dd-smoke-tests/springboot-tomcat/application/src/main/java/datadog/smoketest/springboot/controller/ViewController.java diff --git a/dd-smoke-tests/springboot-tomcat/src/main/resources/application.properties b/dd-smoke-tests/springboot-tomcat/application/src/main/resources/application.properties similarity index 100% rename from dd-smoke-tests/springboot-tomcat/src/main/resources/application.properties rename to dd-smoke-tests/springboot-tomcat/application/src/main/resources/application.properties diff --git a/dd-smoke-tests/springboot-tomcat/build.gradle b/dd-smoke-tests/springboot-tomcat/build.gradle index 14d0705eeca..6ae55b8e65d 100644 --- a/dd-smoke-tests/springboot-tomcat/build.gradle +++ b/dd-smoke-tests/springboot-tomcat/build.gradle @@ -1,126 +1,34 @@ -import org.springframework.boot.gradle.tasks.bundling.BootWar - plugins { - id 'war' - id 'org.springframework.boot' version '2.5.12' -} - -ext { - serverName = 'tomcat' - serverModule = 'tomcat-9' - serverVersion = '9.0.117' - serverExtension = 'zip' + id 'dd-trace-java.smoke-test-app' } apply from: "$rootDir/gradle/java.gradle" -apply from: "$rootDir/gradle/spring-boot-plugin.gradle" + description = 'SpringBoot Tomcat Smoke Tests.' -repositories { - ivy { - url = 'https://dlcdn.apache.org' - patternLayout { - artifact '/[organisation]/[module]/v[revision]/bin/apache-[organisation]-[revision].[ext]' - } - metadataSources { - it.artifact() - } - } -} +def serverName = 'tomcat' +def serverVersion = '9.0.117' -configurations { - serverFile { - extendsFrom implementation - canBeResolved = true +smokeTestApp { + application { + taskName = 'bootWar' + artifactPath = 'libs/springboot-tomcat-smoketest.war' + sysProperty = 'datadog.smoketest.springboot.war.path' + additionalSystemProperties.put('datadog.smoketest.tomcatDir', "apache-${serverName}-${serverVersion}") } } dependencies { - // uses the ivy repository url to download the tomcat server - // organisation = serverName, revision = serverVersion, module = serverModule, ext = serverExtension - serverFile "${serverName}:${serverModule}:${serverVersion}@${serverExtension}" - testImplementation project(':dd-smoke-tests') -} - -tasks.register("unzip", Copy) { - def zipFileNamePrefix = "tomcat" - def serverZipTree = providers.provider { - // eager access - def zipPath = project.configurations.serverFile.find { - it.name.startsWith(zipFileNamePrefix) - } - if (zipPath == null) { - throw new GradleException("Can't find server zip file that starts with: " + zipFileNamePrefix) - } - zipTree(zipPath) - } - - from serverZipTree - into layout.buildDirectory - - // When tests are disabled this would still be run, so disable this manually - onlyIf { !project.rootProject.hasProperty("skipTests") } -} - -dependencies { - implementation group: 'org.springframework.boot', name: 'spring-boot-starter-web', version: '2.5.12' - providedRuntime group: 'org.springframework.boot', name: 'spring-boot-starter-tomcat', version: '2.5.12' testImplementation group: 'commons-io', name: 'commons-io', version: '2.11.0' - testImplementation project(':dd-smoke-tests') -} - -tasks.named('sourcesJar') { - dependsOn 'unzip' -} - -tasks.named('javadocJar') { - dependsOn 'unzip' -} - -tasks.named('bootWar') { - dependsOn 'unzip' -} - -tasks.named('bootWarMainClassName') { - dependsOn 'unzip' } -tasks.named('war') { - dependsOn 'unzip' -} - -tasks.named('javadocJar') { - dependsOn 'unzip' -} - -tasks.named('sourcesJar') { - dependsOn 'unzip' -} - -tasks.named('forbiddenApisMain') { - dependsOn 'unzip' -} - -tasks.named('spotbugsMain') { - dependsOn 'unzip' -} - -tasks.matching({it.name.startsWith('compileTest')}).configureEach { - dependsOn 'war', 'bootWar', 'unzip' -} - -tasks.withType(Test).configureEach { - dependsOn "war", "bootWar", "unzip" +spotless { + java { + target "**/*.java" + } - jvmArgumentProviders.add(new CommandLineArgumentProvider() { - @Override - Iterable asArguments() { - def bootWarTask = tasks.named('bootWar', BootWar).get() - return [ - "-Ddatadog.smoketest.springboot.war.path=${bootWarTask.archiveFile.get().getAsFile()}", - "-Ddatadog.smoketest.tomcatDir=${layout.buildDirectory.get()}/apache-${serverName}-${serverVersion}" - ] - } - }) + groovyGradle { + target '*.gradle', "**/*.gradle" + } } diff --git a/dd-smoke-tests/springboot-velocity/application/build.gradle b/dd-smoke-tests/springboot-velocity/application/build.gradle new file mode 100644 index 00000000000..866c726b521 --- /dev/null +++ b/dd-smoke-tests/springboot-velocity/application/build.gradle @@ -0,0 +1,31 @@ +plugins { + id 'java' + id 'org.springframework.boot' version '2.7.15' + id 'io.spring.dependency-management' version '1.0.15.RELEASE' +} + +def sharedRootDir = "$rootDir/../../../" +def sharedConfigDirectory = "$sharedRootDir/gradle" +rootProject.ext.sharedConfigDirectory = sharedConfigDirectory + +apply from: "$sharedConfigDirectory/repositories.gradle" + +if (hasProperty('appBuildDir')) { + buildDir = property('appBuildDir') +} + +version = "" + +// Pin bytecode target: the nested daemon now runs on JDK 21, but the smoke test launches +// the produced jar on Java 8. +java { + sourceCompatibility = JavaVersion.VERSION_1_8 +} + +dependencies { + implementation group: 'org.springframework.boot', name: 'spring-boot-starter-web', version: '1.5.18.RELEASE' + implementation group: 'org.apache.velocity', name: 'velocity', version: '1.5' + implementation(group: 'org.apache.velocity', name: 'velocity-tools', version: '1.3') { + exclude group: 'javax.servlet', module: 'servlet-api' + } +} diff --git a/dd-smoke-tests/springboot-velocity/application/settings.gradle b/dd-smoke-tests/springboot-velocity/application/settings.gradle new file mode 100644 index 00000000000..0d5e7d082bc --- /dev/null +++ b/dd-smoke-tests/springboot-velocity/application/settings.gradle @@ -0,0 +1,32 @@ +pluginManagement { + repositories { + mavenLocal() + if (settings.hasProperty("gradlePluginProxy")) { + maven { + url settings["gradlePluginProxy"] + allowInsecureProtocol = true + } + } + if (settings.hasProperty("mavenRepositoryProxy")) { + maven { + url settings["mavenRepositoryProxy"] + allowInsecureProtocol = true + } + } + gradlePluginPortal() + mavenCentral() + } +} + +def isCI = providers.environmentVariable("CI").isPresent() + +if (isCI) { + def sharedRootDir = "$rootDir/../../../" + buildCache { + local { + directory = "$sharedRootDir/workspace/build-cache" + } + } +} + +rootProject.name = 'springboot-velocity-smoketest' diff --git a/dd-smoke-tests/springboot-velocity/src/main/java/datadog/smoketest/springboot/SpringbootApplication.java b/dd-smoke-tests/springboot-velocity/application/src/main/java/datadog/smoketest/springboot/SpringbootApplication.java similarity index 100% rename from dd-smoke-tests/springboot-velocity/src/main/java/datadog/smoketest/springboot/SpringbootApplication.java rename to dd-smoke-tests/springboot-velocity/application/src/main/java/datadog/smoketest/springboot/SpringbootApplication.java diff --git a/dd-smoke-tests/springboot-velocity/src/main/java/datadog/smoketest/springboot/XssController.java b/dd-smoke-tests/springboot-velocity/application/src/main/java/datadog/smoketest/springboot/XssController.java similarity index 100% rename from dd-smoke-tests/springboot-velocity/src/main/java/datadog/smoketest/springboot/XssController.java rename to dd-smoke-tests/springboot-velocity/application/src/main/java/datadog/smoketest/springboot/XssController.java diff --git a/dd-smoke-tests/springboot-velocity/src/main/resources/templates/velocity-insecure.vm b/dd-smoke-tests/springboot-velocity/application/src/main/resources/templates/velocity-insecure.vm similarity index 100% rename from dd-smoke-tests/springboot-velocity/src/main/resources/templates/velocity-insecure.vm rename to dd-smoke-tests/springboot-velocity/application/src/main/resources/templates/velocity-insecure.vm diff --git a/dd-smoke-tests/springboot-velocity/src/main/resources/templates/velocity-secure.vm b/dd-smoke-tests/springboot-velocity/application/src/main/resources/templates/velocity-secure.vm similarity index 100% rename from dd-smoke-tests/springboot-velocity/src/main/resources/templates/velocity-secure.vm rename to dd-smoke-tests/springboot-velocity/application/src/main/resources/templates/velocity-secure.vm diff --git a/dd-smoke-tests/springboot-velocity/build.gradle b/dd-smoke-tests/springboot-velocity/build.gradle index 76881a53bc1..79f63efeb90 100644 --- a/dd-smoke-tests/springboot-velocity/build.gradle +++ b/dd-smoke-tests/springboot-velocity/build.gradle @@ -1,34 +1,52 @@ -import org.springframework.boot.gradle.tasks.bundling.BootJar - plugins { - id 'java' - id 'org.springframework.boot' version '2.7.15' - id 'io.spring.dependency-management' version '1.0.15.RELEASE' + id 'dd-trace-java.smoke-test-app' id 'java-test-fixtures' } apply from: "$rootDir/gradle/java.gradle" -apply from: "$rootDir/gradle/spring-boot-plugin.gradle" + description = 'SpringBoot Velocity Smoke Tests.' -dependencies { - implementation group: 'org.springframework.boot', name: 'spring-boot-starter-web', version: '1.5.18.RELEASE' - implementation group: 'org.apache.velocity', name: 'velocity', version: '1.5' - implementation(group: 'org.apache.velocity', name: 'velocity-tools', version: '1.3') { - exclude group: 'javax.servlet', module: 'servlet-api' +smokeTestApp { + application { + taskName = 'bootJar' + artifactPath = 'libs/springboot-velocity-smoketest.jar' + sysProperty = 'datadog.smoketest.springboot.shadowJar.path' } +} +dependencies { testImplementation project(':dd-smoke-tests') testImplementation(testFixtures(project(":dd-smoke-tests:iast-util"))) } +// XssController loads templates from the filesystem at "resources/main/templates" relative to +// the test JVM's working directory (this module's build dir). Mirror the nested app's +// processed resources so that path resolves at runtime. +def applicationResourcesProvider = layout.buildDirectory.dir("application/resources/main") +tasks.register('copyAppResources', Copy) { + dependsOn 'bootJar' + from applicationResourcesProvider + into layout.buildDirectory.dir("resources/main") +} + +// `java.gradle` applies the `java` plugin so an empty `jar` task is created with +// `build/resources/main` as one of its inputs. Wire the dependency so Gradle knows +// `copyAppResources` writes there. +tasks.named('jar') { + dependsOn 'copyAppResources' +} + tasks.withType(Test).configureEach { - dependsOn "bootJar" - def bootJarTask = tasks.named('bootJar', BootJar) - jvmArgumentProviders.add(new CommandLineArgumentProvider() { - @Override - Iterable asArguments() { - return bootJarTask.map { ["-Ddatadog.smoketest.springboot.shadowJar.path=${it.archiveFile.get()}"] }.get() - } - }) + dependsOn 'copyAppResources' +} + +spotless { + java { + target "**/*.java" + } + + groovyGradle { + target '*.gradle', "**/*.gradle" + } } From 5c3a181ecc578a27bfdfa2add7e580d8c79d74ac Mon Sep 17 00:00:00 2001 From: Brice Dutheil Date: Wed, 20 May 2026 12:44:17 +0200 Subject: [PATCH 5/5] docs(smoke-tests): document nested-build Gradle config choices Address review feedback on #11408: add comments explaining the legacy Spring Boot 2.7.x / OpenTracing pins, the iastUtilJar property wired from the outer build, the CI-only shared build cache (f6ec1f5cc8 / #982, b34ccbc048), the internal Maven mirror proxies, and the Java 11 baseline for the OpenFeature smoke test. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../apm-tracing-disabled/application/build.gradle | 6 ++++++ .../apm-tracing-disabled/application/settings.gradle | 9 +++++++++ dd-smoke-tests/kafka-2/application/build.gradle | 7 +++++++ dd-smoke-tests/kafka-2/application/settings.gradle | 9 +++++++++ dd-smoke-tests/openfeature/application/build.gradle | 3 +++ dd-smoke-tests/openfeature/application/settings.gradle | 9 +++++++++ 6 files changed, 43 insertions(+) diff --git a/dd-smoke-tests/apm-tracing-disabled/application/build.gradle b/dd-smoke-tests/apm-tracing-disabled/application/build.gradle index 3f5c868f46a..b5653805e95 100644 --- a/dd-smoke-tests/apm-tracing-disabled/application/build.gradle +++ b/dd-smoke-tests/apm-tracing-disabled/application/build.gradle @@ -1,3 +1,6 @@ +// Spring Boot 2.7.x is the last line that still supports Java 8, which this smoke test +// exercises (see the `sourceCompatibility = '1.8'` below). Do not bump to 3.x without +// also moving the smoke test off Java 8. plugins { id 'java' id 'org.springframework.boot' version '2.7.15' @@ -33,6 +36,9 @@ if (hasProperty('apiJar')) { dependencies { compileOnly 'com.github.spotbugs:spotbugs-annotations:4.9.8' implementation 'org.springframework.boot:spring-boot-starter-web' + // OpenTracing 0.32.0 is the last release and is intentionally pinned: this smoke test + // exercises the legacy OpenTracing bridge in dd-trace-ot. Do not "upgrade" — there is + // no newer version. implementation group: 'io.opentracing', name: 'opentracing-api', version: '0.32.0' implementation group: 'io.opentracing', name: 'opentracing-util', version: '0.32.0' } diff --git a/dd-smoke-tests/apm-tracing-disabled/application/settings.gradle b/dd-smoke-tests/apm-tracing-disabled/application/settings.gradle index aac1278eba5..1cd03bc7775 100644 --- a/dd-smoke-tests/apm-tracing-disabled/application/settings.gradle +++ b/dd-smoke-tests/apm-tracing-disabled/application/settings.gradle @@ -1,3 +1,7 @@ +// The `gradlePluginProxy` / `mavenRepositoryProxy` properties point to internal Maven +// mirrors used by CI when the public repos are unreachable; they are forwarded from the +// outer build via the smoke-test plugin. `allowInsecureProtocol` is required because the +// mirrors are reached over plain HTTP inside the CI network. pluginManagement { repositories { mavenLocal() @@ -20,6 +24,11 @@ pluginManagement { def isCI = providers.environmentVariable("CI").isPresent() +// On CI, point the local Gradle build cache to the shared workspace directory under the +// repository root, so cache entries are reused across the many smoke-test nested builds +// (and across CI jobs that mount the same workspace). See f6ec1f5cc8 / #982 for the +// root-level cache, and b34ccbc048 for the `isCI` gating — locally we keep the default +// per-user cache to avoid leaking entries into the repo tree. if (isCI) { def sharedRootDir = "$rootDir/../../../" buildCache { diff --git a/dd-smoke-tests/kafka-2/application/build.gradle b/dd-smoke-tests/kafka-2/application/build.gradle index 9304c311ebe..31411ab9e3e 100644 --- a/dd-smoke-tests/kafka-2/application/build.gradle +++ b/dd-smoke-tests/kafka-2/application/build.gradle @@ -1,3 +1,6 @@ +// Spring Boot 2.7.x is the last line that still supports Java 8, which this smoke test +// exercises (see the Java 8 `sourceCompatibility` below). Do not bump to 3.x without +// also moving the smoke test off Java 8. plugins { id 'java' id 'org.springframework.boot' version '2.7.15' @@ -22,6 +25,10 @@ java { sourceCompatibility = JavaVersion.VERSION_1_8 } +// `iastUtilJar` is wired up by the outer `smokeTestApp { projectJar('iastUtilJar', ...) }` +// block in ../build.gradle: it passes the path of the built `:dd-smoke-tests:iast-util` +// jar into this nested build as a Gradle property. We add it as a flat-file dependency +// because the outer build's projects are not addressable from inside the nested build. if (hasProperty('iastUtilJar')) { dependencies { implementation files(property('iastUtilJar')) diff --git a/dd-smoke-tests/kafka-2/application/settings.gradle b/dd-smoke-tests/kafka-2/application/settings.gradle index f5d4088d9b5..52cb42bea22 100644 --- a/dd-smoke-tests/kafka-2/application/settings.gradle +++ b/dd-smoke-tests/kafka-2/application/settings.gradle @@ -1,3 +1,7 @@ +// The `gradlePluginProxy` / `mavenRepositoryProxy` properties point to internal Maven +// mirrors used by CI when the public repos are unreachable; they are forwarded from the +// outer build via the smoke-test plugin. `allowInsecureProtocol` is required because the +// mirrors are reached over plain HTTP inside the CI network. pluginManagement { repositories { mavenLocal() @@ -20,6 +24,11 @@ pluginManagement { def isCI = providers.environmentVariable("CI").isPresent() +// On CI, point the local Gradle build cache to the shared workspace directory under the +// repository root, so cache entries are reused across the many smoke-test nested builds +// (and across CI jobs that mount the same workspace). See f6ec1f5cc8 / #982 for the +// root-level cache, and b34ccbc048 for the `isCI` gating — locally we keep the default +// per-user cache to avoid leaking entries into the repo tree. if (isCI) { def sharedRootDir = "$rootDir/../../../" buildCache { diff --git a/dd-smoke-tests/openfeature/application/build.gradle b/dd-smoke-tests/openfeature/application/build.gradle index a74020164f9..9f7f9558e9b 100644 --- a/dd-smoke-tests/openfeature/application/build.gradle +++ b/dd-smoke-tests/openfeature/application/build.gradle @@ -16,6 +16,9 @@ if (hasProperty('appBuildDir')) { version = "" +// Java 11 (not Java 8 like the other Spring Boot 2.x smoke tests): the OpenFeature SDK +// requires Java 11+. This matches what the outer (pre-nested) build was doing before +// the application was extracted into this nested build. java { sourceCompatibility = 11 targetCompatibility = 11 diff --git a/dd-smoke-tests/openfeature/application/settings.gradle b/dd-smoke-tests/openfeature/application/settings.gradle index cd52c32ced8..6e990889506 100644 --- a/dd-smoke-tests/openfeature/application/settings.gradle +++ b/dd-smoke-tests/openfeature/application/settings.gradle @@ -1,3 +1,7 @@ +// The `gradlePluginProxy` / `mavenRepositoryProxy` properties point to internal Maven +// mirrors used by CI when the public repos are unreachable; they are forwarded from the +// outer build via the smoke-test plugin. `allowInsecureProtocol` is required because the +// mirrors are reached over plain HTTP inside the CI network. pluginManagement { repositories { mavenLocal() @@ -20,6 +24,11 @@ pluginManagement { def isCI = providers.environmentVariable("CI").isPresent() +// On CI, point the local Gradle build cache to the shared workspace directory under the +// repository root, so cache entries are reused across the many smoke-test nested builds +// (and across CI jobs that mount the same workspace). See f6ec1f5cc8 / #982 for the +// root-level cache, and b34ccbc048 for the `isCI` gating — locally we keep the default +// per-user cache to avoid leaking entries into the repo tree. if (isCI) { def sharedRootDir = "$rootDir/../../../" buildCache {