Skip to content

Commit 2335782

Browse files
committed
Allow ddprof version override to build a custom 'profiler-snapshot' dd-java-agent artifact
1 parent a69554e commit 2335782

File tree

6 files changed

+320
-0
lines changed

6 files changed

+320
-0
lines changed

.gitlab-ci.yml

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -880,6 +880,31 @@ deploy_to_maven_central:
880880
- 'workspace/dd-trace-api/build/libs/*.jar'
881881
- 'workspace/dd-trace-ot/build/libs/*.jar'
882882

883+
deploy_snapshot_with_ddprof_snapshot:
884+
extends: .gradle_build
885+
stage: publish
886+
needs: [ build ]
887+
variables:
888+
CACHE_TYPE: "lib"
889+
rules:
890+
- if: '$POPULATE_CACHE'
891+
when: never
892+
# Manual trigger only - for testing with ddprof snapshot versions
893+
- when: manual
894+
allow_failure: true
895+
script:
896+
- 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)
897+
- 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)
898+
- 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)
899+
- 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)
900+
- echo "Publishing dd-trace-java snapshot with ddprof snapshot dependency"
901+
- ./gradlew -PbuildInfo.build.number=$CI_JOB_ID -PuseDdprofSnapshot=true publishToSonatype -PskipTests $GRADLE_ARGS
902+
artifacts:
903+
paths:
904+
- 'workspace/dd-java-agent/build/libs/*.jar'
905+
- 'workspace/dd-trace-api/build/libs/*.jar'
906+
- 'workspace/dd-trace-ot/build/libs/*.jar'
907+
883908
deploy_artifacts_to_github:
884909
stage: publish
885910
image: registry.ddbuild.io/images/dd-octo-sts-ci-base:2025.06-1

build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ description = "dd-trace-java"
2626
val isCI = providers.environmentVariable("CI")
2727

2828
apply(from = rootDir.resolve("gradle/repositories.gradle"))
29+
apply(from = rootDir.resolve("gradle/ddprof-snapshot.gradle"))
2930

