表达式
Azure DevOps Services | Azure DevOps Server 2022 - Azure DevOps Server 2019
可以在创作管道时需要指定字符串、布尔值或数字值的多个位置使用表达式。 表达式的最常见用途是在确定作业或步骤应运行 的条件 中。
# Expressions are used to define conditions for a step, job, or stage
steps:
- task: ...
condition: <expression>
表达式的另一个常见用途是定义变量。
可以在 编译时 或 运行时计算表达式。
编译时间表达式可在任何位置使用;运行时表达式可用于变量和条件。 运行时表达式旨在用于计算变量和状态的内容, (示例: condition
) 。
# Two examples of expressions used to define variables
# The first one, a, is evaluated when the YAML file is compiled into a plan.
# The second one, b, is evaluated at runtime.
# Note the syntax ${{}} for compile time and $[] for runtime expressions.
variables:
a: ${{ <expression> }}
b: $[ <expression> ]
运行时和编译时表达式语法之间的差异主要在于可用的上下文。
在) (${{ <expression> }}
编译时表达式中,可以访问 parameters
静态定义的 variables
。
在运行时表达式 ($[ <expression> ]
) 中,可以访问更多 variables
参数,但没有参数。
在此示例中,运行时表达式设置 的值 $(isMain)
。 编译表达式中的静态变量设置 的值 $(compileVar)
。
variables:
staticVar: 'my value' # static variable
compileVar: ${{ variables.staticVar }} # compile time expression
isMain: $[eq(variables['Build.SourceBranch'], 'refs/heads/main')] # runtime expression
steps:
- script: |
echo ${{variables.staticVar}} # outputs my value
echo $(compileVar) # outputs my value
echo $(isMain) # outputs True
表达式可以是文本、对变量的引用、对依赖项的引用、函数或这些表达式的有效嵌套组合。
文本
作为表达式的一部分,可以使用布尔值、null、数字、字符串或版本文本。
# Examples
variables:
someBoolean: ${{ true }} # case insensitive, so True or TRUE also works
someNumber: ${{ -1.2 }}
someString: ${{ 'a b c' }}
someVersion: ${{ 1.2.3 }}
布尔
True
和 False
是布尔文本表达式。
Null
Null 是从字典未命中返回的特殊文本表达式,例如, (variables['noSuch']
) 。 Null 可以是表达式的输出,但不能在表达式中直接调用。
Number
从“-”、“.”或“0”到“9”开头。
String
必须是单引号。 例如:'this is a string'
。
若要表示文本单引号,请使用单引号将其转义。
例如:'It''s OK if they''re using contractions.'
。
可以对多行字符串使用管道字符 (|
) 。
myKey: |
one
two
three
版本
最多包含四个段的版本号。
必须以数字开头,并且必须包含两个或三个句点, (.
) 个字符。
例如:1.2.3.4
。
变量
作为表达式的一部分,可以使用以下两种语法之一来访问变量:
- 索引语法:
variables['MyVar']
- 属性取消引用语法:
variables.MyVar
要使用属性解除参考语法,属性名称必须:
a-Z
从 或 开始_
- 后跟
a-Z
0-9
或_
根据执行上下文,可以使用不同的变量。
变量始终是字符串。 如果要使用类型化值,则应改用 参数 。
注意
通过变量选项卡 UI 设置此类变量时,将变量与经典管道和 YAML 管道的表达式结合使用存在限制。 定义为表达式的变量不应依赖于另一个值为表达式的变量 ,因为不能保证 这两个表达式都会得到正确计算。 例如,我们有一个变量 a
,其值 $[ <expression> ]
用作变量 b
值的一部分。 由于处理变量的顺序不能保证变量 b
在计算后变量的值 a
可能不正确。
只有在 YAML 管道中通过 variables 关键字 设置变量时,才允许使用描述的构造。 需要按处理变量的顺序放置变量,以便在处理后获取正确的值。
函数
以下内置函数可用于表达式。
和
- 如果所有参数都为 ,则计算结果
True
为True
- 最小参数:2. 最大参数:N
- 将参数强制转换为布尔值以供计算
- 第一次后短路
False
- 示例:
and(eq(variables.letters, 'ABC'), eq(variables.numbers, 123))
coalesce
- 按顺序计算参数,并返回不等于 null 或空字符串的值。
- 最小参数:2. 最大参数:N
- 示例:
coalesce(variables.couldBeNull, variables.couldAlsoBeNull, 'literal so it always works')
contains
True
计算左参数 String 是否包含右侧参数- 最小参数:2. 最大参数:2
- 将参数强制转换为 String 以供计算
- 执行序号忽略大小写比较
- 示例:
contains('ABCDE', 'BCD')
(返回 True)
containsValue
True
计算左侧参数是否为数组,并且任何项是否等于右侧参数。 此外,计算True
左侧参数是否为对象,并且任何属性的值是否等于右侧参数。- 最小参数:2. 最大参数:2
- 如果左侧参数是一个数组,请转换每个项以匹配右侧参数的类型。 如果左侧参数是对象,请转换每个属性的值以匹配右侧参数的类型。 如果转换失败,将计算
False
每个特定项的相等性比较。 - 字符串的序号忽略大小写比较
- 第一场比赛后短路
注意
YAML 管道中没有用于指定数组的文本语法。 此函数在常规管道中的用途有限。 它旨在与系统提供的数组(例如步骤列表)一起在 管道修饰器上下文 中使用。
可以使用 containsValue
表达式在 对象中查找匹配的值。 以下示例演示如何在源分支列表中查找 的 Build.SourceBranch
匹配项。
parameters:
- name: branchOptions
displayName: Source branch options
type: object
default:
- refs/heads/main
- refs/heads/test
jobs:
- job: A1
steps:
- ${{ each value in parameters.branchOptions }}:
- script: echo ${{ value }}
- job: B1
condition: ${{ containsValue(parameters.branchOptions, variables['Build.SourceBranch']) }}
steps:
- script: echo "Matching branch found"
convertToJson
- 获取复杂对象并将其输出为 JSON。
- 最小参数:1. 最大参数:1。
parameters:
- name: listOfValues
type: object
default:
this_is:
a_complex: object
with:
- one
- two
steps:
- script: |
echo "${MY_JSON}"
env:
MY_JSON: ${{ convertToJson(parameters.listOfValues) }}
脚本输出:
{
"this_is": {
"a_complex": "object",
"with": [
"one",
"two"
]
}
}
counter
- 此函数只能在定义变量的表达式中使用。 它不能用作步骤、作业或阶段的条件的一部分。
- 计算一个随着管道每次运行而递增的数字。
- 参数:2。
prefix
和seed
。 - Prefix 是字符串表达式。 针对前缀的每个唯一值跟踪计数器的单独值。
prefix
应使用 UTF-16 字符。 - Seed 是计数器的起始值
可以创建一个计数器,该计数器在管道的每次执行中自动递增 1。 定义计数器时,请提供 prefix
和 seed
。 以下示例演示了这一点。
variables:
major: 1
# define minor as a counter with the prefix as variable major, and seed as 100.
minor: $[counter(variables['major'], 100)]
steps:
- bash: echo $(minor)
在上面的示例中,在管道第一次运行时的 值为 minor
100。 第二次运行时,如果 的值 major
仍为 1,则为 101。
如果编辑 YAML 文件,并将变量 major
的值更新为 2,则在下次运行管道时,的值 minor
将为 100。 后续运行会将计数器递增为 101、102、103、 ...
稍后,如果编辑 YAML 文件并将 值 major
重新设置为 1,则计数器的值将恢复该前缀的保留位置。 在此示例中,它恢复为 102。
下面是将变量设置为作为计数器的另一个示例,该计数器从 100 开始,每次运行递增 1,每天重置为 100。
注意
pipeline.startTime
在表达式之外不可用。 pipeline.startTime
格式化 system.pipelineStartTime
为日期和时间对象,使其可用于表达式。
的默认时区为 pipeline.startTime
UTC。 可以 更改组织的时区 。
jobs:
- job:
variables:
a: $[counter(format('{0:yyyyMMdd}', pipeline.startTime), 100)]
steps:
- bash: echo $(a)
下面是一个示例,说明有一个计数器,该计数器为 PR 和 CI 运行维护单独的值。
variables:
patch: $[counter(variables['build.reason'], 0)]
计数器的范围限定为管道。 换句话说,该管道的每次运行都会递增其值。 没有项目范围的计数器。
endsWith
True
计算左参数字符串是否以右参数结尾- 最小参数:2。 最大参数:2
- 将参数强制转换为 String 以求值
- 执行序号忽略大小写比较
- 示例:
endsWith('ABCDE', 'DE')
(返回 True)
eq
True
计算参数是否相等- 最小参数:2。 最大参数:2
- 转换右参数以匹配左参数的类型。 如果转换失败,
False
则返回 。 - 字符串的序号忽略大小写比较
- 示例:
eq(variables.letters, 'ABC')
format
- 计算尾随参数并将其插入到前导参数字符串中
- 最小参数:1。 最大参数:N
- 示例:
format('Hello {0} {1}', 'John', 'Doe')
- 将 .NET 自定义日期和时间格式说明符用于日期格式设置,
yyyy
(、yy
、MM
、K
ff
s
ffff
f
ss
mm
H
d
m
M
dd
HH
) - 示例:
format('{0:yyyyMMdd}', pipeline.startTime)
。 在这种情况下pipeline.startTime
,是一个特殊的日期时间对象变量。 - 通过加倍大括号逃脱。 例如:
format('literal left brace {{ and literal right brace }}')
ge
True
计算左参数是否大于或等于右参数- 最小参数:2。 最大参数:2
- 转换右参数以匹配左参数的类型。 转换失败时出错。
- 字符串的序号忽略大小写比较
- 示例:
ge(5, 5)
(返回 True)
gt
True
计算左参数是否大于右参数- 最小参数:2。 最大参数:2
- 转换右参数以匹配左参数的类型。 转换失败时出错。
- 字符串的序号忽略大小写比较
- 示例:
gt(5, 2)
(返回 True)
in
True
计算左参数是否等于任何右参数- 最小参数:1。 最大参数:N
- 转换右参数以匹配左参数的类型。 相等性比较会
False
评估转换是否失败。 - 字符串的序号忽略大小写比较
- 第一场比赛后短路
- 示例:
in('B', 'A', 'B', 'C')
(返回 True)
join
- 连接右参数数组中的所有元素,用左参数字符串分隔。
- 最小参数:2。 最大参数:2
- 数组中的每个元素都转换为字符串。 复杂对象将转换为空字符串。
- 如果右参数不是数组,则结果为转换为字符串的右参数。
在此示例中,在数组中的每个项之间添加分号。 参数类型是 对象。
parameters:
- name: myArray
type: object
default:
- FOO
- BAR
- ZOO
variables:
A: ${{ join(';',parameters.myArray) }}
steps:
- script: echo $A # outputs FOO;BAR;ZOO
le
True
计算左参数是否小于或等于右参数- 最小参数:2。 最大参数:2
- 转换右参数以匹配左参数的类型。 转换失败时出错。
- 字符串的序号忽略大小写比较
- 示例:
le(2, 2)
(返回 True)
length
- 返回字符串或数组的长度,可以是来自系统或参数的字符串或数组的长度
- 最小参数:1。 最大参数 1
- 示例:
length('fabrikam')
返回 8
lower
- 将字符串或变量值转换为所有小写字符
- 最小参数:1. 最大参数 1
- 返回字符串的小写等效项
- 示例:
lower('FOO')
返回foo
lt
True
计算左参数是否小于右侧参数- 最小参数:2. 最大参数:2
- 转换右参数以匹配左参数的类型。 转换失败时出错。
- 字符串的序号忽略大小写比较
- 示例:
lt(2, 5)
(返回 True)
ne
True
计算参数是否不相等- 最小参数:2. 最大参数:2
- 转换右参数以匹配左参数的类型。 如果转换失败,
True
则返回 。 - 字符串的序号忽略大小写比较
- 示例:
ne(1, 2)
(返回 True)
not
True
计算参数是否为False
- 最小参数:1. 最大参数:1
- 将值转换为布尔值进行评估
- 示例:
not(eq(1, 2))
(返回 True)
notIn
True
如果左参数不等于任何右参数,则计算- 最小参数:1. 最大参数:N
- 转换右参数以匹配左参数的类型。 相等性比较计算
False
是否转换失败。 - 字符串的序号忽略大小写比较
- 第一场比赛后短路
- 示例:
notIn('D', 'A', 'B', 'C')
(返回 True)
或
True
计算是否有任何参数True
- 最小参数:2. 最大参数:N
- 将参数强制转换为布尔值以供计算
- 第一次后短路
True
- 示例:
or(eq(1, 1), eq(2, 3))
(返回 True,短路)
replace
- 返回一个新字符串,其中当前实例中字符串的所有实例都替换为另一个字符串
- 最小参数:3. 最大参数:3
replace(a, b, c)
:返回 ,b 的所有实例替换为 c- 示例:
replace('https://www.tinfoilsecurity.com/saml/consume','https://www.tinfoilsecurity.com','http://server')
(返回http://server/saml/consume
)
split
- 根据指定的分隔符将字符串拆分为子字符串
- 最小参数:2. 最大参数:2
- 第一个参数是要拆分的字符串
- 第二个参数是分隔符
- 返回子字符串的数组。 当分隔符连续出现或在字符串末尾时,数组包含空字符串
- 示例:
variables: - name: environments value: prod1,prod2 steps: - ${{ each env in split(variables.environments, ',')}}: - script: ./deploy.sh --environment ${{ env }}
- 将 split () 与 replace () 配合使用的示例:
parameters: - name: resourceIds type: object default: - /subscriptions/mysubscription/resourceGroups/myResourceGroup/providers/Microsoft.Network/loadBalancers/kubernetes-internal - /subscriptions/mysubscription02/resourceGroups/myResourceGroup02/providers/Microsoft.Network/loadBalancers/kubernetes - name: environments type: object default: - prod1 - prod2 trigger: - main steps: - ${{ each env in parameters.environments }}: - ${{ each resourceId in parameters.resourceIds }}: - script: echo ${{ replace(split(resourceId, '/')[8], '-', '_') }}_${{ env }}
startsWith
True
计算左参数字符串是否以右参数开头- 最小参数:2. 最大参数:2
- 将参数强制转换为 String 以供计算
- 执行序号忽略大小写比较
- 示例:
startsWith('ABCDE', 'AB')
(返回 True)
upper
- 将字符串或变量值转换为所有大写字符
- 最小参数:1. 最大参数 1
- 返回字符串的大写等效项
- 示例:
upper('bah')
返回BAH
xor
True
计算是否正好有一个参数True
- 最小参数:2. 最大参数:2
- 将参数强制转换为布尔值以供计算
- 示例:
xor(True, False)
(返回 True)
作业状态检查函数
可以在条件中将以下状态检查函数用作表达式,但不能在变量定义中。
通用
- 即使取消) ,也始终计算结果
True
为 (。 注意:严重故障可能仍会阻止任务运行。 例如,如果获取来源失败。
canceled
- 如果取消了管道,则计算结果
True
为 。
“失败”
- 对于步骤,等效于
eq(variables['Agent.JobStatus'], 'Failed')
。 - 对于作业:
- 在没有参数的情况下,仅当依赖项关系图中的任何上一个作业失败时,计算结果才为
True
。 - 如果作业名称作为参数,则仅当这些作业中的任何一个失败时,计算结果才为
True
。
- 在没有参数的情况下,仅当依赖项关系图中的任何上一个作业失败时,计算结果才为
succeeded
- 对于步骤,等效于
in(variables['Agent.JobStatus'], 'Succeeded', 'SucceededWithIssues')
dependsOn
在处理作业时使用 ,并且你想要评估上一个作业是否成功。 作业设计为并行运行,阶段按顺序运行。- 对于作业:
- 在没有参数的情况下,仅当依赖项关系图中以前的所有作业都成功或部分成功时,计算结果
True
才为 。 - 如果作业名称作为参数,则计算结果是否
True
所有这些作业都成功或部分成功。 - 如果取消管道,则计算结果
False
为 。
- 在没有参数的情况下,仅当依赖项关系图中以前的所有作业都成功或部分成功时,计算结果
succeededOrFailed
对于步骤,等效于
in(variables['Agent.JobStatus'], 'Succeeded', 'SucceededWithIssues', 'Failed')
对于作业:
- 在没有参数的情况下,无论依赖项关系图中的任何作业是成功还是失败,都计算
True
结果为 。 - 将作业名称作为参数,计算结果为
True
这些作业是成功还是失败。
这类似于
always()
,不同之处在于它会在取消管道时进行评估False
。- 在没有参数的情况下,无论依赖项关系图中的任何作业是成功还是失败,都计算
条件插入
可以使用 if
、 elseif
和 else
子句有条件地分配变量值或设置任务的输入。 还可以在满足条件时有条件地运行步骤。
可以使用 if
有条件地分配变量值或为任务设置输入。 还可以在满足条件时有条件地运行步骤。
elseif
和 else
子句从 Azure DevOps 2022 开始可用,不适用于 Azure DevOps Server 2020 及更低版本的 Azure DevOps。
仅当使用模板语法时,条件才起作用。 详细了解 变量语法。
对于模板,可以在添加序列或映射时使用条件插入。 详细了解 模板中的条件插入。
有条件地分配变量
variables:
${{ if eq(variables['Build.SourceBranchName'], 'main') }}: # only works if you have a main branch
stageName: prod
pool:
vmImage: 'ubuntu-latest'
steps:
- script: echo ${{variables.stageName}}
有条件地设置任务输入
pool:
vmImage: 'ubuntu-latest'
steps:
- task: PublishPipelineArtifact@1
inputs:
targetPath: '$(Pipeline.Workspace)'
${{ if eq(variables['Build.SourceBranchName'], 'main') }}:
artifact: 'prod'
${{ else }}:
artifact: 'dev'
publishLocation: 'pipeline'
有条件地运行步骤
如果没有设置变量,或者 的值 foo
与条件不匹配 if
,则 else
语句将运行。 此处, 的值 foo
在 条件中 elseif
返回 true。
variables:
- name: foo
value: contoso # triggers elseif condition
pool:
vmImage: 'ubuntu-latest'
steps:
- script: echo "start"
- ${{ if eq(variables.foo, 'adaptum') }}:
- script: echo "this is adaptum"
- ${{ elseif eq(variables.foo, 'contoso') }}: # true
- script: echo "this is contoso"
- ${{ else }}:
- script: echo "the value is not adaptum or contoso"
Each 关键字
可以使用 each
关键字循环访问对象类型的参数。
parameters:
- name: listOfStrings
type: object
default:
- one
- two
steps:
- ${{ each value in parameters.listOfStrings }}:
- script: echo ${{ value }}
依赖项
表达式可以使用依赖项上下文来引用以前的作业或阶段。 可以使用依赖项来:
- 引用上一作业的作业状态
- 引用上一阶段的阶段状态
- 在同一阶段引用上一个作业中的输出变量
- 引用阶段中上一阶段的输出变量
- 在下一阶段的上一阶段中引用作业中的输出变量
上下文是针对作业和阶段调用 dependencies
的,其工作原理与变量非常类似。
在作业中,如果在另一个阶段中引用作业的输出变量,则上下文称为 stageDependencies
。
如果在输出变量中包含引号字符 ('
或 "
) 时遇到问题,请参阅 此故障排除指南。
阶段到阶段依赖项
在结构上,dependencies
对象是 和 的作业和阶段名称results
outputs
映射。
表示为 JSON,如下所示:
"dependencies": {
"<STAGE_NAME>" : {
"result": "Succeeded|SucceededWithIssues|Skipped|Failed|Canceled",
"outputs": {
"jobName.stepName.variableName": "value"
}
},
"...": {
// another stage
}
}
使用此形式 dependencies
在变量中映射或在阶段级别检查条件。
在此示例中,阶段 B 运行阶段 A 是成功还是跳过。
注意
以下示例使用标准管道语法。 如果使用部署管道,变量和条件变量语法将有所不同。 有关要使用的特定语法的信息,请参阅 部署作业。
stages:
- stage: A
condition: false
jobs:
- job: A1
steps:
- script: echo Job A1
- stage: B
condition: in(dependencies.A.result, 'Succeeded', 'SucceededWithIssues', 'Skipped')
jobs:
- job: B1
steps:
- script: echo Job B1
阶段还可以使用另一个阶段的输出变量。 在此示例中,阶段 B 依赖于阶段 A 中的变量。
stages:
- stage: A
jobs:
- job: A1
steps:
- bash: echo "##vso[task.setvariable variable=shouldrun;isOutput=true]true"
# or on Windows:
# - script: echo ##vso[task.setvariable variable=shouldrun;isOutput=true]true
name: printvar
- stage: B
condition: and(succeeded(), eq(dependencies.A.outputs['A1.printvar.shouldrun'], 'true'))
dependsOn: A
jobs:
- job: B1
steps:
- script: echo hello from Stage B
注意
默认情况下,管道中的每个阶段都依赖于 YAML 文件中它前面的阶段。
如果需要引用不是紧接当前阶段之前的阶段,可以通过向阶段添加节 dependsOn
来替代此自动默认值。
一个阶段内的作业到作业依赖关系
在单个阶段内的作业级别, dependencies
数据不包含阶段级信息。
"dependencies": {
"<JOB_NAME>": {
"result": "Succeeded|SucceededWithIssues|Skipped|Failed|Canceled",
"outputs": {
"stepName.variableName": "value1"
}
},
"...": {
// another job
}
}
在此示例中,作业 A 将始终被跳过,作业 B 将运行。 作业 C 将运行,因为其所有依赖项要么成功,要么跳过。
jobs:
- job: a
condition: false
steps:
- script: echo Job A
- job: b
steps:
- script: echo Job B
- job: c
dependsOn:
- a
- b
condition: |
and
(
in(dependencies.a.result, 'Succeeded', 'SucceededWithIssues', 'Skipped'),
in(dependencies.b.result, 'Succeeded', 'SucceededWithIssues', 'Skipped')
)
steps:
- script: echo Job C
在此示例中,作业 B 依赖于作业 A 中的输出变量。
jobs:
- job: A
steps:
- bash: echo "##vso[task.setvariable variable=shouldrun;isOutput=true]true"
# or on Windows:
# - script: echo ##vso[task.setvariable variable=shouldrun;isOutput=true]true
name: printvar
- job: B
condition: and(succeeded(), eq(dependencies.A.outputs['printvar.shouldrun'], 'true'))
dependsOn: A
steps:
- script: echo hello from B
跨阶段的作业到作业依赖关系
在作业级别,还可以引用上一阶段作业的输出。
这需要使用 stageDependencies
上下文。
"stageDependencies": {
"<STAGE_NAME>" : {
"<JOB_NAME>": {
"result": "Succeeded|SucceededWithIssues|Skipped|Failed|Canceled",
"outputs": {
"stepName.variableName": "value"
}
},
"...": {
// another job
}
},
"...": {
// another stage
}
}
在此示例中,如果跳过作业 A1,作业 B1 将运行。 作业 B2 将检查作业 A1 中输出变量的值,以确定它是否应运行。
trigger: none
pool:
vmImage: 'ubuntu-latest'
stages:
- stage: A
jobs:
- job: A1
steps:
- bash: echo "##vso[task.setvariable variable=shouldrun;isOutput=true]true"
# or on Windows:
# - script: echo ##vso[task.setvariable variable=shouldrun;isOutput=true]true
name: printvar
- stage: B
dependsOn: A
jobs:
- job: B1
condition: in(stageDependencies.A.A1.result, 'Skipped') # change condition to `Succeeded and stage will be skipped`
steps:
- script: echo hello from Job B1
- job: B2
condition: eq(stageDependencies.A.A1.outputs['printvar.shouldrun'], 'true')
steps:
- script: echo hello from Job B2
如果作业依赖于部署作业在不同阶段中定义的变量,则语法会有所不同。 在以下示例中,如果部署作业run_tests
设置为 runTests
true
,则build_job
作业将运行。 请注意,用于字典的 outputs
键是 build_job.setRunTests.runTests
。
stages:
- stage: build
jobs:
- deployment: build_job
environment:
name: Production
strategy:
runOnce:
deploy:
steps:
- task: PowerShell@2
name: setRunTests
inputs:
targetType: inline
pwsh: true
script: |
$runTests = "true"
echo "setting runTests: $runTests"
echo "##vso[task.setvariable variable=runTests;isOutput=true]$runTests"
- stage: test
dependsOn:
- 'build'
jobs:
- job: run_tests
condition: eq(stageDependencies.build.build_job.outputs['build_job.setRunTests.runTests'], 'true')
steps:
...
阶段,具体取决于作业输出
如果生成后无需更改,则可能希望在某些情况下跳过管道中的阶段。 例如,使用 Terraform 计划时,想要触发审批,并且仅在计划包含更改时应用。
在阶段使用此条件时,必须使用 dependencies
变量,而不是 stageDependencies
。
以下示例是一个简单的脚本,它设置变量 (使用阶段中某个步骤中 Terraform Plan) 的实际信息,然后仅在变量具有特定值时才调用第二阶段。
stages:
- stage: plan_dev
jobs:
- job: terraform_plan_dev
steps:
- bash: echo '##vso[task.setvariable variable=terraform_plan_exitcode;isOutput=true]2'
name: terraform_plan
- stage: apply_dev
dependsOn: plan_dev
condition: eq(dependencies.plan_dev.outputs['terraform_plan_dev.terraform_plan.terraform_plan_exitcode'], '2')
jobs:
- job: part_b
steps:
- bash: echo "BA"
如果阶段依赖于不同阶段中的部署作业定义的变量,则语法会有所不同。 在以下示例中,阶段test
取决于 到 true
的部署build_job
设置shouldTest
。 请注意,在 condition
阶段的 test
中, build_job
出现两次。
stages:
- stage: build
jobs:
- deployment: build_job
environment:
name: Production
strategy:
runOnce:
deploy:
steps:
- task: PowerShell@2
name: setRunTests
inputs:
targetType: inline
pwsh: true
script: |
$runTests = "true"
echo "setting runTests: $runTests"
echo "##vso[task.setvariable variable=runTests;isOutput=true]$runTests"
- stage: test
dependsOn:
- 'build'
condition: eq(dependencies.build.outputs['build_job.build_job.setRunTests.runTests'], 'true')
jobs:
...
在上面的示例中,条件引用环境,而不是环境资源。 若要引用环境资源,需要将环境资源名称添加到依赖项条件。 在以下示例中,条件引用名为 的环境 vmtest
虚拟机资源。
stages:
- stage: build
jobs:
- deployment: build_job
environment:
name: vmtest
resourceName: winVM2
resourceType: VirtualMachine
strategy:
runOnce:
deploy:
steps:
- task: PowerShell@2
name: setRunTests
inputs:
targetType: inline
pwsh: true
script: |
$runTests = "true"
echo "setting runTests: $runTests"
echo "##vso[task.setvariable variable=runTests;isOutput=true]$runTests"
- stage: test
dependsOn:
- 'build'
condition: eq(dependencies.build.outputs['build_job.Deploy_winVM2.setRunTests.runTests']
, 'true')
jobs:
...
筛选的数组
在对项集合进行操作时,可以使用 *
语法来应用筛选的数组。 筛选数组返回所有对象/元素,而不考虑其名称。
例如,以名为 foo
的对象数组为例。 我们希望获取数组 id
中每个 对象中 属性值的数组。
[
{ "id": 1, "a": "avalue1"},
{ "id": 2, "a": "avalue2"},
{ "id": 3, "a": "avalue3"}
]
我们可以执行以下操作:
foo.*.id
这会告知系统作为筛选数组进行操作 foo
, id
然后选择 属性。
这将返回:
[ 1, 2, 3 ]
类型转换
表达式中的值可能会在计算表达式时从一种类型转换为另一种类型。 计算表达式时,参数合并为相关数据类型,然后重新转换为字符串。
例如,在此 YAML 中,当计算表达式时,值 True
和 False
将转换为 1
和 0
。
当左参数小于右参数时,函数 lt()
将返回 True
。
variables:
firstEval: $[lt(False, True)] # 0 vs. 1, True
secondEval: $[lt(True, False)] # 1 vs. 0, False
steps:
- script: echo $(firstEval)
- script: echo $(secondEval)
在此示例中,值 variables.emptyString
和空字符串都计算为空字符串。
函数 coalesce()
按顺序计算参数,并返回不等于 null 或空字符串的第一个值。
variables:
coalesceLiteral: $[coalesce(variables.emptyString, '', 'literal value')]
steps:
- script: echo $(coalesceLiteral) # outputs literal value
下面进一步列出了详细的转换规则。
从/到 | Boolean | Null | Number | 字符串 | 版本 |
---|---|---|---|---|---|
布尔值 | - | - | 是 | 是 | - |
Null | 是 | - | 是 | 是 | - |
数字 | 是 | - | - | 是 | 部分 |
字符串 | 是 | 部分 | 部分 | - | 部分 |
版本 | 是 | - | - | 是 | - |
布尔
要编号:
False
→0
True
→1
字符串:
False
→'False'
True
→'True'
Null
- 到布尔值:
False
- 要编号:
0
- 字符串:
''
(空字符串)
Number
- 到布尔值:
0
→False
,任何其他数字→True
- 版本:必须大于零,并且必须包含非零小数。 必须小于 Int32.MaxValue (也) 的十进制组件。
- 到字符串:将数字转换为没有千位分隔符和无小数分隔符的字符串。
字符串
- 为布尔值:
''
(空字符串) →False
,任何其他字符串→True
- 为 null:
''
(空字符串) →Null
,任何其他不可转换的字符串 - 若要 number:
''
(空字符串) → 0,否则,使用 InvariantCulture 和以下规则运行 C#Int32.TryParse
的 :AllowDecimalPoint |AllowLeadingSign |AllowLeadingWhite |AllowThousands |AllowTrailingWhite。 如果TryParse
失败,则无法转换。 - 若要版本:运行 C# 的
Version.TryParse
。 必须至少包含主要和次要组件。 如果TryParse
失败,则无法转换。
版本
- 到布尔值:
True
- 字符串:Major.Minor 或 Major.Minor.Build 或 Major.Minor.Build.Revision。
常见问题解答
我想执行表达式不支持的事情。 我有哪些用于扩展管道功能的选项?
可以使用包含表达式的脚本自定义管道。 例如,此代码片段采用 BUILD_BUILDNUMBER
变量并使用 Bash 对其进行拆分。 此脚本为主要和$MINOR_RUN
次要运行编号输出两个新变量 $MAJOR_RUN
和 。
然后,这两个变量用于创建两个管道变量, $major
以及 $minor
task.setvariable。 这些变量可用于下游步骤。 若要跨管道共享变量,请参阅 变量组。
steps:
- bash: |
MAJOR_RUN=$(echo $BUILD_BUILDNUMBER | cut -d '.' -f1)
echo "This is the major run number: $MAJOR_RUN"
echo "##vso[task.setvariable variable=major]$MAJOR_RUN"
MINOR_RUN=$(echo $BUILD_BUILDNUMBER | cut -d '.' -f2)
echo "This is the minor run number: $MINOR_RUN"
echo "##vso[task.setvariable variable=minor]$MINOR_RUN"
- bash: echo "My pipeline variable for major run is $(major)"
- bash: echo "My pipeline variable for minor run is $(minor)"