Reputation: 1831
I'm building a complex pipeline in yaml and I'm trying to create a dependency between two jobs such that the latter job runs after the former, but only if the former is set to run based on a parameter. I can't seem to wrap my head around whether this is doable or not.
I have a pipeline defined like this:
parameters:
- name: doJobA
type: boolean
stages:
jobs:
- job: JobA
condition: eq('${{ parameters.doJobA }}', true)
# ... details removed for brevity
- job: JobB
dependsOn: JobA
# ... details removed for brevity
JobB
should run after JobA
if parameters.doJobA
is true, or immediately if parameters.doJobA
is false. Simply adding the dependsOn
condition causes JobB
to be skipped if the JobA
condition is not met which makes sense, but I'd like it to run regardless.
Is it possible to define a conditional dependsOn
in this manner?
EDIT: I've run into an additional problem with this that renders the solution below unusable. I need the condition to depend upon a variable set by an earlier running PowerShell script and not based on parameters.
Upvotes: 29
Views: 43417
Reputation: 41
I had a similar case when I had a singe pipeline working with various environments and for one of them I needed mandatory approval checks. The problem with approval checks is that they are implemented in the TFS 'Environment' object and triggered every time object is touched. Therefore this code didn't work:
jobs:
- deployment: approvalChecksJob
condition: eq('${{ parameters.restoreEnvironment }}', 'production')
environment:
name: 'ApprovalRequirements'
strategy:
...
- job: dbRestoreJob
dependsOn: approvalChecksJob
condition: in(dependencies.approvalChecksJob.result, 'Succeeded', 'Skipped')
steps:
...
What I end up doing is making the whole job to be skipped based on a condition and then making 'dependsOn' also conditional:
jobs:
- ${{ if eq(parameters.restoreEnvironment, 'production') }}:
- deployment: approvalChecksJob
environment:
name: 'ApprovalRequirements'
strategy:
...
- job: dbRestoreJob
${{ if eq(parameters.restoreEnvironment, 'production') }}:
dependsOn: approvalChecksJob
steps:
...
Upvotes: 1
Reputation: 1238
The following solution works if your JobA
parameter is a string. (Also works for boolean parameters)
parameters:
- name: doJobA
type: string
stages:
jobs:
- job: JobA
condition: eq('${{ parameters.doJobA }}', 'string')
# ... details removed for brevity
- job: JobB
dependsOn: JobA
condition: or(
and(succeeded(), eq('${{ parameters. doJobA }}', 'yourstring')),
and(always(), ne('${{ parameters. doJobA }}', 'yourstring'))
)
# ... details removed for brevity
Upvotes: 1
Reputation: 882
Simpler solution from https://elanderson.net/2020/05/azure-devops-pipelines-depends-on-with-conditionals-in-yaml/
parameters:
- name: doJobA
type: boolean
stages:
jobs:
- job: JobA
condition: eq('${{ parameters.doJobA }}', true)
# ... details removed for brevity
- job: JobB
dependsOn: JobA
condition: in(dependencies.JobA.result, 'Succeeded', 'Skipped')
# ... details removed for brevity
Upvotes: 50
Reputation: 153
Here is the code sample I came up with (you can see the example). Job 2 is always run, and is run after Job 1 if Job 1 runs.
- job: One
condition: eq('${{ parameters.DoJobOne }}', true)
pool:
vmImage: 'windows-2019'
steps:
- powershell: |
throw "simulate Job One failing"
echo "##vso[task.setvariable variable=JobOneRan;isOutput=true]true"
name: setvarStep
- script: |
echo $(setvarStep.JobOneRan)
name: echovariable
- job: Two
condition: and(always(), eq('${{ parameters.DoJobOne }}', eq(dependencies.One.outputs['setvarStep.JobOneRan'], true)))
dependsOn: One
pool:
vmImage: 'windows-2019'
variables:
myVariableFromJobOne: $[ dependencies.One.outputs['setvarStep.JobOneRan'] ]
steps:
- script: echo $(myVariableFromJobOne)
name: echovariable
Hope that helps.
Wes
Upvotes: 4
Reputation: 1831
I've found a slightly inelegant solution. By combining expressions with boolean parameters I'm able to do what I need, but it is a bit tricky:
parameters:
- name: doJobA
type: boolean
stages:
jobs:
- job: JobA
condition: eq('${{ parameters.doJobA }}', true)
# ... details removed for brevity
- job: JobB
${{ if eq(parameters.doJobA, true) }}:
dependsOn: JobA
condition: succeeded()
# ... details removed for brevity
Here I insert a dependent clause only if the parameter doJobA
is true. Otherwise it is not present. In order to ensure that JobB
only runs if JobA
succeeds I must also add a condition, but only if dependsOn is present.
The result is that the job runs immediately if doJobA
is false because the resulting yaml will not contain any dependsOn
or condition
entries, but in the other case it will depend on the successful execution of JobA
.
I'm still hoping there is a better way to achieve this though as this seems a bit complex (imo).
Edit: This solution only works for static properties and not dynamic variables.
Upvotes: 3