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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitlab-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ variables:
GRADLE_PLUGIN_PROXY: "https://depot-read-api-java.us1.ddbuild.io/magicmirror/magicmirror/@current/"
BUILDER_IMAGE_REPO: "registry.ddbuild.io/images/mirror/dd-trace-java-docker-build" # images are pinned in images/mirror.lock.yaml in the ddoghq/images repo
BUILDER_IMAGE_VERSION_PREFIX: "ci-" # use either an empty string (e.g. "") for latest images or a version followed by a hyphen (e.g. "ci-" or "123_merge-")
# shortcut: tag republishing is not detected; use a content hash when CI builds the image.
ORG_GRADLE_PROJECT_ciBuilderImage: "${BUILDER_IMAGE_REPO}:${BUILDER_IMAGE_VERSION_PREFIX}"
TEST_COUNTS_S3_BUCKET: "dd-trace-java-ci-test-reports"
REPO_NOTIFICATION_CHANNEL: "#apm-java-escalations"
DEFAULT_TEST_JVMS: /^(8|11|17|21|25|tip)$/ # the latest "tip" version is 27
Expand Down
24 changes: 24 additions & 0 deletions build-logic/conventions/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# CI builder image inputs

The `dd-trace-java.ci-builder-inputs` convention tracks the CI builder image identity
in Gradle build cache keys. It is enabled only in CI (`CI=true`).
It reads the `ciBuilderImage` Gradle property and adds
`ciBuilderIdentity` inputs to `Test`, `Exec` and `JavaExec` tasks in projects that apply it.

> [!NOTE]
> The property is an opaque identity. It can hold the current builder repository
> and version prefix, such as `registry.example/builder:ci-`, or a future content
> hash. Moving a tag to different contents without changing the property does not
> invalidate cached results.

For other tasks, declare the input explicitly. The provider returns an empty map locally:

```Gradle Kotlin DSL
plugins {
id("dd-trace-java.ci-builder-inputs")
}

tasks.named("generateNativeLibrary") {
inputs.property("ciBuilderIdentity", ciBuilderInputs.identity)
}
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package datadog.buildlogic.ci

import org.gradle.api.GradleException
import org.gradle.api.Task
import org.gradle.api.provider.Provider
import org.gradle.api.provider.ProviderFactory
import javax.inject.Inject

/** Tracks the declared builder identity and platform used by selected CI tasks. */
open class CiBuilderInputsExtension
@Inject
constructor(
providers: ProviderFactory,
) {
// CI selection changes task configuration, so it is a configuration-cache input.
private val enabled = providers.environmentVariable("CI").orNull == "true"

/** Builder identity and platform in CI; an empty map in local builds. */
val identity: Provider<Map<String, String>> =
if (enabled) {
providers.gradleProperty("ciBuilderImage").orElse("").map { image ->
if (image.isBlank()) {
throw GradleException("ciBuilderImage must be a nonblank CI builder identity when CI=true")
}
mapOf(
"image" to image,
"operatingSystem" to System.getProperty("os.name"),
"architecture" to System.getProperty("os.arch"),
)
}
} else {
providers.provider { emptyMap() }
}

internal fun addTo(task: Task) {
if (enabled) {
task.inputs.property("ciBuilderIdentity", identity)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import datadog.buildlogic.ci.CiBuilderInputsExtension
import org.gradle.api.tasks.Exec
import org.gradle.api.tasks.JavaExec
import org.gradle.api.tasks.testing.Test
import org.gradle.kotlin.dsl.create
import org.gradle.kotlin.dsl.withType

val ciBuilderInputs = extensions.create<CiBuilderInputsExtension>("ciBuilderInputs")

tasks.withType<Test>().configureEach {
ciBuilderInputs.addTo(this)
}

tasks.withType<Exec>().configureEach {
ciBuilderInputs.addTo(this)
}

tasks.withType<JavaExec>().configureEach {
ciBuilderInputs.addTo(this)
}
2 changes: 2 additions & 0 deletions dd-java-agent/agent-ci-visibility/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import org.jetbrains.kotlin.gradle.dsl.JvmTarget
import org.jetbrains.kotlin.gradle.dsl.KotlinVersion

plugins {
// Git tests generate and read pack files using the image's Git executable.
id 'dd-trace-java.ci-builder-inputs'
id 'com.gradleup.shadow'
id 'org.jetbrains.kotlin.jvm'
id 'dd-trace-java.version-file'
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
plugins {
// Tests load the native profiler selected for the image's libc variant.
id 'dd-trace-java.ci-builder-inputs'
id 'dd-trace-java.module.internal-library'
}

Expand Down
3 changes: 3 additions & 0 deletions dd-smoke-tests/quarkus-native/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import java.util.concurrent.Callable
import java.util.regex.Pattern

plugins {
// Native smoke builds use GraalVM and native tools from the builder environment.
id 'dd-trace-java.ci-builder-inputs'
id 'dd-trace-java.smoke-test-app'
id 'dd-trace-java.module.smoke-test'
}
Expand Down Expand Up @@ -46,6 +48,7 @@ smokeTestApp {
environment.put('GRAALVM_HOME', graalvmHome)
inputs {
property('graalvmRelease', fileContent(graalvmHome, 'release'))
property('ciBuilderIdentity', ciBuilderInputs.identity)
}
}
projectJar('apiJar', project(':dd-trace-api'))
Expand Down
3 changes: 3 additions & 0 deletions dd-smoke-tests/spring-boot-3.0-native/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import java.util.concurrent.Callable
import java.util.regex.Pattern

plugins {
// Native smoke builds use GraalVM and native tools from the builder environment.
id 'dd-trace-java.ci-builder-inputs'
id 'dd-trace-java.smoke-test-app'
id 'dd-trace-java.module.smoke-test'
}
Expand Down Expand Up @@ -44,6 +46,7 @@ smokeTestApp {
environment.put('NATIVE_IMAGE_DEPRECATED_BUILDER_SANITATION', 'true')
inputs {
property('graalvmRelease', fileContent(graalvmHome, 'release'))
property('ciBuilderIdentity', ciBuilderInputs.identity)
}
}
projectJar('apiJar', project(':dd-trace-api'))
Expand Down
12 changes: 12 additions & 0 deletions docs/how_to_work_with_gradle.md
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,18 @@ tasks.register("processData") {
> Prefer annotations in custom task classes for better type safety and documentation.
> Use the programmatic API for ad-hoc tasks registered with `tasks.register`.

#### CI Builder Image Inputs

Apply the [`dd-trace-java.ci-builder-inputs` convention](../build-logic/conventions/README.md)
when a module's cacheable tasks depend on the CI image's native toolchain, runtime libraries,
or tool-specific output, such as Git pack generation. Routine uses of `cat`, `echo`, `ls`
or `sleep` alone do not justify invalidating tasks on every image change.

The convention adds the builder identity to `Test`, `Exec` and `JavaExec` inputs when
`CI=true`. Other task types, including native smoke producers, declare the identity
explicitly. See the convention reference for the CI property and input declarations.
Local builds require no configuration.

#### Lazy Configuration with Providers

Gradle uses **lazy configuration** to defer value resolution until needed. Instead of setting values directly, you use `Property` and `Provider` types:
Expand Down
Loading