Is it possible to change the name of a build based on the branch name in Azure Pipelines? - azure-devops

Most of my builds are from either feature branches or develop, and so I tend to use a known build variable to track the build number such as:
variables:
- group: BuildVars
name: $(BuildPrefix)$(Rev:r)
This works and provides me with a nicely formatted build version that I can then follow through into releases, etc:
However, when we're planning a release, we name our branches after the release, for example: release/1.1, and I'd like to have the build name reference that instead of the hardcoded (previous) version.
I know that I can reference the branch name via the Build.SourceBranch variable, but I don't see an obvious way to read and modify that outside of a build step, by which time I believe it's too late? I don't really want to have to manually change the BuildPrefix variable until the release has been deployed out to production.
Building on from this would then be the ability to append appropriate pre-release tags, etc. based on the branch name...

you can always update the build name during the execution of a build using this:
- pwsh: |
Write-Host "##vso[build.updatebuildnumber]value_goes_here"
so you could calculate the value in the same (or previous step) and update the build name with that value

Is it possible to change the name of a build based on the branch name in Azure Pipelines?
The answer is yes.
The solution we currently use is add a Run Inline Powershell task to update build number based on the Build_SourceBranchName:
$branch = $Env:Build_SourceBranchName
Write-Host "Current branch is $branch"
if ($branch -eq "Dev")
{
Write-Host "##vso[build.updatebuildnumber]$DevBuildNumber"
}
elseif ($branch -eq "Beta")
{
Write-Host "##vso[build.updatebuildnumber]$BetaBuildNumber"
}
elseif ($branch -eq "Test")
{
Write-Host "##vso[build.updatebuildnumber]$TestBuildNumber"
}
Check the Logging Command during the build for some more details.
Hope this helps.

Related

Don't trigger builds for branches that already have a pull request in Azure DevOps

We use Azure DevOps for continuous integration. The pipeline is configured to run a build whenever a change is pushed to a feature branch. This is desired for quick feedback.
Additionally, we have the policy for the master branch that a successful validation build is required before a feature branch can be merged. Azure DevOps now automatically triggers the corresponding validation build when a pull request (PR) is created for a feature branch.
All of this is fine, but there is an adversity: if a PR is already created and the feature branch is updated, two builds are triggered (one for the feature branch alone and one for the outcome of the merge, i.e., the validation build).
I understand that some people might want both builds, but in our case (an probably in every normal case) it would be better if only the validation build was triggered.
Question: Is there a way to tell Azure DevOps that it should ignore branch triggers for any branch that already has a PR? Workarounds with an equivalent outcome are also welcome, of course.
The question has already been posted as an issue here, but I could not find a satisfying answer in the replies (e.g., branch filters and a naming strategy do not solve the problem).
"Out-of-box" - you can not. However as a workaround, you can use rest API to check active pull requests and if they exist just fail your unneeded build:
Get Pull Requests - Targeting a specific branch
Use the system access token from your build pipeline. Access repositories, artifacts, and other resources
Exit with Powershell from a build: exit 1
Because that's the design, thus, both build will be triggered but you could have try with follow method to avoid the build queued at the same time.
In the build validation policy - disable automatic queuing. Or mark the PR as draft, while changes are being worked on. After this change any of the changes will only trigger CI build/pipeline, and when ready just publish the PR or queue the PR manually.
I have solved the issue like suggested by Shamrai. I'm adding this as another answer to share my code.
Add the following PowerShell code to a step at the beginning of the pipeline. It uses the Azure DevOps REST API to check for an existing PR of the current branch. If there is no such PR or if the current build was manually queued, or if the PR is not ready to be merged (e.g. conflicts), the build continues as normal. Otherwise, it is cancelled.
$BaseApiUri_Builds = "https://my.tfs.server.com/MyCollection/MyProject/_apis/build/builds"
$BaseApiUri_GitRepos = "https://my.tfs.server.com/MyCollection/MyProject/_apis/git/repositories"
$AuthenicationHeader = #{ Authorization = "Bearer ${env:System_AccessToken}" }
# Cancels the current build
function Cancel-This-Build()
{
Cancel-Build -BuildId ${env:Build_BuildId}
}
# Cancels the given build
function Cancel-Build([String] $BuildId)
{
Write-Host "Cancelling build ${BuildId}..."
$BuildApiUri = "${BaseApiUri_Builds}/${BuildId}?api-version=5.1"
$CancelBody = #{ status = "cancelling" } | ConvertTo-Json
Invoke-RestMethod -Uri $BuildApiUri -Method PATCH -ContentType application/json -Body $CancelBody -Header $AuthenicationHeader
}
# Detects if a validation build is queued for the given branch. This is the case if an active PR exists that does not have merge conflicts.
function Check-For-Validation-Build([String] $BranchName)
{
Write-Host "Checking for validation builds of branch '${BranchName}' in repository ${env:Build_Repository_ID}..."
$GetPRsApiUri = "${BaseApiUri_GitRepos}/${env:Build_Repository_ID}/pullrequests?api-version=5.1&searchCriteria.sourceRefName=${BranchName}"
$PRs = Invoke-RestMethod -Uri $GetPRsApiUri -Method GET -Header $AuthenicationHeader
ForEach($PR in $PRs.Value)
{
Write-Host "Found PR $($PR.pullRequestId) '$($PR.title)': isDraft=$($PR.isDraft), status=$($PR.status), mergeStatus=$($PR.mergeStatus)"
if (!$PR.isDraft -and ($PR.mergeStatus -eq "succeeded") -and ($PR.status -eq "active"))
{
Write-Host "Validation build is queued for branch '${BranchName}'."
return $true
}
}
Write-Host "No validation build is queued for branch '${BranchName}'."
return $false
}
# Check if a valid PR exists. If so, cancel this build, because a validation build is also queued.
$HasValidationBuild = Check-For-Validation-Build -BranchName ${env:Build_SourceBranch}
if (($HasValidationBuild -eq $true) -and (${env:Build_Reason} -ne "Manual") -and !${env:Build_SourceBranch}.EndsWith('/merge'))
{
Cancel-This-Build
}
Note that the System.AccessToken environment variable must be made visible for the script to work.

