Run template conditionally on azure pipeline yaml - azure-devops

I have two different yml pipelines. I always trigger pipeline & send variable values via postman body. Here is the body portion.
{
"definition": {
"id": 151
},
"parameters": "{\"Plan\":\"sand\"}"
}
Now i want to run a template with the condition that if the Plan is sand, then template will run. I have used many conditions but nothing is working. Providing some conditions that i tried,
- ${{ if eq(variables.Plan, 'sand') }}:
- template: Sandbox Tasks/sand.yml#templates
- ${{ if eq(parameters.Plan, 'sand') }}:
- template: Sandbox Tasks/sand.yml#templates
- template: Sandbox Tasks/sand.yml#templates
condition: eq(variables['Plan'], 'sand')
- template: Sandbox Tasks/sand.yml#templates
condition: eq(parameters['Plan'], 'sand')
- ${{ if eq(variables['Plan'], 'sand') }}:
- template: Sandbox Tasks/sand.yml#templates
- ${{ if eq(parameters['Plan'], 'sand') }}:
- template: Sandbox Tasks/sand.yml#templates
What would be the proper way to run a template with conditions by matching a variables value?

- ${{ if eq(parameters.is_python, true)}}:
- template: ../Python/install-python.yml
parameters:
variable_group: '${{parameters.variable_group}}'
- ${{ if eq(parameters.is_python, false)}}:
- template: cdk-installation.yml
parameters:
variable_group: '${{parameters.variable_group}}'

Related

Azure DevOps: An error occurred while loading the YAML build pipeline. An item with the same key has already been added

Lately I've been trying to make an Azure DevOps pipeline to deploy to 3 environments, with 2 different data centers and 2 different service connections. I've been trying to achieve this with using as little lines of YAML as possible.
After a lot of trial and error, I'm stuck on this message "An error occurred while loading the YAML build pipeline. An item with the same key has already been added."
deploy-env.yaml:
parameters:
- name: OPENSHIFT_NAMESPACE
displayName: 'OpenShift namespace'
type: object
values: []
- name: DCR
displayName: 'Data Center'
type: object
values: []
- name: OSC
displayName: 'Openshift service connection'
type: object
values: []
stages:
- ${{ each namespace in parameters.OPENSHIFT_NAMESPACE }}:
- ${{ each dcr in parameters.DCR }}:
- ${{ each osc in parameters.OSC }}:
- stage: deploy-${{ convertToJson(namespace) }}
jobs:
- deployment: deploy_to_dcr
environment: ${{ namespace }}
displayName: 'Deploy to DCR1'
strategy:
runOnce:
deploy:
steps:
- template: steps/deploy_to_cluster_with_helm_templating.yml#pipeline_templates
parameters:
DATA_CENTER: ${{ dcr }}
OPENSHIFT_NAMESPACE: ${{ namespace }}
OPENSHIFT_SERVICE_CONNECTION: '${{ osc }}'
HELM_VALUES:
- 'global.namespace=${{ namespace }}'
- 'global.data_center=${{ DCR }}'
azure-pipeline.yaml
resources:
repositories:
- repository: pipeline_templates
type: git
name: pipeline-templates
stages:
- template: deploy-env.yaml
parameters:
OPENSHIFT_NAMESPACE:
- development
- test
- acceptance
DCR:
- dcr1
- dcr2
OSC:
- OCP4DCR1
- OCP4DCR2
Does anyone knows why this error occurs? I've found other articles where stage/job names we're not unique, but that is not the case in this example.
Thanks in advance.
This line is getting repeated twelve times, with only four different values:
- stage: deploy-${{ convertToJson(namespace) }}
Stage names must be unique.

Issues while passing variable groups parameter to template from azure pipeline.yml

