5

Consider the following pipeline snippet, this is part of a template.

- task: Bash@3
  inputs:
    targetType: 'inline'
    script: |
      echo "##vso[task.setvariable variable=AppType;]WebJob"
      echo "##[debug] AppType set to WebJob"

# This works, using the task condition
- task: DotNetCoreCLI@2
  condition: eq(variables['AppType'], 'WebJob')
  displayName: 'net publish for WebJob'
  inputs:
    command: 'publish'

# This doesn't work, using the conditional insertion, index syntax
- ${{ if eq(variables['AppType'], 'WebJob') }}:
  - task: DotNetCoreCLI@2
    displayName: 'net publish for WebJob'
    inputs:
      command: 'publish'

# This also doesn't work, using the conditional insertion, property dereference syntax
- ${{ if eq(variables.AppType, 'WebJob') }}:
  - task: DotNetCoreCLI@2
    displayName: 'net publish for WebJob'
    inputs:
      command: 'publish'

Why the task condition works but the conditional insertion doesn't? With the 2nd I don't get any error, the task is just not there, like the if condition is not met.

goosseno
  • 145
  • 2
  • 12

4 Answers4

5

Azure YAML pipelines conditional insertion doesn't work

As we know, the syntax ${{}} for compile time:

Expressions

# Note the syntax ${{}} for compile time and $[] for runtime expressions.

So, when we execute the pipeline, the conditional insertion ${{ if eq(variables['AppType'], 'WebJob') }} has already been evaluated, however, the Bash task has not been run, the value of AppType would be always null. That the reason why the conditional insertion does not work.

To resolve this issue, we could define the variable directly:

 variables:
   AppType: WebJob

Or we could define the Runtime parameters:

parameters:
  - name: AppType
    displayName: AppType
    default: WebJob
Leo Liu
  • 71,098
  • 10
  • 114
  • 135
  • Thanks, you saved me a tons of time. You explanation should be written **IN RED** at the top of the "expressions", "variables" and "conditions" documentation for Azure Pipelines. – Pavel Sapehin Jan 18 '21 at 06:24
2

The ${{}} syntax is evaluated at template compile time, not during execution, so the task will be removed from the workflow when the job is being setup as the variable doesn't exist yet, it doesn't wait until it actually needs to run the task to evaluate the condition.

You can use the $[] conditional syntax for runtime evaluation, or rely on the condition:syntax.

From the docs:

# Two examples of expressions used to define variables
# The first one, a, is evaluated when the YAML file is compiled into a plan.
# The second one, b, is evaluated at runtime.
# Note the syntax ${{}} for compile time and $[] for runtime expressions.
variables:
  a: ${{ <expression> }}
  b: $[ <expression> ]

See:

jessehouwing
  • 106,458
  • 22
  • 256
  • 341
  • 1
    Thanks for the explanation. The syntax `- $[ if eq(variables.AppType, 'WebJob') ]:` is not valid. – goosseno Dec 26 '20 at 09:48
  • you using azure devops server by any chance? – 4c74356b41 Dec 26 '20 at 10:24
  • I don't think the runtime condition is valid in that context. Template conditional must use the compile time expression syntax. https://learn.microsoft.com/en-us/azure/devops/pipelines/process/templates – jessehouwing Dec 26 '20 at 12:06
0

I have tested your condition on a pipeline and change it like this and it's worked correctly. you should change condition syntax and everything will be correct.

- task: Bash@3
  inputs:
   targetType: 'inline'
   script: |
     echo "##vso[task.setvariable variable=AppType;]WebJob"
     echo "##[debug] AppType set to WebJob"
- task: CmdLine@2
  inputs:
    script: echo Key:'$(AppType)' 
# This doesn't work, using the conditional insertion, index syntax
  ${{ if eq(variables['AppType'], 'WebJob') }}:
- task: CmdLine@2
  inputs:
    script: echo Key:'$(AppType)'
# This also doesn't work, using the conditional insertion, property dereference syntax
  ${{ if eq(variables.AppType, 'WebJob') }}:
- task: CmdLine@2
  inputs:
    script: echo Key:'$(AppType)'

I recommend you try the visual studio code and an extension or any ide to correct your YAML file.

iman ansari
  • 103
  • 8
0

I had been hoping to set a variable at the bottom of a template at runtime and use a conditional include at the top prevent portions of the template from being included again later...

But the compile time limitation that Leo Liu pointed out was preventing me from doing so. The closest I could get was by doing this with a parameter:

# some-template.yml
parameters:
- name: firstParameter
  type: string
  default: ''
- name: hasAlreadyBeenRun
  type: boolean
  default: false

steps:
- ${{ if ne(parameters.hasAlreadyBeenRun, true) }}:
  - task1 that only needs run once
  - task2 that only needs run once
  - task3 that only needs run once
- task to repeat
# consuming-definition.yml
steps:
- ${{ if eq(someCondition1, true) }}:
  - template 'some-template.yml'
  - some task 1
- ${{ if eq(someCondition2, true) }}:
  - some task 2
  - some task 3
- ${{ if eq(someCondition3, true) }}:
  - template 'some-template.yml'
    parameters:
      hasAlreadyBeenRun: ${{ eq(someCondition1, true) }}
  - some task 4
- ${{ if eq(someCondition4, true) }}:
  - template 'some-template.yml'
    parameters:
      hasAlreadyBeenRun: ${{ or(eq(someCondition1, true), eq(someCondition3, true)) }}
  - some task 5
Ryan Thomas
  • 479
  • 5
  • 16