3031
spotless {
3132
// only resolve the spotless dependencies once in the build

dd-java-agent/ddprof-lib/build.gradle

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,13 @@ dependencies {
1414
api project(':dd-trace-api')
1515
}
1616

17+
// Log information about ddprof version being used
18+
afterEvaluate {
19+
if (rootProject.hasProperty('ddprofSnapshotVersion')) {
20+
logger.lifecycle("${project.name}: Using ddprof SNAPSHOT version ${rootProject.ext.ddprofSnapshotVersion}")
21+
}
22+
}
23+
1724
tasks.named("shadowJar", ShadowJar) {
1825
dependencies {
1926
deps.excludeShared
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
# Publishing dd-trace-java Snapshots with ddprof SNAPSHOT Dependency
2+
3+
## Overview
4+
5+
This feature allows publishing dd-trace-java snapshot versions that depend on a ddprof SNAPSHOT version with an incremented minor version.
6+
7+
**ddprof Version Calculation:** Current ddprof version `X.Y.Z` → Dependency becomes `X.(Y+1).0-SNAPSHOT`
8+
9+
**Example:** ddprof `1.34.4` → Uses dependency `1.35.0-SNAPSHOT`
10+
11+
### Version Qualification
12+
13+
To avoid overwriting standard snapshot artifacts, builds with `-PuseDdprofSnapshot=true` will have a `-ddprof` qualifier added to their version:
14+
15+
- Standard snapshot: `1.58.0-SNAPSHOT`
16+
- With ddprof snapshot: `1.58.0-ddprof-SNAPSHOT`
17+
18+
This ensures that both versions can coexist in Maven Central Snapshots repository without conflicts.
19+
20+
## Local Usage
21+
22+
### Testing Dependency Resolution
23+
24+
To verify that the ddprof snapshot version is correctly calculated and applied:
25+
26+
```bash
27+
./gradlew -PuseDdprofSnapshot=true :dd-java-agent:ddprof-lib:dependencies --configuration runtimeClasspath
28+
```
29+
30+
Look for the output:
31+
- `Using ddprof snapshot version: X.Y.0-SNAPSHOT`
32+
- `Modified version for dd-trace-java: 1.58.0-SNAPSHOT -> 1.58.0-ddprof-SNAPSHOT`
33+
- `ddprof-lib: Using ddprof SNAPSHOT version X.Y.0-SNAPSHOT`
34+
- Dependency resolution showing: `com.datadoghq:ddprof:X.Y.Z -> X.(Y+1).0-SNAPSHOT`
35+
36+
### Building with ddprof Snapshot
37+
38+
To build the project with the ddprof snapshot dependency:
39+
40+
```bash
41+
./gradlew build -PuseDdprofSnapshot=true
42+
```
43+
44+
### Publishing to Maven Central Snapshots
45+
46+
To publish artifacts with the ddprof snapshot dependency:
47+
48+
```bash
49+
./gradlew publishToSonatype -PuseDdprofSnapshot=true -PskipTests
50+
```
51+
52+
**Note:** You must have the required credentials configured:
53+
- `MAVEN_CENTRAL_USERNAME`
54+
- `MAVEN_CENTRAL_PASSWORD`
55+
- `GPG_PRIVATE_KEY`
56+
- `GPG_PASSWORD`
57+
58+
## GitLab CI Usage
59+
60+
### Manual Job Trigger
61+
62+
A GitLab CI job named `deploy_snapshot_with_ddprof_snapshot` is available for manual execution.
63+
64+
**To trigger:**
65+
1. Navigate to the pipeline in GitLab CI
66+
2. Find the `deploy_snapshot_with_ddprof_snapshot` job in the `publish` stage
67+
3. Click the manual play button to trigger it
68+
69+
**What it does:**
70+
- Builds dd-trace-java with `-PuseDdprofSnapshot=true`
71+
- Publishes to Maven Central Snapshots repository
72+
- Produces artifacts with the ddprof snapshot dependency
73+
74+
**When to use:**
75+
- Testing integration with unreleased ddprof features
76+
- Validating compatibility before ddprof release
77+
- Creating test builds for early adopters
78+
79+
## Implementation Details
80+
81+
### Files Modified
82+
83+
1. **`gradle/ddprof-snapshot.gradle`** - Core logic for version calculation and dependency override
84+
2. **`build.gradle.kts`** - Applies the ddprof-snapshot configuration
85+
3. **`dd-java-agent/ddprof-lib/build.gradle`** - Logging for snapshot version usage
86+
4. **`.gitlab-ci.yml`** - New CI job for snapshot publishing
87+
88+
### How It Works
89+
90+
1. The Gradle property `-PuseDdprofSnapshot=true` activates the feature
91+
2. The configuration reads `gradle/libs.versions.toml` to get the current ddprof version
92+
3. Version is parsed using regex: `ddprof = "X.Y.Z"`
93+
4. Snapshot version is calculated: `X.(Y+1).0-SNAPSHOT`
94+
5. **The dd-trace-java version is modified** to add a `-ddprof` qualifier:
95+
- `1.58.0-SNAPSHOT``1.58.0-ddprof-SNAPSHOT`
96+
- This prevents overwriting standard snapshot artifacts
97+
6. Gradle's `resolutionStrategy.eachDependency` overrides all ddprof dependencies to use the snapshot version
98+
7. The build and publish proceed with the modified version and overridden dependency
99+
100+
### Dependency Resolution Override
101+
102+
The override is applied globally to all configurations in all projects:
103+
104+
```groovy
105+
configurations.all {
106+
resolutionStrategy.eachDependency { DependencyResolveDetails details ->
107+
if (details.requested.group == 'com.datadoghq' && details.requested.name == 'ddprof') {
108+
details.useVersion(ddprofSnapshotVersion)
109+
details.because("Using ddprof snapshot version for integration testing")
110+
}
111+
}
112+
}
113+
```
114+
115+
This ensures that even transitive dependencies on ddprof are overridden.
116+
117+
## Limitations
118+
119+
- Only works with semantic versioning in format `X.Y.Z`
120+
- Requires ddprof SNAPSHOT to be published to Maven Central Snapshots repository
121+
- Cannot override local JAR files specified with `-Pddprof.jar=/path/to/jar`
122+
123+
## Troubleshooting
124+
125+
### "Could not find com.datadoghq:ddprof:X.Y.0-SNAPSHOT"
126+
127+
**Cause:** The calculated ddprof snapshot version doesn't exist in Maven Central Snapshots.
128+
129+
**Solutions:**
130+
- Verify ddprof has published the snapshot version
131+
- Check Maven Central Snapshots repository: https://central.sonatype.com/repository/maven-snapshots/
132+
- Wait for ddprof CI to complete if a new snapshot is being published
133+
134+
### Version not being overridden
135+
136+
**Cause:** The property might not be correctly set or parsed.
137+
138+
**Solutions:**
139+
- Ensure you're using `-PuseDdprofSnapshot=true` (not `-DuseDdprofSnapshot`)
140+
- Check Gradle output for "Using ddprof snapshot version" message
141+
- Run with `--info` flag to see detailed dependency resolution logs

gradle/ddprof-override.gradle

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
// Configuration for using ddprof snapshot versions
2+
// When -PuseDdprofSnapshot=true is set, this will:
3+
// 1. Parse the current ddprof version from libs.versions.toml
4+
// 2. Calculate the next minor snapshot version: X.Y.Z -> X.(Y+1).0-SNAPSHOT
5+
// 3. Override the ddprof dependency resolution to use the snapshot version
6+
// 4. Add a qualifier to the dd-trace-java version to avoid overwriting standard snapshots
7+
8+
def useDdprofSnapshot = project.hasProperty('useDdprofSnapshot') && project.property('useDdprofSnapshot').toBoolean()
9+
10+
if (useDdprofSnapshot) {
11+
def ddprofSnapshotVersion = calculateDdprofSnapshotVersion()
12+
logger.lifecycle("Using ddprof snapshot version: ${ddprofSnapshotVersion}")
13+
14+
// Store the calculated version as an extra property for use in subprojects
15+
rootProject.ext.ddprofSnapshotVersion = ddprofSnapshotVersion
16+
17+
// Add qualifier to the project version to differentiate from standard snapshots
18+
// This ensures we don't overwrite the regular SNAPSHOT artifacts
19+
allprojects {
20+
def originalVersion = version.toString()
21+
if (originalVersion.contains('-SNAPSHOT')) {
22+
// Insert qualifier before -SNAPSHOT: X.Y.Z-SNAPSHOT -> X.Y.Z-ddprof-SNAPSHOT
23+
version = originalVersion.replace('-SNAPSHOT', '-ddprof-SNAPSHOT')
24+
} else if (originalVersion.contains('-')) {
25+
// For versions with trailer: X.Y.Z-12-g8ab3f42d -> X.Y.Z-ddprof-12-g8ab3f42d
26+
def parts = originalVersion.split('-', 2)
27+
version = "${parts[0]}-ddprof-${parts[1]}"
28+
} else {
29+
// For release versions (shouldn't happen, but handle it): X.Y.Z -> X.Y.Z-ddprof
30+
version = "${originalVersion}-ddprof"
31+
}
32+
logger.lifecycle("Modified version for ${project.name}: ${originalVersion} -> ${version}")
33+
}
34+
35+
// Override the ddprof dependency resolution for all configurations
36+
allprojects {
37+
configurations.all {
38+
resolutionStrategy.eachDependency { DependencyResolveDetails details ->
39+
if (details.requested.group == 'com.datadoghq' && details.requested.name == 'ddprof') {
40+
details.useVersion(ddprofSnapshotVersion)
41+
details.because("Using ddprof snapshot version for integration testing")
42+
}
43+
}
44+
}
45+
}
46+
}
47+
48+
def calculateDdprofSnapshotVersion() {
49+
// Read the libs.versions.toml file
50+
def versionsFile = rootProject.file('gradle/libs.versions.toml')
51+
if (!versionsFile.exists()) {
52+
throw new GradleException("Could not find gradle/libs.versions.toml")
53+
}
54+
55+
def currentVersion = null
56+
versionsFile.eachLine { line ->
57+
// Look for the ddprof version line: ddprof = "X.Y.Z"
58+
def matcher = line =~ /^\s*ddprof\s*=\s*"([0-9]+)\.([0-9]+)\.([0-9]+)"\s*$/
59+
if (matcher) {
60+
def major = matcher[0][1]
61+
def minor = matcher[0][2]
62+
// Increment the minor version
63+
def nextMinor = (minor as Integer) + 1
64+
currentVersion = "${major}.${nextMinor}.0-SNAPSHOT"
65+
}
66+
}
67+
68+
if (currentVersion == null) {
69+
throw new GradleException("Could not parse ddprof version from gradle/libs.versions.toml")
70+
}
71+
72+
return currentVersion
73+
}

gradle/ddprof-snapshot.gradle

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
// Configuration for using ddprof snapshot versions
2+
// When -PuseDdprofSnapshot=true is set, this will:
3+
// 1. Parse the current ddprof version from libs.versions.toml
4+
// 2. Calculate the next minor snapshot version: X.Y.Z -> X.(Y+1).0-SNAPSHOT
5+
// 3. Override the ddprof dependency resolution to use the snapshot version
6+
// 4. Add a qualifier to the dd-trace-java version to avoid overwriting standard snapshots
7+
8+
def useDdprofSnapshot = project.hasProperty('useDdprofSnapshot') && project.property('useDdprofSnapshot').toBoolean()
9+
10+
if (useDdprofSnapshot) {
11+
def ddprofSnapshotVersion = calculateDdprofSnapshotVersion()
12+
logger.lifecycle("Using ddprof snapshot version: ${ddprofSnapshotVersion}")
13+
14+
// Store the calculated version as an extra property for use in subprojects
15+
rootProject.ext.ddprofSnapshotVersion = ddprofSnapshotVersion
16+
17+
// Add qualifier to the project version to differentiate from standard snapshots
18+
// This ensures we don't overwrite the regular SNAPSHOT artifacts
19+
allprojects {
20+
def originalVersion = version.toString()
21+
if (originalVersion.contains('-SNAPSHOT')) {
22+
// Insert qualifier before -SNAPSHOT: X.Y.Z-SNAPSHOT -> X.Y.Z-ddprof-SNAPSHOT
23+
version = originalVersion.replace('-SNAPSHOT', '-ddprof-SNAPSHOT')
24+
} else if (originalVersion.contains('-')) {
25+
// For versions with trailer: X.Y.Z-12-g8ab3f42d -> X.Y.Z-ddprof-12-g8ab3f42d
26+
def parts = originalVersion.split('-', 2)
27+
version = "${parts[0]}-ddprof-${parts[1]}"
28+
} else {
29+
// For release versions (shouldn't happen, but handle it): X.Y.Z -> X.Y.Z-ddprof
30+
version = "${originalVersion}-ddprof"
31+
}
32+
logger.lifecycle("Modified version for ${project.name}: ${originalVersion} -> ${version}")
33+
}
34+
35+
// Override the ddprof dependency resolution for all configurations
36+
allprojects {
37+
configurations.all {
38+
resolutionStrategy.eachDependency { DependencyResolveDetails details ->
39+
if (details.requested.group == 'com.datadoghq' && details.requested.name == 'ddprof') {
40+
details.useVersion(ddprofSnapshotVersion)
41+
details.because("Using ddprof snapshot version for integration testing")
42+
}
43+
}
44+
}
45+
}
46+
}
47+
48+
def calculateDdprofSnapshotVersion() {
49+
// Read the libs.versions.toml file
50+
def versionsFile = rootProject.file('gradle/libs.versions.toml')
51+
if (!versionsFile.exists()) {
52+
throw new GradleException("Could not find gradle/libs.versions.toml")
53+
}
54+
55+
def currentVersion = null
56+
versionsFile.eachLine { line ->
57+
// Look for the ddprof version line: ddprof = "X.Y.Z"
58+
def matcher = line =~ /^\s*ddprof\s*=\s*"([0-9]+)\.([0-9]+)\.([0-9]+)"\s*$/
59+
if (matcher) {
60+
def major = matcher[0][1]
61+
def minor = matcher[0][2]
62+
// Increment the minor version
63+
def nextMinor = (minor as Integer) + 1
64+
currentVersion = "${major}.${nextMinor}.0-SNAPSHOT"
65+
}
66+
}
67+
68+
if (currentVersion == null) {
69+
throw new GradleException("Could not parse ddprof version from gradle/libs.versions.toml")
70+
}
71+
72+
return currentVersion
73+
}

0 commit comments

Comments
 (0)