azure-pipelines-agent: Build.SourceBranchName does not include full name, if name includes forward slash

Agent version and platform

Version of your agent: 2.105.7

Windows Server 2012 R2

VSTS type and version

On-Prem TFS 2017

What’s not working?

The Build.SourceBranchName variable does not include full branch name, if branch name includes forward slash like feature/mynewfeature or bug/bug1234.

If the branch includes a forward slash, then Build.SourceBranchName will only include the last segment: mynewfeature or bug1234.

Actual:

Build.SourceBranch Build.SourceBranchName
refs/heads/feature/mynewfeature mynewfeature
refs/heads/bug/bug1234 bug1234

Expected:

Build.SourceBranch Build.SourceBranchName
refs/heads/feature/mynewfeature feature/mynewfeature
refs/heads/bug/bug1234 bug/bug1234

Build scripts

You can reproduce by creating a branch called feature/something

and have a build definition with a singe powershell script:

Write-Output "BUILD_BUILDNUMBER = ${env:BUILD_BUILDNUMBER}"
Write-Output "BUILD_SOURCEBRANCH= ${env:BUILD_SOURCEBRANCH}"
Write-Output "BUILD_SOURCEBRANCHNAME= ${env:BUILD_SOURCEBRANCHNAME}"
Write-Output "BUILD_SOURCESDIRECTORY= ${env:BUILD_SOURCESDIRECTORY}"
Write-Output "BUILD_SOURCEVERSION= ${env:BUILD_SOURCEVERSION}"

Output

2017-03-07T12:17:43.4744817Z ##[section]Starting: PowerShell Script
2017-03-07T12:17:43.6463541Z ##[command]. 'C:\Users\TFSBUILD\AppData\Local\Temp\3ed8057f-da6d-4ee2-9e51-04fb192d1677.ps1' 
2017-03-07T12:17:44.9782144Z BUILD_BUILDNUMBER = mybuild_07
2017-03-07T12:17:44.9782144Z BUILD_SOURCEBRANCH= refs/heads/feature/something
2017-03-07T12:17:44.9782144Z BUILD_SOURCEBRANCHNAME= something
2017-03-07T12:17:44.9782144Z BUILD_SOURCESDIRECTORY= D:\B\A1\_work\17\s
2017-03-07T12:17:44.9782144Z BUILD_SOURCEVERSION= 264c7662370f39ef0db9ab2c46489a686ac22724
2017-03-07T12:17:45.1344955Z ##[section]Finishing: PowerShell Script

Expected output

...
2017-03-07T12:17:44.9782144Z BUILD_SOURCEBRANCH= refs/heads/feature/something
2017-03-07T12:17:44.9782144Z BUILD_SOURCEBRANCHNAME= feature/something
...

About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Reactions: 40
  • Comments: 54 (4 by maintainers)

Commits related to this issue

Most upvoted comments

I can’t help but feel that the current functionality is simply wrong - if I create a branch called test/awesome-branch then the branch name is test/awesome-branch, not awesome-branch.

It’s quite annoying to have a task group which works if they specify a branch without a slash in it, but breaks if it does.

What can we do to change your mind on this issue?

EDIT: I understand that it could break backwards compatibility if the variable was changed, but the proposed solution of adding a Build.SourceBranchFullName variable seems perfectly reasonable.

@gjonespf We have evaluated this in the past and made the determination not to change the existing variable. That’s not to say we won’t change it, but I imagine that likelihood to be very, very low especially given how many years this behavior has existed.

There are use cases for just the very last segment (e.g. releases/m123, and just the milestone component is required).

In your scenario it sounds, it sounds like the current solution would be to add a step that performs the string manipulation and sets the variable you desire. For example: steps:

steps:
- powershell: |
    write-host "##vso[task.setvariable variable=branch]$($env:build_sourceBranch.substring($env:build_sourceBranch.indexOf('/', 5) + 1))"
- script: set branch

As a workaround for now I use Expressions so you can write something like:

name: $[ replace(variables['System.PullRequest.SourceBranch'], 'refs/heads/release/', '') ]

So you can get a build name 1.2.3 when building for a PR from realease/1.2.3 to master.

You can even do more complex things like this:

name: $[ variables['branchName'] ]

