I'm Andrew Hoefling, and I work for FileOnQ as a Lead Software Engineer building mobile technologies for Government, Financial and First Responders using Xamarin. 

 

Conditional Insertion in Azure Pipelines


Using Conditional Insertion in Azure Pipelines allows a build to insert tasks depending on parameters. This differs than a conditional task becaues it can remove or add the task to the build task list. This means you can completely customize the build tasks and only show the ones that the build is interested in.

Conditional Tasks != Conditional Insertion

When defining project builds for Azure Pipelines it is common to have tasks run if a certain criteria is true. This technique is called conditions and it can be applied to any task. Some options available in a condition are:

  • Prevent task from running
  • Run task even if build failed
  • Allow task to run if a criteria is true

In all cases with Conditions the build task still shows up in the build history. When building large yaml builds this can create a lot of noise that will make it difficult to debug the problem.

Standard Condition Example

- script: echo Hello World
  condition: and(succeeded(), eq('$(MyVar)', 'true'))

What is Conditional Insertion?

Conditional Insertion uses a similar expression syntax as a standard Task Expression, with one major exception. If the statement evaluates to false the task is not added to the build task list. This means the task will only show up if the expression evaluates to true.

The syntax is a little tricky to get right

Conditional Insertion uses the ${{ }} notation and is a little confusing at first glance. It is adding code flow to yaml which combines a couple different paradigms: configuration files and code. It is best to think of conditional insertion as an if statement inside of your build task list.

The most basic example provided by the microsoft docs is changing a variable based on a conditional insertion. See the code snippet below:

variables:
  ${{ if eq(variables['Build.SourceBranchName'], 'main') }}: # only works if you have a main branch
    stageName: prod

pool:
  vmImage: 'ubuntu-latest'

steps:
- script: echo ${{variables.stageName}}

Breaking this syntax down the actual expression is

${{ if eq(variables['Build.SourceBranchName'], 'main') }}:

Let's analyze the different components that make up a conditional insertion statement

  • Open and Closing braces
  • Code
  • Closing colon

Open and Closing braces

Anytime you attempt to access parameters or the code flow of Azure Pipelines yaml files you use the ${{ }}. Conditional Insertions are no different with one major exception

Boolean Expression

To implement the Conditional Insertion you will need to add an if statement into the code block. The rules can match identically to the Condtion that you have used in the past. The major difference is you need to explicitly list out the if command and then your boolean expression.

if eq(variables['Build.SourceBranchName'], 'main')

Closing Colon

This is the most important part of Conditional Insertion without it your yaml files will fail with little explanation. After the opening and closing braces ${{ }} you will need to include colon : which tells the build system to only insert the next statement if the expression evaluates as true.

Let's compare 2 different conditional statements:

Valid Expression

${{ if eq(variables['Build.SourceBranchName'], 'main') }}:

 Invalid Expression - missing trailing colon

${{ if eq(variables['Build.SourceBranchName'], 'main') }}

Add Condtional Task

Let's look at how we can apply this concept to a build script to conditionally add tasks. Then we can look at the build output to demonstrate when a task is added to the build task list and when it is not. Before we learned using the ${{ }} code block we can conditionaly insert statements into a yaml file. This same concept can be applied to tasks with a few changes and proper indenting.

Consider the following yaml file that has 2 tasks that run a script to print a message to the console.

trigger:
- main

pool:
  vmImage: 'ubuntu-latest'

steps:
- script: echo Hello, world!
  displayName: 'Run a one-line script'

- script: echo This is a hidden task
  displayName: 'Run hidden task'

Let's add a parameter to the script that will determine if the 2nd task will execute or not.

parameters:
  - name: runSecondTask
    default: true

Before we add the Conditional Insertion you need to be aware that of a couple rules

  • All task statements start with a -
  • All statements following the Conditional Insertion is indented 2 spaces

Putting all of this together we can update our 2nd task as follows

- ${{ if eq(parameters.runSecondTask, 'true') }}: 
  - script: echo This is a hidden task
    displayName: 'Run hidden task'

Now putting the entire script together

trigger:
- main

pool:
  vmImage: 'ubuntu-latest'

parameters:
  - name: runSecondTask
    default: true

steps:
- script: echo Hello, world!
  displayName: 'Run a one-line script'

- ${{ if eq(parameters.runSecondTask, 'true') }}: 
  - script: echo This is a hidden task
    displayName: 'Run hidden task'

Troubleshooting

Creating builds with yaml is powerful and confusing, you are bound to run into an error that has no explanation. Below are some tips that may help you get through issues you run into.

Missing Dash

If you are using Conditional Insertion for a task you must have a - leading the statement otherwise the build will not work. The steps definition in your build expects an array of items the - syntax tells the build system that you are evaluating a new item in the array.

Missing Trailing Colon

All Conditional Insertion statements must end with a colon :. The colol tells the build system that the next line will be inserted if the expression evaluates to true.

Invalid Spacing

The infamous spacing of yaml files has caused hours upon hours of frustration for developers. Conditional Insertion adds potential problems with spacing. All statements after the expression must have an additional 2 spaces.

Conclusion

You should have the knowledge to add statements conditionally to your build yaml file using Conditional Insertion. This can be applied to parameters, variables, steps and more. If you want to see a working example, checkout my code sample on GitHub

- Happy Coding


Share

Tags

Azure PipelinesYAMLBuildCI