60

Azure Pipelines has Expressions and Conditions, but I can find no way to assign one of two values to a variable, based on a condition.

Is there any way to accomplish what this pseudo-code would?

    ${{ if endsWith( variables['Build.SourceBranchName'], '/master' ) }}: 
      buildVersion: variables['mavenVersion']
    ${{ else }}: 
      buildVersion: variables['Build.SourceBranchName']
riQQ
  • 9,878
  • 7
  • 49
  • 66
Mike Murray
  • 1,201
  • 1
  • 9
  • 12
  • 1
    Now your yaml is valid :) https://learn.microsoft.com/en-us/azure/devops/release-notes/2021/sprint-192-update#new-yaml-conditional-expressions – Krzysztof Madej Sep 09 '21 at 15:10

7 Answers7

60

As an extension to @Mike Murray's answer, if you are using variable groups you must define additional variables as name value pairs. To use conditional variable assignment in this case would be as follows:

variables:
- group: 'my-variable-group'
- name: myfirstadditionalvariable
  value: 100
- name: myconditionalvariable
  ${{ if eq( variables['Build.SourceBranchName'], 'master' ) }}: 
    value: masterBranchValue
  ${{ if ne( variables['Build.SourceBranchName'], 'master' ) }}: 
    value: featureBranchValue
Evan Citulsky
  • 601
  • 1
  • 6
  • 7
  • Hello! This syntax gives me an `Unexpected property ${{ if .... }}` in Azure's online editor. When I save the file anyway and hit the `Validate` / `Run` button, I get a popup indicating `'value' is already defined` – Hellium Oct 05 '20 at 21:10
  • Nevermind, my two conditions were evaluated to true, hence the error when validating / running. The online editor still gives me the warning but that's not a big deal. – Hellium Oct 05 '20 at 21:47
  • @Hellium How did you fix `'value' is already defined`? I am also using `eq` and `ne` and I don't understand how they are both evaluating to true. – Heather Sawatsky Apr 20 '21 at 22:29
  • In my case, the conditions were more complex than the ones of this answer and I got mixed up. I've fixed the conditions so that they are mutually exclusive. How do your conditions look like? – Hellium Apr 22 '21 at 06:53
  • Thanks a lot! Was trying to figure out exactly this: how to use conditions with the name value syntax. – axk May 03 '21 at 18:43
  • @HeatherSawatsky in my case I fixed the " 'value' is already defined " error by adding a tab spacing before value: masterBranchValue. The yaml expected a +1 indentation level with reference to the previous sentence – brunochaina Sep 10 '21 at 16:19
46

I was closer than I thought. This is not pretty, but it worked. (with more yaml context)

variables:
  ${{ if eq( variables['Build.SourceBranchName'], 'master' ) }}: 
    buildVersion: ${{ variables['mavenVersion'] }}
  ${{ if ne( variables['Build.SourceBranchName'], 'master' ) }}: 
    buildVersion: ${{ variables['Build.SourceBranchName'] }}

  buildKey: ${{ format('{0}_{1}', variables['supportReleaseNumber'], variables['buildVersion']) }}
  buildNum: $[counter(variables['buildKey'], 1)]  # same as $(Rev:r), but more widely usable 

