From 373de76be6d80772f3228e63059c58fe9a02cc00 Mon Sep 17 00:00:00 2001 From: Mo Atie Date: Fri, 23 Oct 2026 15:14:53 -0400 Subject: [PATCH 1/3] Increment patch version on release branches checked out as detached HEAD GitLab checks out the pipeline commit as a detached HEAD, so `git rev-parse --abbrev-ref HEAD` returns "HEAD" and release branch builds were versioned with a minor bump instead of a patch bump. Fall back to CI_COMMIT_BRANCH when git reports a detached HEAD. Co-Authored-By: Claude Opus 5.5 --- .../plugin/version/TracerVersionPlugin.kt | 13 ++++- .../version/TracerVersionIntegrationTest.kt | 48 ++++++++++++++++++- 2 files changed, 59 insertions(+), 2 deletions(-) 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 4cd8669c389..02c74f3f244 100644 --- a/buildSrc/src/main/kotlin/datadog/gradle/plugin/version/TracerVersionPlugin.kt +++ b/buildSrc/src/main/kotlin/datadog/gradle/plugin/version/TracerVersionPlugin.kt @@ -5,6 +5,7 @@ import org.gradle.api.Plugin import org.gradle.api.Project import org.gradle.api.logging.Logging import org.gradle.api.model.ObjectFactory +import org.gradle.api.provider.Provider import org.gradle.api.provider.ProviderFactory import org.gradle.kotlin.dsl.property import java.io.File @@ -48,7 +49,7 @@ class TracerVersionPlugin @Inject constructor( // Not a git repository extension.defaultVersion.get() } else { - val currentBranchProvider = gitCurrentBranchProvider(repoWorkingDirectory) + val currentBranchProvider = currentBranchProvider(repoWorkingDirectory) providerFactory.zip( currentBranchProvider.flatMap { currentBranch -> // Use --first-parent only on release branches so they stay anchored to their own @@ -80,6 +81,16 @@ class TracerVersionPlugin @Inject constructor( return buildVersion } + private fun currentBranchProvider( + repoWorkingDirectory: File + ): Provider = + gitCurrentBranchProvider(repoWorkingDirectory).zip( + providerFactory.environmentVariable("CI_COMMIT_BRANCH").orElse("") + ) { gitBranch, ciBranch -> + // GitLab checks out a detached HEAD, where git reports "HEAD" instead of the branch name + if (gitBranch == "HEAD" && ciBranch.isNotBlank()) ciBranch else gitBranch + } + private fun gitCurrentBranchProvider( repoWorkingDirectory: File ) = providerFactory.of(GitCommandValueSource::class.java) { diff --git a/buildSrc/src/test/kotlin/datadog/gradle/plugin/version/TracerVersionIntegrationTest.kt b/buildSrc/src/test/kotlin/datadog/gradle/plugin/version/TracerVersionIntegrationTest.kt index eb909d71862..61099579717 100644 --- a/buildSrc/src/test/kotlin/datadog/gradle/plugin/version/TracerVersionIntegrationTest.kt +++ b/buildSrc/src/test/kotlin/datadog/gradle/plugin/version/TracerVersionIntegrationTest.kt @@ -127,6 +127,44 @@ class TracerVersionIntegrationTest : VersionPluginsFixture() { ) } + @Test + fun `should increment patch on release branch checked out as detached HEAD in GitLab`() { + assertTracerVersion( + expectedVersion = "1.52.2-SNAPSHOT", + // GitLab checks out the pipeline commit as a detached HEAD and exposes the branch name in CI_COMMIT_BRANCH + env = mapOf("CI_COMMIT_BRANCH" to "release/v1.52.x"), + beforeGradle = { + initGitRepo() + exec("git", "tag", "v1.52.0", "-m", "") + exec("git", "switch", "-c", "release/v1.52.x") + writeSettings("// Committed change ", append = true) + exec("git", "commit", "-am", "Another commit") + exec("git", "tag", "v1.52.1", "-m", "") + writeSettings("// Another committed change ", append = true) + exec("git", "commit", "-am", "Another commit") + exec("git", "switch", "--detach") + }, + ) + } + + @Test + fun `should use exact version on tag checked out as detached HEAD in GitLab`() { + assertTracerVersion( + expectedVersion = "1.52.1", + // GitLab tag pipelines set CI_COMMIT_TAG, not CI_COMMIT_BRANCH + unsetEnv = setOf("CI_COMMIT_BRANCH"), + beforeGradle = { + initGitRepo() + exec("git", "tag", "v1.52.0", "-m", "") + exec("git", "switch", "-c", "release/v1.52.x") + writeSettings("// Committed change ", append = true) + exec("git", "commit", "-am", "Another commit") + exec("git", "tag", "v1.52.1", "-m", "") + exec("git", "switch", "--detach", "v1.52.1") + }, + ) + } + @Test fun `should compute version on worktrees`(@TempDir workTreeDir: File) { assertTracerVersion( @@ -191,6 +229,8 @@ class TracerVersionIntegrationTest : VersionPluginsFixture() { private fun assertTracerVersion( expectedVersion: String, workingDirectory: File = projectDir, + env: Map = emptyMap(), + unsetEnv: Set = emptySet(), beforeGradle: VersionPluginsFixture.() -> Unit = {}, ) { writeSettings( @@ -215,7 +255,13 @@ class TracerVersionIntegrationTest : VersionPluginsFixture() { beforeGradle() - val buildResult = run("printVersion", "--quiet", gradleProjectDir = workingDirectory) + val buildResult = run( + "printVersion", + "--quiet", + env = env, + unsetEnv = unsetEnv, + gradleProjectDir = workingDirectory + ) assertThat(buildResult.output.lines().first()).isEqualTo(expectedVersion) } From 5f8212da88bde4c224e803538fac4a0d9adc2252 Mon Sep 17 00:00:00 2001 From: Mo Atie Date: Fri, 23 Oct 2026 15:47:33 -0400 Subject: [PATCH 2/3] Update buildSrc/src/main/kotlin/datadog/gradle/plugin/version/TracerVersionPlugin.kt Co-authored-by: Douglas Q Hawkins --- .../datadog/gradle/plugin/version/TracerVersionPlugin.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) 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 02c74f3f244..6e7c094829c 100644 --- a/buildSrc/src/main/kotlin/datadog/gradle/plugin/version/TracerVersionPlugin.kt +++ b/buildSrc/src/main/kotlin/datadog/gradle/plugin/version/TracerVersionPlugin.kt @@ -87,7 +87,9 @@ class TracerVersionPlugin @Inject constructor( gitCurrentBranchProvider(repoWorkingDirectory).zip( providerFactory.environmentVariable("CI_COMMIT_BRANCH").orElse("") ) { gitBranch, ciBranch -> - // GitLab checks out a detached HEAD, where git reports "HEAD" instead of the branch name + // GitLab checks out a detached HEAD, where git reports "HEAD" instead of the branch name. + // Pipelines that don't set CI_COMMIT_BRANCH to the release branch itself (merge requests, + // merge queue working branches) still get the next minor version. if (gitBranch == "HEAD" && ciBranch.isNotBlank()) ciBranch else gitBranch } From 60ab6cd966bfe6621cbeb6c2dbe8e66cd59195aa Mon Sep 17 00:00:00 2001 From: Mo Atie Date: Fri, 23 Oct 2026 15:51:39 -0400 Subject: [PATCH 3/3] Apply suggestion from @dougqh Co-authored-by: Douglas Q Hawkins --- .../version/TracerVersionIntegrationTest.kt | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/buildSrc/src/test/kotlin/datadog/gradle/plugin/version/TracerVersionIntegrationTest.kt b/buildSrc/src/test/kotlin/datadog/gradle/plugin/version/TracerVersionIntegrationTest.kt index 61099579717..7cda763d57a 100644 --- a/buildSrc/src/test/kotlin/datadog/gradle/plugin/version/TracerVersionIntegrationTest.kt +++ b/buildSrc/src/test/kotlin/datadog/gradle/plugin/version/TracerVersionIntegrationTest.kt @@ -165,6 +165,23 @@ class TracerVersionIntegrationTest : VersionPluginsFixture() { ) } + @Test + fun `should increment minor on detached HEAD without CI_COMMIT_BRANCH`() { + assertTracerVersion( + expectedVersion = "1.53.0-SNAPSHOT", + // Merge request pipelines, local detached checkouts and other CIs don't set CI_COMMIT_BRANCH + unsetEnv = setOf("CI_COMMIT_BRANCH"), + beforeGradle = { + initGitRepo() + exec("git", "tag", "v1.52.0", "-m", "") + exec("git", "switch", "-c", "release/v1.52.x") + writeSettings("// Committed change ", append = true) + exec("git", "commit", "-am", "Another commit") + exec("git", "switch", "--detach") + }, + ) + } + @Test fun `should compute version on worktrees`(@TempDir workTreeDir: File) { assertTracerVersion(