DevOps | Scripts | Automation

Azure DevOps

How to add dependency in Azure Pipeline Stages?

Overview

Many scenarios you come across when you create an Azure Pipeline that you need dependency between stages like you want to run the next stage only if the previous stage is succeeded or you need to run the next stage even if the last stage is failed.

For all such scenarios, we need to create a dependency between stages. In this article, we are going to explain how you can create a dependency between stages using the YAML pipeline.

Possible Scenarios

  • Without Dependency
  • Run stages in Parallel
  • Run stage conditionally
  • Run Stage always

Let’s go through each scenario.

Scenario 1: Without dependency

In this case, we will fail stage A to see if stage B can run and we have a basic pipeline for it as shown below.

trigger:
- None

pool:
  vmImage: ubuntu-latest

stages:
  - stage: A
    displayName: Stage A
    jobs:
      - job: Job1
        steps:
          - task: PowerShell@2
            inputs:
              targetType: 'inline'
              script: |
                throw 'Failing this stage explicitly'
                
  
  - stage: B
    displayName: Stage B
    jobs:
      - job: Job1
        steps:
          - task: PowerShell@2
            inputs:
              targetType: 'inline'
              script: |
                Write-Host "This stage will not run"

Output:

Stage B won’t run

As shown in the above output, stage B will not run if stage A failed because, in the YAML pipeline, we haven’t specified anything that creates dependency.

This scenario is similar to preventing the next stage run if the last stage is failed because, in the “Stages to run” section, it says Stage B is dependent on Stage A.

Default stage dependency

The above pipeline code for stage B is similar to,

  - stage: B
    displayName: Stage B
    dependsOn: A
    jobs:
      - job: Job1
        steps:
          - task: PowerShell@2
            inputs:
              targetType: 'inline'
              script: |
                Write-Host "This stage will not run"

Here, the dependsOn parameter is used to specify the dependency between stages means that Stage B will always run after Stage A if Stage A is successful.

Scenario 2: Run Stages in Parallel

In the first scenario, we have seen that if there are two stages then they will run in sequence only. In this case, if you want to run two stages in parallel then better to opt for one stage and multiple jobs so they can be executed in parallel.

Let’s consider the scenario below,

Stage Execution

As shown in the above image, we need to run Stage-B and Stage-C in parallel with Stage-A and stage-D after Stage-B and Stage-C.

The below code just shows how this scenario can be created. Full code you can download it from Git Repo.

https://github.com/chiragce17/MyPublicRepo/blob/main/AzurePipeline/StageDependency.yaml

stages:
- stage: A

- stage: B
  dependsOn: A   # this stage runs after Stage-A

- stage: C
  dependsOn: A   # this stage runs in parallel with Stage-B, after A

- stage: D
  dependsOn:         # this stage runs after Stage-B and Stage-C
  - B
  - C

If you see the stages to run,

Stages to Run

In another way, you can clearly see the stage dependency when you run the pipeline as shown below

Stages during execution

Stage Output:

Stage Output

Scenario 3: Run Stage conditionally

In scenario-2 we have specified only the stage dependencies and how they can be executed in serially and parallelly but we haven’t decided how the stage will run on condition bases.

For example, I need to run stage B even if stage-A fails then the code will be as below.

trigger:
- None

pool:
  vmImage: ubuntu-latest

stages:
  - stage: A
    displayName: Stage A
    jobs:
      - job: Job1
        steps:
          - task: PowerShell@2
            inputs:
              targetType: 'inline'
              script: |
                throw 'Failing Stage-A'
                
  
  - stage: B
    displayName: Stage B
    condition: failed()
    jobs:
      - job: Job1
        steps:
          - task: PowerShell@2
            inputs:
              targetType: 'inline'
              script: |
                Write-Host "This stage will run if the stage-A failed"

Output:

Stage A Failed and Stage B executed.

If there are more stages then you can specify the stage name inside the condition. For example, failed(‘A’). In this case, if Stage-A is succeeded then Stage-B is skipped.

Stage-A Succeeded and Stage-B skipped

Let’s add one more stage and I want the new Stage-C will run only if stage-B is succeeded. For that, you need to use succeeded() condition with the Stage name specified.

Code you can get from my GitHub repository.

https://github.com/chiragce17/MyPublicRepo/blob/main/AzurePipeline/StageCondition.yaml

Output:

Stage-C is executed when Stage-B is succeeded.

Scenario 4: Run Stage Always

In some scenarios, we need to run stage(s) always regardless of the previous stage status. You need to use Always() function there.

Always() is the expression for the Stage condition. More conditions you can find in the article below.

https://learn.microsoft.com/en-us/azure/devops/pipelines/process/expressions?view=azure-devops#always

StageB you need to specify like this,

- stage: B
    displayName: Stage B
    condition: always()
    jobs:
      - job: Job1
        steps:
          - task: PowerShell@2
            inputs:
              targetType: 'inline'
              script: |
                Write-Host "This stage will always run"

Let’s run the pipeline.

Pipeline output

As you can see Stage B was executed regardless of the status of stage A. Here Stage A is failed.

Loading