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

Created on 7 Mar 2017  路  41Comments  路  Source: microsoft/azure-pipelines-agent

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
...

Most helpful comment

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.

All 41 comments

@ChristophLindemann thanks for reporting, BUILD_SOURCEBRANCHNAME is a variable TFS/VSTS server set. I don't know why it set this way, i will see how can i fix it. :)

@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?

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.

@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)

+1 would also like to see support for BUILD_SOURCEBRANCHFULLNAME

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

+1

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

+1

@TingluoHuang & @ericsciple any chance of a workaround for this, if a feature is not made available? I'm aware this isn't really in the wheelhouse of the agent, but we have no visibility of the workload for the VSTS project itself (as @ChristophLindemann has mentioned it's not public). Some way of e.g. populating as a VSTS variable, that can be pushed through to the agent? As others have said, this pretty much makes GitFlow unworkable as it stands unfortunately.

That would be really helpful to identify NuGet packages coming from features, hotfixes, etc. using semantic versioning

@gjonespf We have evaluated this in the past and made the determination not to change the existing variable. That鈥檚 not to say we won鈥檛 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

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.

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.

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

We use this variable for docker tags, and changing the behaviour of an existing variable will break our use. (e.g run docker tag on releases/*, tag using this variable to get repo/image:RelA for things from releases/RelA)

Adding a new variable is fine.

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

I've got the same frustrating problem today

I too, a few days ago was reading about the Team Foundation Build predefined variables and came across the Build.SourceBranchName variable and immediately realized it's severe shortcomings. I came here today quite by accident looking for information on something else entirely.

In any event, I was also looking at automating my version numbers and during my research I came across the following here: $(Build.SourceVersion.Replace('C','')) to get rid of the C prefixing the TFVC changeset ID. _But_, this string replacement on an MS Build variable is being performed from within an MSBuild script.

Remembering that I had seen string replacement performed on a variable, I was going to try something similar: $(Build.SourceBranch.Replace('$/TeamProjectName/','')) to get at anything after the Team Project name for TFVC. In Git, $(Build.SourceBranch.Replace('refs/*/','')), perhaps? But again, I'm not sure this would work as expected for modifying the Branch.SourceBranch variable, depending on whether or not you can use function calls on these like you can in MSBuild scripts. (I mean, I would think that the whole build is a giant MSBuild script, so, it might work?) If anyone knows off-hand whether or not this would work, or gives this a try before I get around to trying this myself, could you please report back here and mention me with the results?

BTW, I'm still on TFS 2017U1 (we're working on upgrading to Azure DevOps Server)--so my options at the current moment are particularly limited. 馃槈

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

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.

seems as if they are simply not listening...
:+1:

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.

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

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.

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"....

I think 3 years is not enough for this feature.

I think 3 years is not enough for this feature.

There鈥檚 soo many things DevOps does well, and then there鈥檚 basic things like this...

I鈥檓 also on the bandwagon it鈥檚 a bug by definition.

@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.

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.

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.

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 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.

Do I read the comment chain correctly, there is still no solution for getting the full branch name? If so, to me this is a BUG, too!

Is there any feedback on further steps?

OK I found Build.SourceBranch which provides the info I need. Is this what the rest is looking for, too?

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

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

4 years down the line and this still hasn't been implemented.

Is there any update on this or do we have to use a workaround?

Is there any update on this or do we have to use a workaround?

I gave up on using Azure DevOps for CI on pull requests.

Still needing this.

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

In addition to @davidorbelian s excellent answer I just wanted to point out that the code can also be used in a compile-time expression, which works on any place of the pipeline: ${{ replace(variables['Build.SourceBranch'], 'refs/heads/', '') }}

My use case was that I wanted to get that value in a pipeline (step) template, where I wasnt allowed to define an additional variables block.

Was this page helpful?
0 / 5 - 0 ratings