variables:
  ${{ if startsWith(variables['Build.SourceBranch'], 'refs/heads/') }}:
    branchName: $[ replace(variables['Build.SourceBranch'], 'refs/heads/', '') ]
  ${{ if startsWith(variables['Build.SourceBranch'], 'refs/pull/') }}:
    branchName: $[ replace(variables['System.PullRequest.SourceBranch'], 'refs/heads/', '') ]

trigger:
- master
pr:
- master

This way you can get the name of the source branch if it is a Trigger build or the name of the pull request source branch if that is a PR build.

This does not negate the fact that the shortcut-like Build.SourceBranchFullName feature is still needed.

@TingluoHuang & @ericsciple The BUILD_SOURCEBRANCHFULLNAME solution would be really appreciated.

For example, we use the branch name to publish intermediate API doc releases to folders named the same as the branch. Now if two people or teams use a branch name that is equal in the last segment, the builds would override each other’s output.

We also use it to drop artifacts in a common drop location, so testers can access build output, while developing features in different branches.

If it is not an agent issue, I kindly ask you to add it to the TFS on prem backlog (which is not public as far as I know)

BUILD_SOURCEBRANCHFULLNAME seems like an entirely reasonable solution to this. In my use case, it’s primarily about consistency with other popular CI solutions; given the branch name iameli/example-branch, I’d get:

service name value
Travis CI TRAVIS_BRANCH iameli/example-branch
CircleCI CIRCLE_BRANCH iameli/example-branch
CodeFresh CF_BRANCH iameli/example-branch
Drone.io DRONE_BRANCH iameli/example-branch
Jenkins GIT_BRANCH origin/iameli/example-branch
Azure Pipelines Build.SourceBranchName example-branch

No need to rename the existing variable, but adding Build.SourceBranchFullName would make my life just a bit easier.

I think 3 years is not enough for this feature.

+1 would also like to see support for BUILD_SOURCEBRANCHFULLNAME

What is the status for this? Why has Build.SourceBranchFullName not been made available? What is the downside of adding this?

We would very much like to have this too, this not being the full branch name for git repos is useless so at least having a variable that is the full name should be added.

seems as if they are simply not listening… 👍

You can also extract the required part from Build.SourceBranch. For windows it would look like this:

- script: |
  set branch=$(Build.SourceBranch)
  set branch=%branch:refs/heads/=%
  echo source branch is %branch%
  git checkout %branch%

Maybe this can be of help for someone…

It was great to find this thread after wasting quite a bit of time trying to figure out why my branch name was ‘merge’ on all PRs. I am surprised Build.SourceBranchFullname is still not an option.

Unfortunately, in my case, I want to use this path as part of the ‘ref’ of a repository, which is parsed well before any script is run.

Another vote for this. There are use cases where you must have the variable available before the possibility of running any scripts to work it out from other variables. For example, generating the build number/name. I place the branch name in my build number, but all PR builds just say “merge” which is utterly useless. I need to see “12345/merge” or whatever the PR branch is called.

I agree with the others that this is a bug. If I have 2 branches as follows:

difficult why/do/you/make/our/lives/so/difficult

Then according to the variable Build.SourceBranchName both of these branches are called difficult which is incorrect. It’s not possible to differentiate, which is entirely the point of having a name.

Please introduce Build.SourceBranchFullName to allow us to get the actual branch name, not a substring of it.

Agree with guys above. The current behaviour is incorrect. It is bug.

We can’t change the existing variable for compat reason, we can add a BUILD_SOURCEBRANCHFULLNAME if really needed. I will close the issue as Eric suggested.

Why this has been closed? The current value of $(Build.SourceBranch) is not different, but it’s actually wrong.

@TingluoHuang Can you please reopen this issue? The solution would be to add a new variable that properly represents a git branch with slashes included and I think it’s fair to resolve this issue AFTER that happens.

@TingluoHuang i’m not sure there is anything to do at this point. also this isnt an agent issue, the server sets. should we close the issue here?

This is an issue for us also. Like a couple of others who have posted, we can’t use string manipulation within a task because we need to use it right at the top of the pipeline, like this:

