表达式

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 }}

布尔

TrueFalse 是布尔文本表达式。

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-Z0-9_

根据执行上下文,可以使用不同的变量。

  • 如果使用 YAML 创建管道,则 管道变量 可用。
  • 如果使用经典编辑器创建生成管道,则 生成变量 可用。
  • 如果使用经典编辑器创建发布管道,则 发布变量 可用。

变量始终是字符串。 如果要使用类型化值,则应改用 参数

注意

通过变量选项卡 UI 设置此类变量时,将变量与经典管道和 YAML 管道的表达式结合使用存在限制。 定义为表达式的变量不应依赖于另一个值为表达式的变量 ,因为不能保证 这两个表达式都会得到正确计算。 例如,我们有一个变量 a ,其值 $[ <expression> ] 用作变量 b值的一部分。 由于处理变量的顺序不能保证变量 b 在计算后变量的值 a 可能不正确。

只有在 YAML 管道中通过 variables 关键字 设置变量时,才允许使用描述的构造。 需要按处理变量的顺序放置变量,以便在处理后获取正确的值。

函数

以下内置函数可用于表达式。

  • 如果所有参数都为 ,则计算结果 TrueTrue
  • 最小参数: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。 prefixseed
  • Prefix 是字符串表达式。 针对前缀的每个唯一值跟踪计数器的单独值。 prefix应使用 UTF-16 字符。
  • Seed 是计数器的起始值

可以创建一个计数器,该计数器在管道的每次执行中自动递增 1。 定义计数器时,请提供 prefixseed。 以下示例演示了这一点。

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 (、yyMMKffsfffffssmmHdmMddHH)
  • 示例: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

条件插入

可以使用 ifelseifelse 子句有条件地分配变量值或设置任务的输入。 还可以在满足条件时有条件地运行步骤。

可以使用 if 有条件地分配变量值或为任务设置输入。 还可以在满足条件时有条件地运行步骤。

elseifelse 子句从 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对象是 和 的作业和阶段名称resultsoutputs映射。 表示为 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设置为 runTeststrue,则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

这会告知系统作为筛选数组进行操作 fooid 然后选择 属性。

这将返回:

[ 1, 2, 3 ]

类型转换

表达式中的值可能会在计算表达式时从一种类型转换为另一种类型。 计算表达式时,参数合并为相关数据类型,然后重新转换为字符串。

例如,在此 YAML 中,当计算表达式时,值 TrueFalse 将转换为 10 。 当左参数小于右参数时,函数 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 - -
数字 - - 部分
字符串 部分 部分 - 部分
版本 - - -

布尔

要编号:

  • False0
  • True1

字符串:

  • False'False'
  • True'True'

Null

  • 到布尔值: False
  • 要编号: 0
  • 字符串: '' (空字符串)

Number

  • 到布尔值: 0False,任何其他数字→ 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 以及 $minortask.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)"