Let's say, I have a stage which, at some point, has a task which writes an output variable:
steps:
- task: PowerShell@2
name: TargetDirectory
displayName: 'Determine Target Directory'
inputs:
targetType: 'inline'
script: |
$targetDirectory = "web_$(Build.BuildId)_$(System.JobAttempt)"
Write-Host "##vso[task.setvariable variable=deploymentTargetDirectory;isOutput=true]$targetDirectory"
And in a later stage, I want to pass this output variable to a job template. This doesn't work, the value is simply taken as is and not interpolated:
- stage: Build
dependsOn: PreProcess
jobs:
- template: build-tpl.yml
parameters:
targetDir: $[ stageDependencies.PreProcess.DeploymentSetup.outputs['TargetDirectory.deploymentTargetDirectory'] ]
While this does work exactly the way it should:
- stage: Build
dependsOn: PreProcess
variables: #It works if I set a stage variable here
deploymentTargetDir: $[ stageDependencies.PreProcess.DeploymentSetup.outputs['TargetDirectory.deploymentTargetDirectory'] ]
jobs:
- template: build-tpl.yml
parameters:
targetDir: $(deploymentTargetDir)
To be clear, I am fairly sure I adress the variable correctly, as I didn't change anything in the working example. Only difference is, that I assign the value of my output variable to a stage variable before passing it to the parameter of the template.
Since I could't not find any refernce and only found that out by trial and error - is this the correct way, or is there a simpler, better way?
The key is understanding the pipeline run sequence:
templates and their parameters are expanded at compile-time. ${{<expr>}}
syntax are for compile-time expressions. Before the pipeline is run, only pre-defined system variables are available. Variables written with macro-syntax $()
or runtime-expressions $[]
have no meaning and are treated as literals.
variables are evaluated at runtime, meaning the most current value is dereferenced. $[<expr>]
are runtime expressions. Only a few locations in the pipeline schema support runtime expressions:
condition
. Note that succeeded()
and $[ succeeded() ]
are functionally equivalent and the $[ ]
syntax is optional for conditions.For the example you've provided, it is possible to pass runtime expressions as parameters and then dereference them as variables in your job template. Following this practice allows the caller to pass a runtime-expression, macro-syntax or literal value.
# build-tpl.yml template
parameters:
- name: targetDir
type: string
jobs:
- job: jobname
variables:
# dereference the runtime expression, macro-syntax or literal value
targetDir: ${{ parameters.targetDir }}
steps:
- pwsh: write-host $(targetDir)
# calling pipeline
stages:
- stage: PreProcess
jobs:
- job: DeploymentSetup
steps:
# ... step to create output variable deploymentTargetDirectory
- stage: Build
dependsOn: PreProcess
jobs:
- template: build-tpl.yml
parameters:
targetDir: $[ stageDependencies.PreProcess.DeploymentSetup.outputs['TargetDirectory.deploymentTargetDirectory'] ]