How do I reference a different Variable group per stage - stage per environment in environments - Azure Devops, template, variable groups - azure

When I run the pipeline below I get an error within jobs.yml - it commplains about an "unexpected value" for the environment parameter... and within stages.yml "unexpected value: parameters" - what am I doing wrong here? The idea is to get the environments and the associated variableGroup - loop thru the environments array in Stages.yml and create a stage per environment... insert correct variableGroup per stage... use variablesGroup values to perform jobs in jobs.yml - each variable group contains the same vars.. with different values.
This is main.yml
#main.yml
trigger: none
extends:
template: /Build/Stages.yml
parameters:
environments:
- environment: Dev
variableGroup: Project-Dev-VarGrp
- environment: QA
variableGroup: Project-QA-VarGrp
dependsOn: Dev
- environment: UAT
variableGroup: Project-UAT-VarGrp
dependsOn: QA
- environment: UAT2
variableGroup: Project-UAT2-VarGrp
dependsOn: UAT
Then here is the next bit... Stages.yml
parameters:
- name: dataFolder
displayName: 'Data folder to process'
type: string
default: '/DataMigrations/Master_Data/'
- name: dataFiles
displayName: List of Data Files or Folder names
type: string
default: 'Dev_Data.zip'
- name: environments
type: object
default: []
stages:
- ${{ each environment in parameters.environments }}:
- stage: '${{ parameters.environment }}'
jobs:
- template: ./jobs.yml
variables:
- group: ${{ parameters.variableGroup }}
parameters:
environment: '${{ parameters.environment }}'
crmURL: $(crmURL)
oauthAppId: $(ClientID)
ClientPass: $(ClientPass)
dataFolder: '${{ parameters.dataFolder }}'
env: '${{ parameters.environment }}'
and here is jobs.yml
jobs:
- deployment: DeployData
displayName: 'Deploying Data to ${{ parameters.environment }}'
environment: ${{ parameters.environment }}
pool:
vmImage: 'windows-latest'
strategy:
runOnce:
deploy:
steps:
- checkout: self
clean: false
- powershell: |
Write-Host "##vso[task.setvariable variable=crmConnectionString]'AuthType=ClientSecret;Url=$(crmURL);ClientId=$(ClientID);ClientSecret=$(ClientPass)'"
displayName: 'PreDeploy configuration'
- task: PowerShell#2
displayName: 'Powershell: Run update-data.ps1'
inputs:
targetType: 'filePath'
filePath: $(System.DefaultWorkingDirectory)/DataMigrations/Scripts/update-data.ps1
arguments: -folderName '${{ parameters.dataFolder }}' -environment '${{ parameters.env }}'
workingDirectory: $(System.DefaultWorkingDirectory)/DataMigrations
- task: PowerShell#2
displayName: 'Powershell: Run zip-import-data.ps1'
inputs:
targetType: 'filePath'
filePath: $(System.DefaultWorkingDirectory)/DataMigrations/Scripts/zip-import-data.ps1
arguments: -folderName '${{ parameters.dataFolder }}' -dataMigrationFilenames '${{ parameters.dataFiles }}' -connectionString $(crmConnectionString)
workingDirectory: $(System.DefaultWorkingDirectory)/DataMigrations

Few things here:
When you're using ${{ each environment in parameters.environments }} then the nested environment and variableGroup are available using this syntax ${{ environment.environment }} and ${{ environment.variableGroup}}
In your Stages.yml file, you're trying to invoke the ./jobs.yml template but the associated parameters are defined after the - group: ${{ parameters.variableGroup }}. A valid syntax should looks like this:
stages:
- ${{ each environment in parameters.environments }}:
- stage: '${{ environment.environment }}'
variables:
- group: ${{ environment.variableGroup }}
jobs:
- template: ./jobs.yml
parameters:
environment: '${{ environment.environment }}'
crmURL: $(crmURL)
oauthAppId: $(ClientID)
ClientPass: $(ClientPass)
dataFolder: '${{ parameters.dataFolder }}'
env: '${{ environment.environment }}'
You also have few space typos. I know it's annoying but you need to have the exact yaml syntax otherwise the files can't be parsed.

Related

Reference a different Variable group per stage - stage per environment in environments - Azure Devops, template, variable groups

I want to get the environments and the associated variableGroup - loop thru the environments array in Stages.yml and create a stage per environment... insert correct variableGroup per stage... use variablesGroup values to perform jobs in jobs.yml - each variable group contains the same vars.. with different values.
``
I have a main.yml file in which I reference my environments and the associated group variable
main.yaml :
name: $(BuildID)
trigger: none
pool:
vmImage: 'leetchi-agentspool-windows'
variables:
- template: vars/variables-api.yaml
extends:
template: deploy-stages.yaml
parameters:
environements:
- environement: 'DV1'
variableGroupName: tf-dv1
- environement: 'IN1'
variableGroupName: tf-in1
A stage template which is supposed to apply with the environment parameters and the group variable.
stage.yaml :
---
parameters:
- name: environements
type: object
default: []
stages:
- ${{ each environement in parameters.environements }}:
- stage: 'Deploy to ${{ environement.environements }}'
variables:
- group: ${{ environement.variableGroup }}
jobs:
- template: template-terraform-deployment.yml
parameters:
environement: ${{environement.environements}}
project: $(project)
definition: $(def)
project1: $(project1)
definition1: $(def1)
stateKey: ${{environement.environement}}$(tfkey)
TerraformDirectory: $(TfDirectory)
azureSubscription: $(service_connection_name)
TfStateResourceGroupName: $(tf_resource_group)
TfStateStorageAccountName: $(tf_storage_account)
TStateContainerName: $(tf_container)
commandOptions: -out=$(System.DefaultWorkingDirectory)/terraform.tfplan -detailed-exitcode
I start in YAML. Could you help me please? Thank you very much in advance
You can modify your main.yaml as below:
trigger: none
pool:
vmImage: 'leetchi-agentspool-windows'
variables:
- template: vars/variables-api.yaml
extends:
template: deploy-stages.yaml
parameters:
- name: environment
values:
- DV1
- IN1
- name: variableGroupName
values:
- tf-dv1
- tf-in1
stage.yaml :
stages:
- stage: 'Deploy to ${{ parameters.environment }}'
variables:
- group: ${{ parameters.variableGroupName}}
jobs:
- template: template-terraform-deployment.yml
parameters:
environment: ${{ parameters.environment }}
project: $(project)
definition: $(def)
project1: $(project1)
definition1: $(def1)
stateKey: ${{ parameters.environment }} + $(tfkey)
TerraformDirectory: $(TfDirectory)
azureSubscription: $(service_connection_name)
TfStateResourceGroupName: $(tf_resource_group)
TfStateStorageAccountName: $(tf_storage_account)
TStateContainerName: $(tf_container)
commandOptions: -out=$(System.DefaultWorkingDirectory)/terraform.tfplan -detailed-exitcode

Making an Azure Terraform pipeline work with multiple subscriptions

I am trying to get my main Terraform pipeline to deploy to multiple subscriptions, using the same service principle. Yet I keep getting errors that state resource group not found when it tries to deploy to the subscription. Both subscriptions are in the same tenant.
Here is my YAML Code:
parameters:
- name: terraformWorkingDirectory
type: string
default: '$(System.DefaultWorkingDirectory)/Terraform/'
- name: serviceConnection
type: string
default: 'JasonTestEnvManagmentGroup'
- name: azureSubscription
type: string
default: 'JasonTestEnvManagmentGroup'
- name: appconnectionname
type: string
default: 'JasonTestEnvManagmentGroup'
- name: RG
type: string
default: 'Jason_Testing_Terraform'
- name: azureLocation
type: string
default: 'UK South'
- name: terraformVersion
type: string
default: '1.0.4'
- name: artifactName
type: string
default: 'Website'
#- name: authartifactName
# type: string
#default: 'AuthServer'
# Only run against develop
#trigger:
# branches:
# include:
# - main
#pool:
#vmImage: "ubuntu-latest"
# Don't run against PRs
#pr: none
#stages:
#- stage: terraformStage
# displayName: Detect Drift
# jobs:
#- job: terraform_plan_and_apply
steps:
- checkout: self
- task: TerraformInstaller#0
displayName: "install"
inputs:
terraformVersion: ${{ parameters.terraformVersion }}
- task: TerraformTaskV2#2
displayName: "init"
inputs:
provider: "azurerm"
command: "init"
backendServiceArm: ${{ parameters.serviceConnection }}
backendAzureRmResourceGroupName: "TerraformBackendForCICTesting"
backendAzureRmStorageAccountName: "nsterraformstatestorage"
backendAzureRmContainerName: "devopsterraformstatefile"
backendAzureRmKey: "terraform.tfstate"
workingDirectory: ${{ parameters.terraformWorkingDirectory }}
- task: TerraformTaskV1#0
displayName: "plan"
inputs:
provider: "azurerm"
command: "plan"
commandOptions: "-input=false"
environmentServiceNameAzureRM: ${{ parameters.serviceConnection }}
workingDirectory: ${{ parameters.terraformWorkingDirectory }}
- task: TerraformTaskV1#0
displayName: "apply"
inputs:
provider: "azurerm"
command: "apply"
commandOptions: "-input=false -auto-approve"
environmentServiceNameAzureRM: ${{ parameters.serviceConnection }}
workingDirectory: ${{ parameters.terraformWorkingDirectory }}
#- stage: put_pipelines_files_in_place
# displayName: Putting Pipeline Files In Place
#- jobs:
#- job: apply_artifiact_to_web_app
# displayName: Putting Files In Place
# dependsOn: terraform_plan_and_apply
# Download Artifact File
#- download: none
- task: DownloadPipelineArtifact#2 # Website Artifact
displayName: 'Download Build Artifacts'
inputs:
artifact: ${{ parameters.artifactName }}
patterns: '/website/**/*.zip'
path: '$(Build.ArtifactStagingDirectory)/website/'
# deploy to Azure Web App
- task: AzureWebApp#1
displayName: 'Azure Web App Deploy: nsclassroom-dgyn27h2dfoyojc' #Website Deploy Artifact
inputs:
package: $(Build.ArtifactStagingDirectory)/website/**/*.zip
azureSubscription: ${{ parameters.azureSubscription }}
ConnectedServiceName: ${{ parameters.appconnectionname}}
appName: 'nsclassroom-dgyn27h2dfoyojc'
ResourceGroupName: ${{ parameters.RG}}
- task: DownloadPipelineArtifact#2 # Authentication Server Artifact
displayName: 'Download Build Artifacts'
inputs:
artifact: ${{ parameters.artifactName}}
patterns: '/authsrv/**/*.zip'
path: '$(Build.ArtifactStagingDirectory)/authsrv/'
# deploy to Azure Web App
- task: AzureWebApp#1
displayName: 'Azure Web App Deploy: nsclassroomauthentication-dgyn27h2dfoyojc' #Authentication Server Deploy Artifact
inputs:
package: $(Build.ArtifactStagingDirectory)/authsrv/**/*.zip
azureSubscription: ${{ parameters.azureSubscription }}
ConnectedServiceName: ${{ parameters.appconnectionname}}
appName: 'nsclassroomauthentication-dgyn27h2dfoyojc'
ResourceGroupName: ${{ parameters.RG}}
The agent is uses is the default Ubuntu agent.
The service connection I have tried two, one mapped to both of the subscriptions doesn't work. Another mapped and scoped to the Management group.
The original service principle did work until I brought in the second subscription.

Microsoft Dev Ops yaml variables between deployments

So at it's core what I'm essentially trying to do is this:
https://learn.microsoft.com/en-us/azure/devops/pipelines/process/deployment-jobs?view=azure-devops&preserve-view=true#support-for-output-variables
Which breaks down to the fact that I have a single deployment template that produces an output variable that I want to map back to a variable in my main template so that I can use it in subsequent deployment templates.
I have created a github project with all of my yaml templates here
https://github.com/MCKRUZ/azure-pipelines
but the crux of the problem lies in these few lines. First I'm calling a template deployment in my main "development.yaml" file.
# Deploy
# ------
- stage: Deploy
displayName: Deploy - Development
jobs:
- template: jobs/jobs-deploy-spa-arm-template.yaml
parameters:
environment: '$(environment)'
serviceConnection: '$(serviceConnection)'
subscriptionId: '$(subscriptionId)'
resourceGroup: '$(resourceGroup)'
storageAccountName: '$(storageAccountName)'
cdnEndpointName: '$(cdnEndpointName)'
cdnProfileName: '$(cdnProfileName)'
deploymentLocation: '$(deploymentLocation)'
armTemplateArtifactName: ${{ variables['armTemplateArtifactName'] }}
storageAccountCSMFilePath: '$(storageAccountCSMFilePath)'
storageAccountCSMParametersFile: '$(storageAccountCSMParametersFile)'
deployCDN: '${{ variables.isProduction }}'
cdnCSMFilePath: '$(cdnCSMFilePath)'
cdnCSMParametersFile: '$(cdnCSMParametersFile)'
That template looks like this:
# Parameters
# ---------
parameters:
- name: environment
type: string
- name: serviceConnection
type: string
- name: subscriptionId
type: string
- name: resourceGroup
type: string
- name: storageAccountName
type: string
- name: cdnEndpointName
type: string
- name: cdnProfileName
type: string
- name: deploymentLocation
type: string
- name: armTemplateArtifactName
type: string
- name: storageAccountCSMFilePath
type: string
- name: storageAccountCSMParametersFile
type: string
- name: deployCDN
type: boolean
default: false
- name: cdnCSMFilePath
type: string
- name: cdnCSMParametersFile
type: string
- name: overrideParameterFile
type: boolean
default: true
# Jobs
# ---------
jobs:
# Job - Deploy SPA ARM Template
# ---------
- #deployment: '${{ parameters.armTemplateArtifactName }}'
deployment: armTemplates
variables:
storageAccountNameCalculated: ''
cdnEndpointNameCalculated: ''
displayName: Deploy SPA ARM Template
environment: ${{ parameters.environment }}
workspace:
clean: all
strategy:
runOnce:
deploy:
steps:
# Bash - Show Input Parameter Variables
# ---------
- bash: |
echo ''
echo '===== Deploy SPA ARM Template Input Variables ====='
echo ''
echo ' ===== Parameters ====='
echo ' environment: ${{ parameters.environment }}'
echo ' serviceConnection: ${{ parameters.serviceConnection }}'
echo ' subscriptionId: ${{ parameters.subscriptionId }}'
echo ' resourceGroup: ${{ parameters.resourceGroup }}'
echo ' storageAccountName: ${{ parameters.storageAccountName }}'
echo ' cdnEndpointName: ${{ parameters.cdnEndpointName }}'
echo ' cdnProfileName: ${{ parameters.cdnProfileName }}'
echo ' deploymentLocation: ${{ parameters.deploymentLocation }}'
echo ' armTemplateArtifactName: ${{ parameters.armTemplateArtifactName }}'
echo ' storageAccountCSMFilePath: ${{ parameters.storageAccountCSMFilePath }}'
echo ' storageAccountCSMParametersFile: ${{ parameters.storageAccountCSMParametersFile }}'
echo ' deployCDN: ${{ parameters.deployCDN }}'
echo ' cdnCSMFilePath: ${{ parameters.cdnCSMFilePath }}'
echo ' cdnCSMParametersFile: ${{ parameters.cdnCSMParametersFile }}'
echo ''
displayName: Debug - Input Parameters
# Task - Deploy Storage Account ARM Template
# ---------
- task: AzureResourceManagerTemplateDeployment#3
displayName: Deploy Storage Account ARM Template
inputs:
deploymentScope: 'Resource Group'
azureResourceManagerConnection: '${{ parameters.serviceConnection }}'
subscriptionId: '${{ parameters.subscriptionId }}'
action: 'Create Or Update Resource Group'
resourceGroupName: '${{ parameters.resourceGroup }}'
location: '${{ parameters.deploymentLocation }}'
templateLocation: 'Linked artifact'
csmFile: '$(Pipeline.Workspace)\${{ parameters.armTemplateArtifactName }}\${{ parameters.storageAccountCSMFilePath }}'
csmParametersFile: '$(Pipeline.Workspace)\${{ parameters.armTemplateArtifactName }}\${{ parameters.storageAccountCSMParametersFile }}'
deploymentMode: 'Incremental'
deploymentName: 'storageAccountDeployment'
deploymentOutputs: 'storageAccountDeploymentOutput'
${{ if eq(parameters.overrideParameterFile, 'true') }}:
overrideParameters: '-formatNames true -environment ${{ parameters.environment }} -storageAccountName ${{ parameters.storageAccountName }}'
# Task - Retrieve Output Variable
#----------
- task: AzurePowerShell#5
displayName: Retrieve Output Variables
name: retrieveStorageAccountDeploymentOutput
condition: succeeded()
inputs:
azureSubscription: '${{ parameters.serviceConnection }}'
scriptType: 'inlineScript'
azurePowerShellVersion: 'LatestVersion'
inline: |
$armOutput = '$(storageAccountDeploymentOutput)' | ConvertFrom-Json
Write-Output "##vso[task.setvariable variable=storageAccountNameCalculated;]$($armOutput.storageAccountName.value)"
- script: echo "##vso[task.setvariable variable=myOutputVar;isOutput=true]this is the deployment variable value"
name: setvarStep
- script: echo $(setvarStep.myOutputVar)
name: echovar
# Task - Add Static Hosting to Storage Account
# ---------
- task: AzurePowerShell#5
displayName: Add Static Hosting to Storage Account
condition: succeeded()
inputs:
azureSubscription: '${{ parameters.serviceConnection }}'
scriptType: 'inlineScript'
azurePowerShellVersion: latestVersion
inline: |
$StorageAccount = Get-AzStorageAccount -Name $(storageAccountNameCalculated) -ResourceGroupName '${{ parameters.resourceGroup }}'
Enable-AzStorageStaticWebsite -Context $StorageAccount.Context -IndexDocument index.html -ErrorDocument404Path index.html
# Task - Deploy CDN ARM Template
# ---------
- task: AzureResourceManagerTemplateDeployment#3
displayName: Deploy CDN ARM Template
condition: and(succeeded(), eq(${{ parameters.deployCDN }}, 'true'))
inputs:
deploymentScope: 'Resource Group'
azureResourceManagerConnection: '${{ parameters.serviceConnection }}'
subscriptionId: '${{ parameters.subscriptionId }}'
action: 'Create Or Update Resource Group'
resourceGroupName: '${{ parameters.resourceGroup }}'
location: '${{ parameters.deploymentLocation }}'
templateLocation: 'Linked artifact'
csmFile: '$(Pipeline.Workspace)\${{ parameters.armTemplateArtifactName }}\${{ parameters.cdnCSMFilePath }}'
csmParametersFile: '$(Pipeline.Workspace)\${{ parameters.armTemplateArtifactName }}\${{ parameters.cdnCSMParametersFile }}'
deploymentMode: 'Incremental'
deploymentName: 'cdnDeployment'
deploymentOutputs: 'CDNDeployOutput'
${{ if eq(parameters.overrideParameterFile, 'true') }}:
overrideParameters: '-formatNames true -environment ${{ parameters.environment }} -cdnEndpointName ${{ parameters.cdnEndpointName }} -cdnProfileName ${{ parameters.cdnProfileName }} -storageAccountPrimaryEndpoint -storageAccountPrimaryEndpoint $storageAccountNameCalculated.z13.web.core.windows.net'
# Task - Retrieve Output Variable
#----------
- task: AzurePowerShell#5
displayName: Retrieve Output Variables
condition: and(succeeded(), eq(${{ parameters.deployCDN }}, 'true'))
inputs:
azureSubscription: '${{ parameters.serviceConnection }}'
scriptType: 'inlineScript'
azurePowerShellVersion: 'LatestVersion'
inline: |
$armOutput = '$(CDNDeployOutput)' | ConvertFrom-Json
Write-Output "##vso[task.setvariable variable=cdnEndpointNameCalculated;isOutput=true]$($armOutput.cdnEndpointName)"
# Bash - Show Output Parameter Variables
# ---------
- bash: |
echo ''
echo '===== Deploy SPA ARM Template Output Variables ====='
echo ''
echo ' ===== Parameters ====='
echo ' storageAccountNameCalculated: $(storageAccountNameCalculated)'
echo ' cdnEndpointName: $(cdnEndpointNameCalculated)'
echo ''
displayName: Debug - Output Parameters
Where I'm using these two lines
- script: echo "##vso[task.setvariable variable=myOutputVar;isOutput=true]this is the deployment variable value"
name: setvarStep
- script: echo $(setvarStep.myOutputVar)
name: echovar
To try and isolate a way that I can create a variable that will be able to be used back in my main yaml file. When I look at the logs, the second echo successfully echos out the variable so I know that part works at least. Once this runs, back in my main yaml file I call this.
- job: job_deploy_code
displayName: Deploy Some Code
dependsOn: armTemplates
variables:
myVarFromDeploymentJob: $[ dependencies.armTemplates.outputs['deploy_Development.setvarStep.myOutputVar'] ]
steps:
- script: "echo $(myVarFromDeploymentJob)"
name: echovar
Which is just supposed to echo back what is in my variable. Right now it's blank. I know it's some stupid syntax that I'm not seeing but I can't for the life of me figure out what it is.
I solved this with the correct syntax
- job: job_deploy_code
displayName: Deploy Some Code
dependsOn: armTemplates
variables:
myVarFromDeploymentJob: $[ dependencies.armTemplates.outputs['armTemplates.setvarStep.myOutputVar'] ]

Can you pass Variable Group values to sub template in yaml?

I'm trying to create a multi-stage pipeline which has Variable Groups defined for each stage of the pipeline. The goal is to pass values from the group as parameters to a sub template. It seems the value of the Group, defined at the stage, is not getting passed in to the sub template. It overrides the "DEFAULTVALUE" with an empty string.
pipeline.yml
trigger:
- none
pool:
name: 'Azure Pipelines'
vmImage: windows-latest
stages:
- stage: DEV
variables:
- group: my-group-dev
jobs:
- template: sub-template.yml
parameters:
env: 'dev'
subscriptionName: '$(SubscriptionName)' # This reference from the variable group doesn't get passed in
subscriptionId: '$(SubscriptionId)'
- stage: TEST
variables:
- group: my-group-test
jobs:
- template: sub-template.yml
parameters:
env: 'test'
subscriptionName: '$(SubscriptionName)' # This reference from the variable group doesn't get passed in
subscriptionId: '$(SubscriptionId)'
sub-template.yml
parameters:
env: 'DEFAULTVALUE'
subscriptionName: 'DEFAULTVALUE'
subscriptionId: 'DEFAULTVALUE'
jobs:
- deployment: ResourceDeployment
displayName: Deploy Resources ${{ parameters.env }}
environment: ${{ parameters.env }}
strategy:
runOnce:
deploy:
steps:
- task: AzureFileCopy#4
displayName: 'Upload ARM Templates'
inputs:
sourcePath: '$(Pipeline.Workspace)/templates'
azureSubscription: '${{ parameters.subscriptionName }}'
destination: 'azureBlob'
storage: 'my-storage-account'
containerName: 'arm'
name: AzureFileCopy
- task: AzureResourceManagerTemplateDeployment#3
inputs:
deploymentScope: 'Resource Group'
azureResourceManagerConnection: '${{ parameters.subscriptionName }}'
subscriptionId: '${{ parameters.subscriptionId }}'
action: 'Create Or Update Resource Group'
resourceGroupName: 'my-resource-group'
location: 'eastus2'
templateLocation: 'URL of the file'
csmFileLink: '$(AzureFileCopy.StorageContainerUri)${{ parameters.env }}/templates/main.json$(AzureFileCopy.StorageContainerSasToken)'
I have also tried adding the variable group within the sub-template but that also doesn't parse correctly...
Does anyone know if this is possible?
It is a known issue that the service connection endpoint cannot be referenced in variable groups defined under stage level.
You can fix this issue by below workarounds:
1, Define the variable groups in the global level instead of stage level See below:
trigger:
- none
pool:
name: 'Azure Pipelines'
vmImage: windows-latest
# define the variable group under global level.
variables:
- group: my-group-dev
- group: my-group-test
stages:
- stage: DEV
jobs:
- template: sub-template.yml
parameters:
env: 'dev'
subscriptionName: '$(SubscriptionName)' # This reference from the variable group doesn't get passed in
subscriptionId: '$(SubscriptionId)'
- stage: TEST
jobs:
- template: sub-template.yml
parameters:
env: 'test'
subscriptionName: '$(SubscriptionName)' # This reference from the variable group doesn't get passed in
subscriptionId: '$(SubscriptionId)'
2, Link the variable groups on the UI page.
On the yaml pipeline edit page--> Click the 3dots-->Triggers-->Variables Tab-->Link Variable group
Please see below threads for more information.
Using a variable for the service connection
Azure subscription endpoint ID cannot be provided through a variable in build definition YAML file
You need to pass variable group name to template and on template level apply it on variables scope like this:
parameters:
env: 'DEFAULTVALUE'
subscriptionName: 'DEFAULTVALUE'
subscriptionId: 'DEFAULTVALUE'
variableGroupName: 'DEFAULTVALUE`
jobs:
- deployment: ResourceDeployment
displayName: Deploy Resources ${{ parameters.env }}
environment: ${{ parameters.env }}
variables:
- group: {{ paramaters.variableGroupName }}
strategy:
runOnce:
deploy:
steps:
- task: AzureFileCopy#4
displayName: 'Upload ARM Templates'
inputs:
sourcePath: '$(Pipeline.Workspace)/templates'
azureSubscription: '${{ parameters.subscriptionName }}'
destination: 'azureBlob'
storage: 'my-storage-account'
containerName: 'arm'
name: AzureFileCopy
- task: AzureResourceManagerTemplateDeployment#3
inputs:
deploymentScope: 'Resource Group'
azureResourceManagerConnection: '${{ parameters.subscriptionName }}'
subscriptionId: '${{ parameters.subscriptionId }}'
action: 'Create Or Update Resource Group'
resourceGroupName: 'my-resource-group'
location: 'eastus2'
templateLocation: 'URL of the file'
csmFileLink: '$(AzureFileCopy.StorageContainerUri)${{ parameters.env }}/templates/main.json$(AzureFileCopy.StorageContainerSasToken)'
This is similar to this topic:
For security reasons, we only allow you to pass information into templated code via explicit parameters.
https://learn.microsoft.com/en-us/azure/devops/pipelines/process/templates?view=azure-devops
The means the author of the pipeline using your template needs to commit changes where they explicitly pass the needed info into your template code.
There are some exceptions to this, where the variable is statically defined in the same file or at pipeline compile time, but generally speaking, it’s probably better to use parameters for everything that does not involve system-defined read-only dynamic variable and custom-defined dynamic output variables.
I have to variables groups
QA
PROD
both has isProd variable
and then my template is
parameters:
variableGroupName: 'QA'
jobs:
- job: ResourceDeployment
variables:
- group: ${{ parameters.variableGroupName }}
steps:
- script: echo '$(isProd)'
and main file is
trigger: none
pr: none
stages:
- stage: QA
jobs:
- template: sub-template.yml
parameters:
variableGroupName: 'QA'
- stage: PROD
jobs:
- template: sub-template.yml
parameters:
variableGroupName: 'PROD'
and I got:
and

Is there a way to set a default value for an array of objects in a yaml template (Azure Pipelines)

I have a yaml template that contains parameters like below. In the array / list I want to be able to set the default value for one of the properties (the object has 3). The reason being is I have some if statements that check these properties and I want them to run regardless of whether or not the property is set in the yaml that uses the template (the third property was added later and I don't want to have to update every repo that uses this template).
Is this something that can be done in the parameter setup?
Notes: Using the below example if the property WebProject is not used I would like everything to go through the template as if it was set to false. I know there is some duplication where I check the property and copy files / publish the artifacts but at the moment I want to get it working and make it more efficient afterwards.
yaml template
parameters:
- name: ArtifactPublish
type: boolean
default: false
- name: Solution
type: string
default: '**/*.sln'
- name: Artifacts
type: object
default: []
jobs:
- job: Build
displayName: 'Build, Pack, and Publish'
pool:
vmImage: 'windows-latest'
variables:
solution: ${{ parameters.Solution }}
buildPlatform: 'Any CPU'
buildConfiguration: 'Release'
- task: VSBuild#1
displayName: 'Build Solution'
inputs:
solution: '$(solution)'
msbuildArgs: '/p:DeployOnBuild=true /p:WebPublishMethod=Package /p:PackageAsSingleFile=true /p:SkipInvalidConfigurations=true /p:PackageLocation="$(Build.ArtifactStagingDirectory)"'
platform: '$(buildPlatform)'
configuration: '$(buildConfiguration)'
- ${{ if eq(parameters.ArtifactPublish, true) }}:
- ${{ each artifact in parameters.Artifacts }}:
- ${{ if eq(artifact.WebProject, false) }}:
- task: CopyFiles#2
displayName: 'Copy .artifactignore: ${{ artifact.ArtifactPath }}'
inputs:
SourceFolder: '$(Build.SourcesDirectory)'
Contents: '.artifactignore'
TargetFolder: '$(Build.SourcesDirectory)/${{ artifact.ArtifactPath }}'
- task: PublishPipelineArtifact#1
displayName: 'Publish Artifact: ${{ artifact.ArtifactName }}'
inputs:
targetPath: '$(Build.SourcesDirectory)/${{ artifact.ArtifactPath }}'
artifactName: '${{ artifact.ArtifactName }}'
- ${{ if eq(artifact.WebProject, true) }}:
- task: CopyFiles#2
displayName: '${{ artifact.ArtifactPath }}*'
inputs:
SourceFolder: $(Build.ArtifactStagingDirectory)
Contents: '${{ artifact.ArtifactPath }}*'
TargetFolder: '$(Build.ArtifactStagingDirectory)/${{ artifact.ArtifactPath }}'
- task: PublishPipelineArtifact#1
displayName: 'Publish Artifact: ${{ artifact.ArtifactName }} (WEB)'
inputs:
targetPath: $(Build.ArtifactStagingDirectory)/${{ artifact.ArtifactPath }}
artifactName: '${{ artifact.ArtifactName }}'
Example yaml that uses the template:
trigger:
- release
- development
- master
- feature/*
- task/*
resources:
repositories:
- repository: templates
name: Project/RepoName
type: git
ref: refs/heads/release
jobs:
- template: Templates/example.yml#templates
parameters:
ArtifactPublish: true
Artifacts:
- ArtifactPath: 'example/path'
ArtifactName: 'exampleName'
- ArtifactPath: 'example/path'
ArtifactName: 'exampleName'
WebProject: true
I am afraid setting the default value for one of the properties cannot be done in the parameters setup.
But you can use the coalesce expression to check if the WebProject parameter is set or not:
Evaluates the parameters in order, and returns the value that does not equal null or empty-string.
Min parameters:
Max parameters: N
Example: coalesce(variables.couldBeNull, variables.couldAlsoBeNull, 'literal so it always works')
So you can use the expression coalesce(artifact.WebProject, false) in your template yaml as below:
- ${{ if eq(parameters.ArtifactPublish, true) }}:
- ${{ each artifact in parameters.Artifacts }}:
- ${{ if eq(coalesce(artifact.WebProject, false),false) }}:
With this expression - ${{ if eq(coalesce(artifact.WebProject, false),false) }}, No matter whether parameter WebProject is set to false or not used, this expression will always be true.

Resources