We continue the review of the wonderful tool for developing under Windows and not only, Azure DevOps. This time, having suffered with environment variables, I decided to bring all the experience into one article.
Starting from the fact that for each execution environment they have a different syntax, ending with the lack of a standard ability to transfer variables from one pipeline stage to another.
I will make a reservation that the main examples will be on the Release Pipelines, because YAML has not yet reached there, and I need the functionality of many stages and many artifacts. This, it seems, has become available in regular Pipelines, which practically equalizes them in terms of functionality. Pipelines YAML has been finished and added to the text view, a small graphic hint with parameters that can be set. Very convenient, no need to go into the documentation for each module. But I will describe this in the next article, but for now, here is a picture of the innovation itself.
Storage and use
Let's start with the fact that in the system we have default variables. They begin, depending on the origin, with the words Release, System, etc. A complete list (as it turns out, no) is available at
steps:
- bash: echo This script could use $SYSTEM_ACCESSTOKEN
env:
SYSTEM_ACCESSTOKEN: $(System.AccessToken)
- powershell: Write-Host "This is a script that could use $env:SYSTEM_ACCESSTOKEN"
env:
SYSTEM_ACCESSTOKEN: $(System.AccessToken)
If you set a variable on the agent running the task, it's $(System.AccessToken). If you want to use it inside a powershell script on the same agent, it will already be $env:SYSTEM_ACCESSTOKEN. If you, God forbid, want to use this variable on some remote host using the PowerShell on target machines task, you need to pass it as an argument to the script using
The same laws do not apply to your own variables, here you are responsible for the syntax. You can set variables locally in each task.
Or globally in the storage of variables, and then link them from the storage. Very comfortably.
As a bonus to this, if the variables are very secret, they can be stored in the Azure cloud in a storage called Azure Vault, you can link Vault to the project in Library.
In general, everything is clear with variables, in pipelines they can still be set manually for each launch, there is no such functionality in release. You can see what you are passing to the pipeline again in the agent initialization logs, but keep in mind that they are already there in a converted form.
Dynamic variables
The fun part starts when we want to get some value in one step and pass it to the next.
We didn't get this functionality. But our hands are not for boredom, and with the help of Google, a solution was found. Thank God, Azure DevOps has an API that allows us to do a little more than what is drawn in the interface.
So, we need a call to update global variables, which we will do directly from within the pipeline. The address is taken from environment variables, the ones about which there is not a word in the documentation, as mentioned earlier. You can ask them yourself or, whatβs there, hardcode if the shop is closed.
$releaseurl = ('{0}{1}/_apis/release/releases/{2}?api-version=5.0' -f $($env:SYSTEM_TEAMFOUNDATIONSERVERURI), $($env:SYSTEM_TEAMPROJECTID), $($env:RELEASE_RELEASEID) )
We set an empty value for the variable we want to pass, set Scope - Release
For example, we make some random value generator. Pay attention to the syntax for declaring a variable inside this stage, such functionality has been delivered.
In the next step, we pass the variable to the script, yes, yes, it is not possible directly, it must be through an argument.
Script under spoiler
PowerShell
#Script requires stageVar variable in release variables set to Release scope
param ( [string] $expVar )
#region variables
$ReleaseVariableName = 'StageVar'
$releaseurl = ('{0}{1}/_apis/release/releases/{2}?api-version=5.0' -f $($env:SYSTEM_TEAMFOUNDATIONSERVERURI), $($env:SYSTEM_TEAMPROJECTID), $($env:RELEASE_RELEASEID) )
#endregion
#region Get Release Definition
Write-Host "URL: $releaseurl"
$Release = Invoke-RestMethod -Uri $releaseurl -Headers @{
Authorization = "Bearer $env:SYSTEM_ACCESSTOKEN"
}
#endregion
#region Output current Release Pipeline
Write-Output ('Release Pipeline variables output: {0}' -f $($Release.variables | ConvertTo-Json -Depth 10))
#endregion
#region Update StageVar with new value
$release.variables.($ReleaseVariableName).value = "$expVar"
#endregion
#region update release pipeline
Write-Output ('Updating Release Definition')
$json = @($release) | ConvertTo-Json -Depth 99
Invoke-RestMethod -Uri $releaseurl -Method Put -Body $json -ContentType "application/json" -Headers @{Authorization = "Bearer $env:SYSTEM_ACCESSTOKEN" }
#endregion
#region Get updated Release Definition
Write-Output ('Get updated Release Definition')
Write-Host "URL: $releaseurl"
$Release = Invoke-RestMethod -Uri $releaseurl -Headers @{
Authorization = "Bearer $env:SYSTEM_ACCESSTOKEN"
}
#endregion
#region Output Updated Release Pipeline
Write-Output ('Updated Release Pipeline variables output: {0}' -f $($Release.variables | ConvertTo-Json -Depth 10))
#endregion
Or
Bash
INPUT_VAR=$1
RELEASE_VAR=$2
echo Test ID: ${INPUT_VAR}
RELEASE_URL="${SYSTEM_TEAMFOUNDATIONSERVERURI}${SYSTEM_TEAMPROJECTID}/_apis/release/releases/${RELEASE_RELEASEID}?api-version=5.0"
echo release url: $RELEASE_URL
RELEASE_JSON=$(curl -H "Authorization: Bearer $SYSTEM_ACCESSTOKEN" $RELEASE_URL)
OUTPUT=`jq ''.variables.${RELEASE_VAR}.value' = '"${INPUT_VAR}"'' <<< $RELEASE_JSON`
curl -H "Authorization: Bearer $SYSTEM_ACCESSTOKEN" -H "Content-Type: application/json" -X PUT -d "$OUTPUT" $RELEASE_URL
In a nutshell, our script takes the variable myVar as input and uses the API to put the value of this variable into stageVar. In the next step, using the syntax of system variables, we can see it.
The example is quite simple, but the functionality opens up good opportunities for us, in addition to my previous
In the next article, if necessary, I will talk about YAML pipelines, there are quite a lot of interesting innovations lately.
Source: habr.com