Reputation: 415
I am in the process of porting some existing Classic ADO pipelines to YAML. There are two separate Classic pipelines for Windows and Linux, but, because I have been able to switch most scripting to bash
, I am close to having a common cross-platform YAML pipeline.
Nevertheless, I still have a few platform-dependent tasks interspersed between the majority platform-independent tasks. Of these few tasks, some only need to run on Windows and don't exist for Linux, and the remainder exist in two platform-specific versions of the tasks - one using bash and the other batch or PowerShell.
My hope was to make the bulk of the script into a template with an isWindows
parameter, and to use this parameters to control the platform-dependent parts. This is roughly what I have, but it is not working:
trigger: none
pool:
name: BuildPool
demands:
- Agent.OS -equals Windows_NT
extends:
template: common-template.yml
parameters:
isWindows: true
Then common-template.yml
itself. Note that the approach here, using condition
, does not work. Although I have omitted most of the cross-platform tasks, these form the majority of the pipeline - there are only a few tasks that need special handling.
parameters:
- name: isWindows
type: boolean
jobs:
- job: MyJob
steps:
- checkout: none
clean: true
# Simple example of cross-platform script task
- bash: |
env
displayName: Print Environment
# ... more cross platform tasks
# Windows only task
- task: CmdLine@2
condition: eq('${{ parameters.isWindows }}', 'true')
inputs:
filename: scripts\windows_only.bat
# ... more cross platform tasks
# Task with specialization for each platform
# WINDOWS version
- task: CmdLine@2
condition: eq('${{ parameters.isWindows }}', 'true')
inputs:
filename: scripts\task_a.bat
# LINUX version
- task: Bash@3
condition: eq('${{ parameters.isWindows }}', 'false')
inputs:
filePath: scripts/task_a.sh
# ... more cross platform tasks
The issue is that when I try to run with a Linux agent I get this error:
No agent found in pool <pool name> satisfies both of the following demands: Agent.OS, Cmd. All demands: Agent.OS -equals Linux, Cmd, Agent.Version ...
I assume this is because CmdLine
tasks are present, even though they are "turned off" via a condition
. I assume the dependency on the task is probably determined before the condition is ever evaluated.
Is what I am trying to do possible? Is there another approach? I am not very experienced with ADO and this is the first time I have tried anything with templates so I am possibly missing something straightforward.
Upvotes: 1
Views: 209
Reputation: 415
After digging into the ADO docs a bit, I discovered that what I needed was called Conditional Insertion:
parameters:
- name: isWindows
type: boolean
jobs:
- job: MyJob
...
# Windows only task
- ${{ if parameters.isWindows }}:
- task: CmdLine@2
inputs:
filename: scripts\windows_only.bat
# Task with specialization for each platform
- ${{ if parameters.isWindows }}:
# WINDOWS version
- task: CmdLine@2
inputs:
filename: scripts\task_a.bat
- $ {{ else }}:
# LINUX version
- task: Bash@3
inputs:
filePath: scripts/task_a.sh
...
There were a few tricky things that might be worth highlighting:
-
.else
. It turned out that the else syntax is a feature of the 2022 release of ADO and we are stuck on the 2020 release. So in my case I had to introduce inverted tests: ${{ if not(parameters.isWindows) }}:
condition
field of a task, use syntax like: condition: eq(variables.isSomeCondition, 'true')
. Note the comparison against a string value. I initially copied this in the inclusion expressions but found that both ${{ if eq(parameters.isWindows, 'true') }}:
and ${{ if eq(parameters.isWindows, 'false') }}:
triggered when the parameter itself was true
. Clearly, the strings 'true'
and 'false'
evaluate to a boolean true
in this context. It's not that this doesn't make sense - it is the inconsistency with the documented examples of the condition
syntax that caught me out.Upvotes: 1
Reputation: 1009
You can use PowerShell steps instead of batch/bash (PowerShell can be installed on both Windows and Linux).
You can also remove the demands and just use the predefined Agent.OS
variable in your conditions for tasks which require specific OS:
- powershell: 'scripts/windows_only.ps1'
condition: eq(variables['Agent.OS', 'Windows_NT')
Upvotes: 1