Reference a pipeline job name in a YAML template - azure-devops

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:
...

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"

YAML Extend Stage Template

Looking to try and get some help figuring out a solution to what seems like a simple task. I am trying to develop some extend YAML templates for security within our ADO pipelines but first I have to get passed this error I am experiencing.
The error being returned by ADO when I try to validate or run the pipeline is
/ADO_Stage_Restrictions_Dev.yml#AdoRestrictions (Line: 7, Col: 3): Unexpected value job
Working Extend Template YAML
This template validates and executes without issue, which to me means I am successfully passing the stages object into the extends template
parameters:
- name: stageObjs
type: stageList
default: []
stages:
- ${{ each stage in parameters.stageObjs }}:
${{ stage }}
Broken Extend Template YAML
This template does not validate and throws the 'Unexpected value job' exception. based on the stage schema I would assume that I would be able to loop the jobs property within the stage.
parameters:
- name: stageObjs
type: stageList
default: []
stages:
- ${{ each stage in parameters.stageObjs }}:
- ${{ each job in stage.jobs }}:
${{ job }}
Build YAML
The main yaml file that extends stages
resources:
repositories:
- repository: self
type: git
ref: refs/heads/Development
- repository: AdoRestrictions
type: git
name: utl-yaml-templates
ref: refs/heads/main
trigger: none
pool:
name: PROD
extends:
template: ADO_Stage_Restrictions_Dev.yml#AdoRestrictions
parameters:
stageObjs:
- stage: 'BuildStage'
displayName: 'Build Test'
jobs:
- job: 'BuildJob'
displayName: 'Build'
steps:
- task: PowerShell#2
displayName: 'Hello World'
inputs:
targetType: inline
script: |
Write-Host "Hello World"
There's nothing in your yaml which defines the start of the stage, or declares the start of the list of jobs; that's why it wasn't expecting to find 'job' there. You can add those parts in, like this:
parameters:
- name: stageObjs
type: stageList
default: []
stages:
- ${{ each stage in parameters.stageObjs }}:
- stage: ${{ stage.stage }}
displayName: ${{ stage.displayName }}
jobs:
- ${{ each job in stage.jobs }}:
${{ job }}

Can't run a templated yaml Azure Devops pipeline with dynamically created stage

My problem
I try to create templated yaml Azure Devops pipeline:
parameters:
- name: envs
type: object
default:
- QUAL
- PROD
- PREPROD
stages:
- template: Orchestrator.yml
parameters:
name: envs
type: object
default:
- QUAL
- PROD
- PREPROD
This is my template:
parameters:
envs: {}
stages:
- ${{ each env in parameters.envs }}:
- stage: ${{ env }}
jobs:
- job: Deploy
steps:
- script: echo Deploy project
displayName: 'Deploy'
- job: Tests
steps:
- script: echo Unit tests
displayName: Test 1
But I get this error message:
An error occurred while loading the YAML build pipeline. The array
must contain at least one element. Parameter name: stages
OK, I modify my main script like this:
parameters:
- name: envs
type: object
default:
- QUAL
- PROD
- PREPROD
stages:
- stage: Build
jobs:
- job: Build
steps:
- script: echo Compilation completed...
displayName: 'Compile'
- template: Orchestrator.yml
parameters:
name: envs
type: object
default:
- QUAL
- PROD
- PREPROD
This time pipeline runs, but only first Job. The Template is not loaded.
What I need
I was able to make this scenario working with a single file script, but I would like to make it working with a templated script.
Is this scenario supported? How I can do?
thanks
Here I have a sample as reference:
In the template YAML file (here I name it template.yaml), write as this.
parameters:
- name: envs
type: object
default:
- QUAL
- PROD
- PREPROD
stages:
- ${{ each env in parameters.envs }}:
- stage: ${{ env }}
displayName: 'Stage ${{ env }}'
jobs:
- job: job1
displayName: 'Job 1'
steps:
- bash: echo "Current job is job1 in ${{ env }}"
- job: job2
displayName: 'Job 2'
steps:
- bash: echo "Current job is job2 in ${{ env }}"
In the pipeline YAML (here I name it pipeline.yaml), write as this.
trigger:
- main
extends:
template: template.yaml
Result
If you do not want to hardcode the value of the parameter 'envs' in template.yaml, you can write like as below.
In template.yaml write as this.
parameters:
- name: envs
type: object
default: []
stages:
- ${{ each env in parameters.envs }}:
- stage: ${{ env }}
displayName: 'Stage ${{ env }}'
jobs:
- job: job1
displayName: 'Job 1'
steps:
- bash: echo "Current job is job1 in ${{ env }}"
- job: job2
displayName: 'Job 2'
steps:
- bash: echo "Current job is job2 in ${{ env }}"
In pipeline.yaml write as this.
trigger:
- main
stages:
- template: template.yaml
parameters:
envs:
- QUAL
- PROD
- PREPROD
Result. Same as above.
To view more details, you can see "YAML schema reference".

Extend a job's dependsOn in a template

I'm creating a template in which I pass a job list. In this template, I add a "pre" job to the job list, and then add all jobs. I'd like to be able to add a dependency on the "pre" job to all jobs in the job list, without breaking any dependencies between the jobs in the joblist parameter. My template looks something like this:
parameters:
- name: Jobs
type: jobList
jobs:
- job: prejob
steps:
- powershell: |
Write-Host "This is my prejob"
- ${{ each job in parameters.Jobs }}:
- ${{ each pair in job }}:
${{ if and(ne(pair.key, 'steps'),ne(pair.key, 'dependsOn')) }}:
${{ pair.key }}: ${{ pair.value }}
dependsOn: 'prejob'
steps:
- ${{ job.steps }}
now this of course overwrites the dependsOn of the jobs passed.
What can I change in the template so I can join the passed job dependencies with the prejob job? The join expression joins 2 arrays, but my prejob text is not an array, and I'm not sure the dependsOn property of a job is always an array.
Please try this:
parameters:
- name: Jobs
type: jobList
jobs:
- job: prejob
steps:
- powershell: |
Write-Host "This is my prejob"
- ${{ each job in parameters.Jobs }}:
- ${{ each pair in job }}:
${{ if and(ne(pair.key, 'steps'),ne(pair.key, 'dependsOn')) }}:
${{ pair.key }}: ${{ pair.value }}
dependsOn:
- 'prejob'
- ${{ if job.dependsOn }}:
- ${{ job.dependsOn }}
steps:
- ${{ job.steps }}
In that way you should be able to make dependency to prejob and keep dependencies from jobs.

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