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
25 changes: 25 additions & 0 deletions .gitlab-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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 -PddprofUseSnapshot 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
Expand Down
1 change: 1 addition & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -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-override.gradle"))

spotless {
// only resolve the spotless dependencies once in the build
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)
}
Expand All @@ -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)
}
}
Original file line number Diff line number Diff line change
@@ -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")
}
1 change: 1 addition & 0 deletions dd-java-agent/ddprof-lib/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
158 changes: 158 additions & 0 deletions docs/publishing-with-ddprof-snapshot.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
# 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 `-PddprofUseSnapshot` 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 -PddprofUseSnapshot :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 -PddprofUseSnapshot
```

### Publishing to Maven Central Snapshots

To publish artifacts with the ddprof snapshot dependency:

```bash
./gradlew publishToSonatype -PddprofUseSnapshot -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 `-PddprofUseSnapshot`
- 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-override.gradle`** - Calculates snapshot version and stores it for convention plugins
2. **`build.gradle.kts`** - Applies the ddprof-snapshot configuration
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` 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
- 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 via a convention plugin to only the projects that need it:

```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")
}
}
}
}
```

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

- 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 `-PddprofUseSnapshot` (not `-DddprofUseSnapshot`)
- Check Gradle output for "Using ddprof snapshot version" message
- Run with `--info` flag to see detailed dependency resolution logs
63 changes: 63 additions & 0 deletions gradle/ddprof-override.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// Configuration for using ddprof snapshot versions
// 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. 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")

if (ddprofUseSnapshot) {
def ddprofSnapshotVersion = calculateDdprofSnapshotVersion()
logger.lifecycle("Using ddprof snapshot version: ${ddprofSnapshotVersion}")

// Store the calculated version as an extra property for use in convention plugins
rootProject.ext.ddprofSnapshotVersion = ddprofSnapshotVersion

// 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"
}
}
}
}

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
}