In the following example, Azure DevOps template expression returns always "False", even if the parameter is true.
Why ?
Main.yml :
trigger: none
pool:
name: Azure Pipelines
vmImage: windows-latest
variables:
- name: myVar
value: true
steps:
- checkout: none
- powershell: |
Write-Host "myVar = $(myVar)" # Display true
- template: TestJppTemplate.yml
parameters:
myParam: $(myVar)
- powershell: |
Write-Host "myVar = $(myVar)" # Display true
TestJppTemplate.yml :
parameters:
- name: myParam
type: string
steps:
- powershell: |
Write-Host "myParam: ${{parameters.myParam}}" # Display true
Write-Host "expression1: ${{eq(parameters.myParam, 'True')}}" # Display False
Write-Host "expression2: ${{eq(parameters.myParam, 'true')}}" # Display False
Write-Host "expression3: ${{eq(lower(parameters.myParam), 'true')}}" # Display False
Write-Host "expression4: ${{eq(parameters.myParam, true)}}" # Display False
Write-Host "expression5: ${{eq(parameters.myParam, True)}}" # Display False
As part of an expression, you may access variables using one of two syntaxes:
Index syntax: variables['MyVar']
Property dereference syntax: variables.MyVar
If you want to use the parameters, you can try to use the "if" condition:
- ${{ if eq(parameters.myParam, 'True') }}:
- script: echo true
How about this set-variables-in-scripts
Related
I have defined a Pipeline variable using the UI interface for my pipeline:
And I am consuming that variable in my pipeline azure-pipelines.yml:
name: MyRepo.Deployment.$(date:yy)$(DayOfYear)$(rev:.r)
...
jobs:
- job:
steps:
...
- template: azure-pipelines.yml#Common-YAML
parameters:
...
enable_datasync_job: ${{ eq(variables.enable_datasync_job, 'true') }}
That variable then gets passed to a template that expects a boolean.
The issue is that when I run the pipeline and the azure-pipelines.yml#Common-YAML template gets expanded, the value of enable_datasync_job is always False
What am I missing here? Is it because both my pipeline and the template share the same variable/parameter name?
Assume that enable_datasync_job is defined in the UI as false
Option 1
To override the above variable that is defined in the UI, you can add this bash task to your pipeline
- bash: |
echo $(ENABLE_DATASYNC_JOB) # outputs as false
echo "##vso[task.setvariable variable=enable_datasync_job;]true" # override
- bash: |
echo $(ENABLE_DATASYNC_JOB) # outputs as true
Since your template accepts the parameter of type boolean, you would have something like the below
# template.yml
parameters:
- name: enable_datasync_job
type: boolean
steps:
- bash: |
echo $(ENABLE_DATASYNC_JOB)
And your main yml file
# azure-pipelines.yml
steps:
- bash: |
echo "##vso[task.setvariable variable=enable_datasync_job;]true" # override
- template: template.yml
parameters:
enable_datasync_job: $(enable_datasync_job) # fail
But the above azure-pipelines.yml will fail because of typecasting of string into boolean. Check this SO post for more details
/azure-pipelines.yml (Line: 11, Col: 28): The 'enable_datasync_job'
parameter value '$(enable_datasync_job)' is not a valid Boolean.
According to the above post, you can change the data type of parameter to string in your template.yml
parameters:
- name: enable_datasync_job
type: string
Final result of option 1
# template.yml
parameters:
- name: enable_datasync_job
type: string
steps:
- bash: |
echo $(ENABLE_DATASYNC_JOB) #outputs true
# azure-pipelines.yml
steps:
- bash: |
echo "##vso[task.setvariable variable=enable_datasync_job;]true" # override
- template: template.yml
parameters:
enable_datasync_job: $(enable_datasync_job)
Option 2
If you are looking to just pass the value true to your template without overriding the pipeline variable, you can reference the value that you passed like this
# template.yml
parameters:
- name: enable_datasync_job
type: boolean
steps:
- bash: |
echo ${{ parameters.enable_datasync_job }} # outputs true
echo $(ENABLE_DATASYNC_JOB) # outputs false
# azure-pipelines.yml
steps:
- template: template.yml
parameters:
enable_datasync_job: true
The reason why it was returning False for you is because you have used this expression while passing value to the parameter
${{ eq(variables.enable_datasync_job, 'true') }}
According to the documentation, the eq function
Evaluates True if parameters are equal
You tried to evaluate if the UI variable was equal to true instead of setting it
The expression that you used above will always return False because false(UI variable value) is not equal to true(set in the expression)
I have an azure pipeline template that takes parameters, and I'd like to set one of the parameters based on an expression:
- template: templates/mytemplate.yml
parameters:
TestBackCompat: eq('${{ parameters.CIBuildId }}', 'MasterLatestBuildId')
CreateNupkg: ${{ parameters.CreateNupkg }}
As written, it doesn't work, because the expression isn't evaluated until runtime.
Is there a way to evaluate the expression at compile-time? Simple variable replacement (e.g., the usage of CreateNuPkg in the script above) works OK.
From this official document:
https://learn.microsoft.com/en-us/azure/devops/pipelines/process/templates?view=azure-devops#template-expressions
Template expressions can expand template parameters, and also
variables. You can use parameters to influence how a template is
expanded. The object works like the variables object in an expression.
How the variable object works:
https://learn.microsoft.com/en-us/azure/devops/pipelines/process/variables?view=azure-devops&tabs=yaml%2Cbatch#runtime-expression-syntax
So the usage in your situation should be like this:
give_parameters.yml
trigger:
- none
parameters:
- name: CIBuildId
type: string
default: 'MasterLatestBuildId'
extends:
template: using_parameters.yml
parameters:
TestBackCompat: ${{ eq(parameters.CIBuildId, 'MasterLatestBuildId')}}
using_parameters.yml
parameters:
- name: CIBuildId
type: string
default: 'x'
- name: TestBackCompat
type: string
default: 'x'
variables:
- name: test1
value: ${{ parameters.TestBackCompat}}
- name: test2
value: ${{ parameters.CIBuildId}}
steps:
- task: PowerShell#2
inputs:
targetType: 'inline'
script: |
Write-Host $(test1)
Write-Host $(test2)
Write-Host ${{ parameters.TestBackCompat}}
Result:
In trying to run a script on a loop only if a variable is true but the script never runs :(
It works if i set it as "condition:" to the script but i would like for the task to not even be printed if not to run, therefore would like to use the ${{if...}}
(tried with boolean and string)
parameters:
charts: []
outputChartsDebugInfo: false
steps:
- ${{ each chart in parameters.charts }}:
- script: |
echo "TEST ${{parameters.outputChartsDebugInfo}}" #this outputs true
echo "Deployment values:"
echo "chart name - ${{chart.Name}}"
#...
displayName: Deploy ${{chart.Name}}
- ${{ if eq(parameters.outputChartsDebugInfo, true) }}:
- script: |
echo "DEBUG:"
#...
displayName: Show ${{chart.Name}} debug info
Should this be working?
The first thing that you need to change is how you set your parameters. Then, you should loop over an object that contains some values. Your charts object is empty in your code.
parameters:
- name: charts
type: object
default: [one,two]
- name: outputChartsDebugInfo
default: false
steps:
- ${{ each chart in parameters.charts }}:
- script: |
echo "TEST ${{parameters.outputChartsDebugInfo}}" #this outputs true
echo "Deployment values:"
echo "chart name - ${{chart}}"
displayName: Deploy ${{chart}}
- ${{ if eq(parameters.outputChartsDebugInfo, true ) }}:
- script: |
echo "DEBUG:"
displayName: Show ${{chart }} debug info
Just it case its handy for anyone, the if inside the loop works fine, the parameters outputChartsDebugInfo was being read from a variable, but the syntax used $(var), expands only at runtime before a task executes, and the necessary is that it expands at compile time, so the fix in this case was change the syntax on the variable in the calling script:
steps:
- template: charts-pipeline-template.yml
parameters:
outputChartsDebugInfo: ${{variables.outputChartsDebugInfo}}
charts:
- Name: xxx
- Name: yyy
instead of
steps:
- template: charts-pipeline-template.yml
parameters:
outputChartsDebugInfo: $(outputChartsDebugInfo)
charts:
- Name: xxx
- Name: yyy
So I have a YAML file where I am trying to do something like the following:
# top of the file, declare global variables
variables:
- name: MyName
value: 'apple'
...
parameters:
- name: SwitchName
type: boolean
default: false
...
stages:
- stage: Build
displayName: 'Build'
...
jobs:
variables:
- ${{ if eq(parameters.SwitchName, true) }}:
- name: MyName
value: '$(MyName)_pie'
...
steps:
- task: PowerShell#1
inputs:
scriptType: inlineScript
inlineScript: |
Write-Output $(MyName)
...
#end of script
The goal is to control the pipeline to print apple in default run and apple_pie when the user selects that parameter in the UI to be true.
I understand that parameters are compile-time and variables are run-time. I know that to overwrite a global variable you can create a variable at a job level and change it as yo see fit. Sadly, the way how template works do not let me redeclare that variable properly and I end up with $(MyName)_pie. For some reason, Yaml fails to see that inside that template there is a runtime variable that is needed to be defined.
What are my options here to achieve desired behavior?
Anything missing in my understanding here?
You can change to use the ${{ variables.MyName }} to call the variable in root level.
For example:
variables:
- name: MyName
value: 'apple'
parameters:
- name: SwitchName
type: boolean
default: false
stages:
- stage: Build
displayName: 'Build'
jobs:
- job: A
variables:
- ${{ if eq(parameters.SwitchName, true) }}:
- name: MyName
value: '${{ variables.MyName }}_pie'
steps:
- script: "echo $(MyName)"
Result:
Since you used an if expression to reassign value, the variable will be assigned at compile time.
Refer to this doc: Runtime expression syntax
You can use the template expression format: ${{ variables.var }}
As a AzureDevops user I want to be able to manually pass different MSBuild constants (via DefineConstants) by turning checkboxes on and off on the "Run Pipeline" UI.
Example:
I achieve that by defining two boolean parameters for the current pipeline:
parameters:
- name: enableDebugErrorMessages
displayName: 'Enable debug error messages'
type: boolean
default: false
- name: enableAnalytics
displayName: 'Enable analytics'
type: boolean
default: true
Now I want to generate a string for MSBuild containing enabled constants. Examples:
/p:DefineConstants="ENABLE_ANALYTICS"
/p:DefineConstants="ENABLE_DEBUG_MESSAGES;ENABLE_ANALYTICS"
so I can pass them for MSBuild this way:
- task: XamariniOS#2
inputs:
args: '<HERE>'
I've tried all possible combination of expressions from the documentation I could think of except I want to do something that is not supported by expressions.
UPDATED: I took (another) crack at it on a trivial pipeline and came up with this:
pool: MyBuildPool
parameters:
- name: ENABLE_ANALYTICS
displayName: "Analytics"
type: boolean
default: false
- name: ENABLE_DEBUG_MESSAGES
displayName: "Debug Messages"
type: boolean
default: true
- name: ENABLE_SOMETHING_ELSE
displayName: "Something Else"
type: boolean
default: false
variables:
- ${{ each p in parameters }}:
- name: "DEFINECONSTANT_${{p.key}}"
value: ${{ p.value }}
steps:
- pwsh: |
$constantVars = Get-ChildItem -Path Env:\ | Where-Object Name -like "DEFINECONSTANT_*"
$constantList = ""
$constantVars | ForEach-Object {
$constantList += "$($_.Name.Replace('DEFINECONSTANT_', ''))=$($_.Value);"
}
Write-Host "/p:DefineConstants=`"$constantList`""
displayName: 'Combine parameter values'
When I have Azure Pipelines expand that file, I get:
parameters:
- name: ENABLE_ANALYTICS
displayName: "Analytics"
type: boolean
default: false
- name: ENABLE_DEBUG_MESSAGES
displayName: "Debug Messages"
type: boolean
default: true
- name: ENABLE_SOMETHING_ELSE
displayName: "Something Else"
type: boolean
default: false
variables:
- name: DEFINECONSTANT_ENABLE_ANALYTICS
value: False
- name: DEFINECONSTANT_ENABLE_DEBUG_MESSAGES
value: True
- name: DEFINECONSTANT_ENABLE_SOMETHING_ELSE
value: False
stages:
- stage: __default
jobs:
- job: Job
pool:
name: MyPoolName
steps:
- task: PowerShell#2
displayName: 'Combine parameter values'
inputs:
targetType: inline
script: |
$constantVars = Get-ChildItem -Path Env:\ | Where-Object Name -like "DEFINECONSTANT_*"
$constantList = ""
$constantVars | ForEach-Object {
$constantList += "$($_.Name.Replace('DEFINECONSTANT_', ''))=$($_.Value);"
}
Write-Host "/p:DefineConstants=`"$constantList`""
pwsh: true
Is that closer to what you want? You can have checkboxes with different constant names, descriptions, and default values.
You could use If expression to set the value of the corresponding variable based on the value of the boolean parameter.
Here is the sample:
variables:
${{ if and(parameters.enableDebugErrorMessages, 'true', ne(parameters.enableAnalytics, 'true')) }}:
DefineConstants: ENABLE_DEBUG_MESSAGES
${{ if and(parameters.enableDebugErrorMessages, 'true', eq(parameters.enableAnalytics, 'true')) }}:
DefineConstants: ENABLE_DEBUG_MESSAGES;ENABLE_ANALYTICS
${{ if and(parameters.enableAnalytics, 'true', ne(parameters.enableDebugErrorMessages, 'true')) }}:
DefineConstants: ENABLE_ANALYTICS
parameters:
- name: enableDebugErrorMessages
displayName: 'Enable debug error messages'
type: boolean
default: false
- name: enableAnalytics
displayName: 'Enable analytics'
type: boolean
default: true
pool:
vmImage: ubuntu-latest
steps:
...
In MSbuild argument, you could use the following format: /p:DefineConstants= "$(DefineConstants)".
select enableDebugErrorMessages -> $(DefineConstants) =
ENABLE_DEBUG_MESSAGES
select enableAnalytics -> $(DefineConstants) = ENABLE_ANALYTICS
select both -> $(DefineConstants) =
ENABLE_DEBUG_MESSAGES;ENABLE_ANALYTICS