Currently I am working on some build and release pipelines to deploy some websites automatically. I have some CI builds running, and some scheduled buils that are deployed automatically. This works fine, but there is some waste in the process.
My CI build is the same as my scheduled build, with 1 major difference. I do not want to start a deployment pipeline for my CI builds, but I do want that for manual and scheduled builds. But how can I distinguish between the 2 builds triggers? I can only configure Continuous Deployment on a Build Definition and not on a trigger.
But there is a solution! Use the tags on a build definition to steer the Continuous Deployment.
Modifying the Build
The build definition can be configured to be a scheduled build, or a CI build, or, of course, a manual build. On the MSDN (docs) page of predefined build variables, the variable $(Build.Reason) is mentioned. But unfortunately, this does not work :-(. Luckily for us, we have the REST API that we can use to reach our goal.
First, I use the REST API, to get the build details, the response JSON contains a field “reason”. The reason is “manual”, “scheduled” or some other value.
Then, I set the Build Tag to this specific value. You can write an output variable and use this in a subsequent task (for example the Add Build Tag Task, found here) or just write the Tag directly in the powershell script using the REST API to write a Tag.
I described both options in earlier posts.
- https://roadtoalm.com/2016/08/11/set-output-variable-in-a-powershell-vsts-build-task/
- https://roadtoalm.com/2016/07/08/controlling-build-quality-using-build-tags-and-vsts-release-management/
Modify the Release
When you updated the build to set the Tag, you can then create or update the Release trigger, to only listen to builds with a certain tag
The Script
For people who are interested, I created a Powershell script that you can use within your build pipeline and that sets that Tag of the build to the trigger.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
param | |
( | |
[string] $BuildID="" | |
) | |
#global variables | |
$baseurl = $env:SYSTEM_TEAMFOUNDATIONCOLLECTIONURI | |
$baseurl += $env:SYSTEM_TEAMPROJECT + "/_apis" | |
Write-Debug "baseurl=$baseurl" | |
Write-Debug "basermurl=$basermurl" | |
<# | |
.Synopsis | |
Creates either a Basic Authentication token or a Bearer token depending on where the method is called from VSTS. | |
When you send a Personal Access Token that you generate in VSTS it uses this one. Within the VSTS pipeline it uses env:System_AccessToken | |
#> | |
function New-VSTSAuthenticationToken | |
{ | |
[CmdletBinding()] | |
[OutputType([object])] | |
$accesstoken = ""; | |
if([string]::IsNullOrEmpty($env:System_AccessToken)) | |
{ | |
if([string]::IsNullOrEmpty($env:PersonalAccessToken)) | |
{ | |
throw "No token provided. Use either env:PersonalAccessToken for Localruns or use in VSTS Build/Release (System_AccessToken)" | |
} | |
Write-Debug $($env:PersonalAccessToken) | |
$userpass = ":$($env:PersonalAccessToken)" | |
$encodedCreds = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes($userpass)) | |
$accesstoken = "Basic $encodedCreds" | |
} | |
else | |
{ | |
$accesstoken = "Bearer $env:System_AccessToken" | |
} | |
return $accesstoken; | |
} | |
<# | |
.Synopsis | |
Sets a Build Tag on a specific BuildID. Semicolon separates multiple Build Tags (e.g. Test;TEST2;Ready) | |
#> | |
function Set-BuildTag | |
{ | |
[CmdletBinding()] | |
[OutputType([object])] | |
param | |
( | |
[string] $BuildID="", | |
[string] $BuildTags="" | |
) | |
$buildTagsArray = $BuildTags.Split(";"); | |
$token = New-VSTSAuthenticationToken | |
Write-Host "BaseURL: [$baseurl]" | |
Write-Host "tagURL: [$tagURL]" | |
Write-Host "token: [$token]" | |
if ($buildTagsArray.Count -gt 0) | |
{ | |
foreach($tag in $buildTagsArray) | |
{ | |
$tagURL = "$baseurl/build/builds/$BuildID/tags/$tag`?api-version=2.0" | |
$response = Invoke-RestMethod –Uri $tagURL –Headers @{Authorization = $token} –Method Put | |
Write-Host $response | |
} | |
} | |
} | |
<# | |
.Synopsis | |
Sets a Build Tag on a specific BuildID. Semicolon separates multiple Build Tags (e.g. Test;TEST2;Ready) | |
#> | |
function Get-BuildTrigger | |
{ | |
[CmdletBinding()] | |
[OutputType([object])] | |
param | |
( | |
[string] $BuildID="" | |
) | |
$token = New-VSTSAuthenticationToken | |
$buildUrl = "$baseurl/build/builds/$($BuildID)?api-version=2.0" | |
$response = Invoke-RestMethod –Uri $buildUrl –Headers @{Authorization = $token} –Method Get | |
return $response.reason | |
} | |
function Set-BuildTagToTrigger | |
{ | |
param | |
( | |
[string] $BuildID="" | |
) | |
$reason = Get-BuildTrigger –BuildID $BuildID | |
Set-BuildTag –BuildID $BuildID –BuildTags $reason | |
} | |
Set-BuildTagToTrigger –BuildID $BuildID |
Add this script to your pipeline and call it using the $(Build.BuildId) parameter and you’re all set !
Trackbacks/Pingbacks
[…] Then, in the Release Pipeline that deploys this build, I set up the trigger Tag, so that it only releases builds with the right trigger. I’ve described that in my previous blog post […]
[…] Then, in the Release Pipeline that deploys this build, I set up the trigger Tag, so that it only releases builds with the right trigger. I’ve described that in my previous blog post […]