resources:
  pipelines:
  - pipeline: build
    source: Build
    branch: $(Build.SourceBranch)
    trigger:
      branches:
        include:
        - release/*

Neither $(Build.SourceBranch) or $(Build.SourceBranchName) will work in this scenario. There would appear to be no workaround, so we’re stuck.

Adding an additional Build.SourceBranchFullName variable seems like a no-brainer.

Well, this is still an issues as far as I can see. This baffles me.

I think 3 years is not enough for this feature.

There’s soo many things DevOps does well, and then there’s basic things like this…

I’m also on the bandwagon it’s a bug by definition.

I was also bitten by this bug… is there any variable with the correct branch name?

Supporting GitFlow it can be useful to have the full branch name including the “prefix” feature/, hotfix/ and release/

+1

OMG The issue is raised from 2021. Why close this issue and leave us here? Still need solution for the full branch name in 2021

I have the exact same issue. I need the branch name to communicate with the SonarQube API, but I’m missing the “feature/*” part which makes it impossible.

It’s not a bug @michielvanderros-tomtom, it’s a feature 😃

I use this code

- powershell: |
    # see also https://github.com/microsoft/azure-pipelines-agent/issues/838
    $SourceBranchLongName = switch ($env:Build_Reason) {
      'PullRequest' { $env:Build_SourceBranch.Replace('refs/pull/','').Replace('/merge','') }
      default { $env:Build_SourceBranch.Replace('refs/heads/','').Replace('refs/tags/','') }
    }
    Write-Host "##vso[task.setvariable variable=SourceBranchLongName]${SourceBranchLongName}"

to have set a SourceBranchLongName variable

This worked for me (didn’t try with pull request yet).

VERY IMPORTANT: Change the $env variables to upper cases, or else it won’t work on Linux/Unix.

$env:Build_SourceBranch => $env:BUILD_SOURCEBRANCH $env:Build_Reason => $env:BUILD_REASON

Same here. I’m not sure why this issue is closed, because it’s not been resolved.

I’m encountering this on Linux the same as OP on Windows

@TingluoHuang @ericsciple Do you know if there’s another issue tracking the addition of a variable to get the full branch name or can we reopen this issue? I believe this is still an issue and manually creating the full branch name as a variable via a script does not seem like a reasonable workaround for such a standard variable.

Considering DevOps leaves you in multiple situations where you are on a Detached HEAD and GitFlow (and general folder paths in Git) are extremely popular, it’s absolutely mind boggling that DevOps hasn’t been updated to support a proper “branch name” strategy with variables. I understand that Microsoft has a bias for a release branching strategy, but real world scenarios at most companies have git flow like strategies. This is a large gap that should absolutely be solved. I mean, how does one state “I don’t know how to get my source branches and check them out” with a response of “we offer a complete solution, but we do not offer this”…

It was great to find this thread after wasting quite a bit of time trying to figure out why my branch name was ‘merge’ on all PRs. I am surprised Build.SourceBranchFullname is still not an option.

Unfortunately, in my case, I want to use this path as part of the ‘ref’ of a repository, which is parsed well before any script is run.

I’ve got the same frustrating problem today

Has this issue been fixed in an upcoming version? The current behaviour is simply incorrect and renders the env var completely useless (and dangerous).

Such a simple fix (Build.SourceBranchFullName) for something that was clearly overlooked initially, and 5 years later the complaints keep coming and the bug just keeps on getting closed without a fix.

is this feature to get Branch full name ever going to be released?

As a workaround for now I use Expressions so you can write something like:

name: $[ replace(variables['System.PullRequest.SourceBranch'], 'refs/heads/release/', '') ]

So you can get a build name 1.2.3 when building for a PR from realease/1.2.3 to master.

You can even do more complex things like this:

name: $[ variables['branchName'] ]

variables:
  ${{ if startsWith(variables['Build.SourceBranch'], 'refs/heads/') }}:
    branchName: $[ replace(variables['Build.SourceBranch'], 'refs/heads/', '') ]
  ${{ if startsWith(variables['Build.SourceBranch'], 'refs/pull/') }}:
    branchName: $[ replace(variables['System.PullRequest.SourceBranch'], 'refs/heads/', '') ]

trigger:
- master
pr:
- master

This way you can get the name of the source branch if it is a Trigger build or the name of the pull request source branch if that is a PR build.

This does not negate the fact that the shortcut-like Build.SourceBranchFullName feature is still needed.

Good workaround to this bug. 10/10. Would use again. 👍

@ckolumbus I don’t think so because that adds extra sutff like refs/heads/${fullBranchName}. It might work for some situations but not all

We would like to use full branch names to build linked template URIs for use with ARM templates

+1