使用模板表达式指定如何在管道初始化期间动态解析值。
将模板表达式包装在此语法中:${{ }}。
模板表达式可以扩展模板参数以及变量。
可以使用参数来影响模板的扩展方式。
parameters 对象的工作方式类似于表达式中的 variables 对象。 在模板表达式中只能使用预定义变量。
注意
只有 stages、jobs、steps 和 containers(在 resources 内)的表达式会扩展。
例如,不能在 trigger 或类似 repositories 的资源中使用表达式。
此外,在 Azure DevOps 2020 RTW 上,不能在 containers 中使用模板表达式。
例如,定义模板:
# File: steps/vsbuild.yml
parameters:
- name: 'solution'
default: '**/*.sln'
type: string
steps:
- task: VSBuild@1
inputs:
solution: ${{ parameters['solution'] }} # index syntax
- task: VSTest@3
inputs:
testSelector: 'testAssemblies'
testAssemblyVer2: ${{ parameters.solution }} # property dereference syntax
searchFolder: '$(System.DefaultWorkingDirectory)'
然后,引用模板并向其传递可选 solution 参数:
# File: azure-pipelines.yml
steps:
- template: steps/vsbuild.yml
parameters:
solution: my.sln
上下文
在模板表达式中,可以访问 parameters 上下文,其中包含传入的参数值。
此外,还可以访问包含 YAML 文件中指定的所有变量以及许多variables(注意该文章中的每个变量)的上下文 。
重要的是,它没有运行时变量,例如管道中存储的变量或在启动运行时给定的变量。
模板扩展发生在运行早期,因此这些变量不可用。
模板表达式函数
可以在模板中使用通用函数。 还可以使用一些模板表达式函数。
格式
- 简单字符串令牌替换
- 最小参数:2。 最大参数:N
- 示例:
${{ format('{0} Build', parameters.os) }}→'Windows Build'
联合
- 求值为第一个非空、非 null 字符串参数
- 最小参数:2。 最大参数:N
- 示例:
parameters:
- name: 'customVersion'
type: string
default: ''
- name: 'defaultVersion'
type: string
default: '1.0.0'
steps:
- script: echo Version is ${{ coalesce(parameters.customVersion, parameters.defaultVersion) }}
注意
字符串参数( default: '' 空字符串)的行为方式因触发管道的方式而异:
-
在管道编辑器中:可以直接运行管道,并遵循空字符串默认值,从而允许
coalesce回退到下一个值。 -
在“运行管道”窗格中:Azure DevOps 要求为具有空字符串默认值的参数提供非空值,以防止
coalesce回退。
插入
可以使用模板表达式来更改 YAML 管道的结构。 例如,要插入序列:
# File: jobs/build.yml
parameters:
- name: 'preBuild'
type: stepList
default: []
- name: 'preTest'
type: stepList
default: []
- name: 'preSign'
type: stepList
default: []
jobs:
- job: Build
pool:
vmImage: 'windows-latest'
steps:
- script: cred-scan
- ${{ parameters.preBuild }}
- task: VSBuild@1
- ${{ parameters.preTest }}
- task: VSTest@3
- ${{ parameters.preSign }}
- script: sign
# File: .vsts.ci.yml
jobs:
- template: jobs/build.yml
parameters:
preBuild:
- script: echo hello from pre-build
preTest:
- script: echo hello from pre-test
将数组插入数组时,嵌套数组将平展。
要插入到映射中,请使用特殊属性 ${{ insert }}。
# Default values
parameters:
- name: 'additionalVariables'
type: object
default: {}
jobs:
- job: build
variables:
configuration: debug
arch: x86
${{ insert }}: ${{ parameters.additionalVariables }}
steps:
- task: VSBuild@1
- task: VSTest@3
jobs:
- template: jobs/build.yml
parameters:
additionalVariables:
TEST_SUITE: L0,L1
有条件插入
如果要有条件地插入到序列或模板中的映射中,请使用插入和表达式计算。 只要使用模板语法,就可以在if使用 语句。
例如,要插入到模板中的序列中,请执行以下操作:
# File: steps/build.yml
parameters:
- name: 'toolset'
default: vsbuild
type: string
values:
- vsbuild
- dotnet
steps:
# msbuild
- ${{ if eq(parameters.toolset, 'msbuild') }}:
- task: VSBuild@1
- task: VSTest@3
# dotnet
- ${{ if eq(parameters.toolset, 'dotnet') }}:
- task: UseDotNet@2
inputs:
command: build
- task: UseDotNet@2
inputs:
command: test
# File: azure-pipelines.yml
steps:
- template: steps/build.yml
parameters:
toolset: dotnet
例如,要插入到模板中的映射中,请执行以下操作:
# File: steps/build.yml
parameters:
- name: 'debug'
type: boolean
default: false
steps:
- script: tool
env:
${{ if eq(parameters.debug, true) }}:
TOOL_DEBUG: true
TOOL_DEBUG_DIR: _dbg
steps:
- template: steps/build.yml
parameters:
debug: true
还可以对变量使用条件插入。 在此示例中,start 始终输出,而 this is a test 仅在变量等于 foo 等于 test 时才会输出。
variables:
- name: foo
value: test
pool:
vmImage: 'ubuntu-latest'
steps:
- script: echo "start" # always runs
- ${{ if eq(variables.foo, 'test') }}:
- script: echo "this is a test" # runs when foo=test
还可以根据其他变量的值来设置变量。 在以下管道中,myVar 用于设置 conditionalVar 的值。
trigger:
- main
pool:
vmImage: 'ubuntu-latest'
variables:
- name: myVar
value: 'baz'
- name: conditionalVar
${{ if eq(variables['myVar'], 'foo') }}:
value: 'bar'
${{ elseif eq(variables['myVar'], 'baz') }}:
value: 'qux'
${{ else }}:
value: 'default'
steps:
- script: echo "start" # always runs
- ${{ if eq(variables.conditionalVar, 'bar') }}:
- script: echo "the value of myVar is set in the if condition" # runs when myVar=foo
- ${{ if eq(variables.conditionalVar, 'qux') }}:
- script: echo "the value of myVar is set in the elseif condition" # runs when myVar=baz
迭代插入
指令 each 允许基于 YAML 序列(数组)或映射(键值对)进行迭代插入。
例如,可以使用其他步骤前和步骤后包装每个作业的步骤:
# job.yml
parameters:
- name: 'jobs'
type: jobList
default: []
jobs:
- ${{ each job in parameters.jobs }}: # Each job
- ${{ each pair in job }}: # Insert all properties other than "steps"
${{ if ne(pair.key, 'steps') }}:
${{ pair.key }}: ${{ pair.value }}
steps: # Wrap the steps
- task: SetupMyBuildTools@1 # Pre steps
- ${{ job.steps }} # Users steps
- task: PublishMyTelemetry@1 # Post steps
condition: always()
# azure-pipelines.yml
jobs:
- template: job.yml
parameters:
jobs:
- job: A
steps:
- script: echo This will get sandwiched between SetupMyBuildTools and PublishMyTelemetry.
- job: B
steps:
- script: echo So will this!
还可以使用 stringList 来定义和遍历包含项列表的参数。
注意
该 stringList 数据类型在模板中不可用。 请改用 object 模板中的数据类型。
parameters:
- name: regions
type: stringList
displayName: Regions
values:
- WUS
- CUS
- EUS
default:
- WUS
- EUS
stages:
- ${{ each stage in parameters.regions}}:
- stage: ${{stage}}
displayName: Deploy to ${{stage}}
jobs:
- job:
steps:
- script: ./deploy ${{stage}}
还可以操作要循环访问的任何属性。 例如,要添加更多依赖项:
# job.yml
parameters:
- name: 'jobs'
type: jobList
default: []
jobs:
- job: SomeSpecialTool # Run your special tool in its own job first
steps:
- task: RunSpecialTool@1
- ${{ each job in parameters.jobs }}: # Then do each job
- ${{ each pair in job }}: # Insert all properties other than "dependsOn"
${{ if ne(pair.key, 'dependsOn') }}:
${{ pair.key }}: ${{ pair.value }}
dependsOn: # Inject dependency
- SomeSpecialTool
- ${{ if job.dependsOn }}:
- ${{ job.dependsOn }}
# azure-pipelines.yml
jobs:
- template: job.yml
parameters:
jobs:
- job: A
steps:
- script: echo This job depends on SomeSpecialTool, even though it's not explicitly shown here.
- job: B
dependsOn:
- A
steps:
- script: echo This job depends on both Job A and on SomeSpecialTool.
转义值
如果需要对字面上包含 ${{ 的值进行转义,请将该值包装在表达式字符串中。 例如,${{ 'my${{value' }} 或 ${{ 'my${{value with a '' single quote too' }}