'Azure multistage pipelines: conditionally skip one stage but not the next

I have an Azure multi-stage CI/CD pipeline. It has stages for Test and UAT deployment.

I want the UAT release to run if Test succeeds or is skipped, but not if it fails.

I can't. Whatever I try, if Test is skipped, UAT is also skipped. Unless I use always(), but then UAT will run even if Test fails.

  ...
  - stage: Test
    condition: and(succeeded(), ne(variables['build.sourceBranchName'], 'DoUAT')) # Skip for UAT deployment tests
    ...

  - stage: UAT
    condition: and(succeeded(), in(variables['build.sourceBranchName'], 'master', 'DoUAT')) # Only deploy off master branch and branch to test UAT deploys.
    ...

How do I skip one stage but not the next one?

What I get vs what I want



Solution 1:[1]

You can use not(failed('Test')) condition, please try below condition.

- stage: UAT
    condition: and(not(failed('Test')), in(variables['build.sourceBranchName'], 'master', DoUAT')) # Only deploy off master branch and branch to test UAT deploys.
    ...

I tested and it worked, check below screenshot.

enter image description here

Solution 2:[2]

I was looking for similar information, and found that you can do an "IN" clause on dependency result. Found this in the Microsoft Docs about expressions

- job: c
  dependsOn:
  - a
  - b
  condition: |
    and
    (
      in(dependencies.a.result, 'Succeeded', 'SucceededWithIssues', 'Skipped'),
      in(dependencies.b.result, 'Succeeded', 'SucceededWithIssues', 'Skipped')
    )

Solution 3:[3]

I think it's because the stage doesn't run that it doesn't get a status (eg succeeded, failed, canceled etc.). There is no status function for skipped.

With that, I think you will need to add a dependency on the stage before Test so that this evaluation can be made. Let's say that stage is called Build.

I think this condition should work: (line breaks are for readability only)

# run the stage if build is successful 
# and test succeeded or skipped 
# AND the branch is correct
and(
  and(succeeded('Build'), not(failed('Test'))), 
  in(variables['build.sourceBranchName'], 'master', 'DoUAT')
)

failed

  • For a job:
    • With no arguments, evaluates to True only if any previous job in the dependency graph failed.
    • With job names as arguments, evaluates to True only if any of those jobs failed.

Because of this documentation, I think it's necessary to add the Test parameter to target that stage specifically. However, I'm not sure if this necessitates that the Test name be added to the dependencies section of the UAT stage.

Solution 4:[4]

Credit to https://github.com/MicrosoftDocs/azure-devops-docs/issues/7738#issuecomment-611815486

@EdH

condition: not(or(failed(), canceled()))

Works with multiple previous stages and works like you need. Run the stage if all previous stages are succeeded or skipped, but not if they are failed or cancelled.

enter image description here

Notes:

  • Skipping does not cause failed() or cancelled() to be true.
  • Skipping does cause succeeded() to be false.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Levi Lu-MSFT
Solution 2 JesusIsMyDriver.dll
Solution 3
Solution 4