Search code examples
azure-devopsazure-pipelinesmultistage-pipeline

AzureDevops stage dependsOn stageDependencies


How to create a multi-stage pipeline depending on a stage/job-name derived from a parameter whereas stages run firstly in parallel and eventually one stage that waits for all previous stages?


Here's what I've tried so far: A multi-stage pipeline runs for several stages depending on a tool parameter in parallel, whereas dependsOn is passed as parameter. Running it in parallel for each tool waiting for the previous stage for the said tool works smoothly.

Main template: all wait for for all

- ${{ each tool in parameters.Tools }}:
  - template: ../stages/all-wait-for-all.yml
    parameters:
      Tool: ${{ tool }}

stages/all-wait-for-all.yml

parameters:
  - name: Tool
    type: string
stages:
  - stage: ALL_WAIT_${{ parameters.Tool}}
    dependsOn:
    - PREPARE_STAGE
    - OTHER_TEMPLATE_EXECUTED_FOR_ALL_TOOLS_${{ parameters.Tool }}

Now there should be one stage that should only run once and not per tool, but it should only run after the individual tool stages are done. It can't be hardcoded as there are various tools. So I hoped defining the individual wait-stages in a prepare job would work out:

Main template: prepare-stage

    - script: |
        toolJson=$(echo '${{ convertToJson(parameters.Tools) }}')
        tools=$(echo "$toolJson" | jq '.[]' | xargs)
        stage="ALL_WAIT"

        for tool in $tools; do
          stageName="${stage}_${tool }"
          stageWaitArray+=($stageName)
        done

        echo "##vso[task.setvariable variable=WAIT_ON_STAGES]${stageWaitArray}"
        echo "##vso[task.setvariable variable=WAIT_ON_STAGES;isOutput=true]${stageWaitArray}"
      displayName: "Define wait stages"
      name: WaitStage

stages/one-waits-for-all.yml

stages:
  - stage: ONE_WAITS
    dependsOn:
    - $[ stageDependencies.PREPARE_STAGE.PREPARE_JOB.outputs['waitStage.WAIT_ON_STAGES'] ]

whereas below error is shown: Stage ONE_WAITS depends on unknown stage $[ stageDependencies.PREPARE_STAGE.PREPARE_JOB.outputs['WaitStage.WAIT_ON_STAGES'] ].


Solution

  • Guess I was overthinking the solution as eventually it was pretty obvious.

    So first template can be called within a loop from the main template whereas it's executed as many times as tools we got. Second template shall be called once waiting on previous stages for all tools, whereas the job/stage prefix is known, only the tool name as postfix was unknown. So just add them in a loop directly in dependsOn..

    Here you go:

    stages:
      - stage: ONE_WAITS
        dependsOn:
        - PREPARE_STAGE
        - ${{ each tool in parameters.Tools }}:
          - OTHER_TEMPLATE_EXECUTED_FOR_ALL_TOOLS_${{ tool}}
          - ALL_WAIT_${{ tool }}