Using variables in Azure DevOps pipelines

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.

Using variables in Azure DevOps pipelines

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 documentation. All schizophrenia with syntax is illustrated by an example from the documentation below. The same variable has three representations, depending on where we call it.

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 stop. With bash it's simpler, you can just pipe in using the $SYSTEM_ACCESSTOKEN argument and syntax.

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.

Using variables in Azure DevOps pipelines

Or globally in the storage of variables, and then link them from the storage. Very comfortably.

Using variables in Azure DevOps pipelines

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.

Using variables in Azure DevOps pipelines

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.

Using variables in Azure DevOps pipelines

Dynamic variables

The fun part starts when we want to get some value in one step and pass it to the next.

Using variables in Azure DevOps pipelines

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

Using variables in Azure DevOps pipelines

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.

Using variables in Azure DevOps pipelines

In the next step, we pass the variable to the script, yes, yes, it is not possible directly, it must be through an argument.

Using variables in Azure DevOps pipelines

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.

Using variables in Azure DevOps pipelines

The example is quite simple, but the functionality opens up good opportunities for us, in addition to my previous article, when we can create a virtual machine at the first stage of testing, do some manipulations with it further, and several in parallel. And the final step is to destroy it. Now we are chasing product autotests every time on fresh virtual machines. Given that they live for 10 minutes, it costs a penny.

In the next article, if necessary, I will talk about YAML pipelines, there are quite a lot of interesting innovations lately.

Source: habr.com

Add a comment