There are three types of variables while working with Azure Pipelines in Azure DevOps:
-predefined variables,
-variables declared/stored in build and release definitions (pipelines), and
– variables declared/stored in variable groups in libraries.
Microsoft has in-depth info about predefined variables at AzureDevOps Pipeline Variables. In this note, I discuss the other two types of variables. I also provide little bits of information that I have learned over the years working with Azure DevOps.
PS: In this note, I am working with the classic editor for build and release definitions.
Variables in build definition:
We can access the variables of a particular build definition by navigating under the variables tab in a build definition.
As we can see, there are three types of variables available to us.
The predefined variables are handy when working with build/release definitions with relative paths. E.g., $(Build.SourcesDirectory) is the folder where the build definition agent drops the source code and copies the build artifact to $(Build.StagingDirectory).
These values are not constant and change based on the build machine and agent allocated to build our solution. Having these variables makes our build steps portable and easy to manage. I would encourage using predefined variables as much as possible so that the build process requires less overhead in the long term.
To add a new variable, click on the “+ Add” button on the same page.
There are four settings to create a new variable in a build definition:
-the variable name,
-the value,
-an option to store as a secret or plain variable (lock toggle), and
-an option to decide whether a value can be settable at queue time.
Let’s review these settings in a little detail. Name and value are quite self-explanatory. The variable is referenced using the format $(VariableName) anywhere in the build definition, like one of the build steps in the definition under the Tasks tab. When a build agent executes a build step, it replaces the $(VariableName) placeholder with the variable’s actual value.
Secret variable types are certain variables like access keys or passwords which should be secured. For such variables, locking them ensures that the values are not accessible. Locking a variable does not impact the execution of a build step when a build agent references the variable. Locking a variable ensures that the build logs do not display the value of the variable. Value is replaced by “*****” in the logs.
The fourth setting is settable at queue time. This setting is a toggle that (when checked) allows a user to input values while queuing a build definition that can override the predefined value already declared in the build definition.
What is the value of having a settable at queue time variable? Imagine a situation where you are harnessing Azure DevOps to automate a system to start and stop. Under normal conditions (without settable at a queue time feature), we’d have two build definitions -one to stop and the other to start. By having a variable as settable at queue time, we may consolidate the two build definitions into one. And on queue time, we may pass (start or stop) to manage the build definition’s behavior. Having an option such as “settable at queue time” allows us to extend a build definition’s capability and usability.
Variables in release definition:
A release definition’s variables are under the variables tab.
There are five factors to remember to create a new variable in a release definition: the variable name, the value associated, an option to store as a secret or plain variable (lock toggle), the scope of the variable, and an option to decide whether a value can be “settable at release time”.
These factors are identical to what I discussed in the build definition, except for scope. Scope of a variable is useful in determining the validity of a variable across stages. The default value of scope is the release definition. A release definition can consist of multiple stages. A variable’s scope can either be the release or one stage (from the drop-down list).
What is the value of scoping variables in release definition? To understand this, we have to understand the stages in a release definition.
Generally speaking, we have a unique artifact getting deployed across multiple environments like Dev, Test, Stage, and Production in a typical continuous delivery pipeline. These environments can be managed as Stages in a release definition. While deploying an artifact to an environment, there may be specific environment-specific configuration values. Those configuration values can be managed as variables with scopes in a release definition. If a variable has the same value across all environments/stages, then the scope can be left to a release. Suppose a variable has specific values for each environment. In that case, we can declare the same variable multiple times with different values and different scopes.
Here is an example of a two-staged release definition.
I created two values of the same variable, “ServiceType”, with different values based on the stage they were getting deployed to -“AWS EC2 -region 1” and “AWS EC2 -region 2”.
Another exciting way to declare variables is by using the Library feature under Pipelines. A library provides an area where we may create variable groups to be referenced by build and release definitions. When accessing Library for the first time, we see a New variable group page and an option to create a new Variable group by clicking on the “+ Variable group” button.
I was able to create a new variable group -ServiceCategory with two variables in it -ServiceList and ServiceStyle.
I also ensured that the option toggle is set to allow access to all pipelines. That will allow us to access the variable from the release definition. Navigate back to the release definition and access Variable groups under Variables tab. We see an option to Link variable group.
We could also select the variable’s scope -either the Release (all stages) or specific Stages. Click on Link to add the variable group type to the release definition. Once added, the variables and associated values become accessible to the release definition. Managing variables in libraries is a good idea if a particular variable is used across the build/release definition. By using the Library feature, it is easy to manage/change the variable value instead of changing it in each release/build definition where it is required.
There is an important note regarding precedence. Say we have a variable declared in a release definition that can also be settable at release time along with a value. As you’d know, during release time, if we provide a value for that variable, that value overrides the default value set in the release definition. We can also declare the same variable in a variable group. In that case, the precedence is as follows:
value declared at release time > default value declared in release definition > value declared in the variable group
Stated differently, if we do not declare a variable in a release definition, the build agent will export the value of the variable from the variable group. There are many such exciting nuances while working with variables in Azure pipelines and, I would encourage you to try these out for yourself.
I hope this note is useful, and if you have any questions or suggestions, please share them in the comments below.