I have a pipeline that takes parameters when triggered manually.
Also, it can be triggered by merging a pull request. Now I am trying to recognize tags in the PR in order to override the parameters that, in the case of PR trigger, cannot be manually defined.
This question is very similar to Azure Pipelines: Passing a variable as a parameter to a template, however, here I don't have a global variable but one computed inside of a stage, which is causing me troubles passing as a parameter.
pipeline.yml
:
parameters:
- name: doSomething
type: boolean
default: false
stages:
- stage: DetectPrTags
displayName: Detect Pull Request Tags
jobs:
- job: DetectPrTags
displayName: Detect Pull Request Tags
pool:
vmImage: 'ubuntu-latest'
steps:
- checkout: none
- task: Bash@3
name: DetectAndSetPrTags
displayName: Detect Pull Request Tags
env:
SYSTEM_ACCESSTOKEN: $(System.AccessToken)
inputs:
targetType: 'inline'
script: |
# ... get tag from PR and write into variable $doSomethingFromTags ...
# Compute effective values
if [ "$doSomethingFromTags" == "true" ] || [ "${{ parameters.doSomething }}" == "true" ]; then
doSomethingEffective="true"
else
doSomethingEffective="false"
fi
echo "Effective DoSomething: $doSomethingEffective"
# Export outputs
echo "##vso[task.setvariable variable=doSomethingEffective;isOutput=true]$doSomethingEffective"
echo "##[endgroup]"
- stage: SecondStage
displayName: Second Stage
dependsOn: DetectPrTags
variables:
doSomethingEffective: $[ stageDependencies.DetectPrTags.DetectPrTags.outputs['DetectAndSetPrTags.doSomethingEffective'] ]
jobs:
- template: second-stage.yml
parameters:
doSomething: ${{ eq(variables.doSomething, 'true') }}
second-stage.yml
:
parameters:
doSomething: false
jobs:
- job: SecondStage
displayName: Second Stage
pool:
vmImage: 'ubuntu-latest'
steps:
- script: |
echo "PARAMETER doSomething: ${{ parameters.doSomething }}"
displayName: Print input parameters
If I set the PR tag do-something, I'd expect the output in the second stage to tell me that doSomething is true, however it stays false.
This is the output I get in the pipeline:
Detect Pull Request Tags Init:
Parent pipeline used these runtime parameters
doSomething: "False"
Detect Pull Request Tags:
Effective DoSomething: true
which shows that the PR tag was recognized and doSomething set to true
Second Stage Init:
Job preparation parameters
Variables:
doSomethingEffective:
Parsing expression: <stageDependencies.DetectPrTags.DetectPrTags.outputs['DetectAndSetPrTags.doSomethingEffective']>
Evaluating: stageDependencies['DetectPrTags']['DetectPrTags']['outputs']['DetectAndSetPrTags.doSomethingEffective']
Result: 'true'
...
Parent pipeline used these runtime parameters
doSomething : "False"
which shows that the variable was correctly recognized and the value is true
Print input parameters:
PARAMETER doSomething: False
here we see that the parameter was not set to true, even though I passed the variable doSomethingEffective, which is true
I have tried several ways of passing the variable, I have tried accessing the variable directly in the second-stage template (it's empty), using a global variable in the pipeline and accessing it directly in the second-stage template (this works, but I can't overwrite it when loading the tags).
Parameters are only available at compile time. When parsing, the value of variables.doSomething is not yet set by your script and the expression
doSomething: ${{ eq(variables.doSomething, 'true') }}
gets executed before the variable gets an actual value at runtime.
The solution for your problem is to skip parameters and stick to runtime variables and expressions wich get processed at runtime after your first script got executed:
- stage: SecondStage
displayName: Second Stage
dependsOn: DetectPrTags
variables:
doSomething: $[ eq(stageDependencies.DetectPrTags.DetectPrTags.outputs['DetectAndSetPrTags.doSomethingEffective'], 'true') ]
jobs:
- template: second-stage.yml
second-stage.yml:
jobs:
- job: SecondStage
displayName: Second Stage
pool:
name: Testing
steps:
- script: |
echo "PARAMETER doSomething: $(doSomething)"
displayName: Print input parameters