I have declared a variable group Agile-Connections as below and the group do not have any restriction for any Pipeline:
I am using another template called vars.yml to store some other variables:
variables:
- group: Agile-Connections
- name: extensions_dir
value: /apps/agile/product/agile936/integration/sdk/extensions
- name: properties_dir
value: /apps/agile/product/Properties
- name: build_name
value: RestrictPreliminaryBOMPX.jar
- name: resource_name
value: RestrictPreliminaryBOMPX.properties
My Azure Pipeline looks like below, which is calling a deploy.yml template, and I am passing two parameters (connection, environment) from azure pipeline.yml to deploy.yml.
Below is my azure-pipeline.yml:
trigger:
- None
pool:
name: AgentBuildAgile
stages:
- template: templates/build.yml
- stage: DEV_Deployment
variables:
- template: templates/vars.yml
jobs:
- job:
steps:
- script:
echo $(Dev-mnode1)
- template: templates/deploy.yml
parameters:
connection: $(Dev-mnode1)
environment: 'DEV'
Below is my deploy.yml:
parameters:
- name: connection
- name: environment
jobs:
- deployment:
variables:
- template: vars.yml
environment: ${{ parameters.environment }}
displayName: Deploy to ${{ parameters.environment }}
strategy:
runOnce:
deploy:
steps:
- script:
echo Initiating Deployment ${{ parameters.connection }}
- template: copy-artifact.yml
parameters:
connection: ${{ parameters.connection }}
# - template: copy-resources.yml
# parameters:
# connection: ${{ parameters.connection }}
From my deploy.yml I am passing a parameter connection further to another template called copy-artifact.yml, which is below:
parameters:
- name: connection
jobs:
- job:
variables:
- template: vars.yml
displayName: 'Copy jar'
steps:
# - script:
# echo ${{ parameters.connection }}
- task: SSH#0
displayName: 'Task - Backup Existing jar file'
inputs:
sshEndpoint: ${{ parameters.connection }}
runOptions: inline
inline:
if [[ -f ${{ variables.extensions_dir }}/${{ variables.build_name }} ]]; then mv ${{ variables.extensions_dir }}/${{ variables.build_name }} ${{ variables.extensions_dir }}/${{ variables.build_name }}_"`date +"%d%m%Y%H%M%S"`"; echo "Successfully Backed up the existing jar"; fi
Now when I run my pipeline I am getting error message :
The pipeline is not valid. Job Job3: Step SSH input sshEndpoint references service connection $(Dev-mnode1) which could not be found. The service connection does not exist or has not been authorized for use. For authorization details, refer to https://aka.ms/yamlauthz.
When I print the value of $(Dev-mnode1) using the commented out lines in copy-artifacts.yml file, it prints fine (Dev11 Connection) but when I try to use that as service connection for my ssh task, it gives me the above error.
Also, there is a service connection Dev11 Connection in my project and all the pipelines are allowed to use that service connection.
The pipeline is not valid. Job Job3: Step SSH input sshEndpoint references service connection $(Dev-mnode1) which could not be found. The service connection does not exist or has not been authorized for use.
From the error message, the parameter not get the variable value when expand the template.
Test the same sample and can reproduce the issue.
When you define the variable template at stage level, the variables in template will expand at runtime and the paramter:connection will be expand at compile time. So the correct value cannot be passed to parameter.
To solve this issue, you can define the variable template at root level.
Refer to the sample:
trigger:
- None
pool:
name: AgentBuildAgile
variables:
- template: templates/vars.yml
stages:
- template: templates/build.yml
- stage: DEV_Deployment
jobs:
- job:
steps:
- script:
echo $(Dev-mnode1)
- template: templates/deploy.yml
parameters:
connection: $(Dev-mnode1)
environment: 'DEV'

Is there any possibilities to call AzDo templated with parameters?

I would like to run a few templates based on the initial value chosen from the parameter and as soon as the value is chosen then a template will be issued which will further ask for more parameters only required for that template.
Let's say in main azure-pipelines.yml if a user chooses dev then simply a template will be called. However, if a user chooses test then template create-stack-tst-template.yml will be issued but along with that, it should prompt the parameters needed for this template. Is it possible?
If not, is there any possibility to club all the parameters only needed for dev and the same for test. So that when the individual templates are called then clubbed parameter will be passed which is necessary for that template to run but not for others.
Is there any kind of segregation exists?
trigger:
- none
parameters:
- name: DeployToEnvType
displayName: |
Select the env type to be deployed
type: string
values:
- dev
- test
stages:
- ${{ if eq(parameters['DeployToEnvType'], 'dev' ) }}:
- template: templates/create-stack-dev-template.yml
- ${{ if ne(parameters['DeployToEnvType'], 'test' ) }}:
- template: templates/create-stack-tst-template.yml
parameters:
- name: ProjectName
type: string
- name: ImageSource
type: string
it should prompt the parameters needed for this template. Is it possible?
This is not possible. You need to provide all parameters and pass further only those which are needed by particular template.
trigger:
- none
parameters:
- name: DeployToEnvType
displayName: |
Select the env type to be deployed
type: string
values:
- dev
- test
- name: ImageSource
type: string
stages:
- ${{ if eq(parameters['DeployToEnvType'], 'dev' ) }}:
- template: templates/create-stack-dev-template.yml
parameters:
ProjectName: projectA
ImageSource: ${{ parameters.ImageSource }}
- ${{ if ne(parameters['DeployToEnvType'], 'test' ) }}:
- template: templates/create-stack-tst-template.yml
parameters:
ProjectName: projectA
ImageSource: ${{ parameters.ImageSource }}
If you need control at runtime you need to make corresponding runtime parameter and pass it down. If you want to have some values fixed you can just put them inline.

AzDo build pipeline to run the step templates based on conditional parameters

