diff --git a/docs/preview/03-Features/powershell/azure-devops.md b/docs/preview/03-Features/powershell/azure-devops.md
index e8821856..bc8ce134 100644
--- a/docs/preview/03-Features/powershell/azure-devops.md
+++ b/docs/preview/03-Features/powershell/azure-devops.md
@@ -40,6 +40,22 @@ PS> Set-AzDevOpsVariable "my-variable" "my-variable-value" -AsSecret
##vso[task.setvariable variable=my-variable;issecret=true] ***
```
+## Setting a variable in an Azure DevOps variable group
+
+Assign a value to a DevOps variable group during the execution of a pipeline.
+
+| Parameter | Mandatory | Description |
+| --------------------- | --------- | ------------------------------------------------------ |
+| `VariableGroupName` | yes | The name of the remote variable group on Azure DevOps |
+| `VariableName` | yes | The name of the variable to set in the variable group |
+| `VariableValue` | yes | The value of the variable to set in the variable group |
+
+**Example**
+
+```powershell
+PS> Set-AzDevOpsGroupVariable -VariableGroupName "product-v1-dev" -VariableName "Product.Api.Url" -VariableValue "https://product/api/"
+```
+
## Setting ARM outputs to Azure DevOps variable group
Stores the Azure Resource Management (ARM) outputs in a variable group on Azure DevOps.
diff --git a/src/Arcus.Scripting.DevOps/Arcus.Scripting.DevOps.psd1 b/src/Arcus.Scripting.DevOps/Arcus.Scripting.DevOps.psd1
index 728c1b72..b7faba8c 100644
Binary files a/src/Arcus.Scripting.DevOps/Arcus.Scripting.DevOps.psd1 and b/src/Arcus.Scripting.DevOps/Arcus.Scripting.DevOps.psd1 differ
diff --git a/src/Arcus.Scripting.DevOps/Arcus.Scripting.DevOps.psm1 b/src/Arcus.Scripting.DevOps/Arcus.Scripting.DevOps.psm1
index 87586675..c414814d 100644
--- a/src/Arcus.Scripting.DevOps/Arcus.Scripting.DevOps.psm1
+++ b/src/Arcus.Scripting.DevOps/Arcus.Scripting.DevOps.psm1
@@ -5,10 +5,10 @@
.Description
Assign a value to a DevOps pipeline variable during the execution of this pipeline.
- .Parameter VariableName
+ .Parameter Name
The name of the variable to set in the pipeline.
- .Parameter VariableValue
+ .Parameter Value
The value of the variable to set in the pipeline.
#>
function Set-AzDevOpsVariable {
@@ -27,6 +27,34 @@ function Set-AzDevOpsVariable {
Export-ModuleMember -Function Set-AzDevOpsVariable
+<#
+ .Synopsis
+ Set a variable in the Azure DevOps variable group.
+
+ .Description
+ Assign a value to a DevOps variable group during the execution of an Azure DevOps pipeline.
+
+ .Parameter VariableGroupName
+ The name of the Azure DevOps variable group to updat with a new variable.
+
+ .Parameter VariableName
+ The name of the variable to set in the variable group.
+
+ .Parameter VariableValue
+ The value of the variable to set in the variable group.
+#>
+function Set-AzDevOpsGroupVariable {
+ param(
+ [string][parameter(Mandatory = $true)]$VariableGroupName,
+ [string][parameter(Mandatory = $true)]$VariableName,
+ [string][parameter(Mandatory = $true)]$VariableValue
+ )
+
+ . $PSScriptRoot\Scripts\Set-AzDevOpsGroupVariable.ps1 -VariableGroupName $VariableGroupName -VariableName $VariableName -VariableValue $VariableValue
+}
+
+Export-ModuleMember -Function Set-AzDevOpsGroupVariable
+
<#
.Synopsis
Sets the ARM outputs as a variable group on Azure DevOps.
diff --git a/src/Arcus.Scripting.DevOps/Arcus.Scripting.DevOps.pssproj b/src/Arcus.Scripting.DevOps/Arcus.Scripting.DevOps.pssproj
index 1ba027ce..4b1290c2 100644
--- a/src/Arcus.Scripting.DevOps/Arcus.Scripting.DevOps.pssproj
+++ b/src/Arcus.Scripting.DevOps/Arcus.Scripting.DevOps.pssproj
@@ -34,6 +34,7 @@
+
diff --git a/src/Arcus.Scripting.DevOps/Scripts/Set-AzDevOpsArmOutputs.ps1 b/src/Arcus.Scripting.DevOps/Scripts/Set-AzDevOpsArmOutputs.ps1
index f044a88d..462811a0 100644
--- a/src/Arcus.Scripting.DevOps/Scripts/Set-AzDevOpsArmOutputs.ps1
+++ b/src/Arcus.Scripting.DevOps/Scripts/Set-AzDevOpsArmOutputs.ps1
@@ -5,59 +5,6 @@ param(
[switch][parameter(Mandatory = $false)] $UpdateVariablesForCurrentJob = $false
)
-function Add-VariableGroupVariable() {
- [CmdletBinding()]
- param(
- [string][parameter(Mandatory = $true)]$VariableGroupName,
- [string][parameter(Mandatory = $true)]$variableName,
- [string][parameter(Mandatory = $true)]$variableValue
- )
- BEGIN {
- Write-Verbose "Retrieving Azure DevOps project details for variable group '$VariableGroupName'..."
- [String]$project = "$env:SYSTEM_TEAMPROJECT"
- [String]$projectUri = "$env:SYSTEM_TEAMFOUNDATIONCOLLECTIONURI"
- [String]$apiVersion = "4.1-preview.1"
- Write-Debug "Using Azure DevOps project: $project, project URI: $projectUri"
-
-
- Write-Verbose "Setting authorization headers to retrieve potential existing Azure DevOps variable group '$VariableGroupName'..."
- if ([string]::IsNullOrEmpty($env:SYSTEM_ACCESSTOKEN)) {
- Write-Error "The SYSTEM_ACCESSTOKEN environment variable is empty. Remember to explicitly allow the build job to access the OAuth Token!"
- }
- $headers = @{ Authorization = "Bearer $env:SYSTEM_ACCESSTOKEN" }
-
-
- Write-Verbose "Getting Azure DevOps variable group '$VariableGroupName'..."
- $getVariableGroupUrl = $projectUri + $project + "/_apis/distributedtask/variablegroups?api-version=" + $apiVersion + "&groupName=" + $VariableGroupName
- $variableGroup = (Invoke-RestMethod -Uri $getVariableGroupUrl -Headers $headers -Verbose)
-
- $releaseName = $env:RELEASE_RELEASENAME
- if ([string]::IsNullOrEmpty($releaseName)) {
- $releaseName = $env:BUILD_DEFINITIONNAME + " " + $env:BUILD_BUILDNUMBER
- }
-
- if ($variableGroup.value) {
- Write-Host "Set properties for update of existing Azure DevOps variable group '$variableGroupName'"
- $variableGroup = $variableGroup.value[0]
- $variableGroup | Add-Member -Name "description" -MemberType NoteProperty -Value "Variable group that got auto-updated by release '$releaseName'." -Force
- $method = "Put"
- $upsertVariableGroupUrl = $projectUri + $project + "/_apis/distributedtask/variablegroups/" + $variableGroup.id + "?api-version=" + $apiVersion
- } else {
- Write-Host "Set properties for creation of new Azure DevOps variable group '$VariableGroupName'"
- $variableGroup = @{name = $VariableGroupName; type = "Vsts"; description = "Variable group that got auto-updated by release '$releaseName'."; variables = New-Object PSObject; }
- $method = "Post"
- $upsertVariableGroupUrl = $projectUri + $project + "/_apis/distributedtask/variablegroups?api-version=" + $apiVersion
- }
-
- $variableGroup.variables | Add-Member -Name $variableName -MemberType NoteProperty -Value @{value = $variableValue } -Force
-
- Write-Verbose "Upserting Azure DevOps variable group '$variableGroupName'..."
- $body = $variableGroup | ConvertTo-Json -Depth 10 -Compress
- Write-Debug $body
- Invoke-RestMethod $upsertVariableGroupUrl -Method $method -Body $body -Headers $headers -ContentType 'application/json; charset=utf-8' -Verbose
- }
-}
-
Write-Verbose "Geting ARM outputs from '$ArmOutputsEnvironmentVariableName' environment variable..."
$json = [System.Environment]::GetEnvironmentVariable($ArmOutputsEnvironmentVariableName)
$armOutputs = ConvertFrom-Json $json
@@ -68,7 +15,7 @@ foreach ($output in $armOutputs.PSObject.Properties) {
if ($UpdateVariableGroup) {
Write-Host Adding variable $output.Name with value $variableValue to variable group $VariableGroupName
- Add-VariableGroupVariable -VariableGroupName $VariableGroupName -variableName $variableName -variableValue $variableValue
+ . $PSScriptRoot\Set-AzDevOpsGroupVariable.ps1 -VariableGroupName $VariableGroupName -VariableName $variableName -VariableValue $variableValue
}
if ($UpdateVariablesForCurrentJob) {
diff --git a/src/Arcus.Scripting.DevOps/Scripts/Set-AzDevOpsGroupVariable.ps1 b/src/Arcus.Scripting.DevOps/Scripts/Set-AzDevOpsGroupVariable.ps1
new file mode 100644
index 00000000..4d11274a
--- /dev/null
+++ b/src/Arcus.Scripting.DevOps/Scripts/Set-AzDevOpsGroupVariable.ps1
@@ -0,0 +1,50 @@
+param(
+ [string][parameter(Mandatory = $true)]$VariableGroupName,
+ [string][parameter(Mandatory = $true)]$VariableName,
+ [string][parameter(Mandatory = $true)]$VariableValue
+)
+
+Write-Verbose "Retrieving Azure DevOps project details for variable group '$VariableGroupName'..."
+[String]$project = "$env:SYSTEM_TEAMPROJECT"
+[String]$projectUri = "$env:SYSTEM_TEAMFOUNDATIONCOLLECTIONURI"
+[String]$apiVersion = "7.1"
+Write-Debug "Using Azure DevOps project: $project, project URI: $projectUri"
+
+
+Write-Verbose "Setting authorization headers to retrieve potential existing Azure DevOps variable group '$VariableGroupName'..."
+if ([string]::IsNullOrEmpty($env:SYSTEM_ACCESSTOKEN)) {
+ Write-Error "The SYSTEM_ACCESSTOKEN environment variable is empty. Remember to explicitly allow the build job to access the OAuth Token!"
+}
+$headers = @{ Authorization = "Bearer $env:SYSTEM_ACCESSTOKEN" }
+
+
+Write-Verbose "Getting Azure DevOps variable group '$VariableGroupName'..."
+$getVariableGroupUrl = $projectUri + $project + "/_apis/distributedtask/variablegroups?api-version=" + $apiVersion + "&groupName=" + $VariableGroupName
+$variableGroup = (Invoke-RestMethod -Uri $getVariableGroupUrl -Headers $headers -Verbose)
+
+$releaseName = $env:RELEASE_RELEASENAME
+if ([string]::IsNullOrEmpty($releaseName)) {
+ $releaseName = $env:BUILD_DEFINITIONNAME + " " + $env:BUILD_BUILDNUMBER
+}
+
+if ($variableGroup.value) {
+ Write-Host "Set properties for update of existing Azure DevOps variable group '$variableGroupName'"
+ $variableGroup = $variableGroup.value[0]
+ $variableGroup | Add-Member -Name "description" -MemberType NoteProperty -Value "Variable group that got auto-updated by pipeline '$releaseName'." -Force
+ $method = "Put"
+ $upsertVariableGroupUrl = $projectUri + $project + "/_apis/distributedtask/variablegroups/" + $variableGroup.id + "?api-version=" + $apiVersion
+} else {
+ Write-Host "Set properties for creation of new Azure DevOps variable group '$VariableGroupName'"
+ $variableGroup = @{name = $VariableGroupName; type = "Vsts"; description = "Variable group that got auto-updated by pipeline '$releaseName'."; variables = New-Object PSObject; }
+ $method = "Post"
+ $upsertVariableGroupUrl = $projectUri + $project + "/_apis/distributedtask/variablegroups?api-version=" + $apiVersion
+}
+
+$variableGroup.variables | Add-Member -Name $VariableName -MemberType NoteProperty -Value @{value = $VariableValue } -Force
+
+Write-Verbose "Upserting Azure DevOps variable group '$variableGroupName'..."
+$body = $variableGroup | ConvertTo-Json -Depth 10 -Compress
+Write-Host $body
+
+Write-Host "$method -> $upsertVariableGroupUrl"
+Invoke-RestMethod $upsertVariableGroupUrl -Method $method -Body $body -Headers $headers -ContentType 'application/json; charset=utf-8' -Verbose
diff --git a/src/Arcus.Scripting.Tests.Integration/Arcus.Scripting.DevOps.tests.ps1 b/src/Arcus.Scripting.Tests.Integration/Arcus.Scripting.DevOps.tests.ps1
index 5ccb0192..4646a00c 100644
--- a/src/Arcus.Scripting.Tests.Integration/Arcus.Scripting.DevOps.tests.ps1
+++ b/src/Arcus.Scripting.Tests.Integration/Arcus.Scripting.DevOps.tests.ps1
@@ -1,5 +1,66 @@
Import-Module -Name $PSScriptRoot\..\Arcus.Scripting.DevOps -ErrorAction Stop
+function global:Get-AzDevOpsGroup {
+ param($VariableGroupName)
+
+ $VariableGroupName = $VariableGroupName -replace ' ', '%20'
+ $projectId = $env:SYSTEM_TEAMPROJECTID
+ $collectionUri = $env:SYSTEM_COLLECTIONURI
+ $getUri = "$collectionUri" + "$projectId/_apis/distributedtask/variablegroups?groupName=" + $VariableGroupName + "&api-version=7.1"
+ $headers = @{ Authorization = "Bearer $env:SYSTEM_ACCESSTOKEN" }
+
+ Write-Host "GET -> $getUri"
+ $getResponse = Invoke-WebRequest -Uri $getUri -Method Get -Headers $headers
+ $json = ConvertFrom-Json $getResponse.Content
+
+ $variableGroup = $json.value[0]
+ Write-Host "$($getResponse.StatusCode) $variableGroup <- $getUri"
+
+ return $variableGroup
+}
+
+function global:Remove-AzDevOpsVariableGroup {
+ param($VariableGroupName)
+
+ $variableGroup = Get-AzDevOpsGroup -VariableGroupName $VariableGroupName
+
+ $VariableGroupName = $VariableGroupName -replace ' ', '%20'
+ $projectId = $env:SYSTEM_TEAMPROJECTID
+ $collectionUri = $env:SYSTEM_COLLECTIONURI
+ $deleteUri = "$collectionUri" + "$projectId/_apis/distributedtask/variablegroups/" + $variableGroup.id + "?api-version=7.1"
+ $headers = @{ Authorization = "Bearer $env:SYSTEM_ACCESSTOKEN" }
+
+ Write-Host "DELETE -> $deleteUri"
+ $deleteResponse = Invoke-WebRequest -Uri $deleteUri -Method Delete -Headers $headers
+ Write-Host "$($deleteResponse.StatusCode) <- $deleteUri"
+}
+
+function global:Get-AzDevOpsGroupVariable {
+ param($VariableGroupName, $VariableName)
+
+ $json = Get-AzDevOpsGroup -VariableGroupName $VariableGroupName
+ $variable = $json.variables.PSObject.Properties | where { $_.Name -eq $VariableName }
+
+ return $variable
+}
+
+function global:Remove-AzDevOpsGroupVariable {
+ param($VariableGroupName, $VariableName)
+
+ $json = Get-AzDevOpsGroup -VariableGroupName $VariableGroupName
+ $json.variables.PSObject.Properties.Remove($VariableName)
+
+ $project = "$env:SYSTEM_TEAMPROJECT"
+ $projectUri = "$env:SYSTEM_TEAMFOUNDATIONCOLLECTIONURI"
+ $upsertVariableGroupUrl = $projectUri + $project + "/_apis/distributedtask/variablegroups/$($json.id)?api-version=7.1"
+ $headers = @{ Authorization = "Bearer $env:SYSTEM_ACCESSTOKEN" }
+
+ $json = $json | ConvertTo-Json -Depth 10 -Compress
+ Write-Host "PUT $json -> $upsertVariableGroupUrl"
+ $putResponse = Invoke-WebRequest -Uri $upsertVariableGroupUrl -Method Put -Headers $headers -Body $json -ContentType 'application/json; charset=utf-8'
+ Write-Host "$($putResponse.StatusCode) <- $upsertVariableGroupUrl"
+}
+
InModuleScope Arcus.Scripting.DevOps {
Describe "Arcus Azure DevOps integration tests" {
BeforeEach {
@@ -43,6 +104,7 @@ InModuleScope Arcus.Scripting.DevOps {
$collectionUri = $env:SYSTEM_COLLECTIONURI
$requestUri = "$collectionUri" + "$projectId/_apis/build/builds/" + $buildId + "/leases?api-version=7.0"
$headers = @{ Authorization = "Bearer $env:SYSTEM_ACCESSTOKEN" }
+
try {
# Act
Save-AzDevOpsBuild -ProjectId $projectId -BuildId $buildId -DaysToKeep 10
@@ -66,6 +128,8 @@ InModuleScope Arcus.Scripting.DevOps {
}
}
}
+ }
+ Context "Azure DevOps variable group" {
It "Sets the DevOps variable group description with the release name" {
# Arrange
$variableGroupName = $config.Arcus.DevOps.VariableGroup.Name
@@ -86,6 +150,40 @@ InModuleScope Arcus.Scripting.DevOps {
$json = ConvertFrom-Json $getResponse.Content
$json.value[0].description | Should -BeLike "*$env:Build_DefinitionName*$env:Build_BuildNumber*"
}
+ It "Sets a new variable to an existing DevOps variable group" {
+ # Arrange
+ $variableGroupName = $config.Arcus.DevOps.VariableGroup.Name
+ $variableName = [System.Guid]::NewGuid().ToString()
+ $expectedValue = [System.Guid]::NewGuid().ToString()
+ try {
+ # Act
+ Set-AzDevOpsGroupVariable -VariableGroupName $variableGroupName -VariableName $variableName -VariableValue $expectedValue
+
+ # Assert
+ $actualValue = Get-AzDevOpsGroupVariable -VariableGroupName $variableGroupName -VariableName $variableName
+ $actualValue | Should -Be $variableValue
+
+ } finally {
+ Remove-AzDevOpsGroupVariable -VariableGroupName $variableGroupName -VariableName $variableName
+ }
+ }
+ It "Sets a new variable to a new DevOps variable group" {
+ # Arrange
+ $variableGroupName = [System.Guid]::NewGuid()
+ $variableName = [System.Guid]::NewGuid()
+ $variableValue = [System.Guid]::NewGuid()
+ try {
+ # Act
+ Set-AzDevOpsGroupVariable -VariableGroupName $variableGroupName -VariableName $variableName -VariableValue $variableValue
+
+ # Assert
+ $actualValue = Get-AzDevOpsGroupVariable -VariableGroupName $variableGroupName -VariableName $variableName
+ $actualValue | Should -Be $variableValue
+
+ } finally {
+ Remove-AzDevOpsVariableGroup -VariableGroupName $variableGroupName
+ }
+ }
}
}
}