Last active
June 5, 2019 15:55
-
-
Save MarcusFelling/3a0d9387495c0be3ee664dea541b4fc4 to your computer and use it in GitHub Desktop.
This file contains hidden or 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
<# | |
.DESCRIPTION | |
Creates a new release for the specified release definition name, using the latest artifact versions available | |
.Parameter PAT | |
Personal Access token. It's recommended to use a service account and pass via encrypted build definition variable. | |
https://docs.microsoft.com/en-us/vsts/organizations/accounts/use-personal-access-tokens-to-authenticate?view=vsts | |
.Parameter ReleaseDefinitionName | |
Name of release definition to create a release for | |
.Notes | |
-Parameters are outside of functions in order to be passed by TFS build definition variables | |
#> | |
[CmdletBinding()] | |
Param | |
( | |
[String] [Parameter(Mandatory = $true)] | |
$PAT, | |
[String] [Parameter(Mandatory = $true)] | |
$ReleaseDefinitionName | |
) | |
# Base64-encodes the Personal Access Token (PAT) appropriately | |
# This is required to pass PAT through HTTP header | |
$script:User = "" # Not needed when using PAT, can be set to anything | |
$script:Base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $User, $PAT))) | |
Function Find-ReleaseDefinition { | |
Param([Parameter(Mandatory = $true)] $TfsUri) | |
$url = [string]::Format("{0}{1}/_apis/release/definitions?`$expand=artifacts&api-version=3.0-preview.1", $TfsUri, $TeamProject) | |
"url= $url" | |
$result = $null | |
Try | |
{ | |
$result = Invoke-RestMethod -Uri $url -Method GET -ContentType "application/json" -Headers @{Authorization = ("Basic {0}" -f $base64AuthInfo)} | |
} | |
Catch | |
{ | |
Write-Verbose $_.Exception.ToString() | |
$response = $_.Exception.Response | |
$responseStream = $response.GetResponseStream() | |
$streamReader = New-Object System.IO.StreamReader($responseStream) | |
$streamReader.BaseStream.Position = 0 | |
$streamReader.DiscardBufferedData() | |
$responseBody = $streamReader.ReadToEnd() | |
$streamReader.Close() | |
Write-Error $responseBody | |
} | |
return $result.value | Where-Object {$_.name -eq $ReleaseDefinitionName} | |
} | |
Function Get-ArtifactsVersions { | |
Param | |
( | |
[Parameter(Mandatory = $true)] $TfsUri, | |
[Parameter(Mandatory = $true)] $Artifacts | |
) | |
"Get artifacts versions" | |
$url = [string]::Format("{0}{1}/_apis/release/artifacts/versions?releaseDefinitionId={2}&api-version=3.0-preview.1", $TfsUri, $TeamProject, $definition.id) | |
"url= $url" | |
$result = $null | |
Try | |
{ | |
$result = Invoke-RestMethod -Uri $url -Method Get -Body $body -ContentType "application/json" -Headers @{Authorization = ("Basic {0}" -f $base64AuthInfo)} | |
} | |
Catch | |
{ | |
Write-Verbose $_.Exception.ToString() | |
$response = $_.Exception.Response | |
$responseStream = $response.GetResponseStream() | |
$streamReader = New-Object System.IO.StreamReader($responseStream) | |
$streamReader.BaseStream.Position = 0 | |
$streamReader.DiscardBufferedData() | |
$responseBody = $streamReader.ReadToEnd() | |
$streamReader.Close() | |
Write-Error $responseBody | |
} | |
return $result | |
} | |
Function Get-Artifacts { | |
Param | |
( | |
[Parameter(Mandatory = $true)] $TfsUri, | |
[Parameter(Mandatory = $true)] $ReleaseDefinition | |
) | |
$artifacts = @() | |
$defArtifacts = $ReleaseDefinition.artifacts | |
If ($null -eq $defArtifacts) | |
{ | |
Write-Error "Cannot find artifacts for the Release Definition." | |
} | |
$versions = Get-ArtifactsVersions -TfsUri $TfsUri -Artifacts $defArtifacts | |
If ($null -eq $versions) | |
{ | |
Write-Error "Cannot find artifacts versions." | |
} | |
foreach ($artifact in $defArtifacts) | |
{ | |
$latestVersion = $versions.artifactVersions | Where-Object -Property alias -eq -Value $artifact.alias | |
$latestVersion = $latestVersion.versions[0] | |
$artifacts += @{ | |
alias = $artifact.alias | |
instanceReference = @{ | |
name = $latestVersion.name | |
id = $latestVersion.id | |
} | |
} | |
} | |
return $artifacts | |
} | |
Function CreateRelease { | |
Param | |
( | |
[Parameter(Mandatory = $true)] $TfsUri, | |
[Parameter(Mandatory = $true)] $ReleaseDefinition, | |
[Parameter(Mandatory = $true)] $Artifacts | |
) | |
"Create release" | |
$url = [string]::Format("{0}{1}/_apis/release/releases?api-version=3.0-preview.1", $TfsUri, $TeamProject) | |
"url= $url" | |
$body = @{ | |
definitionId = $ReleaseDefinition.id | |
description = "" | |
artifacts = $Artifacts | |
isDraft = $false | |
manualEnvironments = @() | |
} | ConvertTo-Json -Depth 4 | |
"body= $body" | |
$result = $null | |
# Create release | |
Try | |
{ | |
$result = Invoke-RestMethod -Uri $url -Method POST -Body $body -ContentType "application/json" -Headers @{Authorization = ("Basic {0}" -f $base64AuthInfo)} | |
} | |
Catch | |
{ | |
Write-Verbose $_.Exception.ToString() | |
$response = $_.Exception.Response | |
$responseStream = $response.GetResponseStream() | |
$streamReader = New-Object System.IO.StreamReader($responseStream) | |
$streamReader.BaseStream.Position = 0 | |
$streamReader.DiscardBufferedData() | |
$responseBody = $streamReader.ReadToEnd() | |
$streamReader.Close() | |
Write-Error $responseBody | |
} | |
# Get release ID from release that was created above | |
$releaseID = $result.id | |
# Wait for deployment to complete | |
Do | |
{ | |
"Deployment of $ReleaseDefinitionName in progress..." | |
# Wait 10 seconds before checking status of release | |
Start-Sleep -s 10 | |
# Use release ID to get status of deployment | |
$url = [string]::Format("{0}{1}/_apis/release/releases/{2}?api-version=3.0-preview.1", $TfsUri, $TeamProject, $releaseID) | |
Try | |
{ | |
$CheckDeployStatusResult = Invoke-RestMethod -Uri $url -Method Get -ContentType "application/json" -Headers @{Authorization = ("Basic {0}" -f $base64AuthInfo)} | |
} | |
Catch | |
{ | |
Write-Verbose $_.Exception.ToString() | |
$response = $_.Exception.Response | |
$responseStream = $response.GetResponseStream() | |
$streamReader = New-Object System.IO.StreamReader($responseStream) | |
$streamReader.BaseStream.Position = 0 | |
$streamReader.DiscardBufferedData() | |
$responseBody = $streamReader.ReadToEnd() | |
$streamReader.Close() | |
Write-Error $responseBody | |
} | |
$deploymentstatus = $CheckDeployStatusResult.environments.status | |
} | |
Until($deploymentstatus -ne "notStarted" -and $deploymentstatus -ne "inProgress") | |
# https://docs.microsoft.com/en-us/rest/api/vsts/release/releases/get%20release?view=vsts-rest-4.1#deployphasestatus | |
Switch($deploymentstatus) | |
{ | |
"canceled" | |
{ | |
Write-Error "Deployment canceled" | |
} | |
"cancelling" | |
{ | |
Write-Error "Deployment cancelling" | |
} | |
"failed" | |
{ | |
Write-Error "Deployment failed" | |
} | |
"partiallySucceeded" | |
{ | |
Write-Error "Deployment partiallySucceeded" | |
} | |
"skipped" | |
{ | |
Write-Error "Deployment skipped" | |
} | |
"succeeded" | |
{ | |
"Deployment succeeded" | |
} | |
"undefined" | |
{ | |
Write-Error "Deployment undefined" | |
} | |
default | |
{ | |
Write-Error "Deployment did not succeed" | |
} | |
} | |
} | |
$ErrorActionPreference = 'Stop' | |
"ReleaseDefinitionName= $ReleaseDefinitionName" | |
$TeamProject= "$env:SYSTEM_TEAMPROJECT" | |
"TeamPreojct= $TeamProject" | |
$tfsUri = "$env:SYSTEM_TEAMFOUNDATIONCOLLECTIONURI" | |
"TfsUri= $tfsUri" | |
$definition = Find-ReleaseDefinition -TfsUri $tfsUri | |
If ($null -eq $definition -or $definition.Count -gt 2) | |
{ | |
Write-Error "Cannot find Release Definition or there are more than one Release Definition with the name." | |
} | |
$artifacts = @(Get-Artifacts -TfsUri $tfsUri -ReleaseDefinition $definition) | |
CreateRelease -TfsUri $tfsUri -ReleaseDefinition $definition -Artifacts $artifacts |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment