Reputation: 1882
To minimize duplicate build scripts, we make use of templates in our pipelines. These templates have parameters. However, I now run into an issue, because I need to pass data to a template that is not yet available when the pipeline starts. (the data is generated in some steps during the pipeline). Since parameters are expanded when the pipeline starts, I cannot pass the data to the template via parameters.
I know I can reference output variables of different tasks, jobs, and stages within my pipeline, but the template I am using has no knowledge of the surrounding pipeline it is executed in. So the template doesn't know how to reference the output variables from other jobs outside of the template, simply because the template doesn't know what jobs have been executed before.
Is there some way I can map variables in my template? Ideally I would like to do something like this:
stages:
- stage: Stage1
jobs:
- some job that creates output variables
- stage: Stage2
jobs:
- template: 'myTemplate.yaml'
variables:
data1: $[ stageDependencies.Stage1.some_job.outputs['taskname.data1']]
and have the data1 variable available within the template.
So I am trying to avoid having to use: $[ stageDependencies.Stage1.some_job.outputs['taskname.data1']]
in the template, because Stage1
might not even exist in all pipelines that uses the template.
I can actually do this, if the template only contains steps, instead of multiple jobs:
- stage: Stage2
jobs:
- job: Job1
variables:
data1: $[ stageDependencies.Stage1.some_job.outputs['taskName.data1']]
steps:
- template: templates/Azure/CreateTenant.yaml
Unfortunately, my templates contain multiple jobs
Update: I've entered a feature request to better support this situation: https://developercommunity.visualstudio.com/idea/1207453/yaml-template-variablesparameters-that-are-expande.html
Upvotes: 5
Views: 16060
Reputation: 4571
In addition to the answer of Leo Liu-MSFT I'd like share two techniques I'm using to pass the YAML variables to templates:
- stage: Stage2
variables:
entireJobOutputInJson: $[convertToJson(stageDependencies.Stage1.some_job.outputs)]
jobs:
- template: templates/Azure/CreateTenant.yaml
parameters:
variableNameWithJobOutputInJson: 'entireJobOutputInJson'
Key points:
And in the template the variable can be expanded simply by the name with $(variableName)
syntax:
parameters:
variableNameWithJobOutputInJson: ''
jobs:
- job: Job1
steps:
- pwsh: |
$obj = ConvertFrom-Json '$(${{ parameters.variableNameWithJobOutputInJson }})'
$props = $obj.psobject.properties.name
foreach ($property in $props ) {
$varName = ($property -split "\.")[-1] # taking only the last part of multipart identifier
echo "##vso[task.setvariable variable=$varName]$($obj.$property)"
}
displayName: 'Import Job output'
I used pwsh here because it works in both windows and linux based agents.
Upvotes: 2
Reputation: 76670
I can actually do this, if the template only contains steps, instead of multiple jobs. Unfortunately, my templates contain multiple jobs
To resolve this issue, you could define the variables at the stage level instead of the job level:
- stage: Stage2
variables:
data1: $[ stageDependencies.Stage1.some_job.outputs['taskName.data1']]
jobs:
- template: templates/Azure/CreateTenant.yaml
Then we could avoid having to use: $[ stageDependencies.Stage1.some_job.outputs['taskname.data1']]
in the template.
You could check the document Variable scopes for some more details.
Upvotes: 2