From f13fc61c08a4e46b58c41db9102da1e3a9cbd830 Mon Sep 17 00:00:00 2001 From: Jaroslav Bachorik Date: Mon, 22 Dec 2025 14:10:45 +0100 Subject: [PATCH 1/8] Allow ddprof version override to build a custom 'profiler-snapshot' dd-java-agent artifact --- .gitlab-ci.yml | 25 +++++ build.gradle.kts | 1 + dd-java-agent/ddprof-lib/build.gradle | 7 ++ docs/publishing-with-ddprof-snapshot.md | 141 ++++++++++++++++++++++++ gradle/ddprof-override.gradle | 73 ++++++++++++ gradle/ddprof-snapshot.gradle | 73 ++++++++++++ 6 files changed, 320 insertions(+) create mode 100644 docs/publishing-with-ddprof-snapshot.md create mode 100644 gradle/ddprof-override.gradle create mode 100644 gradle/ddprof-snapshot.gradle diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 049ac973c29..c93755eabe0 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -888,6 +888,31 @@ deploy_to_maven_central: - 'workspace/dd-trace-api/build/libs/*.jar' - 'workspace/dd-trace-ot/build/libs/*.jar' +deploy_snapshot_with_ddprof_snapshot: + extends: .gradle_build + stage: publish + needs: [ build ] + variables: + CACHE_TYPE: "lib" + rules: + - if: '$POPULATE_CACHE' + when: never + # Manual trigger only - for testing with ddprof snapshot versions + - when: manual + allow_failure: true + script: + - export MAVEN_CENTRAL_USERNAME=$(aws ssm get-parameter --region us-east-1 --name ci.dd-trace-java.central_username --with-decryption --query "Parameter.Value" --out text) + - export MAVEN_CENTRAL_PASSWORD=$(aws ssm get-parameter --region us-east-1 --name ci.dd-trace-java.central_password --with-decryption --query "Parameter.Value" --out text) + - export GPG_PRIVATE_KEY=$(aws ssm get-parameter --region us-east-1 --name ci.dd-trace-java.signing.gpg_private_key --with-decryption --query "Parameter.Value" --out text) + - export GPG_PASSWORD=$(aws ssm get-parameter --region us-east-1 --name ci.dd-trace-java.signing.gpg_passphrase --with-decryption --query "Parameter.Value" --out text) + - echo "Publishing dd-trace-java snapshot with ddprof snapshot dependency" + - ./gradlew -PbuildInfo.build.number=$CI_JOB_ID -PuseDdprofSnapshot=true publishToSonatype -PskipTests $GRADLE_ARGS + artifacts: + paths: + - 'workspace/dd-java-agent/build/libs/*.jar' + - 'workspace/dd-trace-api/build/libs/*.jar' + - 'workspace/dd-trace-ot/build/libs/*.jar' + deploy_artifacts_to_github: stage: publish image: registry.ddbuild.io/images/dd-octo-sts-ci-base:2025.06-1 diff --git a/build.gradle.kts b/build.gradle.kts index 0a54e90658b..8966ba8b99d 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -26,6 +26,7 @@ description = "dd-trace-java" val isCI = providers.environmentVariable("CI") apply(from = rootDir.resolve("gradle/repositories.gradle")) +apply(from = rootDir.resolve("gradle/ddprof-snapshot.gradle")) spotless { // only resolve the spotless dependencies once in the build diff --git a/dd-java-agent/ddprof-lib/build.gradle b/dd-java-agent/ddprof-lib/build.gradle index 0d265cc7db9..397f2d17a23 100644 --- a/dd-java-agent/ddprof-lib/build.gradle +++ b/dd-java-agent/ddprof-lib/build.gradle @@ -14,6 +14,13 @@ dependencies { api project(':dd-trace-api') } +// Log information about ddprof version being used +afterEvaluate { + if (rootProject.hasProperty('ddprofSnapshotVersion')) { + logger.lifecycle("${project.name}: Using ddprof SNAPSHOT version ${rootProject.ext.ddprofSnapshotVersion}") + } +} + tasks.named("shadowJar", ShadowJar) { dependencies { deps.excludeShared diff --git a/docs/publishing-with-ddprof-snapshot.md b/docs/publishing-with-ddprof-snapshot.md new file mode 100644 index 00000000000..56c70d36d6b --- /dev/null +++ b/docs/publishing-with-ddprof-snapshot.md @@ -0,0 +1,141 @@ +# Publishing dd-trace-java Snapshots with ddprof SNAPSHOT Dependency + +## Overview + +This feature allows publishing dd-trace-java snapshot versions that depend on a ddprof SNAPSHOT version with an incremented minor version. + +**ddprof Version Calculation:** Current ddprof version `X.Y.Z` → Dependency becomes `X.(Y+1).0-SNAPSHOT` + +**Example:** ddprof `1.34.4` → Uses dependency `1.35.0-SNAPSHOT` + +### Version Qualification + +To avoid overwriting standard snapshot artifacts, builds with `-PuseDdprofSnapshot=true` will have a `-ddprof` qualifier added to their version: + +- Standard snapshot: `1.58.0-SNAPSHOT` +- With ddprof snapshot: `1.58.0-ddprof-SNAPSHOT` + +This ensures that both versions can coexist in Maven Central Snapshots repository without conflicts. + +## Local Usage + +### Testing Dependency Resolution + +To verify that the ddprof snapshot version is correctly calculated and applied: + +```bash +./gradlew -PuseDdprofSnapshot=true :dd-java-agent:ddprof-lib:dependencies --configuration runtimeClasspath +``` + +Look for the output: +- `Using ddprof snapshot version: X.Y.0-SNAPSHOT` +- `Modified version for dd-trace-java: 1.58.0-SNAPSHOT -> 1.58.0-ddprof-SNAPSHOT` +- `ddprof-lib: Using ddprof SNAPSHOT version X.Y.0-SNAPSHOT` +- Dependency resolution showing: `com.datadoghq:ddprof:X.Y.Z -> X.(Y+1).0-SNAPSHOT` + +### Building with ddprof Snapshot + +To build the project with the ddprof snapshot dependency: + +```bash +./gradlew build -PuseDdprofSnapshot=true +``` + +### Publishing to Maven Central Snapshots + +To publish artifacts with the ddprof snapshot dependency: + +```bash +./gradlew publishToSonatype -PuseDdprofSnapshot=true -PskipTests +``` + +**Note:** You must have the required credentials configured: +- `MAVEN_CENTRAL_USERNAME` +- `MAVEN_CENTRAL_PASSWORD` +- `GPG_PRIVATE_KEY` +- `GPG_PASSWORD` + +## GitLab CI Usage + +### Manual Job Trigger + +A GitLab CI job named `deploy_snapshot_with_ddprof_snapshot` is available for manual execution. + +**To trigger:** +1. Navigate to the pipeline in GitLab CI +2. Find the `deploy_snapshot_with_ddprof_snapshot` job in the `publish` stage +3. Click the manual play button to trigger it + +**What it does:** +- Builds dd-trace-java with `-PuseDdprofSnapshot=true` +- Publishes to Maven Central Snapshots repository +- Produces artifacts with the ddprof snapshot dependency + +**When to use:** +- Testing integration with unreleased ddprof features +- Validating compatibility before ddprof release +- Creating test builds for early adopters + +## Implementation Details + +### Files Modified + +1. **`gradle/ddprof-snapshot.gradle`** - Core logic for version calculation and dependency override +2. **`build.gradle.kts`** - Applies the ddprof-snapshot configuration +3. **`dd-java-agent/ddprof-lib/build.gradle`** - Logging for snapshot version usage +4. **`.gitlab-ci.yml`** - New CI job for snapshot publishing + +### How It Works + +1. The Gradle property `-PuseDdprofSnapshot=true` activates the feature +2. The configuration reads `gradle/libs.versions.toml` to get the current ddprof version +3. Version is parsed using regex: `ddprof = "X.Y.Z"` +4. Snapshot version is calculated: `X.(Y+1).0-SNAPSHOT` +5. **The dd-trace-java version is modified** to add a `-ddprof` qualifier: + - `1.58.0-SNAPSHOT` → `1.58.0-ddprof-SNAPSHOT` + - This prevents overwriting standard snapshot artifacts +6. Gradle's `resolutionStrategy.eachDependency` overrides all ddprof dependencies to use the snapshot version +7. The build and publish proceed with the modified version and overridden dependency + +### Dependency Resolution Override + +The override is applied globally to all configurations in all projects: + +```groovy +configurations.all { + resolutionStrategy.eachDependency { DependencyResolveDetails details -> + if (details.requested.group == 'com.datadoghq' && details.requested.name == 'ddprof') { + details.useVersion(ddprofSnapshotVersion) + details.because("Using ddprof snapshot version for integration testing") + } + } +} +``` + +This ensures that even transitive dependencies on ddprof are overridden. + +## Limitations + +- Only works with semantic versioning in format `X.Y.Z` +- Requires ddprof SNAPSHOT to be published to Maven Central Snapshots repository +- Cannot override local JAR files specified with `-Pddprof.jar=/path/to/jar` + +## Troubleshooting + +### "Could not find com.datadoghq:ddprof:X.Y.0-SNAPSHOT" + +**Cause:** The calculated ddprof snapshot version doesn't exist in Maven Central Snapshots. + +**Solutions:** +- Verify ddprof has published the snapshot version +- Check Maven Central Snapshots repository: https://central.sonatype.com/repository/maven-snapshots/ +- Wait for ddprof CI to complete if a new snapshot is being published + +### Version not being overridden + +**Cause:** The property might not be correctly set or parsed. + +**Solutions:** +- Ensure you're using `-PuseDdprofSnapshot=true` (not `-DuseDdprofSnapshot`) +- Check Gradle output for "Using ddprof snapshot version" message +- Run with `--info` flag to see detailed dependency resolution logs diff --git a/gradle/ddprof-override.gradle b/gradle/ddprof-override.gradle new file mode 100644 index 00000000000..2033f9dcd56 --- /dev/null +++ b/gradle/ddprof-override.gradle @@ -0,0 +1,73 @@ +// Configuration for using ddprof snapshot versions +// When -PuseDdprofSnapshot=true is set, this will: +// 1. Parse the current ddprof version from libs.versions.toml +// 2. Calculate the next minor snapshot version: X.Y.Z -> X.(Y+1).0-SNAPSHOT +// 3. Override the ddprof dependency resolution to use the snapshot version +// 4. Add a qualifier to the dd-trace-java version to avoid overwriting standard snapshots + +def useDdprofSnapshot = project.hasProperty('useDdprofSnapshot') && project.property('useDdprofSnapshot').toBoolean() + +if (useDdprofSnapshot) { + def ddprofSnapshotVersion = calculateDdprofSnapshotVersion() + logger.lifecycle("Using ddprof snapshot version: ${ddprofSnapshotVersion}") + + // Store the calculated version as an extra property for use in subprojects + rootProject.ext.ddprofSnapshotVersion = ddprofSnapshotVersion + + // Add qualifier to the project version to differentiate from standard snapshots + // This ensures we don't overwrite the regular SNAPSHOT artifacts + allprojects { + def originalVersion = version.toString() + if (originalVersion.contains('-SNAPSHOT')) { + // Insert qualifier before -SNAPSHOT: X.Y.Z-SNAPSHOT -> X.Y.Z-ddprof-SNAPSHOT + version = originalVersion.replace('-SNAPSHOT', '-ddprof-SNAPSHOT') + } else if (originalVersion.contains('-')) { + // For versions with trailer: X.Y.Z-12-g8ab3f42d -> X.Y.Z-ddprof-12-g8ab3f42d + def parts = originalVersion.split('-', 2) + version = "${parts[0]}-ddprof-${parts[1]}" + } else { + // For release versions (shouldn't happen, but handle it): X.Y.Z -> X.Y.Z-ddprof + version = "${originalVersion}-ddprof" + } + logger.lifecycle("Modified version for ${project.name}: ${originalVersion} -> ${version}") + } + + // Override the ddprof dependency resolution for all configurations + allprojects { + configurations.all { + resolutionStrategy.eachDependency { DependencyResolveDetails details -> + if (details.requested.group == 'com.datadoghq' && details.requested.name == 'ddprof') { + details.useVersion(ddprofSnapshotVersion) + details.because("Using ddprof snapshot version for integration testing") + } + } + } + } +} + +def calculateDdprofSnapshotVersion() { + // Read the libs.versions.toml file + def versionsFile = rootProject.file('gradle/libs.versions.toml') + if (!versionsFile.exists()) { + throw new GradleException("Could not find gradle/libs.versions.toml") + } + + def currentVersion = null + versionsFile.eachLine { line -> + // Look for the ddprof version line: ddprof = "X.Y.Z" + def matcher = line =~ /^\s*ddprof\s*=\s*"([0-9]+)\.([0-9]+)\.([0-9]+)"\s*$/ + if (matcher) { + def major = matcher[0][1] + def minor = matcher[0][2] + // Increment the minor version + def nextMinor = (minor as Integer) + 1 + currentVersion = "${major}.${nextMinor}.0-SNAPSHOT" + } + } + + if (currentVersion == null) { + throw new GradleException("Could not parse ddprof version from gradle/libs.versions.toml") + } + + return currentVersion +} diff --git a/gradle/ddprof-snapshot.gradle b/gradle/ddprof-snapshot.gradle new file mode 100644 index 00000000000..2033f9dcd56 --- /dev/null +++ b/gradle/ddprof-snapshot.gradle @@ -0,0 +1,73 @@ +// Configuration for using ddprof snapshot versions +// When -PuseDdprofSnapshot=true is set, this will: +// 1. Parse the current ddprof version from libs.versions.toml +// 2. Calculate the next minor snapshot version: X.Y.Z -> X.(Y+1).0-SNAPSHOT +// 3. Override the ddprof dependency resolution to use the snapshot version +// 4. Add a qualifier to the dd-trace-java version to avoid overwriting standard snapshots + +def useDdprofSnapshot = project.hasProperty('useDdprofSnapshot') && project.property('useDdprofSnapshot').toBoolean() + +if (useDdprofSnapshot) { + def ddprofSnapshotVersion = calculateDdprofSnapshotVersion() + logger.lifecycle("Using ddprof snapshot version: ${ddprofSnapshotVersion}") + + // Store the calculated version as an extra property for use in subprojects + rootProject.ext.ddprofSnapshotVersion = ddprofSnapshotVersion + + // Add qualifier to the project version to differentiate from standard snapshots + // This ensures we don't overwrite the regular SNAPSHOT artifacts + allprojects { + def originalVersion = version.toString() + if (originalVersion.contains('-SNAPSHOT')) { + // Insert qualifier before -SNAPSHOT: X.Y.Z-SNAPSHOT -> X.Y.Z-ddprof-SNAPSHOT + version = originalVersion.replace('-SNAPSHOT', '-ddprof-SNAPSHOT') + } else if (originalVersion.contains('-')) { + // For versions with trailer: X.Y.Z-12-g8ab3f42d -> X.Y.Z-ddprof-12-g8ab3f42d + def parts = originalVersion.split('-', 2) + version = "${parts[0]}-ddprof-${parts[1]}" + } else { + // For release versions (shouldn't happen, but handle it): X.Y.Z -> X.Y.Z-ddprof + version = "${originalVersion}-ddprof" + } + logger.lifecycle("Modified version for ${project.name}: ${originalVersion} -> ${version}") + } + + // Override the ddprof dependency resolution for all configurations + allprojects { + configurations.all { + resolutionStrategy.eachDependency { DependencyResolveDetails details -> + if (details.requested.group == 'com.datadoghq' && details.requested.name == 'ddprof') { + details.useVersion(ddprofSnapshotVersion) + details.because("Using ddprof snapshot version for integration testing") + } + } + } + } +} + +def calculateDdprofSnapshotVersion() { + // Read the libs.versions.toml file + def versionsFile = rootProject.file('gradle/libs.versions.toml') + if (!versionsFile.exists()) { + throw new GradleException("Could not find gradle/libs.versions.toml") + } + + def currentVersion = null + versionsFile.eachLine { line -> + // Look for the ddprof version line: ddprof = "X.Y.Z" + def matcher = line =~ /^\s*ddprof\s*=\s*"([0-9]+)\.([0-9]+)\.([0-9]+)"\s*$/ + if (matcher) { + def major = matcher[0][1] + def minor = matcher[0][2] + // Increment the minor version + def nextMinor = (minor as Integer) + 1 + currentVersion = "${major}.${nextMinor}.0-SNAPSHOT" + } + } + + if (currentVersion == null) { + throw new GradleException("Could not parse ddprof version from gradle/libs.versions.toml") + } + + return currentVersion +} From ec5eff63fdec0a62b0cf419437e35ecaf819dbe5 Mon Sep 17 00:00:00 2001 From: Jaroslav Bachorik Date: Mon, 22 Dec 2025 14:15:44 +0100 Subject: [PATCH 2/8] Rename ddprof-snapshot.gradle to ddprof-override.gradle --- build.gradle.kts | 2 +- docs/publishing-with-ddprof-snapshot.md | 2 +- gradle/ddprof-snapshot.gradle | 73 ------------------------- 3 files changed, 2 insertions(+), 75 deletions(-) delete mode 100644 gradle/ddprof-snapshot.gradle diff --git a/build.gradle.kts b/build.gradle.kts index 8966ba8b99d..6b421263717 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -26,7 +26,7 @@ description = "dd-trace-java" val isCI = providers.environmentVariable("CI") apply(from = rootDir.resolve("gradle/repositories.gradle")) -apply(from = rootDir.resolve("gradle/ddprof-snapshot.gradle")) +apply(from = rootDir.resolve("gradle/ddprof-override.gradle")) spotless { // only resolve the spotless dependencies once in the build diff --git a/docs/publishing-with-ddprof-snapshot.md b/docs/publishing-with-ddprof-snapshot.md index 56c70d36d6b..a82363ea7cf 100644 --- a/docs/publishing-with-ddprof-snapshot.md +++ b/docs/publishing-with-ddprof-snapshot.md @@ -80,7 +80,7 @@ A GitLab CI job named `deploy_snapshot_with_ddprof_snapshot` is available for ma ### Files Modified -1. **`gradle/ddprof-snapshot.gradle`** - Core logic for version calculation and dependency override +1. **`gradle/ddprof-override.gradle`** - Core logic for version calculation and dependency override 2. **`build.gradle.kts`** - Applies the ddprof-snapshot configuration 3. **`dd-java-agent/ddprof-lib/build.gradle`** - Logging for snapshot version usage 4. **`.gitlab-ci.yml`** - New CI job for snapshot publishing diff --git a/gradle/ddprof-snapshot.gradle b/gradle/ddprof-snapshot.gradle deleted file mode 100644 index 2033f9dcd56..00000000000 --- a/gradle/ddprof-snapshot.gradle +++ /dev/null @@ -1,73 +0,0 @@ -// Configuration for using ddprof snapshot versions -// When -PuseDdprofSnapshot=true is set, this will: -// 1. Parse the current ddprof version from libs.versions.toml -// 2. Calculate the next minor snapshot version: X.Y.Z -> X.(Y+1).0-SNAPSHOT -// 3. Override the ddprof dependency resolution to use the snapshot version -// 4. Add a qualifier to the dd-trace-java version to avoid overwriting standard snapshots - -def useDdprofSnapshot = project.hasProperty('useDdprofSnapshot') && project.property('useDdprofSnapshot').toBoolean() - -if (useDdprofSnapshot) { - def ddprofSnapshotVersion = calculateDdprofSnapshotVersion() - logger.lifecycle("Using ddprof snapshot version: ${ddprofSnapshotVersion}") - - // Store the calculated version as an extra property for use in subprojects - rootProject.ext.ddprofSnapshotVersion = ddprofSnapshotVersion - - // Add qualifier to the project version to differentiate from standard snapshots - // This ensures we don't overwrite the regular SNAPSHOT artifacts - allprojects { - def originalVersion = version.toString() - if (originalVersion.contains('-SNAPSHOT')) { - // Insert qualifier before -SNAPSHOT: X.Y.Z-SNAPSHOT -> X.Y.Z-ddprof-SNAPSHOT - version = originalVersion.replace('-SNAPSHOT', '-ddprof-SNAPSHOT') - } else if (originalVersion.contains('-')) { - // For versions with trailer: X.Y.Z-12-g8ab3f42d -> X.Y.Z-ddprof-12-g8ab3f42d - def parts = originalVersion.split('-', 2) - version = "${parts[0]}-ddprof-${parts[1]}" - } else { - // For release versions (shouldn't happen, but handle it): X.Y.Z -> X.Y.Z-ddprof - version = "${originalVersion}-ddprof" - } - logger.lifecycle("Modified version for ${project.name}: ${originalVersion} -> ${version}") - } - - // Override the ddprof dependency resolution for all configurations - allprojects { - configurations.all { - resolutionStrategy.eachDependency { DependencyResolveDetails details -> - if (details.requested.group == 'com.datadoghq' && details.requested.name == 'ddprof') { - details.useVersion(ddprofSnapshotVersion) - details.because("Using ddprof snapshot version for integration testing") - } - } - } - } -} - -def calculateDdprofSnapshotVersion() { - // Read the libs.versions.toml file - def versionsFile = rootProject.file('gradle/libs.versions.toml') - if (!versionsFile.exists()) { - throw new GradleException("Could not find gradle/libs.versions.toml") - } - - def currentVersion = null - versionsFile.eachLine { line -> - // Look for the ddprof version line: ddprof = "X.Y.Z" - def matcher = line =~ /^\s*ddprof\s*=\s*"([0-9]+)\.([0-9]+)\.([0-9]+)"\s*$/ - if (matcher) { - def major = matcher[0][1] - def minor = matcher[0][2] - // Increment the minor version - def nextMinor = (minor as Integer) + 1 - currentVersion = "${major}.${nextMinor}.0-SNAPSHOT" - } - } - - if (currentVersion == null) { - throw new GradleException("Could not parse ddprof version from gradle/libs.versions.toml") - } - - return currentVersion -} From cde741b3715fc0c1aba9cf0f2c18117a1f4bdd0d Mon Sep 17 00:00:00 2001 From: Jaroslav Bachorik Date: Mon, 22 Dec 2025 15:29:32 +0100 Subject: [PATCH 3/8] Rename the gradle property useDdprofSnapshot -> ddprofUseSnapshot --- .gitlab-ci.yml | 2 +- dd-java-agent/ddprof-lib/build.gradle | 2 +- docs/publishing-with-ddprof-snapshot.md | 14 +++++++------- gradle/ddprof-override.gradle | 6 +++--- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index c93755eabe0..0333a6e6456 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -906,7 +906,7 @@ deploy_snapshot_with_ddprof_snapshot: - export GPG_PRIVATE_KEY=$(aws ssm get-parameter --region us-east-1 --name ci.dd-trace-java.signing.gpg_private_key --with-decryption --query "Parameter.Value" --out text) - export GPG_PASSWORD=$(aws ssm get-parameter --region us-east-1 --name ci.dd-trace-java.signing.gpg_passphrase --with-decryption --query "Parameter.Value" --out text) - echo "Publishing dd-trace-java snapshot with ddprof snapshot dependency" - - ./gradlew -PbuildInfo.build.number=$CI_JOB_ID -PuseDdprofSnapshot=true publishToSonatype -PskipTests $GRADLE_ARGS + - ./gradlew -PbuildInfo.build.number=$CI_JOB_ID -PddprofUseSnapshot=true publishToSonatype -PskipTests $GRADLE_ARGS artifacts: paths: - 'workspace/dd-java-agent/build/libs/*.jar' diff --git a/dd-java-agent/ddprof-lib/build.gradle b/dd-java-agent/ddprof-lib/build.gradle index 397f2d17a23..3aad9482d2c 100644 --- a/dd-java-agent/ddprof-lib/build.gradle +++ b/dd-java-agent/ddprof-lib/build.gradle @@ -16,7 +16,7 @@ dependencies { // Log information about ddprof version being used afterEvaluate { - if (rootProject.hasProperty('ddprofSnapshotVersion')) { + if (rootProject.hasProperty('ddprofUseSnapshot')) { logger.lifecycle("${project.name}: Using ddprof SNAPSHOT version ${rootProject.ext.ddprofSnapshotVersion}") } } diff --git a/docs/publishing-with-ddprof-snapshot.md b/docs/publishing-with-ddprof-snapshot.md index a82363ea7cf..4c11c632465 100644 --- a/docs/publishing-with-ddprof-snapshot.md +++ b/docs/publishing-with-ddprof-snapshot.md @@ -10,7 +10,7 @@ This feature allows publishing dd-trace-java snapshot versions that depend on a ### Version Qualification -To avoid overwriting standard snapshot artifacts, builds with `-PuseDdprofSnapshot=true` will have a `-ddprof` qualifier added to their version: +To avoid overwriting standard snapshot artifacts, builds with `-PddprofUseSnapshot=true` will have a `-ddprof` qualifier added to their version: - Standard snapshot: `1.58.0-SNAPSHOT` - With ddprof snapshot: `1.58.0-ddprof-SNAPSHOT` @@ -24,7 +24,7 @@ This ensures that both versions can coexist in Maven Central Snapshots repositor To verify that the ddprof snapshot version is correctly calculated and applied: ```bash -./gradlew -PuseDdprofSnapshot=true :dd-java-agent:ddprof-lib:dependencies --configuration runtimeClasspath +./gradlew -PddprofUseSnapshot=true :dd-java-agent:ddprof-lib:dependencies --configuration runtimeClasspath ``` Look for the output: @@ -38,7 +38,7 @@ Look for the output: To build the project with the ddprof snapshot dependency: ```bash -./gradlew build -PuseDdprofSnapshot=true +./gradlew build -PddprofUseSnapshot=true ``` ### Publishing to Maven Central Snapshots @@ -46,7 +46,7 @@ To build the project with the ddprof snapshot dependency: To publish artifacts with the ddprof snapshot dependency: ```bash -./gradlew publishToSonatype -PuseDdprofSnapshot=true -PskipTests +./gradlew publishToSonatype -PddprofUseSnapshot=true -PskipTests ``` **Note:** You must have the required credentials configured: @@ -67,7 +67,7 @@ A GitLab CI job named `deploy_snapshot_with_ddprof_snapshot` is available for ma 3. Click the manual play button to trigger it **What it does:** -- Builds dd-trace-java with `-PuseDdprofSnapshot=true` +- Builds dd-trace-java with `-PddprofUseSnapshot=true` - Publishes to Maven Central Snapshots repository - Produces artifacts with the ddprof snapshot dependency @@ -87,7 +87,7 @@ A GitLab CI job named `deploy_snapshot_with_ddprof_snapshot` is available for ma ### How It Works -1. The Gradle property `-PuseDdprofSnapshot=true` activates the feature +1. The Gradle property `-PddprofUseSnapshot=true` activates the feature 2. The configuration reads `gradle/libs.versions.toml` to get the current ddprof version 3. Version is parsed using regex: `ddprof = "X.Y.Z"` 4. Snapshot version is calculated: `X.(Y+1).0-SNAPSHOT` @@ -136,6 +136,6 @@ This ensures that even transitive dependencies on ddprof are overridden. **Cause:** The property might not be correctly set or parsed. **Solutions:** -- Ensure you're using `-PuseDdprofSnapshot=true` (not `-DuseDdprofSnapshot`) +- Ensure you're using `-PddprofUseSnapshot=true` (not `-DddprofUseSnapshot`) - Check Gradle output for "Using ddprof snapshot version" message - Run with `--info` flag to see detailed dependency resolution logs diff --git a/gradle/ddprof-override.gradle b/gradle/ddprof-override.gradle index 2033f9dcd56..0c8cae284d2 100644 --- a/gradle/ddprof-override.gradle +++ b/gradle/ddprof-override.gradle @@ -1,13 +1,13 @@ // Configuration for using ddprof snapshot versions -// When -PuseDdprofSnapshot=true is set, this will: +// When -PddprofUseSnapshot=true is set, this will: // 1. Parse the current ddprof version from libs.versions.toml // 2. Calculate the next minor snapshot version: X.Y.Z -> X.(Y+1).0-SNAPSHOT // 3. Override the ddprof dependency resolution to use the snapshot version // 4. Add a qualifier to the dd-trace-java version to avoid overwriting standard snapshots -def useDdprofSnapshot = project.hasProperty('useDdprofSnapshot') && project.property('useDdprofSnapshot').toBoolean() +def ddprofUseSnapshot = project.hasProperty('ddprofUseSnapshot') && project.property('ddprofUseSnapshot').toBoolean() -if (useDdprofSnapshot) { +if (ddprofUseSnapshot) { def ddprofSnapshotVersion = calculateDdprofSnapshotVersion() logger.lifecycle("Using ddprof snapshot version: ${ddprofSnapshotVersion}") From 0235bccafeb32e951daed5df8ce9ece5547da994 Mon Sep 17 00:00:00 2001 From: Jaroslav Bachorik Date: Mon, 22 Dec 2025 15:42:55 +0100 Subject: [PATCH 4/8] Simplify the property --- gradle/ddprof-override.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/ddprof-override.gradle b/gradle/ddprof-override.gradle index 0c8cae284d2..585c0b8c532 100644 --- a/gradle/ddprof-override.gradle +++ b/gradle/ddprof-override.gradle @@ -5,7 +5,7 @@ // 3. Override the ddprof dependency resolution to use the snapshot version // 4. Add a qualifier to the dd-trace-java version to avoid overwriting standard snapshots -def ddprofUseSnapshot = project.hasProperty('ddprofUseSnapshot') && project.property('ddprofUseSnapshot').toBoolean() +def ddprofUseSnapshot = project.hasProperty("ddprofUseSnapshot") if (ddprofUseSnapshot) { def ddprofSnapshotVersion = calculateDdprofSnapshotVersion() From 39e62b20510a85576673d0b835b52766be779a59 Mon Sep 17 00:00:00 2001 From: Jaroslav Bachorik Date: Mon, 22 Dec 2025 15:47:28 +0100 Subject: [PATCH 5/8] Update the doc --- docs/publishing-with-ddprof-snapshot.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/publishing-with-ddprof-snapshot.md b/docs/publishing-with-ddprof-snapshot.md index 4c11c632465..f3973c37b56 100644 --- a/docs/publishing-with-ddprof-snapshot.md +++ b/docs/publishing-with-ddprof-snapshot.md @@ -10,7 +10,7 @@ This feature allows publishing dd-trace-java snapshot versions that depend on a ### Version Qualification -To avoid overwriting standard snapshot artifacts, builds with `-PddprofUseSnapshot=true` will have a `-ddprof` qualifier added to their version: +To avoid overwriting standard snapshot artifacts, builds with `-PddprofUseSnapshot` will have a `-ddprof` qualifier added to their version: - Standard snapshot: `1.58.0-SNAPSHOT` - With ddprof snapshot: `1.58.0-ddprof-SNAPSHOT` @@ -24,7 +24,7 @@ This ensures that both versions can coexist in Maven Central Snapshots repositor To verify that the ddprof snapshot version is correctly calculated and applied: ```bash -./gradlew -PddprofUseSnapshot=true :dd-java-agent:ddprof-lib:dependencies --configuration runtimeClasspath +./gradlew -PddprofUseSnapshot :dd-java-agent:ddprof-lib:dependencies --configuration runtimeClasspath ``` Look for the output: @@ -38,7 +38,7 @@ Look for the output: To build the project with the ddprof snapshot dependency: ```bash -./gradlew build -PddprofUseSnapshot=true +./gradlew build -PddprofUseSnapshot ``` ### Publishing to Maven Central Snapshots @@ -46,7 +46,7 @@ To build the project with the ddprof snapshot dependency: To publish artifacts with the ddprof snapshot dependency: ```bash -./gradlew publishToSonatype -PddprofUseSnapshot=true -PskipTests +./gradlew publishToSonatype -PddprofUseSnapshot -PskipTests ``` **Note:** You must have the required credentials configured: @@ -67,7 +67,7 @@ A GitLab CI job named `deploy_snapshot_with_ddprof_snapshot` is available for ma 3. Click the manual play button to trigger it **What it does:** -- Builds dd-trace-java with `-PddprofUseSnapshot=true` +- Builds dd-trace-java with `-PddprofUseSnapshot` - Publishes to Maven Central Snapshots repository - Produces artifacts with the ddprof snapshot dependency @@ -87,7 +87,7 @@ A GitLab CI job named `deploy_snapshot_with_ddprof_snapshot` is available for ma ### How It Works -1. The Gradle property `-PddprofUseSnapshot=true` activates the feature +1. The Gradle property `-PddprofUseSnapshot` activates the feature 2. The configuration reads `gradle/libs.versions.toml` to get the current ddprof version 3. Version is parsed using regex: `ddprof = "X.Y.Z"` 4. Snapshot version is calculated: `X.(Y+1).0-SNAPSHOT` @@ -136,6 +136,6 @@ This ensures that even transitive dependencies on ddprof are overridden. **Cause:** The property might not be correctly set or parsed. **Solutions:** -- Ensure you're using `-PddprofUseSnapshot=true` (not `-DddprofUseSnapshot`) +- Ensure you're using `-PddprofUseSnapshot` (not `-DddprofUseSnapshot`) - Check Gradle output for "Using ddprof snapshot version" message - Run with `--info` flag to see detailed dependency resolution logs From 5e27268dfd35753f2bbc273e67f8097e969d4fe8 Mon Sep 17 00:00:00 2001 From: Jaroslav Bachorik Date: Mon, 22 Dec 2025 15:48:51 +0100 Subject: [PATCH 6/8] Update the gitlab definition --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 0333a6e6456..a4354c59d6d 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -906,7 +906,7 @@ deploy_snapshot_with_ddprof_snapshot: - export GPG_PRIVATE_KEY=$(aws ssm get-parameter --region us-east-1 --name ci.dd-trace-java.signing.gpg_private_key --with-decryption --query "Parameter.Value" --out text) - export GPG_PASSWORD=$(aws ssm get-parameter --region us-east-1 --name ci.dd-trace-java.signing.gpg_passphrase --with-decryption --query "Parameter.Value" --out text) - echo "Publishing dd-trace-java snapshot with ddprof snapshot dependency" - - ./gradlew -PbuildInfo.build.number=$CI_JOB_ID -PddprofUseSnapshot=true publishToSonatype -PskipTests $GRADLE_ARGS + - ./gradlew -PbuildInfo.build.number=$CI_JOB_ID -PddprofUseSnapshot publishToSonatype -PskipTests $GRADLE_ARGS artifacts: paths: - 'workspace/dd-java-agent/build/libs/*.jar' From f90a3552cec9083be4abc8ff9e706a0921ad9219 Mon Sep 17 00:00:00 2001 From: Jaroslav Bachorik Date: Wed, 7 Jan 2026 11:46:24 +0100 Subject: [PATCH 7/8] Update documentation to reflect convention plugin architecture - Document new convention plugin approach - Update file list to include new files - Clarify that dependency override only affects relevant projects - Add example of plugin application in build files --- docs/publishing-with-ddprof-snapshot.md | 45 +++++++++++++++++-------- 1 file changed, 31 insertions(+), 14 deletions(-) diff --git a/docs/publishing-with-ddprof-snapshot.md b/docs/publishing-with-ddprof-snapshot.md index f3973c37b56..977befdd9e6 100644 --- a/docs/publishing-with-ddprof-snapshot.md +++ b/docs/publishing-with-ddprof-snapshot.md @@ -80,39 +80,56 @@ A GitLab CI job named `deploy_snapshot_with_ddprof_snapshot` is available for ma ### Files Modified -1. **`gradle/ddprof-override.gradle`** - Core logic for version calculation and dependency override +1. **`gradle/ddprof-override.gradle`** - Calculates snapshot version and stores it for convention plugins 2. **`build.gradle.kts`** - Applies the ddprof-snapshot configuration -3. **`dd-java-agent/ddprof-lib/build.gradle`** - Logging for snapshot version usage -4. **`.gitlab-ci.yml`** - New CI job for snapshot publishing +3. **`buildSrc/src/main/kotlin/dd-trace-java.profiling-ddprof-override.gradle.kts`** - Convention plugin for dependency override +4. **`buildSrc/src/main/kotlin/datadog/gradle/plugin/version/TracerVersionPlugin.kt`** - Enhanced to support version qualifiers +5. **`dd-java-agent/ddprof-lib/build.gradle`** - Applies the convention plugin +6. **`.gitlab-ci.yml`** - New CI job for snapshot publishing ### How It Works 1. The Gradle property `-PddprofUseSnapshot` activates the feature 2. The configuration reads `gradle/libs.versions.toml` to get the current ddprof version 3. Version is parsed using regex: `ddprof = "X.Y.Z"` -4. Snapshot version is calculated: `X.(Y+1).0-SNAPSHOT` +4. Snapshot version is calculated: `X.(Y+1).0-SNAPSHOT` and stored in `rootProject.ext.ddprofSnapshotVersion` 5. **The dd-trace-java version is modified** to add a `-ddprof` qualifier: - `1.58.0-SNAPSHOT` → `1.58.0-ddprof-SNAPSHOT` - This prevents overwriting standard snapshot artifacts -6. Gradle's `resolutionStrategy.eachDependency` overrides all ddprof dependencies to use the snapshot version -7. The build and publish proceed with the modified version and overridden dependency + - Users can also explicitly set this via `-PtracerVersion.qualifier=ddprof` +6. The `dd-trace-java.profiling-ddprof-override` convention plugin is applied to projects that depend on ddprof +7. The convention plugin overrides ddprof dependencies to use the snapshot version +8. The build and publish proceed with the modified version and overridden dependency ### Dependency Resolution Override -The override is applied globally to all configurations in all projects: +The override is applied via a convention plugin to only the projects that need it: -```groovy -configurations.all { - resolutionStrategy.eachDependency { DependencyResolveDetails details -> - if (details.requested.group == 'com.datadoghq' && details.requested.name == 'ddprof') { - details.useVersion(ddprofSnapshotVersion) - details.because("Using ddprof snapshot version for integration testing") +```kotlin +// Convention plugin: dd-trace-java.profiling-ddprof-override +if (rootProject.hasProperty("ddprofUseSnapshot")) { + val ddprofSnapshotVersion = rootProject.property("ddprofSnapshotVersion").toString() + + configurations.all { + resolutionStrategy.eachDependency { + if (requested.group == "com.datadoghq" && requested.name == "ddprof") { + useVersion(ddprofSnapshotVersion) + because("Using ddprof snapshot version for integration testing") + } } } } ``` -This ensures that even transitive dependencies on ddprof are overridden. +Projects apply this plugin explicitly in their build files: + +```groovy +plugins { + id "dd-trace-java.profiling-ddprof-override" +} +``` + +This ensures that only projects that actually depend on ddprof are affected by the override. ## Limitations From c5fa7cf0769c2d04199aa20f51321326adec8bf7 Mon Sep 17 00:00:00 2001 From: Jaroslav Bachorik Date: Wed, 7 Jan 2026 11:46:41 +0100 Subject: [PATCH 8/8] Refactor ddprof override to use convention plugin Address PR review feedback from bric3: - Create dd-trace-java.profiling-ddprof-override convention plugin - Apply plugin only to projects that depend on ddprof (ddprof-lib) - Remove allprojects blocks from ddprof-override.gradle - Enhance TracerVersionPlugin to support version qualifiers - Use consistent property access (property() instead of ext) Benefits: - Only affects projects that explicitly apply the plugin - Follows Gradle best practices and project conventions - More maintainable and easier to understand - Clear separation of concerns The ddprof dependency override now happens via a convention plugin that projects can opt into, rather than affecting all projects globally. --- .../plugin/version/TracerVersionPlugin.kt | 13 +++++ ...-java.profiling-ddprof-override.gradle.kts | 24 ++++++++++ dd-java-agent/ddprof-lib/build.gradle | 8 +--- gradle/ddprof-override.gradle | 48 ++++++++----------- 4 files changed, 57 insertions(+), 36 deletions(-) create mode 100644 buildSrc/src/main/kotlin/dd-trace-java.profiling-ddprof-override.gradle.kts diff --git a/buildSrc/src/main/kotlin/datadog/gradle/plugin/version/TracerVersionPlugin.kt b/buildSrc/src/main/kotlin/datadog/gradle/plugin/version/TracerVersionPlugin.kt index 85385ea5e2d..1250e96d907 100644 --- a/buildSrc/src/main/kotlin/datadog/gradle/plugin/version/TracerVersionPlugin.kt +++ b/buildSrc/src/main/kotlin/datadog/gradle/plugin/version/TracerVersionPlugin.kt @@ -28,6 +28,10 @@ class TracerVersionPlugin @Inject constructor( .orElse(false) ) + extension.versionQualifier.set( + providerFactory.gradleProperty("tracerVersion.qualifier") + ) + val versionProvider = versionProvider(targetProject, extension) targetProject.allprojects { version = versionProvider @@ -125,6 +129,14 @@ class TracerVersionPlugin @Inject constructor( return buildString { append(version.toString()) + // Add optional version qualifier (e.g., "-ddprof") + if (extension.versionQualifier.isPresent) { + val qualifier = extension.versionQualifier.get() + if (qualifier.isNotBlank()) { + append("-").append(qualifier) + } + } + if (hasLaterCommits) { append(if (extension.useSnapshot.get()) "-SNAPSHOT" else describeTrailer) } @@ -143,5 +155,6 @@ class TracerVersionPlugin @Inject constructor( val useSnapshot = objectFactory.property(Boolean::class) .convention(true) val detectDirty = objectFactory.property(Boolean::class) + val versionQualifier = objectFactory.property(String::class) } } diff --git a/buildSrc/src/main/kotlin/dd-trace-java.profiling-ddprof-override.gradle.kts b/buildSrc/src/main/kotlin/dd-trace-java.profiling-ddprof-override.gradle.kts new file mode 100644 index 00000000000..8fe48f9dc41 --- /dev/null +++ b/buildSrc/src/main/kotlin/dd-trace-java.profiling-ddprof-override.gradle.kts @@ -0,0 +1,24 @@ +/** + * Convention plugin for overriding ddprof dependency version with snapshot. + * + * When the root project has the property 'ddprofUseSnapshot' set, this plugin: + * 1. Reads the calculated snapshot version from root project + * 2. Overrides all ddprof dependencies to use the snapshot version + * + * Apply this plugin only to projects that depend on ddprof. + */ + +if (rootProject.hasProperty("ddprofUseSnapshot")) { + val ddprofSnapshotVersion = rootProject.property("ddprofSnapshotVersion").toString() + + configurations.all { + resolutionStrategy.eachDependency { + if (requested.group == "com.datadoghq" && requested.name == "ddprof") { + useVersion(ddprofSnapshotVersion) + because("Using ddprof snapshot version for integration testing") + } + } + } + + logger.lifecycle("${project.name}: Configured to use ddprof SNAPSHOT version $ddprofSnapshotVersion") +} diff --git a/dd-java-agent/ddprof-lib/build.gradle b/dd-java-agent/ddprof-lib/build.gradle index 3aad9482d2c..b4f3219ae23 100644 --- a/dd-java-agent/ddprof-lib/build.gradle +++ b/dd-java-agent/ddprof-lib/build.gradle @@ -2,6 +2,7 @@ import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar plugins { id "com.gradleup.shadow" + id "dd-trace-java.profiling-ddprof-override" } apply from: "$rootDir/gradle/java.gradle" @@ -14,13 +15,6 @@ dependencies { api project(':dd-trace-api') } -// Log information about ddprof version being used -afterEvaluate { - if (rootProject.hasProperty('ddprofUseSnapshot')) { - logger.lifecycle("${project.name}: Using ddprof SNAPSHOT version ${rootProject.ext.ddprofSnapshotVersion}") - } -} - tasks.named("shadowJar", ShadowJar) { dependencies { deps.excludeShared diff --git a/gradle/ddprof-override.gradle b/gradle/ddprof-override.gradle index 585c0b8c532..c6bacfd327e 100644 --- a/gradle/ddprof-override.gradle +++ b/gradle/ddprof-override.gradle @@ -2,8 +2,10 @@ // When -PddprofUseSnapshot=true is set, this will: // 1. Parse the current ddprof version from libs.versions.toml // 2. Calculate the next minor snapshot version: X.Y.Z -> X.(Y+1).0-SNAPSHOT -// 3. Override the ddprof dependency resolution to use the snapshot version -// 4. Add a qualifier to the dd-trace-java version to avoid overwriting standard snapshots +// 3. Store the snapshot version for use by convention plugins +// 4. Set the version qualifier property to add "ddprof" to the version +// This ensures we don't overwrite the regular SNAPSHOT artifacts +// The version will become: X.Y.Z-ddprof-SNAPSHOT instead of X.Y.Z-SNAPSHOT def ddprofUseSnapshot = project.hasProperty("ddprofUseSnapshot") @@ -11,35 +13,23 @@ if (ddprofUseSnapshot) { def ddprofSnapshotVersion = calculateDdprofSnapshotVersion() logger.lifecycle("Using ddprof snapshot version: ${ddprofSnapshotVersion}") - // Store the calculated version as an extra property for use in subprojects + // Store the calculated version as an extra property for use in convention plugins rootProject.ext.ddprofSnapshotVersion = ddprofSnapshotVersion - // Add qualifier to the project version to differentiate from standard snapshots - // This ensures we don't overwrite the regular SNAPSHOT artifacts - allprojects { - def originalVersion = version.toString() - if (originalVersion.contains('-SNAPSHOT')) { - // Insert qualifier before -SNAPSHOT: X.Y.Z-SNAPSHOT -> X.Y.Z-ddprof-SNAPSHOT - version = originalVersion.replace('-SNAPSHOT', '-ddprof-SNAPSHOT') - } else if (originalVersion.contains('-')) { - // For versions with trailer: X.Y.Z-12-g8ab3f42d -> X.Y.Z-ddprof-12-g8ab3f42d - def parts = originalVersion.split('-', 2) - version = "${parts[0]}-ddprof-${parts[1]}" - } else { - // For release versions (shouldn't happen, but handle it): X.Y.Z -> X.Y.Z-ddprof - version = "${originalVersion}-ddprof" - } - logger.lifecycle("Modified version for ${project.name}: ${originalVersion} -> ${version}") - } - - // Override the ddprof dependency resolution for all configurations - allprojects { - configurations.all { - resolutionStrategy.eachDependency { DependencyResolveDetails details -> - if (details.requested.group == 'com.datadoghq' && details.requested.name == 'ddprof') { - details.useVersion(ddprofSnapshotVersion) - details.because("Using ddprof snapshot version for integration testing") - } + // Set the version qualifier property that TracerVersionPlugin will read + // Note: Users can also explicitly set this via -PtracerVersion.qualifier=ddprof + if (!project.hasProperty("tracerVersion.qualifier")) { + // Add the qualifier to the version after it has been calculated + // This is a workaround since we can't set gradle properties programmatically + allprojects { + def originalVersion = it.version.toString() + if (originalVersion.contains('-SNAPSHOT')) { + it.version = originalVersion.replace('-SNAPSHOT', '-ddprof-SNAPSHOT') + } else if (originalVersion.contains('-')) { + def parts = originalVersion.split('-', 2) + it.version = "${parts[0]}-ddprof-${parts[1]}" + } else { + it.version = "${originalVersion}-ddprof" } } }