Skip to content

Commit 2baf459

Browse files
feat: added optional DaysToKeep parameter to Save-AzDevOpsBuild (#383)
Co-authored-by: Stijn Moreels <9039753+stijnmoreels@users.noreply.github.com> Co-authored-by: Pim Simons <pim.simons@codit.eu>
1 parent 6207b8b commit 2baf459

5 files changed

Lines changed: 101 additions & 25 deletions

File tree

docs/preview/03-Features/powershell/azure-devops.md

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -175,18 +175,31 @@ Example of how to use this function in an Azure DevOps pipeline:
175175

176176
Saves/retains a specific Azure DevOps pipeline run.
177177

178-
| Parameter | Mandatory | Description |
179-
| --------------- | --------- | ---------------------------------------------------------------------------|
180-
| `ProjectId` | yes | The Id of the Project where the build that must be retained can be found |
181-
| `BuildId` | yes | The Id of the build that must be retained |
178+
| Parameter | Mandatory | Description |
179+
| --------------- | --------- | ---------------------------------------------------------------------------------------------------------------------------------- |
180+
| `ProjectId` | yes | The Id of the project where the build that must be retained can be found |
181+
| `BuildId` | yes | The Id of the build that must be retained |
182+
| `DaysToKeep` | no | The number of days to keep the Azure DevOps pipeline run, if not supplied the Azure DevOps pipeline run will be saved indefinitely |
182183

183184
**Example**
184185

186+
Saving an Azure DevOps pipeline run indefinitely
187+
185188
```powershell
186189
PS> Save-AzDevOpsBuild `
187190
-ProjectId $(System.TeamProjectId) `
188191
-BuildId $(Build.BuildId)
189-
# Saved Azure DevOps build with build ID $BuildId in project $ProjectId
192+
# Saved Azure DevOps build indefinitely with build ID $BuildId in project $ProjectId
193+
```
194+
195+
Saving an Azure DevOps pipeline run for 10 days
196+
197+
```powershell
198+
PS> Save-AzDevOpsBuild `
199+
-ProjectId $(System.TeamProjectId) `
200+
-BuildId $(Build.BuildId) `
201+
-DaysToKeep 10
202+
# Saved Azure DevOps build for 10 days with build ID $BuildId in project $ProjectId
190203
```
191204

192205
> 💡 The variables $(System.TeamProjectId) and $(Build.BuildId) are predefined Azure DevOps variables. Information on them can be found here: https://docs.microsoft.com/en-us/azure/devops/pipelines/build/variables?view=azure-devops&tabs=yaml

src/Arcus.Scripting.DevOps/Arcus.Scripting.DevOps.psm1

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,10 +98,11 @@ Export-ModuleMember -Function Set-AzDevOpsArmOutputsToPipelineVariables
9898
function Save-AzDevOpsBuild {
9999
param(
100100
[Parameter(Mandatory = $true)][string] $ProjectId = $(throw "ProjectId is required"),
101-
[Parameter(Mandatory = $true)][string] $BuildId = $(throw "BuildId is required")
101+
[Parameter(Mandatory = $true)][string] $BuildId = $(throw "BuildId is required"),
102+
[Parameter(Mandatory = $false)][int] $DaysToKeep
102103
)
103104

104-
. $PSScriptRoot\Scripts\Save-AzDevOpsBuild.ps1 -ProjectId $ProjectId -BuildId $BuildId
105+
. $PSScriptRoot\Scripts\Save-AzDevOpsBuild.ps1 -ProjectId $ProjectId -BuildId $BuildId -DaysToKeep $DaysToKeep
105106
}
106107

107108
Export-ModuleMember -Function Save-AzDevOpsBuild
Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,35 @@
11
param(
22
[Parameter(Mandatory = $true)][string] $ProjectId = $(throw "ProjectId is required"),
3-
[Parameter(Mandatory = $true)][string] $BuildId = $(throw "BuildId is required")
3+
[Parameter(Mandatory = $true)][string] $BuildId = $(throw "BuildId is required"),
4+
[Parameter(Mandatory = $false)][int] $DaysToKeep
45
)
56

6-
$retentionPayload = @{
7-
keepforever='true'
7+
if ($DaysToKeep -eq '' -Or $DaysToKeep -eq 0) {
8+
$daysValid = 99999
9+
} else {
10+
$daysValid = $DaysToKeep
811
}
912

10-
$requestBody = $retentionPayload | ConvertTo-Json -Depth 1 -Compress
13+
$retentionPayload = @{ daysValid = $daysValid; definitionId = $env:SYSTEM_DEFINITIONID; ownerId = "User:$env:BUILD_REQUESTEDFORID"; protectPipeline = $true; runId = $BuildId };
14+
$requestBody = ConvertTo-Json @($retentionPayload);
1115

1216
$collectionUri = $env:SYSTEM_COLLECTIONURI
1317
if ($collectionUri.EndsWith('/') -eq $false) {
14-
$collectionUri = $collectionUri + '/'
18+
$collectionUri = $collectionUri + '/'
1519
}
1620

17-
$requestUri = "$collectionUri" + "$ProjectId/_apis/build/builds/" + $BuildId + "?api-version=6.0"
21+
$urlEncodedProjectId = [uri]::EscapeDataString($ProjectId)
22+
$requestUri = "$collectionUri" + "$urlEncodedProjectId/_apis/build/retention/leases?api-version=7.0"
1823

19-
Write-Verbose "Saving Azure DevOps build with build ID $BuildId in project $ProjectId by posting '$requestBody' to '$requestUri'..."
20-
$response = Invoke-WebRequest -Uri $requestUri -Method Patch -Body $requestBody -ContentType "application/json" -Headers @{ Authorization = "Bearer $env:SYSTEM_ACCESSTOKEN" }
24+
Write-Verbose "Saving Azure DevOps build for $daysValid days with build ID $BuildId in project $ProjectId by posting '$requestBody' to '$requestUri'..."
25+
$response = Invoke-WebRequest -Uri $requestUri -Method Post -Body $requestBody -ContentType "application/json" -Headers @{ Authorization = "Bearer $env:SYSTEM_ACCESSTOKEN" }
2126

2227
if ($response.StatusCode -ne 200) {
23-
throw "Unable to retain Azure DevOps build indefinetely with build ID $BuildId in project $ProjectId. API request returned statuscode $($response.StatusCode)"
28+
throw "Unable to retain Azure DevOps build with build ID $BuildId in project $ProjectId. API request returned statuscode $($response.StatusCode)"
2429
}
2530

26-
Write-Host "Saved Azure DevOps build with build ID $BuildId in project $ProjectId" -ForegroundColor Green
31+
if ($DaysToKeep -eq '') {
32+
Write-Host "Saved Azure DevOps build indefinitely with build ID $BuildId in project $ProjectId" -ForegroundColor Green
33+
} else {
34+
Write-Host "Saved Azure DevOps build for $DaysToKeep days with build ID $BuildId in project $ProjectId" -ForegroundColor Green
35+
}

src/Arcus.Scripting.Tests.Integration/Arcus.Scripting.DevOps.tests.ps1

Lines changed: 44 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,12 @@ InModuleScope Arcus.Scripting.DevOps {
77
& $PSScriptRoot\Connect-AzAccountFromConfig.ps1 -config $config
88
}
99
Context "Save Azure DevOps build" {
10-
It "Saves the Azure DevOps build indefinetely" {
10+
It "Saves the Azure DevOps build indefinitely" {
1111
# Arrange
1212
$projectId = $env:SYSTEM_TEAMPROJECTID
1313
$buildId = $env:BUILD_BUILDID
1414
$collectionUri = $env:SYSTEM_COLLECTIONURI
15-
$requestUri = "$collectionUri" + "$projectId/_apis/build/builds/" + $buildId + "?api-version=6.0"
15+
$requestUri = "$collectionUri" + "$projectId/_apis/build/builds/" + $buildId + "/leases?api-version=7.0"
1616
$headers = @{ Authorization = "Bearer $env:SYSTEM_ACCESSTOKEN" }
1717
try {
1818
# Act
@@ -21,12 +21,49 @@ InModuleScope Arcus.Scripting.DevOps {
2121
# Assert
2222
$getResponse = Invoke-WebRequest -Uri $requestUri -Method Get -Headers $headers
2323
$json = ConvertFrom-Json $getResponse.Content
24-
$json.keepForever | Should -Be $true
24+
foreach ($lease in $json.value) {
25+
$lease.protectPipeline | Should -Be $true
26+
$date = Get-Date -Year 2200 -Month 1 -Day 1
27+
$lease.validUntil | Should -BeGreaterThan $date
28+
}
2529
} finally {
26-
$retentionPayload = @{ keepforever='false' }
27-
$requestBody = $retentionPayload | ConvertTo-Json -Compress
28-
$patchResponse = Invoke-WebRequest -Uri $requestUri -Method Patch -Headers $headers -Body $requestBody -ContentType "application/json"
29-
$patchResponse.StatusCode | Should -Be 200
30+
$getResponse = Invoke-WebRequest -Uri $requestUri -Method Get -Headers $headers
31+
$json = ConvertFrom-Json $getResponse.Content
32+
foreach ($lease in $json.value) {
33+
$deleteUri = "$collectionUri" + "$projectId/_apis/build/retention/leases?ids=" + $lease.leaseId + "&api-version=7.0"
34+
$deleteResponse = Invoke-WebRequest -Uri $deleteUri -Method Delete -Headers $headers
35+
$deleteResponse.StatusCode | Should -Be 204
36+
}
37+
}
38+
}
39+
It "Saves the Azure DevOps build for 10 days" {
40+
# Arrange
41+
$projectId = $env:SYSTEM_TEAMPROJECTID
42+
$buildId = $env:BUILD_BUILDID
43+
$collectionUri = $env:SYSTEM_COLLECTIONURI
44+
$requestUri = "$collectionUri" + "$projectId/_apis/build/builds/" + $buildId + "/leases?api-version=7.0"
45+
$headers = @{ Authorization = "Bearer $env:SYSTEM_ACCESSTOKEN" }
46+
try {
47+
# Act
48+
Save-AzDevOpsBuild -ProjectId $projectId -BuildId $buildId -DaysToKeep 10
49+
50+
# Assert
51+
$getResponse = Invoke-WebRequest -Uri $requestUri -Method Get -Headers $headers
52+
$json = ConvertFrom-Json $getResponse.Content
53+
foreach ($lease in $json.value) {
54+
$lease.protectPipeline | Should -Be $true
55+
$expectedDate = (Get-Date).AddDays(10)
56+
$actualDate = [DateTime]$lease.validUntil
57+
$actualDate.ToUniversalTime().ToString("yyyy-MM-dd") | Should -Be $expectedDate.ToUniversalTime().ToString("yyyy-MM-dd")
58+
}
59+
} finally {
60+
$getResponse = Invoke-WebRequest -Uri $requestUri -Method Get -Headers $headers
61+
$json = ConvertFrom-Json $getResponse.Content
62+
foreach ($lease in $json.value) {
63+
$deleteUri = "$collectionUri" + "$projectId/_apis/build/retention/leases?ids=" + $lease.leaseId + "&api-version=7.0"
64+
$deleteResponse = Invoke-WebRequest -Uri $deleteUri -Method Delete -Headers $headers
65+
$deleteResponse.StatusCode | Should -Be 204
66+
}
3067
}
3168
}
3269
It "Sets the DevOps variable group description with the release name" -Skip {

src/Arcus.Scripting.Tests.Unit/Arcus.Scripting.DevOps.tests.ps1

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ InModuleScope Arcus.Scripting.DevOps {
205205
# Act and Assert
206206
{ Save-AzDevOpsBuild -ProjectId $projectId -BuildId $buildId } | Should -Throw
207207
}
208-
It "Save-AzDevOpsBuild succeeds when API call does return success-code" {
208+
It "Save-AzDevOpsBuild indefinitely succeeds when API call does return success-code" {
209209
# Arrange
210210
$env:SYSTEM_COLLECTIONURI = "https://dev.azure.com/myorganization/"
211211
$env:ACCESS_TOKEN = "mocking accesstoken"
@@ -221,6 +221,22 @@ InModuleScope Arcus.Scripting.DevOps {
221221
# Act and Assert
222222
{ Save-AzDevOpsBuild -ProjectId $projectId -BuildId $buildId } | Should -Not -Throw
223223
}
224+
It "Save-AzDevOpsBuild for 10 days succeeds when API call does return success-code" {
225+
# Arrange
226+
$env:SYSTEM_COLLECTIONURI = "https://dev.azure.com/myorganization/"
227+
$env:ACCESS_TOKEN = "mocking accesstoken"
228+
$projectId = "abc123"
229+
$buildId = 128
230+
231+
Mock Invoke-WebRequest {
232+
$statusCode = 200
233+
$response = New-Object System.Net.Http.HttpResponseMessage $statusCode
234+
return $response
235+
} -ModuleName Arcus.Scripting.DevOps
236+
237+
# Act and Assert
238+
{ Save-AzDevOpsBuild -ProjectId $projectId -BuildId $buildId -DaysToKeep 10} | Should -Not -Throw
239+
}
224240
It "Save-AzDevOpsBuild correctly builds API endpoint when CollectionUri has trailing slash" {
225241
# Arrange
226242
$env:SYSTEM_COLLECTIONURI = "https://dev.azure.com/myorganization/"

0 commit comments

Comments
 (0)