Does Azure YAML pipelne support wildcards in path filter in trigger?

I have this structure of projects (folders) in git repository:
/src
/src/Sample.Backend.Common
/src/Sample.Backend.Common.Tests
/src/Sample.Backend.Common.Domain
/src/Sample.Backend.Common.Domain.Tests
/src/Sample.Backend.Pricing.Abstractions
/src/Sample.Backend.Pricing.Domain
/src/Sample.Backend.Pricing.Domain.Tests
/src/Sample.Backend.Pricing.Persistence
/src/Sample.Backend.Pricing.Persistence.Tests
/src/Sample.Backend.Accounting.Abstractions
/src/Sample.Backend.Accounting.Domain
/src/Sample.Backend.Accounting.Domain.Tests
/src/Sample.Backend.Accounting.Persistence
/src/Sample.Backend.Accounting.Persistence.Tests
/src/Sample.Backend.Api
/src/Sample.Common
/src/Sample.Frontend.Common
/src/Sample.Frontend.Web
/src/Sample.Tests.Common
(The sample is simplified, in real there are much more projects/folders.)
I want different pipelines for different parts. For example a pipeline to be triggered whenever any file is commited in master branch in any Backend project. Something like this:
trigger:
branches:
include:
- master
paths:
include:
- src/Sample.Backend.*
- src/Sample.Common
- src/Sample.Tests.Common
The problem is, that filter src/Sample.Backend.* is not working. I have to add exact name of each Backend folder to get it working. I could use exclude but I have the same problem - there are many other projects and I would have to name them all.
I found that wildcards are not supported: https://github.com/MicrosoftDocs/azure-devops-docs/issues/397#issuecomment-422958966
Is there any other way to achieve the same result?
Does Azure YAML pipelne support wildcards in path filter in trigger?
This is a known request on our main forum for product:
Support wildcards (*) in Trigger > Path Filters
This feature has not yet been implemented; you could add your comment and vote this on user voice.
As a workaround for us, we add an inline PowerShell task as the first task to execute the git command line git diff HEAD HEAD~ --name-only then get the modified file names and filter the files name in the latest submit, and use Logging Command to sets variables which are then referenced in custom conditions in the next steps in the build pipeline:
and(succeeded(), eq(variables['CustomVar'], 'True'))
Our inline PowerShell script:
cd $(System.DefaultWorkingDirectory)
$editedFiles = git diff HEAD HEAD~ --name-only
echo "$($editedFiles.Length) files modified:"
$editedFiles | ForEach-Object {
echo $_
Switch -Wildcard ($_ ) {
'XXXX/Src/Sample.Backend.*' {
Write-Host ("##vso[task.setvariable variable=CustomVar]True")
}
'XXXX/Src/Sample.Common*' {
Write-Host ("##vso[task.setvariable variable=CustomVar]True")}
'XXXX/Src/Sample.Tests.Common' {
Write-Host ("##vso[task.setvariable variable=CustomVar]True")}
}
}
Then add the condition for all remaining tasks:
In this case, if the changed files do not meet our filters, then all remaining tasks will be skipped.
UPDATE: 09/09/2021
This is possible now as it is written here
Wild cards can be used when specifying inclusion and exclusion branches for CI or PR triggers in a pipeline YAML file. However, they cannot be used when specifying path filters. For instance, you cannot include all paths that match src/app//myapp*. This has been pointed out as an inconvenience by several customers. This update fills this gap. Now, you can use wild card characters (, *, or ?) when specifying path filters.
Note: documentation seems to be not updated yet.
Old answer:
No this is not possible at the moment. You have even feature request here and I would recommend to upvote it. (I already did this) Rick in above mentioned topic shared his idea how to overcome the issue:
I currently achieve this by having 3 files:
azure-pipelines.yml ( This calls some python on each commit )
azure-pipelines.py (This checks for changed folders and has some parameters to ignore certain folders, then calls the API directly)
azure-pipelines-trigger.yml ( This is called by the python based on the changed folders )
It works well enough, but it is unfortunate for the need to go through these loops.
But it needs an extra work.
This feature will roll out over the next two to three weeks according to the latest release notes
Update on this.
It took a few weeks but the change mentioned by pavlo in the comments above finally got rolled out and path triggers are now supported in YAML.

How to refer previous task and stop the build in azure devops if there is no new data to publish an artifact

Getsolution.exe will give New data available or no new data available, if new data available then next jobs should be executed else nothing should be executed. How should i do it? (i am working on classic editor)
example: i have set of tasks, consider 4 tasks:
task-1: builds the solution
task-2: runs the Getstatus.exe which get the status of data available or no data available
task-3: i should be able to use the above task and make a condition/use some api query and to proceed to publish an artifact if data is available if not cleanly break out of the task and stop the build. it Shouldn't proceed to publish artifact or move to the next available task
task-4:publish artifact
First what you need is to set a variable in your task where you run Getstatus.exe:
and then set condition in next tasks:
If you set doThing to different valu than Yes you will get this:
How to refer previous task and stop the build in azure devops if there is no new data to publish an artifact
Since we need to execute different task based on the different results of Getstatus.exe running, we need set the condition based on the result of Getstatus.exe running.
To resolve this, just like the Krzysztof Madej said, we could set variable(s) based on the return value of Getstatus.exe in the inline powershell task:
$dataAvailable= $(The value of the `Getstatus.exe`)
if ($dataAvailable -eq "True")
{
Write-Host ("##vso[task.setvariable variable=Status]Yes")
}
elseif ($dataAvailable -eq "False")
{
Write-Host ("##vso[task.setvariable variable=Status]No")
}
Then set the different condition for next task:
You could check the document Specify conditions for some more details.

How to receive Revision in Azure Pipelines YAML build definition

I created a new build with Azure Pipelines (Azure DevOps) and it worked really well.
Usually, you use $(Rev:.r) to get the revision in the build. Unfortunately, it seems the variable isn't replaced/set in the build steps. The only place where you can use it is the name: property in the YAML document.
Now I set it in the name and extract it in some PowerShell, which isn't necessary if you can get it via an environment variable.
How do I get the Revision (like $(Rev)) in the new builds (outside of the name: property in the YAML document)?
(The Build Agents running on-premise, inside Docker - but this shouldn't affect the things above)
You can't get the revision number without parsing, it is not stored as a separate field somewhere or in an environment variable.
The $(Rev:.r) portion instructs Azure DevOps to come up with the first number that makes the build number unique (and, in that specific example, put a dot in front of it).
Like you said, the only way is to use PowerShell script to get the value:
$buildNumber = $Env:BUILD_BUILDNUMBER
$revision= $buildNumber.Substring($buildNumber.LastIndexOf('.') + 1)
Edit:
You can install the Get Revision Number extension that does it.
Another possible solution to the above problem could be to use counter expression for ex: we difine the variable and use it in a task to build nuget package.
variables:
counterVar: $[counter($(versionVariable),0)]
.......
- task: CmdLine#2
inputs:
script: >
nuget pack ClassLibrary1/ClassLibrary1.csproj
-OutputDirectory $(Build.ArtifactStagingDirectory)
-NonInteractive
-Properties Configuration=release
-Version $(versionVariable).$(counterVar)
-Verbosity Detailed
-IncludeReferencedProjects
Here versionVariable is a custome variable defined in pipelines->variables.And the seed value is 0(2nd param to counter).
It works as below
Let's assume the versionVariable is 1.19
Build Run 1 counterVar will be 0.
Build Run 2 counterVar will be 1.
Now say we change the versionVariable to 1.20
Build Run 3 counterVar will be 0.
https://learn.microsoft.com/en-us/azure/devops/pipelines/process/expressions?view=azure-devops
Check the counter expression in above link it reset its value for diff prefix.
P.S. Benefit of using counter over $(Rev:r) is that it can start from 0 unlike $(Rev:r)

Access SourceBranchName in Release pipeline

I'm trying to release my buildartifacts to a specific folder based on the name of the sourcebranch which upon creating a pull request triggered the build and therefor the release.
I've managed to so far to get:
write-host $env:RELEASE_TRIGGERINGARTIFACT_ALIAS
$triggerAlias = $env:RELEASE_TRIGGERINGARTIFACT_ALIAS
This alias (from my point of view) is the primary artifcat alias which I need to access
Release.Artifacts.{Primary artifact alias}.SourceBranchName
based on this documentation. So how do I combine the alias to get the sourcebranchname
$env:RELEASE_ARTIFACTS_{$triggerAlias}_SOURCEBRANCHNAME
This doesn't seem to be working and neither does
$env:RELEASE_ARTIFACTS_$($triggerAlias)_SOURCEBRANCHNAME
Any advice is much appreciated.
You can read the variable in this way:
$triggerAlias = $env:RELEASE_TRIGGERINGARTIFACT_ALIAS
$branchNameVariable = "RELEASE_ARTIFACTS_$($triggerAlias)_SOURCEBRANCHNAME"
#Get the value of the environment variable Release.Artifacts.{alias}.SourceBranchName
$branchName = (Get-item env:$branchNameVariable).Value