Consider the following Azure yaml pipeline and template that uses the convertToJson function to convert an object parameter to a json string:
parameters:
- name: foo
type: string
default: 'b"ar'
trigger: none
pool:
vmImage: 'ubuntu-latest'
variables:
- name: foo
value: 'b"ar'
steps:
- checkout: none
- template: /pipelines/steps/set-settings.yaml
parameters:
settings:
fooLiteral: 'b"ar'
fooParameter: ${{ parameters.foo }}
fooCompiledVariable: ${{ variables.foo }}
fooRuntimeVariable: $(foo)
Template /pipelines/steps/set-settings.yaml:
parameters:
- name: settings
type: object
steps:
- script: |
echo $SETTINGS
displayName: 'Display settings'
env:
SETTINGS: ${{ convertToJson(parameters.settings) }}
When running the pipeline, why do all values get properly escaped except fooRuntimeVariable
?
Test the same YAML sample and I can reproduce the same issue.
The root cause of the issue is that the macro variable($(foo)
) is not expand when the expression: ConvertToJson executes.
When the ConvertToJson expression executes, fooRuntimeVariable will keep the value of $(foo)
instead of expand the value to 'b"ar'
.
So its actual conversion result:
{ "fooLiteral": "b\"ar", "fooParameter": "b\"ar", "fooCompiledVariable": "b\"ar", "fooRuntimeVariable": "$(foo)" }
After you print it in the script task, the $(foo)
will expand to the value: 'b"ar'
.
{ "fooLiteral": "b\"ar", "fooParameter": "b\"ar", "fooCompiledVariable": "b\"ar", "fooRuntimeVariable": "b"ar" }
To prove this, I added condition to the template to check the conversion result:
Here is my example:
Template YAML:
parameters:
- name: settings
type: object
steps:
- script: |
echo $SETTINGS
displayName: 'Display settings'
condition: eq('${{ convertToJson(parameters.settings) }}', 'b"ar')
env:
SETTINGS: ${{ convertToJson(parameters.settings) }}
Main YAML:
parameters:
- name: foo
type: string
default: b"ar
trigger: none
pool:
vmImage: 'Ubuntu-latest'
variables:
- name: foo
value: b"ar
steps:
- checkout: none
- template: test.yml
parameters:
settings:
fooLiteral: b"ar
fooParameter: ${{ parameters.foo }}
fooCompiledVariable: ${{ variables.foo }}
fooRuntimeVariable: $(foo)
When we run the Pipeline, the Display settings task will skip. Then we can check the condition result: it will show the $(foo)
for the fooRuntimeVariable.
To sum up, when we use ConvertToJson Expression, I suggest that we can use compile time expressions (${{xxx}}
) to use variables.