Azure DevOps Services |Azure DevOps Server |Azure DevOps Server 2022 |Azure DevOps Server 2020
本文介绍允许 Azure Pipelines 阶段、作业或步骤运行的不同条件,以及如何在 YAML 管道定义中设置这些条件。
注意
本文讨论 YAML 管道功能。 对于经典管道,可以在每个任务的控制选项中和发布管道中的作业的附加选项中,指定任务或作业运行的某些条件。
阶段、作业或步骤的运行条件
默认情况下,如果管道作业或阶段不依赖于任何其他作业或阶段,或者其所有依赖项都已完成且 成功,则运行该作业或阶段。 依赖项要求适用于直接依赖项及其间接依赖项,以递归方式计算。
默认情况下,如果作业中的任何步骤尚未失败,且前一步骤已经完成,则该步骤将运行。 有关阶段、作业和步骤的更多上下文,请参阅 Azure Pipelines 的关键概念。
你可以通过设置阶段、作业或步骤来替代或自定义这些默认行为,即使以前的依赖项失败或有另一个结果也是如此。 还可以定义 自定义条件。 在 YAML 管道定义中,可以使用 condition 该属性指定阶段、作业或步骤可以运行的条件。
注意
条件适用于具有相同代理池的所有以前的直接和间接依赖项。 不同代理池中的阶段或作业同时运行。
基于以前的依赖项状态的条件包括:
-
成功:仅当所有以前的依赖项都成功时运行。 如果未在 YAML 中设置任何条件,则此行为是默认值。 若要应用此条件,请指定
condition: succeeded()。 -
成功或失败:即使以前的依赖项失败,也运行,除非取消运行。 若要应用此条件,请指定
condition: succeededOrFailed()。 -
始终:即使以前的依赖项失败,运行也会失败,即使已取消运行。 若要应用此条件,请指定
condition: always()。 -
失败:仅在以前的依赖项失败时运行。 若要应用此条件,请指定
condition: failed()。
重要
为阶段、作业或步骤指定 condition 属性时,将覆盖默认条件。 即使取消生成,你的阶段、作业或步骤也可能运行。 确保条件将父阶段或作业的状态考虑在内。
条件示例
以下 YAML 示例演示了和always()failed()条件。 作业 1 中的第一个脚本任务有一个 always 条件,因此即使依赖项失败或生成被取消,它也会运行。 在第二个脚本任务中,exit job1 强制 job1 作业失败。
默认情况下,管道阶段按顺序运行,但作业可以并行运行。 可以使用该 dependsOn 属性显式定义阶段或作业之间的依赖关系。
若要设置依赖于另一个作业结果的作业的条件,请使用 dependsOn 它来定义依赖项。 在以下示例中,由于失败,job2依赖于并运行job1。job1
jobs:
- job: job1
steps:
- script: echo Hello!
condition: always() # this step runs even if the build is canceled
- script: |
echo "This task will fail."
exit job1
- job: job2
dependsOn: job1
condition: failed() # this job runs only if job1 fails
注意
还可以使用 Azure Pipelines UI 在父阶段失败时手动运行依赖阶段。 有关详细信息,请参阅 父阶段失败时运行子阶段。
自定义条件
如果内置条件不符合你的需求,则可以在 YAML 管道定义中将自定义条件指定为 表达式 。
代理从最内部的函数开始计算表达式,然后向外执行。 最终结果是一个布尔值,该值确定是否运行阶段、作业或步骤。 有关语法的完整指南,请参阅表达式。
重要
通过评估条件来确定是否启动某个阶段、作业或步骤。 因此,在阶段、作业或步骤的运行时未计算任何内容可用于同一阶段、作业或步骤。 例如,如果使用具有 $[ ] 语法的运行时表达式在作业中设置变量,则无法在该作业内的条件下使用该变量。
条件中的变量
可以设置管道变量并在条件中使用它们。 以下管道设置一个 isMain 变量,并在仅在生成源分支 main为时运行阶段 B 的条件使用该变量。
variables:
isMain: $[eq(variables['Build.SourceBranch'], 'refs/heads/main')]
stages:
- stage: A
jobs:
- job: A1
steps:
- script: echo Hello Stage A!
- stage: B
condition: and(succeeded(), eq(variables.isMain, true))
jobs:
- job: B1
steps:
- script: echo Hello Stage B!
- script: echo $(isMain)
如果变量为 null 或空字符串,则可以设置要运行的条件。 所有变量都被视为 Azure Pipelines 中的字符串,因此空字符串等效于 null 以下管道中:
variables:
- name: testEmpty
value: ''
jobs:
- job: A
steps:
- script: echo testEmpty is blank
condition: eq(variables.testEmpty, '')
其他作业条件中使用的作业输出变量
可以在作业中创建一个变量,同一阶段中的其他作业可以在条件中指定。 可用于依赖作业的变量必须使用以下代码标记为isOutput=true:
jobs:
- job: A
steps:
- bash: |
echo "This is job A."
echo "##vso[task.setvariable variable=doThing;isOutput=true]Yes" #set variable doThing to Yes
name: DetermineResult
- job: B
dependsOn: A
condition: eq(dependencies.A.outputs['DetermineResult.doThing'], 'Yes') #map doThing and check the value
steps:
- script: echo "Job A ran and doThing is Yes."
后续步骤条件中使用的步骤变量
可以在一个步骤中创建变量,以便同一作业中的后续步骤可以在条件中指定。 默认情况下,从步骤创建的变量可用于作业中未来的步骤,无需标记为多作业输出变量。
在作业中的步骤中创建的变量具有以下限制:
以下示例在步骤中创建管道变量,并在后续步骤的脚本条件中使用该变量。
steps:
# This step creates a new pipeline variable: doThing. This variable is available to subsequent steps.
- bash: |
echo "##vso[task.setvariable variable=doThing]Yes"
displayName: Step 1
# This step uses doThing in its condition
- script: |
# Access the variable from Step 1 as an environment variable.
echo "Value of doThing (as DOTHING env var): $DOTHING."
displayName: Step 2
condition: and(succeeded(), eq(variables['doThing'], 'Yes')) # or and(succeeded(), eq(variables.doThing, 'Yes'))
各种结果的条件设置
下表显示了 condition 生成各种所需结果的设置。
| 所需结果 | 示例条件设置 |
|---|---|
如果源分支为 main源分支,即使父级或上一阶段、作业或步骤失败或已取消,也运行。 |
eq(variables['Build.SourceBranch'], 'refs/heads/main') |
如果源分支为 main 父分支或上一阶段、作业或步骤成功,则运行。 |
and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/main')) |
如果源分支不是 main,并且父级或上一阶段、作业或步骤成功,则运行。 |
and(succeeded(), ne(variables['Build.SourceBranch'], 'refs/heads/main')) |
如果父级或上一阶段、作业或步骤成功,则为 user 分支运行。 |
and(succeeded(), startsWith(variables['Build.SourceBranch'], 'refs/heads/users/')) |
| 如果父级或上一阶段、作业或步骤成功,则为持续集成 (CI) 生成运行。 | and(succeeded(), in(variables['Build.Reason'], 'IndividualCI', 'BatchedCI')) |
| 如果拉取请求触发了生成,并且父阶段或上一阶段、作业或步骤失败,则运行。 | and(failed(), eq(variables['Build.Reason'], 'PullRequest')) |
| 即使父级或上一阶段、作业或步骤失败或已取消,也为计划生成运行。 | eq(variables['Build.Reason'], 'Schedule') |
| 如果变量设置为 |
eq(variables['System.debug'], true) |
注意
Release.Artifacts.{artifact-alias}.SourceBranch 等效于 Build.SourceBranch。
取消生成时的条件结果
取消生成并不意味着其所有阶段、作业和步骤都停止运行。 哪些作业、阶段或步骤停止运行取决于指定的条件,以及取消生成管道的执行时间点。 如果跳过阶段、作业或步骤的父级,则无论其条件如何,阶段、作业或步骤都不会运行。
只要一个阶段、作业或步骤的条件评估为 true,它就会运行。 如果某个条件不考虑任务的父级的状态,则即使任务的父级被取消,该任务也可能运行。 若要控制在取消生成时是否运行作业、阶段或步骤,请在条件中包含 作业状态检查功能 。
如果在队列阶段但尚未运行时取消生成,则会取消整个运行,包括所有其他阶段。
注意
如果任一条件使任务即使在生成取消后也能运行,请指定 一个取消超时 值,该值为取消运行后的任务提供足够的时间。
示例阶段条件结果
以下示例显示了取消生成时在阶段设置的各种条件的结果。
阶段示例 1
在以下管道中,默认情况下 stage2 取决于 stage1 成功完成。 但是,无论状态如何, stage2 都有一个 condition 设置为在源分支 main处于运行状态时 stage1 运行。
如果在 main 分支上排队构建,然后在 stage1 仍在运行时取消构建,那么 stage2 仍会运行,因为 eq(variables['Build.SourceBranch'], 'refs/heads/main') 的计算结果为 true。
stages:
- stage: stage1
jobs:
- job: A
steps:
- script: echo 1; sleep 30
- stage: stage2
condition: eq(variables['Build.SourceBranch'], 'refs/heads/main')
jobs:
- job: B
steps:
- script: echo 2
阶段示例 2
在以下管道中,默认情况下 stage2 取决于 stage1 成功完成。 每当源分支为B时,作业中的stage2condition作业main都设置为运行。
如果在分支上 main 排队生成并在运行时取消生成 stage1 , stage2 并且其作业根本不运行,即使该阶段包含其条件的计算结果为 true的作业也是如此。
stages:
- stage: stage1
jobs:
- job: A
steps:
- script: echo 1; sleep 30
- stage: stage2
jobs:
- job: B
condition: eq(variables['Build.SourceBranch'], 'refs/heads/main')
steps:
- script: echo 2
阶段示例 3
在以下管道中,默认情况下 stage2 取决于 stage1 成功完成。 每当源分支为B时,作业内的stage2condition步骤都有一main组要运行的步骤。
如果在分支上main排队生成并在运行时取消生成stage1,stage2并且作业根本不运行,即使作业BB包含其条件计算结果为true的步骤也是如此。
Stage2 已完全跳过,因为 stage1 已取消。
stages:
- stage: stage1
jobs:
- job: A
steps:
- script: echo 1; sleep 30
- stage: stage2
jobs:
- job: B
steps:
- script: echo 2
condition: eq(variables['Build.SourceBranch'], 'refs/heads/main')
示例作业条件结果
以下示例显示了在取消生成时针对作业设置的各种条件的结果。
作业示例 1
在以下 YAML 管道中,正在运行的作业 B 取决于正在运行的作业 A 。 每当源分支为B时,作业condition也具有一个main要运行的集合。
如果你在 main 分支上将某个构建排队,并且在作业 A 仍在运行时取消该构建,则作业 B 仍会运行,因为 condition: eq(variables['Build.SourceBranch'], 'refs/heads/main') 的计算结果为 true。
jobs:
- job: A
steps:
- script: sleep 30
- job: B
dependsOn: A
condition: eq(variables['Build.SourceBranch'], 'refs/heads/main')
steps:
- script: echo step 2.1
如果希望仅当作业成功且生成源为B时运行作业Amain,则必须将它conditionand(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/main'))设置为 。
作业示例 2
在以下 YAML 管道中,作业 B 依赖于作业 A 成功。 每当作业B成功且生成源分支为condition时,作业A都有一组main要运行。
如果在分支上 main 排队生成并在作业 A 运行时取消它,则作业 B 不会运行,即使作业的 condition 计算结果为 true。 作业 B 条件的计算结果 false 为:作业 A 未成功。 因此,将跳过作业 B 及其步骤。
jobs:
- job: A
steps:
- script: sleep 30
- job: B
dependsOn: A
steps:
- script: echo step 2.1
condition: and(eq(variables['Build.SourceBranch'], 'refs/heads/main'), succeeded())
示例步骤条件结果
还可以设置步骤的条件。 在以下管道中,每当源分支为 condition 时,步骤 2.3 都有一个要运行的 main 集。
如果你在 main 分支上将生成排队,并在步骤 2.1 或 2.2 运行时将其取消,则步骤 2.3 仍会运行,因为 eq(variables['Build.SourceBranch'], 'refs/heads/main') 计算结果为 true。
steps:
- script: echo step 2.1
- script: echo step 2.2; sleep 30
- script: echo step 2.3
condition: eq(variables['Build.SourceBranch'], 'refs/heads/main')
条件中的参数
可以在条件中使用参数。 参数扩展发生在管道运行之前,并使用文本参数值替换括起来 ${{ }} 的值。 由于参数扩展发生在条件评估之前,因此可以在管道中声明参数,并将参数嵌入该管道中的任何条件中。
condition以下示例中合并了两个函数:succeeded()和 ${{ eq(parameters.doThing, true) }}。
succeeded() 函数检查上一步是否成功。 如果没有上一步, true 此函数也会返回。
${{ eq(parameters.doThing, true) }}函数检查 doThing 参数是否等于 true。 以下示例中的脚本步骤会运行,因为没有上一步, parameters.doThing 默认情况下是 true 。
parameters:
- name: doThing
default: true
type: boolean
steps:
- script: echo I did a thing
condition: and(succeeded(), ${{ eq(parameters.doThing, true) }})
条件中的模板参数
将参数传递到管道模板时,可以在模板文件中设置参数的值 ,或使用 templateContext 将参数传递给模板。
以下parameters.yml模板文件使用默认值doThing声明true参数,并在作业条件中使用参数。
# parameters.yml
parameters:
- name: doThing
default: true
type: boolean
jobs:
- job: B
steps:
- script: echo I did a thing
condition: ${{ eq(parameters.doThing, true) }}
以下 azure-pipelines.yml 管道定义引用 parameters.yml 模板文件中的作业。 管道的输出是因为 I did a thing 参数 doThing 默认为 true。
# azure-pipelines.yml
extends:
template: parameters.yml
有关更多模板参数示例,请参阅模板使用情况参考。
FAQ
如果前一个作业成功但有问题,如何触发作业?
可以在条件中使用上一个作业的结果。 在以下 YAML 中,条件 eq(dependencies.A.result,'SucceededWithIssues') 设置作业 B 在作业 A 成功后运行并出现问题。
jobs:
- job: A
steps:
- script: echo Job A ran
- job: B
dependsOn: A
condition: eq(dependencies.A.result,'SucceededWithIssues') # targets the result of the previous job
steps:
- script: echo Job A had issues
为什么在取消生成后仍在运行?
如果在阶段中配置的条件不包含作业状态检查函数,则会遇到此问题。 要解决此问题,请向条件中添加作业状态检查函数。 有关详细信息,请参阅 取消生成时的条件结果。