I have below main.yml build pipeline,
parameters:
- name: ListOfEnvironments
type: object
default:
- dev
- tst
- acc
- prd
stages:
- ${{ each value in parameters.ListOfEnvironments }}:
- template: templates/stage.yml
parameters:
environment_name: ${{ value }}
Now above template works and able to call different env specific stage.yml templates.
now inside stage.yml I have the below structure:
stages:
- stage: deploy_to_env
displayName: Deploy
jobs:
- job: deploy
displayName: Deploy
variables:
- name: environment
value: ${{ parameters.environment_name }}
steps:
${{ if eq(parameters.environment_name, "dev") }}:
template: ../steps_templates/dev_steps.yml
${{ if eq(parameters.environment_name, "acc") }}:
template: ../steps_templates/acc_steps.yml
I'm not able to call steps template based on the conditions. Also, I tried to do like below
${{ if eq(parameters.environment_name, "dev") }}:
steps:
- template: ../steps_templates/dev_steps.yml
${{ if eq(parameters.environment_name, "acc") }}:
steps:
- template: ../steps_templates/acc_steps.yml
It's not working, does anyone have any idea how to call steps based on the conditional parameters.
UPDATE:
I finally managed to go further like this, where it recognized the env variable but now it complains Unrecognized value: '"dev"'. Located at position 33 within expression: eq(parameters.environment_name, dev)
steps:
- ${{ if eq(parameters.environment_name, "dev") }}:
- template: ../steps_templates/dev_steps.yml
- ${{ if eq(parameters.environment_name, "acc") }}:
- template: ../steps_templates/acc_steps.yml
it's working now, after changing " to ' . It's all good now.
May be someone will find this helpful:
The below layout will work fine:
steps:
- ${{ if eq(parameters.environment_name, 'dev') }}:
- template: ../steps_templates/dev_steps.yml
- ${{ if eq(parameters.environment_name, 'acc') }}:
- template: ../steps_templates/acc_steps.yml

Optional job templates in YAML Pipelines

Is it possible to optionally include templates based on some kind of template expression? Specifically, I want my top-level definition in azure-pipelines.yml to call out which build job templates to use in an included stage template:
azure-pipelines.yml :
stages:
- template: generic-build-stage.yml # Template reference
parameters:
# Example of optional build templates to use
buildTypes: [SpecificBuildJobs1, SpecificBuildJobs3, SpecificBuildJobs4]
generic-build-stage.yml :
parameters:
buildTypes: ???
stages:
- stage: generic_build
jobs:
${{ }} # ???? What goes here to include the appropriate templates
- template: ???
The template expression above would ideally expand to this:
jobs:
- template: specific-build-jobs1.yml
- template: specific-build-jobs3.yml
- template: specific-build-jobs4.yml
Edit: The "Iterative insertion" example in the docs seems to suggest that some form of dynamic, parse-time insertion is possible.
The following method worked to allow a top-level pipeline definition to consume a variable number of job sets at a lower level.
azure-pipelines.yml :
stages:
- template: generic-build-stage.yml # Template reference
parameters:
# Example of optional build templates to use
buildTypes: [SpecificBuildJobs1, SpecificBuildJobs3, SpecificBuildJobs4]
generic-build-stage.yml :
parameters:
buildTypes: [MissingBuildType] # Use this if buildTypes is not provided
stages:
- stage: build_stage
jobs:
# Note: VS Code extension for Pipelines (1.1574.4) will
# say this is an "Unexpected property", but this works in ADO
- ${{ if containsValue(parameters.buildTypes, 'MissingBuildType') }}:
- template: build-stage-null.yml
- ${{ if containsValue(parameters.buildTypes, 'SpecificBuildJobs1') }}:
- template: specific-build-jobs1.yml
- ${{ if containsValue(parameters.buildTypes, 'SpecificBuildJobs2') }}:
- template: specific-build-jobs2.yml
- ${{ if containsValue(parameters.buildTypes, 'SpecificBuildJobs3') }}:
- template: specific-build-jobs3.yml
- ${{ if containsValue(parameters.buildTypes, 'SpecificBuildJobs4') }}:
- template: specific-build-jobs4.yml
It seems to be impossible, for the template reference is resolved at parse time.
You may have to set multiple templates for main pipeline, and set the value for buildTypes as the specific template name for job templates, and in generic-build-stage.yml use - template:${{parameters.buildTypes}}.yml to call corresponding job template;
Azure-pipelines.yml:
stages:
- template: generic-build-stage.yml
parameters:
buildTypes:specific-build-jobs1
- template: generic-build-stage.yml
parameters:
buildTypes:specific-build-jobs3
generic-build-stage.yml
parameters:
buildTypes: ""
stages:
- stage: generic_build
jobs:
- template: ${{parameters.buildTypes}}.yml