How do I do the condition part in the code below under "Approval_Test" stage? I have to generate the condition dynamically , can't hardcode it due to some requirements. The stage will also be generated dynamically based on the parameters param.
"Approval_Test" stage can only be run after all solution1, 2 and 3 are finished and/or skipped
#azure-pipeline.yml
trigger: none
#Package Parameter
parameters:
- name: "params"
type: object
default:
Solution1:
name: "Solution1"
Solution2:
name: "Solution2"
Solution3:
name: "Solution3"
stages:
- ${{ each param in parameters.params }}:
- stage: Deploy_dev_${{ param.value.name }}
jobs:
- template: deploy-dev.yml
- stage: Approval_Test
dependsOn:
- ${{ each param2 in parameters.params }}:
- Deploy_dev_${{ param2.value.name }}
condition: |
#The "each" below would not work and throw errors.
and
(
- ${{ each param2 in parameters.params }}:
in(dependencies.Deploy_dev_${{ param2.value.name }}.result, 'Succeeded', 'SucceededWithIssues', 'Skipped'),\
)
jobs:
- deployment: Approval
environment: 'sandbox'
This was a tough nut to crack and I wasn't able to solve it with the each keyword, but please let me present a feasible alternative.
Alternate solution: Job status check functions
Without your requirement of also having the skipped stages the solution would be adding condition: succeeded() to the stage: Approval_Test :
But this doesn't work for a skipped stage.
Not Failed?
Unfortunately there is no 'Skipped' to check from the job status functions, but what if we take the opposite of failed(), not(failed())!?
The works out fine:
#azure-pipeline.yml
trigger: none
#Package Parameter
parameters:
- name: "params"
type: object
default:
Solution1:
name: "Solution1"
Solution2:
name: "Solution2"
Solution3:
name: "Solution3"
stages:
- ${{ each param in parameters.params }}:
- stage: Deploy_dev_${{ param.value.name }}
jobs:
- template: deploy-dev.yml
- stage: skipped # test to simulate a skip from the template
condition: failed()
jobs:
- job: concat
steps:
- ${{ each parameter in parameters.params }}:
- script: echo Deploy_dev_${{ parameter.value.name }}.result
- stage: Approval_Test
condition: not(failed())
dependsOn:
- skipped # test to simulate a skip from the template
- ${{ each param2 in parameters.params }}:
- Deploy_dev_${{ param2.value.name }}
jobs:
- deployment: Approval
environment: 'sandbox'
(Don't) use the equivalent
According to the docs failed() is a equivalent for eq(variables['Agent.JobStatus'], 'Failed').
Would eq(variables['Agent.JobStatus'], 'Succeeded', 'SucceededWithIssues', 'Skipped') not be the solution then?
No!
Why I don't understand, but in my tests (above) with the yaml (below) it wouldn't fly.
#azure-pipeline.yml
trigger: none
#Package Parameter
parameters:
- name: "params"
type: object
default:
Solution1:
name: "Solution1"
Solution2:
name: "Solution2"
Solution3:
name: "Solution3"
stages:
- ${{ each param in parameters.params }}:
- stage: Deploy_dev_${{ param.value.name }}
jobs:
- template: deploy-dev.yml
- stage: skipped # test to simulate a skip from the template
condition: failed()
jobs:
- job: concat
steps:
- ${{ each parameter in parameters.params }}:
- script: echo Deploy_dev_${{ parameter.value.name }}.result
- stage: Approval_Test
condition: in(variables['Agent.JobStatus'], 'Succeeded', 'SucceededWithIssues', 'Skipped')
dependsOn:
- skipped # test to simulate a skip from the template
- ${{ each param2 in parameters.params }}:
- Deploy_dev_${{ param2.value.name }}
jobs:
- deployment: Approval
environment: 'sandbox'
Conclusion
If not(failed()) works for you, I advice you to use that.
Related
I'm trying to build a new yaml file that reads keyvault secrets based on the parameters at the runtime and declared variables with the condition as per the parameters, but this isn't working.
- name: azure_subscription
displayName: " Select subscription "
type: string
default: "service-connection-dev"
values:
- 'service-connection-dev'
- 'service-connection-sit'
- 'service-connection-tes'
- 'service-connection-prd'
variables:
- ${{ if eq('${{ parameters.azure_subscription }}', 'service-connection-sit') }}:
name: key_vault
value: 'core-kv-sit'
- ${{ if eq('${{ parameters.azure_subscription }}', 'service-connection-dev') }}:
name: key_vault
value: 'core-kv-dev'
stages:
- stage: Validate
${{ if eq(parameters.azure_subscription, 'service-connection-dev') }}:
pool:
name: agent-pool-win-dev
${{ if eq(parameters.azure_subscription, 'service-connection-sit') }}:
pool:
name: agent-pool-win-sit
jobs:
- job: Validate
steps:
- task: AzureKeyVault#2
inputs:
KeyVaultName: "${{variables.key_vault}}"
SecretsFilter: "*"
RunAsPreJob: false
azureSubscription: ${{ parameters.azure_subscription }}
I've tried using variables inside jobs, but that is also not working. Can someone please help?
Also, I'll have to declare 2 more variables as per the parameters input, Is it possible ?
Thanks in advance
- ${{ if eq('${{ parameters.azure_subscription }}', 'service-connection-sit') }}:
You're using a literal value of "${{ parameters.azure_subscription }}" for the left side of the comparison. The comparison should just be parameters.azure_subscription.
So: - ${{ if eq(parameters.azure_subscription, 'service-connection-sit') }}:
I have a pipeline setup that is very basic and using the below template
parameters:
- name: countries
type: object
default:
- country: 'uk'
envs: ['development', 'preproduction', 'production']
- country: 'us'
envs: ['development', 'preproduction', 'production']
stages:
- ${{ each c in parameters.countries }}:
- stage: ${{ c.country }}
displayName: ${{ c.country }}
# some variable here to control if to use [] to deploy to all stages or just one
dependsOn: []
jobs:
- ${{ each env in c.envs }}:
- job: ${{ c.country }}_${{ env }}
steps:
- script: echo "Hello world"
condition: contains(variables['System.JobDisplayName'], 'production')
- script: echo "Hello world 2"
I want to have it so it only deploys to the new job loop in the pipeline if the previous job loop has succeeded. I can't seem to figure out a way of doing this. Any help will be appreicated. Thanks!
I managed to achieve this with the below job spec
- job: ${{ c.country }}_${{ env }}
${{if eq(env, 'preproduction')}}:
condition: eq(dependencies.${{ c.country }}_development.result, 'Succeeded')
dependsOn: ${{ c.country }}_development
${{if eq(env, 'production')}}:
condition: eq(dependencies.${{ c.country }}_preproduction.result, 'Succeeded')
dependsOn: ${{ c.country }}_preproduction
steps:
Essentially I am trying to use a if else logic inside a yaml template instead of the caller pipeline.
I have following two pipelines azure-caller.yml and template.yaml
azure-caller.yml
parameters:
- name: test
displayName: 'select true or false'
values:
- true
- false
variables:
- name: test-true
${{ if eq(parameters.test, 'true') }}:
value: false
${{ elseif eq(parameters.test, 'false') }}:
value: true
stages:
- template: job-templates/template.yml
parameters:
testrue: $(test-true)
template.yml
parameters:
testrue: test_true
stages:
- stage: A
jobs:
- job: JA
steps:
- script: |
echo "Reverted value is" ${{ parameters.testrue }}
name: DetermineResult
How can I move the if else logic in the template.yml instead of azure-caller.yml? Your input will be helpful. thx
Below pipeline should do the trick with a limitation that the scope of variable test-true in the template will be limited only for stage: A
azure-caller.yml
parameters:
- name: test
displayName: 'select true or false'
values:
- true
- false
stages:
- template: job-templates/template.yml
parameters:
testrue: ${{ parameters.test }}
template.yml
parameters:
testrue: default
stages:
- stage: A
variables:
- name: test-true
${{ if eq(parameters.testrue, 'true') }}:
value: NewValueForTrueParam
${{ elseif eq(parameters.testrue, 'false') }}:
value: NewValueForFalseParam
jobs:
- job: JA
steps:
- script: |
echo "Echo value is" $(test-true)
Result
I have a number of jobs for different platforms I'd like to run in parallel. I'd like to build a different set of platforms for different situations (i.e. full build, smoke, pull request, etc.). How can I make a list of jobs dynamic based on variables?
For example, if this is one of the "hard-coded" implementations:
jobs:
- job: Platform1
pool: Pool1
steps:
- template: minimal_template.yml
parameters:
BuildTarget: Platform1
- job: Platform2
pool: Pool1
steps:
- template: minimal_template.yml
parameters:
BuildTarget: Platform2
- job: Platform3
pool: Pool2
steps:
- template: minimal_template.yml
parameters:
BuildTarget: Platform3
How could I instead extract out a collection of variable sets, i.e.
[[Platform1, Pool1], [Platform2, Pool1], [Platform3, Pool2]]
And execute that on a pipeline like:
jobs:
??(Foreach platform in platforms)??
- job: $(platform[0])
pool: $(platform[1])
steps:
- template: minimal_template.yml
parameters:
BuildTarget: $(platform[0])
You can define it in the parameters and loop it:
parameters:
- name: Platforms
type: object
default:
- name: 'Platform1'
pool: 'Platform1Pool'
- name: 'Platform2'
pool: 'Platform2Pool'
jobs:
- ${{ each platform in parameters.Platforms}}:
- job: ${{ platform.name }}
pool: ${{ platform.pool }}
steps:
- template: minimal_template.yml
You may alos use 'jobList' type for template parameters:
parameters:
- name: 'testsJobsList'
type: jobList
default: []
jobs:
- ${{ each job in parameters.testsJobsList }}: # Each job
- ${{ each pair in job }}: # Insert all properties other than "steps"
${{ if ne(pair.key, 'steps') }}:
${{ pair.key }}: ${{ pair.value }}
steps: # Wrap the steps
- ${{ job.steps }} # Users steps
And then:
trigger:
- none
pool:
vmImage: 'windows-latest'
jobs:
- template: deployment-template.yml
parameters:
testsJobsList:
- job: Platform1
pool: Platform1Pool
steps:
- template: minimal_template.yml
- job: Platform2
pool: Platform2Pool
steps:
- template: minimal_template.yml
You’re looking for conditions: https://learn.microsoft.com/en-us/azure/devops/pipelines/process/conditions?view=azure-devops&tabs=yaml
Stages, jobs, and steps can all have a condition defined.
For example, running a job if a variable is set to true:
condition: eq(variables['System.debug'], 'true')
I want to have multiple dependencies over a template. Is there a way to establish condition over the iteration of a parameter array ?
parameters:
deps: [Integration, Migration]
jobs:
- deployment: Deploy
displayName: 'Deploy'
dependsOn:
- ${{ each dep in parameters.deps }}:
- ${{ dep }}
condition:
- ${{ each dep in parameters.deps }}:
- in(dependencies.${{ dep }}.result, 'Succeeded', 'Skipped')
environment: QA
strategy:
runOnce:
deploy:
steps:
- bash: |
echo "Deploy dev"
This one is marked as (Line: 12, Col: 3): A sequence was not expected
The error is caused by below condition:
condition:
- ${{ each dep in parameters.deps }}:
- in(dependencies.${{ dep }}.result, 'Succeeded', 'Skipped')
Above yaml will be evaluated to :
condition:
- in(dependencies.Integration.result, 'Succeeded', 'Skipped')
- in(dependencies.Migration.result, 'Succeeded', 'Skipped')
Condition cannot accept a sequence of expressions. Multiple expressions should be joined with and , or or xor. See here for more information.
You might have to evaluate the condition outside the template.
For example, add an additional job in your azure-pipelines.yml to depend on the above jobs: See below:
#azure-pipelines.yml
- job: CheckStatus
dependsOn:
- Integration
- Migration
condition: |
and
(
in(dependencies.Integration.result, 'Succeeded', 'SucceededWithIssues', 'Skipped'),
in(dependencies.Migration.result, 'Succeeded', 'SucceededWithIssues', 'Skipped')
)
steps:
- powershell:
- template: template.yaml
parameters:
deps: CheckStatus
Then you can just check the status of job CheckStatus in the template:
#template.yml
parameters:
deps: CheckStatus
jobs:
- job: secure_buildjob
dependsOn: ${{parameters.deps}}
condition: eq(dependencies.${{ parameters.deps }}.result, 'Succeeded')