name: $(buildKey)_$(buildNum)  # build run name
Mike Murray
  • 1,201
  • 1
  • 9
  • 12
  • Hi, I'm following your example and I got an error like `Unexpected value 'env'`, which `env` is my variable to assign the value. I think it's because I'm using it with variable group so I can't use the example as it is. Do you have this IF ELSE expression(?) reference url that I can refer to my case? – kevmando Nov 12 '19 at 16:12
  • The three docs links I included in the original post were all I could find related to this topic. There is no 'else', so you need to chain 'if's. Different variables types require different syntax. Check the [Understand variable syntax](https://learn.microsoft.com/en-us/azure/devops/pipelines/process/variables?view=azure-devops&tabs=yaml%2Cbatch#understand-variable-syntax) section. – Mike Murray Nov 13 '19 at 17:31
  • Thanks. I found [if](https://learn.microsoft.com/en-us/azure/devops/pipelines/process/templates?view=azure-devops#conditional-insertion) from templates section in the end. I was trying not to use template to simplify, so didn't know there was an explanation of if there. – kevmando Nov 13 '19 at 17:42
11

This should do the trick....

BuildVersion is initialised as $(Build.SourceBranch) if it's the master branch you change that to the $(mavenVersion) else no change.

variables:
  mavenVersion: '1.0'
  buildVersion: $(Build.SourceBranch)

pool:
  vmImage: 'ubuntu-latest'

steps:

- script: echo '##vso[task.setvariable variable=buildVersion]$(mavenVersion)'
  displayName: "Set the buildVersion as mavenVersion if the Build.SourceBranch = 'refs/heads/master' "
  condition: eq(variables['Build.SourceBranch'], 'refs/heads/master')

- script: echo $(buildVersion)
  displayName: 'Printing the variable'

non-master branches prints 'refs/heads/branch_name' which is mavenVersion non-master branches prints 'refs/heads/branch_name' which is mavenVersion

master branch prints 1.0 which is mavenVersion master branch prints 1.0 which is mavenVersion

  • Thanks. That is a good answer, and I might be able to use that type of solution in the future. I neglected to mention that I need to use this variable to construct the build run name, so I need the variable before any steps are run. name: $(buildKey)_$(buildNum) # build run name – Mike Murray Aug 17 '19 at 00:56
  • you could potentially have two builds which has triggers for branches. one with include and the other with exclude. not sure if that is what you are after.. – Venura Athukorala Aug 17 '19 at 01:00
  • The code I posted, which goes in the variables section of the pipeline, solved my need for variables to use to define the build run name for the pipeline. Thanks. – Mike Murray Aug 18 '19 at 02:35
11

With this update your YAML is valid:

    ${{ if endsWith( variables['Build.SourceBranchName'], '/master' ) }}: 
      buildVersion: variables['mavenVersion']
    ${{ else }}: 
      buildVersion: variables['Build.SourceBranchName']

All works fine with this

trigger: none

name: if-else

pool:
  vmImage: ubuntu-latest

variables:
  ${{ if endsWith( variables['Build.SourceBranchName'], 'master' ) }}: 
    buildVersion: 'master'
  ${{ else }}: 
    buildVersion: 'none-master'

steps:
- script: |
    echo "$(Build.SourceBranchName)"
    echo "$(buildVersion)"
  displayName: 'Display buildVersion'

Simply Build.SourceBranchName contains just master.

Generating script.
========================== Starting Command Output ===========================
/usr/bin/bash --noprofile --norc /home/vsts/work/_temp/1121efc8-6445-4e19-be5a-8d525a76467e.sh
master
master
Finishing: Display buildVersion

Note: This doesn't work on Azure DevOps Server - please be aware of that! Thanks @psulek for highlighting this!

Krzysztof Madej
  • 32,704
  • 10
  • 78
  • 107
3

@Mike Murray, thank you for this! I have been trying to solve this for ages. When builds are triggered from pull requests the SourceBranchName is always 'merge'. Your answer helped me come up with this solution for getting the target branch name for both scenarios, manual builds and builds triggered by pull-requests:

${{ if ne( variables['Build.SourceBranchName'], 'merge' ) }}: 
    environment: ${{ variables['Build.SourceBranchName'] }}
  ${{ if endsWith( variables['System.PullRequest.TargetBranch'], 'dev' ) }}: 
    environment: dev
  ${{ if endsWith( variables['System.PullRequest.TargetBranch'], 'staging' ) }}: 
    environment: staging
  ${{ if endsWith( variables['System.PullRequest.TargetBranch'], 'master' ) }}: 
    environment: prod

Not very pretty, but finally works.

  • 1
    This does not work. As shown on [The docs of predefined variables](https://learn.microsoft.com/en-us/azure/devops/pipelines/build/variables?view=azure-devops&tabs=yaml#system-variables), everything in `System.PullRequest` (except `IsFork`) is **NOT** available in template syntax – Mickael V. Aug 11 '20 at 10:24
3

You can have conditional variables based on parameters:

parameters:
- name: example
  default: master
  values:
  - master
  - branch1
  - branch2

variables:
  ${{ if eq( parameters.example, 'master' ) }}: 
    buildVersion: 'this'
  ${{ else }}: 
    buildVersion: 'that' # buildVersion = this

Won't work if the variables are in a separate template.

SoloDolo
  • 174
  • 1
  • 5
  • Any reason as to why the `${{ }}` does not work in a separate template or another way to get around it? – cp5 Dec 22 '22 at 09:16
0

In a template with parameters you are maybe tempted to try something like this (remark: variables in templates can be declared in jobs or stages):

variables:
  ${{ if eq( ${{parameters.Environment}}, 'DEV' ) }}: 
    targetenv: myDevMachine
  ${{ if eq( ${{parameters.Environment}}, 'TST' ) }}: 
    targetenv: myTSTMachine

Unfortunately that doesn't work. A workaround for that is to store the template variable first in a temporary variable like this:

variables:
  env: ${{parameters.Environment}} 
  ${{ if eq( variables.env, 'DEV' ) }}: 
    targetenv: myDevMachine
  ${{ if eq( variables.env, 'TST' ) }}: 
    targetenv: myTSTMachine