Last active
December 16, 2017 21:37
-
-
Save jsblock78/87ddefe3555ee8df28a631153638822e to your computer and use it in GitHub Desktop.
This script queues a build in VSTS/TFS, based on the build definition ID or the build definition name and waits until the build completes.
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
<# | |
.SYNOPSIS | |
Queues a build in TFS, and waits until it completes successfully. | |
.DESCRIPTION | |
This script queues a build in VSTS/TFS, based on the build definition ID or the build definition name and waits until the build completes. | |
.INPUTS | |
No objects can be piped to this script. | |
.OUTPUTS | |
System.Management.Automation.PSObject. Returns a PSObject representing details about the build. | |
.PARAMETER TeamFoundationCollectionUri | |
The URI of the team foundation collection. For example: https://fabrikamfiber.visualstudio.com/. | |
.PARAMETER TeamProject | |
The name of the team project that contains the build to modify. | |
.PARAMETER DefinitionId | |
The ID of the build definition. | |
.PARAMETER DefinitionName | |
The name of the build definition. | |
.PARAMETER PersonalAccessToken | |
The personal access token used to authenticate with TFS/VSTS. If omitted, the script will attempt to use the system OAUTH token or default credentials. | |
.PARAMETER UseDefaultCredentials | |
Uses the credentials of the current user to make the request. | |
.PARAMETER Timeout | |
The amount of time, in minutes, before the script times out. This defaults to 30 minutes. | |
.PARAMETER Interval | |
The amount of time, in seconds, between each request for the status of the build. This defaults to 5 seconds. | |
.EXAMPLE | |
# Start a new build for build definition id 42, and return the build information when it completes. | |
.\Invoke-TfsBuild.ps1 -DefinitionId 42 | |
.EXAMPLE | |
# Start a new build for the definition named "TestBuild" using a personal access token, and return the build information when it completes. | |
.\Invoke-TfsBuild.ps1 -DefinitionName TestBuild -PersalAccessToken $personalAccessToken | |
.NOTES | |
Author: Jeff Block <jeff.block@nosnitor.net> | |
About: http://www.rcsit.com/2017/12/16/executing-a-vsts-tfs-build/ | |
Location: https://gist.github.com/jsblock78/87ddefe3555ee8df28a631153638822e | |
#> | |
[CmdletBinding()] | |
Param( | |
[string] $TeamFoundationCollectionUri = $env:SYSTEM_TEAMFOUNDATIONCOLLECTIONURI, | |
[string] $TeamProject = $env:SYSTEM_TEAMPROJECT, | |
[int] $DefinitionId, | |
[string] $DefinitionName, | |
[string] $PersonalAccessToken = "", | |
[switch] $UseDefaultCredentials, | |
[int] $Timeout = 30, | |
[int] $Interval = 5 | |
) | |
# Validate parameters | |
If ([string]::IsNullOrEmpty($TeamFoundationCollectionUri)) { | |
Throw "TeamFoundationCollectionUri parameter cannot be null or empty." | |
} | |
If ([string]::IsNullOrEmpty($TeamProject)) { | |
Throw "TeamProject parameter cannot be null or empty." | |
} | |
If ((($DefinitionId -eq 0) -and ([string]::IsNullOrEmpty($DefinitionName))) -or (($DefinitionId -gt 0) -and (![string]::IsNullOrEmpty($DefinitionName)))) { | |
Throw "Either DefinitionId or DefinitionName parameter must be supplied, but not both." | |
} | |
If (!([string]::IsNullOrEmpty($PersonalAccessToken)) -and ($UseDefaultCredentials -eq $true)) { | |
Throw "PersonalAccessToken and UseDefaultCredentials parameters can not both be supplied." | |
} | |
Write-Verbose "TeamFoundationCollectionUri : $TeamFoundationCollectionUri" | |
Write-Verbose "TeamProject : $TeamProject" | |
$baseUrl = "$TeamFoundationCollectionUri/$TeamProject/_apis" | |
# Auth | |
$token = "" | |
$headers = $null | |
If (!($UseDefaultCredentials)) { | |
If (!([string]::IsNullOrEmpty($PersonalAccessToken))) { | |
Write-Verbose "Using personal access token." | |
$creds = ":$($PersonalAccessToken)" | |
$encodedCreds = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes($creds)) | |
$token = "Basic $encodedCreds" | |
$headers = @{Authorization = $token} | |
} | |
ElseIf (!([string]::IsNullOrEmpty($env:System_AccessToken))) { | |
Write-Verbose "Using system access token." | |
$token = "Bearer $($env:System_AccessToken)" | |
$headers = @{Authorization = $token} | |
} | |
Else { | |
$UseDefaultCredentials = $true | |
} | |
} | |
Write-Verbose "BaseUrl: [$baseUrl]" | |
Write-Verbose "Token: [$token]" | |
If ($DefinitionName) { | |
Write-Verbose "Definition Name : $DefinitionName" | |
# Get Definition ID | |
Try { | |
$Uri = "$baseUrl/build/definitions?api-version=2.0&name=$DefinitionName" | |
$response = Invoke-RestMethod -Uri $Uri -Method Get -Headers:$headers -UseDefaultCredentials:$UseDefaultCredentials | |
if ($response.GetType().Name -eq "String") { | |
if ($response.Contains("Visual Studio Team Services | Sign In")) { | |
Throw "Unable to authenticate using supplied authorization." | |
} | |
} | |
If ($response.Count -eq 0) | |
{ | |
Throw "No build definitions returned." | |
} | |
$DefinitionId = $response.value[0].Id | |
} | |
Catch { | |
Write-Host "##vso[task.logissue type=error;]Could not determine build definition ID from name `"$DefinitionName`". $($_.Exception.Message)" | |
Throw "Could not determine build definition ID from name `"$DefinitionName`". $($_.Exception.Message)" | |
} | |
} | |
Write-Verbose "DefinitionId : $DefinitionId" | |
If ($DefinitionId -gt 0) { | |
Try { | |
$body = @" | |
{ | |
"definition": { | |
"id": $DefinitionId | |
} | |
} | |
"@ | |
$buildUrl = "$baseUrl/build/builds`?api-version=2.0" | |
$response = Invoke-RestMethod -Uri $buildUrl -Method Post -Headers:$headers -UseDefaultCredentials:$UseDefaultCredentials -ContentType application/json -Body $body | |
if ($response.GetType().Name -eq "String") { | |
if ($response.Contains("Visual Studio Team Services | Sign In")) { | |
Throw "Unable to authenticate using supplied authorization." | |
} | |
} | |
$buildId = $response.id | |
} | |
Catch { | |
Write-Host "##vso[task.logissue type=error;]Could not start build with definition ID $DefinitionId." | |
Throw "Could not start build with definition ID $DefinitionId. $($_.Exception.Message)" | |
} | |
Try { | |
$buildUrl = "$baseUrl/build/builds/$BuildId`?api-version=2.0" | |
$ts = New-TimeSpan -Minutes $Timeout | |
$sw = [Diagnostics.Stopwatch]::StartNew() | |
while ($sw.elapsed -lt $ts) { | |
$response = Invoke-RestMethod -Method Get -Headers:$headers -UseDefaultCredentials:$UseDefaultCredentials -ContentType application/json -Uri $buildUrl | |
if ($response.GetType().Name -eq "String") { | |
if ($response.Contains("Visual Studio Team Services | Sign In")) { | |
Throw "Unable to authenticate using supplied authorization." | |
} | |
} | |
if ($response.status -eq "completed") { | |
Write-Verbose "Response:`r`n$response" | |
if ($response.result -ne "succeeded") | |
{ | |
Write-Host "##vso[task.logissue type=error;]Build $($response.buildNumber) failed." | |
Throw "Build $($response.buildNumber) failed." | |
} | |
return $response | |
} | |
Start-Sleep -Seconds $Interval | |
} | |
} | |
Catch { | |
Throw "An exception was encountered while checking status of build $buildId. $($_.Exception.Message)" | |
} | |
Throw "Timed out waiting for build to complete." | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment