Azure DevOps YAML - if statement not working through template with number/int - azure-devops

Checking a version number in a yaml pipeline with an if statement and wanting to run a particular task dependent on version. Works fine directly but I'm using templates and passing the value through it doesn't seem to work.
This works:
trigger:
- main
pool:
vmImage: ubuntu-latest
parameters:
- name: TF_VERSION
default: 1.3.3
steps:
- ${{ if lt(parameters.TF_VERSION, 1) }}:
- powershell: Write-Host "I'm running lt 1.0"
- ${{ if ge(parameters.TF_VERSION, 1) }}:
- powershell: Write-Host "I'm running ge 1.0"
This doesn't with the first condition always returning true:
trigger:
- main
pool:
vmImage: ubuntu-latest
resources:
repositories:
- repository: templates
type: git
name: YAML-Templates
ref: refs/heads/main
variables:
- name: TF_VERSION
value: 1.3.3
steps:
- template: if/if.yml#templates
parameters:
TF_VERSION: $(TF_VERSION)
template:
parameters:
- name: TF_VERSION
steps:
- ${{ if lt(parameters.TF_VERSION, 1) }}:
- powershell: Write-Host "I'm running lt 1.0"
- ${{ if ge(parameters.TF_VERSION, 1) }}:
- powershell: Write-Host "I'm running ge 1.0"
Anyone know why???

I can reproduce your problem.
I can partly solve it by adding the mandatory type to the parameter in the template:
parameters:
- name: TF_VERSION
type: number
steps:
- ${{ if lt(parameters.TF_VERSION, 1) }}:
- powershell: Write-Host "I'm running lt 1.0"
- ${{ if ge(parameters.TF_VERSION, 1) }}:
- powershell: Write-Host "I'm running ge 1.0"
The only down side seems to be that I'm not able to pass a variable from the calling YAML due to this error.
This issue can be overcome by setting the number directly in the parameter like this:
trigger:
- main
pool:
vmImage: ubuntu-latest
resources:
repositories:
- repository: templates
type: git
name: YAML-Templates
ref: refs/heads/main
steps:
- template: if/if.yml#templates
parameters:
TF_VERSION: 1.5
Like you mentioned, 1.3.3, a version number, is still not a number.
Alternative
Alternatively you could go for startsWith like so:
parameters:
- name: TF_VERSION
steps:
- ${{ if startsWith(parameters.TF_VERSION, '0.') }}:
- powershell: Write-Host "I'm running 0.x"
- ${{ if startsWith(parameters.TF_VERSION, '1.') }}:
- powershell: Write-Host "I'm running 1.x"
I hope this answers the question, why it is not working and what a possible alternative is.
Edit-2
The solution of Antonia Wu-MSFT's also work, the why is still a bit unclear. But I think it has to do with: https://learn.microsoft.com/en-us/azure/devops/pipelines/process/variables?view=azure-devops&tabs=yaml%2Cbatch#template-expression-syntax
But to be honest, still don't understand why a type is mandatory according to the documentation, but not used in this case.

I have tried only to change the TF_VERSION: $(TF_VERSION) to TF_VERSION: ${{ variables.TF_VERSION }} in the main yaml.
trigger:
- main
pool:
vmImage: ubuntu-latest
resources:
repositories:
- repository: templates
type: git
name: YAML-Templates
ref: refs/heads/main
variables:
- name: TF_VERSION
value: 1.3.3
steps:
- template: /if/if.yml#templates
parameters:
TF_VERSION: ${{ variables.TF_VERSION }}
Then run the pipeline with the template it seems work and get this:
Please kindly try whether it works on your side. And hope it could do some help:>

Related

How to create Azure Pipeline Template to run a jobList all on the same agent?

I am trying to make a pipeline template that takes a JobList a parameter and runs all the jobs, while ensuring that they run on the same agent every time. Basically the approach I've been taking is to try to adapt this answer into a genericized template format.
This is what I have so far, and I've tried a lot of slight tweaks of this with nothing passing the Validate test on the pipeline that calls it.
parameters:
- name: jobsToRun
type: jobList
- name: pool
type: string
default: Default
- name: demands
type: object
default: []
jobs:
- job:
steps:
- script: echo "##vso[task.setvariable variable=agentName;isOutput=true;]$(Agent.Name)"
pool:
name: ${{ parameters.pool }}
demands:
- ${{ each demand in parameters.demands }}:
${{ demand }}
- ${{ each j in parameters.jobsToRun }}:
${{ each pair in j }}:
${{ pair.key }} : ${{ pair.value }}
pool:
name: Default
demands:
- Agent.Name -equals $(agentName)
What am I doing wrong here? It seems like it should be possible if that answer I reference is correct, but it seems like I'm just a bit off.
Name missing on the job.., example below.
- job: 'test-Name'
Steps need a associated job and pool to run is declared inside
jobsToRun:
- job: sample_job1
displayName: "sample_job1"
pool:
name: "your_PoolName"
steps:
- script: |
echo "Hi"
On this bottom pool declaration...
pool:
name: Default
demands:
- Agent.Name -equals $(agentName)
i am not sure but i have tried this many times but i think this can't be included separate to the job since each individual job is passed as parameter. pool definition needs to be inside the job or inside the job template if you are using templates..
example:
jobsToRun:
- job: output_message_job1
displayName: "in pipe Output Message Job"
pool:
name: "your_PoolName"
steps:
- script: |
echo "Hi"

Conditional Default-Value in Azure Pipeline DevOps

I use Azure Pipelines to Build my solution. When building manually the user can decide which Build Configuration to use. Now I want the default value (and so the value when triggered automatically) to be different according to the branch. This is my (non-working) approach:
name: PR-$(Build.SourceBranchName)-$(Date:yyyyMMdd)$(Rev:.r)
trigger:
- develop
- test
- master
pool:
vmImage: 'windows-latest'
parameters:
- name: BuildConfiguration
displayName: Build Configuration
${{ if eq(variables['Build.SourceBranch'], 'refs/heads/develop') }}:
default: Debug
${{ if eq(variables['Build.SourceBranch'], 'refs/heads/test') }}:
default: Release
${{ if eq(variables['Build.SourceBranch'], 'refs/heads/master') }}:
default: Release
values:
- Debug
- Release
The conditional part (${{...}) simply does not work. (*"A template expression is not allowed in this context")
Is there any other approach to make this happen?
This is not posssible to use expressins to select default value for paramataers.
Paramaters alco can't be optionla:
Parameters must contain a name and data type. Parameters cannot be optional. A default value needs to be assigned in your YAML file or when you run your pipeline. If you do not assign a default value or set default to false, the first available value will be used.
What you can do is use parameters and variables:
name: PR-$(Build.SourceBranchName)-$(Date:yyyyMMdd)$(Rev:.r)
trigger:
- develop
- test
- master
pool:
vmImage: 'windows-latest'
parameters:
- name: BuildConfiguration
displayName: Build Configuration
default: Default
values:
- Debug
- Release
- Default
variables:
- name: buildConfiguration
${{ if and(eq(variables['Build.SourceBranch'], 'refs/heads/develop'), eq(parameters.BuildConfiguration, 'Default')) }}:
value: Debug
${{ elseif and(eq(variables['Build.SourceBranch'], 'refs/heads/test'), eq(parameters.BuildConfiguration, 'Default')) }}:
value: Release
${{ elseif and(eq(variables['Build.SourceBranch'], 'refs/heads/master'), eq(parameters.BuildConfiguration, 'Default')) }}:
value: Release
${{ else }}:
value: ${{parameters.BuildConfiguration}}
steps:
- script: |
echo $(buildConfiguration)
echo $(Build.SourceBranch)

Azure Devops YML Template Conditions and Dependencies

I have a requirement for a couple of job templates but I can’t get the conditions and dependencies configured to run how I want. I have the basic yaml below:
parameters:
- name: environment
displayName: Environment
- name: action
values:
- deploy
- undeploy
- redeploy
default: redeploy
stages:
- stage: app
displayName: App
jobs:
- deployment: kickoff
environment:
name: ${{ parameters.environment }}
resourceType: virtualMachine
tags: app
strategy:
runOnce:
deploy:
steps:
- checkout: none
- powershell: Write-Host "Run kickoff tasks"
- template: undeploy.yml
parameters:
environment: ${{ parameters.environment }}
action: ${{ parameters.action }}
- template: deploy.yml
parameters:
environment: ${{ parameters.environment }}
action: ${{ parameters.action }}
The requirements I have are the below:
Undeploy.yml: if Action = ‘Deploy’, does not run. If Action = ‘Undeploy’, only run this template. Action = ‘Redeploy’, run both templates but undeploy.yml must run first.
Deploy.yml: If Action = ‘Deploy’, only run this template. If Action = ‘Undeploy’, does not run. If Action = ‘Redeploy’, run both templates but deploy.yml must run second.
Closest I can get to is setting the templates yaml as below:
undeploy.yml
parameters:
- name: environment
default: environmentToDeployTo
- name: action
values:
- deploy
- undeploy
- redeploy
default: redeploy
jobs:
- deployment: undeploy
dependsOn: kickoff
condition: ne ('${{parameters.action}}', 'deploy')
environment:
name: ${{ parameters.environment }}
resourceType: virtualMachine
tags: app
strategy:
runOnce:
deploy:
steps:
- checkout: none
#undeploy steps here#
deploy.yml
parameters:
- name: environment
default: environmentToDeployTo
- name: action
values:
- deploy
- undeploy
- redeploy
default: redeploy
jobs:
- deployment: dploy
dependsOn: undeploy
condition: ne ('${{parameters.action}}', 'undeploy')
environment:
name: ${{ parameters.environment }}
resourceType: virtualMachine
tags: app
strategy:
runOnce:
deploy:
steps:
- checkout: none
#dploy steps here#
This results only affects deploy.yml but it is not able to run in isolation - the undeploy.yml job template will have to run beforehand. However, without the "dependsOn", I can see no other way to ensure that undeploy.yml runs first.
Is there anyway to achieve this as per requirements outlined above?
Thanks in advance
dependsOn takes the name of a stage or job as input, not the name of a template file. Seeing more of your templates would be useful, but if you could use the name of the stage or job in dependsOn, you might get the result you're looking for.
Think of the expanded template as your guide here - you can refer to a stage or job that's declared in a different template, so long as it expands to the right place when the pipeline runs.

Reference a pipeline job name in a YAML template

Is there a way to reference a job parameter's name in an Azure DevOps YAML template? I know that I could pass in the job name as its own string parameter, but I was hoping for something that's a little less clumsy.
template.yml
parameters:
- name: MyJob
type: job
jobs:
- ${{ parameters.MyJob }}
- job: Job2
dependsOn: # How to make this depend on MyJob?
azure-pipelines.yml
stages:
- stage: Stage1
jobs:
- template: template.yml
parameters:
MyJob:
job: SomeJobName
steps:
- script: echo Hello
I tried accessing ${{ parameters.MyJob.name }} but it doesn't appear to exist.
I've figured out, though it took a lot of trial and error to get the exact syntax and spacing right. The docs aren't super clear about spacing and expressions, and when to lead with a dash.
parameters:
- name: MyJob
type: job
jobs:
- ${{ parameters.MyJob }}
- job: Job2
${{ each pair in parameters.MyJob }}:
${{ if eq(pair.key, 'job') }}:
dependsOn: ${{ pair.value }}
steps:
...
Can't comment, but as you see in previous answer, the property is not "name", but "job". You don't need the foreach then:
parameters:
- name: MyJob
type: job
jobs:
- ${{ parameters.MyJob }}
- job: Job2
dependsOn: ${{ parameters.MyJob.job }}
steps:
...

Pass pipeline variable from Designer to YAML job template

I initially wanted to define pipeline variables in my azure-pipelines.yml that I can optionally set at queue time, but it seems that this is not supported at the moment: variables that can be set at queue time can only be defined in the Designer. This variable (comma-separated) is named nx_versions and will be used to build a matrix strategy. Here's a minimal example:
# azure-pipelines.yml
jobs:
- template: job-template.yml
parameters:
nx_versions: $(nx_versions)
and
# job-template.yml
parameters:
nx_versions:
- 1
jobs:
- job: build
strategy:
matrix:
${{ each nxver in parameters.nx_versions }}:
NX_${{ nxver }}:
NXVersion: ${{ nxver }}
steps:
- powershell: echo $(NXVersion)
Queuing the build with nx_versions = 2,3 (value doesn't actually matter) results in an error:
/job-template.yml (Line: 9, Col: 9): Expected a sequence or mapping. Actual value '$(nx_versions)'
Is this even possible? I also tried using ${{ nx_versions }} and ${{ variables.nx_versions }} to no avail.
This is possible with a full Designer solution.
The trivial pipeline (not referencing templates, but could be extended easily to do so)
parameters:
- name: nx_versions
type: object
default:
- 1
- 4
jobs:
- job: build
strategy:
matrix:
${{ each nxver in parameters.nx_versions }}:
NX_${{ nxver }}:
NXVersion: ${{ nxver }}
steps:
- powershell: echo $(NXVersion)
Expands to
parameters:
- name: nx_versions
type: object
default:
- 1
- 4
stages:
- stage: __default
jobs:
- job: build
strategy:
matrix:
NX_1:
NXVersion: 1
NX_4:
NXVersion: 4
steps:
- task: PowerShell#2
inputs:
targetType: inline
script: echo $(NXVersion)
If you go to queue a build for that, you get a parameters page with the defaults:
that you can override:
which results in:
I am running into the same issue. I don't think this is currently possible. I believe this is being worked on https://github.com/Microsoft/azure-pipelines-yaml/pull/129