'Azure Pipeline: Setting variable in one template, use it in expression in another
What I tried to achive:
- Set variable featureName in template 1 called
set-variable.yml
- Pass variable featureName as parameter to template 2 called
check-variable.yml
- Check if featureName parameter is empty in a compile time expression in template 2.
pipeline.yml:
trigger:
- '*' # Run on all Branches
pool:
vmImage: ubuntu-latest
stages:
- stage: test1
jobs:
- job: test1
steps:
- template: set-variable.yml
- template: check-variable.yml
parameters:
featureName: $(setVariables.featureName)
set-variable.yml:
steps:
- script: |
featureName=''
echo "##vso[task.setvariable variable=featureName;isOutput=true]$featureName"
displayName: Set variable
name: setVariables
check-variable.yml:
parameters:
- name: featureName
type: string
default: ''
steps:
- ${{ if ne(parameters.featureName, '') }}:
- script: |
echo "This should not be executed, but it is!"
displayName: "featureName != ''"
The problem is, that the step featureName != ''
in check-variable.yml
gets executed, even though I set the featureName
variable in the set-variables.yml
template to be empty.
(Passing of the variable featureName
as a parameter to template check-variable.yml
is working, see debugging attempts below)
=== Debugging 1 ===
For debugging purpose, I've expanded the check-variable.yml
with some debugging tasks.
check-variable.yml:
parameters:
- name: featureName
type: string
default: ''
steps:
- script: |
echo "Check feature"
echo "- featureNameDotted: [${{ parameters.featureName }}]"
echo "- featureNameArray: [${{ parameters['featureName'] }}]"
echo "- featureNameEnvDotted: [$featureNameEnvDotted]"
echo "- featureNameEnvArray: [$featureNameEnvArray]"
echo "- json: [${{ convertToJson(parameters.featureName) }}]"
echo "- length: [${{ length(parameters.featureName) }}]"
echo
if [[ -z $featureNameEnvDotted ]]; then
echo "featureNameEnvDotted is (empty or null)"
else
echo "featureNameEnvDotted not (empty or null)"
fi
echo
if [[ $featureNameEnvDotted = '' ]]; then
echo "featureNameEnvDotted = ''"
else
echo "featureNameEnvDotted != ''"
fi
echo
if [[ $featureNameEnvDotted = 'hello' ]]; then
echo "featureNameEnvDotted = 'hello'"
else
echo "featureNameEnvDotted != 'hello'"
fi
env:
featureNameEnvDotted: ${{ parameters.featureName }}
featureNameEnvArray: ${{ parameters['featureName'] }}
displayName: "Debug: All"
- ${{ if eq(parameters.featureName, '') }}:
- script: |
echo
env:
featureName: ${{ parameters.featureName }}
displayName: "Debug: Empty!!"
- ${{ if ne(parameters.featureName, '') }}:
- script: |
echo
env:
featureName: ${{ parameters.featureName }}
displayName: "Debug: Not empty!!"
- ${{ if eq(parameters.featureName, 'hello') }}:
- script: |
echo
env:
featureName: ${{ parameters.featureName }}
displayName: "Debug: Equals 'hello'"
- ${{ if ne(parameters.featureName, '') }}:
- script: |
echo "This should not be executed, but it is!"
displayName: "featureName != ''"
The output of the task Debug: All
is:
Check feature
- featureNameDotted: []
- featureNameArray: []
- featureNameEnvDotted: []
- featureNameEnvArray: []
- json: []
- length: [27]
featureNameEnvDotted is (empty or null)
featureNameEnvDotted = ''
featureNameEnvDotted != 'hello'
The bash if's work all well. featureName is empty and it is not 'hello'. The 'length' one I don't understand.
And the following tasks get executed:
- Set variable
- Debug: All
- Debug: Not empty!!
- featureName != ''
Why do the tasks Debug: Not empty!!
and featureName != ''
get executed, but task Debug: Empty!!
not? featureName parameter IMO is empty!
=== Debugging 2 ===
I've left check-variable.yml
the same. But I set featureName
in the set-variable.yml
template to the value "hello". With this I wanted to check if the variable featureName
does get properly passed to the parameter of the template check-variable.yml
set-variable.yml:
steps:
- script: |
featureName='hello'
echo "##vso[task.setvariable variable=featureName;isOutput=true]$featureName"
displayName: Set variable
name: setVariables
The output of the task Debug: All
is:
Check feature
- featureNameDotted: [hello]
- featureNameArray: [hello]
- featureNameEnvDotted: [hello]
- featureNameEnvArray: [hello]
- json: [hello]
- length: [27]
featureNameEnvDotted not (empty or null)
featureNameEnvDotted != ''
featureNameEnvDotted = 'hello'
This again looks well. The parameter does hold the value 'hello' and the if's look good (still, length I don't understand).
And here the list of tasks which get executed:
- Set variable
- Debug: All
- Debug: Not empty!!
- featureName != ''
Why is Debug: Equals 'hello'
not executed?
parameters.featureName
holds something like the value 'hello', but it is not exactly the string 'hello'. Am I doing something wrong here?
Solution 1:[1]
I found the problem. The ${{ length(parameters.featureName) }}
which evaluates to 27 pushed me in the right direction. 27 is the length of the string $(setVariables.featureName)
which is passed to the template check-variable.yml
.
This can be tested with the following expression which I put into check-variable.yml
:
- ${{ if eq(parameters.featureName, '$(setVariables.featureName)') }}:
- script: |
echo
env:
featureName: ${{ parameters.featureName }}
displayName: "Debug: Equals 'dollar(setVariables.featureName)'"
This always executes, when featureName was set or if it was empty.
I think what happens is that when the compile time expressions like ${{ ... }}
are evaluated inside a template, the parameter featureName is evaluated to $(setVariables.featureName)
. This is the case in the ${{ if ... }}
expressions as well as in the script tasks with ${{ parameters...}}
. After the ${{ ... }}
expressions have been evaluated, it starts executing the script tasks. There it finds the variable $(setVariables.featureName)
and evaluates it. But evaluation of the $(setVariables.featureName)
is never done for the compile time expressions with an if statement. There it just takes the name of the variable.
So to get it to work I did a work around where I set a variable in a script task, and use a task condition to evaluate it.
check-variable.yml:
parameters:
- name: featureName
type: string
default: ''
steps:
- script: |
echo "##vso[task.setvariable variable=featureName]${{ parameters.featureName }}"
displayName: "Set featureName var"
- script: |
echo "Only execute me when featureName is not empty"
displayName: "featureName != ''"
condition: and(succeeded(), ne(variables.featureName, ''))
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Simon Lang |