conditional-statementsazure-pipelineseach

Azure pipelines conditions with each loop inside the condition


I have a job in azure-pipelines that receives a variable number of dependencies. It could have zero dependencies, or "n" dependencies depending what previous jobs were executed before this one.

Let's see an example:

file: "dependent-job.yml"

parameters:

- name: Dependencies
  type: Array
  default:
     - Job1
     - Job2

Jobs:
  - job: Variousdependencies
    name: MyJob
    ${{ if parameters.Dependencies }} 
      dependsOn: ${{ parameters.Dependencies }}
    condition: |
      and(eq(dependencies.Job1.result, 'Succeeded'),
          eq(dependencies.Job2.result, 'Succeeded'),
          eq(variables[MyJobEnabled,'True'),
          eq('${{ parameters.ForceJob }}','True')
      )

If I have 3 dependencies, I need to add another dependency in condition:

    condition: |
      and(eq(dependencies.Job1.result, 'Succeeded'),
          eq(dependencies.Job2.result, 'Succeeded'),
          eq(dependencies.Job3.result, 'Succeeded'),
          eq(variables[MyJobEnabled,'True'),
          eq('${{ parameters.ForceJob }}','True')
      )

I would like to generate the lines that check if the previous jobs ended sucessfuly using the each syntax. This is what I tried:

    condition: |
      and(${{ each job in dependencies }}
             eq(dependencies.{{ job }}.result, 'Succeeded'),
          eq(variables[MyJobEnabled,'True'),
          eq('${{ parameters.ForceJob }}','True')
     )

but I received the following error when trying to run it:

The directive 'each' is not allowed in this context. Directives are not supported for expressions that are embedded within a string. Directives are only supported when the entire value is an expression.

Solution

  • Consider adding a condition property to the Dependencies parameter and use filtered arrays to dynamically set the dependencies and conditions of the job.

    Sample pipeline:

    pool:
      vmImage: ubuntu-latest
    
    trigger: none
    
    parameters:
      - name: ForceJob
        type: boolean
        default: true
    
      - name: Dependencies
        type: object
        default: 
          - jobName: Job1
            condition: eq(dependencies.Job1.result, 'Succeeded')
            exitCode: 0 # Change to 1 to simulate a failed job
          - jobName: Job2
            condition: eq(dependencies.Job2.result, 'Succeeded')
            exitCode: 0 # Change to 1 to simulate a failed job
    
    variables:
      - name: MyJobEnabled
        value: True
    
    jobs:
      - ${{ each dependency in parameters.Dependencies }}:
        - job: ${{ dependency.jobName }}
          displayName: ${{ dependency.jobName }}
          steps:
            - checkout: none
            - script: |
                echo "Job: ${{ dependency.jobName }}"
                exit ${{ dependency.exitCode }}
              displayName: 'Display job name'
    
      - job: AnotherJob
        dependsOn: ${{ parameters.Dependencies.*.jobName }}
        condition: |
          and(
            ${{ coalesce(join(', ', parameters.Dependencies.*.condition), 'True') }},
            eq(variables['MyJobEnabled'], 'True'),
            eq('${{ parameters.ForceJob }}', 'True')
          )
        steps:
          - checkout: none
          - script: |
              echo "conditions: ${{ join(', ', parameters.Dependencies.*.condition) }}"
            displayName: 'Display conditions'
    

    Notes: