Azure pipeline yml - Change value in task and execute based on if else condition - azure

In the below task, based on the branch, how do I specify a different value for assembleQaDebug. If the branch is qa it has to be assembleQaDebug; if develop, it has to be assembleDevelopDebug . And if prod branch, it has to be assembleProdRelease. What is the best approach doing this, if there is one. Any help is much appreciated.
- task: Gradle#3
displayName: 'Build Task'
continueOnError: false
inputs:
tasks: assembleQaDebug -PversionCode=$(Build.BuildId) -PdisablePreDex --no-daemon
publishJUnitResults: false

Not sure if it's the best way to do this, but I love using variables for those kind of use cases, so check this one :
...
variables:
- name: assembleDebug
${{ if eq(variables['Build.SourceBranch'], 'refs/heads/prod') }}:
value: assembleProdRelease
${{ elseif eq(variables['Build.SourceBranch'], 'refs/heads/qa') }}:
value: assembleQaDebug
${{ elseif eq(variables['Build.SourceBranch'], 'refs/heads/develop') }}:
value: assembleDevelopDebug
...
- task: Gradle#3
displayName: 'Build Task'
continueOnError: false
inputs:
tasks: $(assembleDebug) -PversionCode=$(Build.BuildId) -PdisablePreDex --no-daemon
publishJUnitResults: false

The values has to be specified in 'variables' section:
variables:
- name: tf_version
value: latest
- name: variablegroupname
${{ if eq(variables['Build.SourceBranchName'], 'develop') }}:
value: assembleDevelopDebug
${{ if eq(variables['Build.SourceBranchName'], 'qa') }}:
value: assembleQaDebug
- name: env
${{ if eq(variables['Build.SourceBranchName'], 'main') }}:
value: prod
${{ if eq(variables['Build.SourceBranchName'], 'dev') }}:
value: develop
Like this you can add your variables and depending on your stage you can replace the values.

Related

Azure DevOps Pipeline - condition expression with pipeline variable

I need to make my stages in DevOps YAML pipeline dependent or not based on pipeline variable (not variable defined in the YAML).
I tried something like this:
- stage: 'test'
${{ if eq(variables.dependent_stages, 'true') }}:
dependsOn: [dev]
${{ elseif eq(variables.dependent_stages, 'false') }}:
dependsOn: []
jobs:
- deployment: approve
environment: TEST
However it always takes it as "true" as it is default value of the variable.
How to make it reflect actual value of the pipeline variable?
Not the solution I hoped for, but solved with parameters:
parameters:
- name: dependent_stages
displayName: Should environments depend on each other?
type: string
default: No
values:
- No
- Yes
...
- stage: 'test'
${{ if eq(parameters.dependent_stages, 'Yes') }}:
dependsOn: [dev]
${{ elseif eq(parameters.dependent_stages, 'No') }}:
dependsOn: []

Yaml Variable not working for dockerfile using variables

So I have the following variable comdition defined in my YAML
${{ if endsWith( variables['Build.SourceBranchName'], 'main' ) }}:
dFile: 'Dockerfile'
${{ if endsWith( variables['Build.SourceBranchName'], 'development' ) }}:
dFile: 'Development.Dockerfile'
I then use this in a build image task like this:
- task: Docker#0
displayName: 'Build an image'
inputs:
azureSubscription: 'Azure Registry'
azureContainerRegistry: 'redacted'
dockerFile: $[variables.dFile]
imageName: '$(Build.Repository.Name)-$(build.sourceBranch):$(Build.BuildNumber)'
includeLatestTag: true
But for some reason this is the output I get:
##[error]Unhandled: No Docker file matching /home/vsts/work/1/s/$[variables.dockerFile] was found.
I also tried '$(dFile)' and got the same error
Defines the variables as name-value pair.
Here is what your variables block would look like:
variables:
- ${{ if endsWith( variables['Build.SourceBranchName'], 'main' ) }}:
- name: dFile
value: 'Dockerfile'
- ${{ if endsWith( variables['Build.SourceBranchName'], 'development' ) }}:
- name: dFile
value: 'Development.Dockerfile'

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

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.

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.

How to select a specific build agent from Azure pipelines to run your build on?

I'm trying to come up with a way to allow an easy selection of a given agent within the build pipeline just for debugging purposes. So far I have the below snippet. Both work without the if snippets wrapped around but I was trying to do one or the other based on either params being set or inturn variables being set so that if it was in debug mode it would select and agent and if it wasn't then it would just use the pool to select an agent to run the builds against. So far no luck though.
variables:
debugMode: 'false'
parameters:
- name: poolOption
type: string
default: 'ZupaDeploymentPool'
- name: debugMode
type: string
default: 'true'
- name: debugMachine
type: string
default: 'ZUPBUILD03'
trigger:
batch: true
branches:
include:
- master
paths:
exclude:
- README.md
${{ if ne($(debugMode), 'false') }}:
pool: ${{ parameters.poolOption }}
${{ if ne($(debugMode), 'true') }}:
pool:
name: ${{ parameters.poolOption }}
demands:
- Agent.Name -equals ${{ parameters.debugMachine }}
So after having a quick chat with kevin-lu-msft above lead me to this solution for handling selecting a specific agent in the pool.
parameters:
- name: debugMachine
displayName: 'Run on selected agent:'
type: string
default: 'Auto Select From Pool'
values:
- 'Auto Select From Pool'
- 'MACHINE01'
- 'MACHINE02'
- 'MACHINE03'
- 'MACHINE04'
- 'MACHINE05'
jobs:
-job: build
# -----------------------------------------------------------------------------------------------
# This is the pool selection section if a specific debug machine is passed in via the params
# It will select that specific one to run the build on. unfortunately azure doesnt let you pass
# vars or params to the process string in the demands which would have made this alot cleaner.
pool:
name: 'YOUAGENTSPOOLNAME'
${{ if ne(parameters.debugMachine, 'Auto Select From Pool') }}:
${{ if eq(parameters.debugMachine, 'MACHINE01') }}:
demands:
- Agent.Name -equals MACHINE01
${{ if eq(parameters.debugMachine, 'MACHINE02') }}:
demands:
- Agent.Name -equals MACHINE02
${{ if eq(parameters.debugMachine, 'MACHINE03') }}:
demands:
- Agent.Name -equals MACHINE03
${{ if eq(parameters.debugMachine, 'MACHINE04') }}:
demands:
- Agent.Name -equals MACHINE04
${{ if eq(parameters.debugMachine, 'MACHINE05') }}:
demands:
- Agent.Name -equals MACHINE05
steps:
- script: "echo finally it works"
I tested your YAML sample and made some modifications. You could try to set the "Expressions" under a stage and check if it could work as expected.
Here is an example, you could refer to it.
trigger:
- master
parameters:
- name: poolOption
type: string
default: 'Windows-latest'
- name: debugMode
type: string
default: false
values:
- true
- false
- name: debugMachine
type: string
default: 'ubuntu-16.04'
stages:
- stage: A
jobs:
- job: testjob
pool:
${{ if eq(parameters.debugmode, 'true') }}:
vmImage: ${{ parameters.poolOption }}
${{ if eq(parameters.debugmode, 'false') }}:
vmImage: ${{ parameters.debugMachine }}
steps:
- script : "echo Hello, world!"
Note: I am using Microsoft-hosted agents, so I am using the vmImage field.
You can specify specific self-hosted agents (name field) according to your needs.

Resources