配置管道的计划

Azure DevOps Services | Azure DevOps Server 2022 - Azure DevOps Server 2019

Azure Pipelines 提供了多种类型的触发器来配置管道的启动方式。

  • 计划触发器会基于计划(例如夜间生成)启动管道。 本文提供有关使用计划触发器基于计划运行管道的指导。
  • 基于事件的触发器启动管道以响应事件,例如创建拉取请求或推送到分支。 有关使用基于事件的触发器的信息,请参阅 Azure Pipelines 中的触发器

可以在管道中组合使用计划触发器和基于事件的触发器,例如,在每次进行推送时(CI 触发器),发送拉取请求时(PR 触发器),以及夜间生成时(计划触发器)验证生成。 如果你只想按计划生成管道,而不响应基于事件的触发器,请确保管道未启用任何其他触发器。 例如,GitHub 存储库中的 YAML 管道默认启用 CI 触发器和 PR 触发器。 有关禁用默认触发器的信息,请参阅 Azure Pipelines 中的触发器,并浏览涉及存储库类型的部分。

计划的触发器

重要

使用管道设置 UI 定义的计划触发器优先于 YAML 计划触发器。

如果 YAML 管道同时具有 YAML 计划触发器和 UI 定义的计划触发器,则仅运行 UI 定义的计划触发器。 要在 YAML 管道中运行 YAML 定义的计划触发器,必须删除管道设置 UI 中定义的计划触发器。 删除所有 UI 计划触发器后,必须进行推送,以便 YAML 计划触发器开始评估。

要从 YAML 管道中删除 UI 计划触发器,请参阅 UI 设置替代 YAML 计划触发器

计划触发器将管道配置为按使用 cron 语法定义的计划运行。

schedules:
- cron: string # cron syntax defining a schedule
  displayName: string # friendly name given to a specific schedule
  branches:
    include: [ string ] # which branches the schedule applies to
    exclude: [ string ] # which branches to exclude from the schedule
  always: boolean # whether to always run the pipeline or only if there have been source code changes since the last successful scheduled run. The default is false.
schedules:
- cron: string # cron syntax defining a schedule
  displayName: string # friendly name given to a specific schedule
  branches:
    include: [ string ] # which branches the schedule applies to
    exclude: [ string ] # which branches to exclude from the schedule
  always: boolean # whether to always run the pipeline or only if there have been source code changes since the last successful scheduled run. The default is false.
  batch: boolean # Whether to run the pipeline if the previously scheduled run is in-progress; the default is false.
  # batch is available in Azure DevOps Server 2022.1 and higher

YAML 中的计划管道具有以下约束。

  • cron 计划的时区为 UTC。
  • 如果指定 exclude 子句而不包含 branchesinclude 子句,则等同于在 include 子句中指定 *
  • 指定计划时,不能使用管道变量。
  • 如果在 YAML 文件中使用模板,必须在主要 YAML 文件中(而不是在模板文件中)指定计划。

计划触发器的分支注意事项

发生以下事件时,会针对分支评估计划触发器。

  • 创建了管道。
  • 管道的 YAML 文件通过推送或通过在管道编辑器中进行编辑来更新。
  • 管道的 YAML 文件路径更新为引用其他 YAML 文件。 此更改仅更新默认分支,因此仅在更新的 YAML 文件中为默认分支选取计划。 如果任何其他分支随后合并了默认分支(例如 git pull origin main),则会针对该分支评估新引用的 YAML 文件中的计划触发器。
  • 创建了新分支。

在分支中发生其中一个事件后,如果该分支与该分支的 YAML 文件中包含的计划触发器的分支筛选器匹配,则会添加该分支的任何计划运行。

重要

仅当分支与特定分支的 YAML 文件中的计划触发器的分支筛选器匹配时,才会添加该分支的计划运行。

例如,使用以下计划创建管道,并将此版本的 YAML 文件签入到 main 分支中。 此计划每天都生成 main 分支。

# YAML file in the main branch
schedules:
- cron: '0 0 * * *'
  displayName: Daily midnight build
  branches:
    include:
    - main

接下来,在 main 的基础上创建一个名为 new-feature 的新分支。 读取新分支的 YAML 文件中的计划触发器,由于 new-feature 分支没有匹配项,因此不会对计划生成进行更改,并且不会使用计划触发器生成 new-feature 分支。

如果 new-feature 已添加到 branches 列表中,并且此更改已推送到 new-feature 分支,则会读取 YAML 文件,由于 new-feature 现在位于分支列表中,因此会为 new-feature 分支添加计划生成。

# YAML file in the new-feature-branch
schedules:
- cron: '0 0 * * *'
  displayName: Daily midnight build
  branches:
    include:
    - main
    - new-feature

现在,基于 main 创建了名为 release 的分支,然后 release 添加到了 main 分支(而不是新创建的 release 分支)的 YAML 文件中的分支筛选器。

# YAML file in the release branch
schedules:
- cron: '0 0 * * *'
  displayName: Daily midnight build
  branches:
    include:
    - main

# YAML file in the main branch with release added to the branches list
schedules:
- cron: '0 0 * * *'
  displayName: Daily midnight build
  branches:
    include:
    - main
    - release

由于 release 已添加到 main 分支中的分支筛选器,但添加到 release 分支中的分支筛选器,因此 release 分支不会基于该计划生成。 仅当 release 分支添加到发布分支的 YAML 文件中的分支筛选器时,计划生成才会添加到计划程序。

计划触发器的分支注意事项

注意

Azure DevOps Server 2022.1 及更高版本上可以使用 batch 属性。

batch 属性设定是否在先前计划正在运行时运行管道;默认值为 false。 这与管道存储库的版本无关。

下表介绍了 alwaysbatch 的交互方式。

始终 Batch 行为
false false 仅当上次成功的计划管道运行发生更改时,才运行管道。
false true 仅当上次成功的计划管道运行发生更改,且没有正在运行的计划管道时,才运行管道。
true false 根据 cron 计划运行管道。
true true 根据 cron 计划运行管道。

重要

alwaystrue 时,管道根据 cron 计划运行,即使 batchtrue也是如此。

Build.CronSchedule.DisplayName variable

注意

Azure DevOps Server 2022.1 及更高版本上可以使用 Build.CronSchedule.DisplayName 变量。

当管道因 cron 计划触发器运行时,预定义的 Build.CronSchedule.DisplayName 变量包含触发管道运行的 cron 计划的 displayName

YAML 管道可能包含多个 cron 计划,并且可能需要管道根据运行的 cron 计划来运行不同的阶段或作业。 例如,你有一个夜间生成和一个每周生成,而你只想在夜间生成期间运行特定阶段。 可以在作业或阶段条件中使用 Build.CronSchedule.DisplayName 变量,以决定是否运行作业或阶段。

- stage: stage1
  # Run this stage only when the pipeline is triggered by the 
  # "Daily midnight build" cron schedule
  condition: eq(variables['Build.CronSchedule.DisplayName'], 'Daily midnight build')

更多示例请参阅《schedules.cron 示例》。

Azure DevOps Server 2019 中的 YAML 语法不支持计划生成。 创建 YAML 生成管道后,可以使用管道设置指定计划触发器。

示例

下面的示例定义了两个计划:

schedules:
- cron: '0 0 * * *'
  displayName: Daily midnight build
  branches:
    include:
    - main
    - releases/*
    exclude:
    - releases/ancient/*
- cron: '0 12 * * 0'
  displayName: Weekly Sunday build
  branches:
    include:
    - releases/*
  always: true

第一个计划每日午夜生成仅在自上次成功的计划运行以来代码发生更改时,才在每天午夜为 main 和所有 releases/* 分支(releases/ancient/* 下的分支除外)运行管道。

第二个计划每周星期日生成在周日中午为所有 releases/* 分支运行管道,无论自上次运行以来是否已更改代码。

注意

cron 计划的时区为 UTC,因此在这些示例中,午夜生成和中午生成是指 UTC 的午夜和中午。

有关更多示例,请参阅从经典编辑器迁移

Azure DevOps Server 2019 中的 YAML 语法不支持计划生成。 创建 YAML 生成管道后,可以使用管道设置指定计划触发器。

Cron 语法

每个 Azure Pipelines 计划触发器 cron 表达式都是一个空格分隔的表达式,按以下顺序包含五个条目。 表达式用单引号 ' 引起来。

mm HH DD MM DW
 \  \  \  \  \__ Days of week
  \  \  \  \____ Months
   \  \  \______ Days
    \  \________ Hours
     \__________ Minutes
字段 接受的值
分钟数 0 到 59
小时 0 到 23
1 到 31
1 到 12,完整英文名称,英文名称的前三个字母
星期几 0 到 6(从星期日开始),完整英文名称,英文名称的前三个字母

值可以是以下格式。

格式 示例 说明
通配符 * 匹配此字段的所有值
单值 5 指定此字段的单个值
逗号分隔 3,5,6 指定此字段的多个值。 可以组合多种格式,例如 1,3-6
范围 1-3 此字段的值的非独占范围
间隔 */41-5/2 要与此字段匹配的间隔,例如每四个值或 1-5 范围,步长间隔为 2
示例 Cron 表达式
每个星期一、星期三和星期五下午 6:00 生成一次 0 18 * * Mon,Wed,Fri0 18 * * 1,3,50 18 * * 1-5/2
每 6 小时生成一次 0 0,6,12,18 * * *0 */6 * * *0 0-18/6 * * *
从上午 9:00 开始每 6 小时生成一次 0 9,15,21 * * *0 9-21/6 * * *

要详细了解支持的格式,请参阅 Crontab 表达式

Azure DevOps Server 2019 中的 YAML 语法不支持计划生成。 创建 YAML 生成管道后,可以使用管道设置指定计划触发器。

“计划运行”视图

通过从管道的管道详细信息页上的上下文菜单中选择计划运行,可以查看即将推出的计划生成的预览。

重要

“计划运行”视图仅显示计划从当前日期起 7 天内运行的管道。 如果 cron 计划的时间间隔长于 7 天,并且下一次运行计划在当前日期的 7 天后开始,则它不会显示在计划运行视图中。

“计划运行”菜单

创建或更新计划触发器后,可以使用计划运行视图进行验证。

计划运行

此示例显示以下计划的计划运行。

schedules:
- cron: '0 0 * * *'
  displayName: Daily midnight build
  branches:
    include:
    - main

计划运行 窗口显示转换为计算机上设置用于浏览到 Azure DevOps 门户的本地时区的时间。 此示例显示在 EST 时区拍摄的屏幕截图。

注意

如果更新正在运行管道的计划,则计划运行视图不会使用新计划进行更新,直到当前正在运行的管道完成。

Azure DevOps Server 2019 中的 YAML 语法不支持计划生成。 创建 YAML 生成管道后,可以使用管道设置指定计划触发器。

即使在没有代码更改的情况下也运行

默认情况下,如果自上次成功计划运行以来没有代码更改,管道就不会按计划运行。 例如,假设已将管道计划为每天晚上 9:00 运行。 在工作日,你将各种更改推送到代码中。 管道按计划运行。 在周末,你不对代码进行任何更改。 如果自星期五的计划运行以来没有代码更改,管道就不会在周末按计划运行。

要强制管道在没有代码更改的情况下运行,可以使用 always 关键字。

schedules:
- cron: ...
  ...
  always: true

此版本的 Azure DevOps Server 中的 YAML 语法不支持计划生成。 创建 YAML 生成管道后,可以使用管道设置指定计划触发器。

YAML 管道中计划运行数的限制

管道计划运行的频率存在一定限制。 实施这些限制是为了防止滥用 Azure Pipelines 资源,尤其是 Microsoft 托管代理。 这些限制包括:

  • 每个管道每周大约运行 1000 次
  • 每个管道每 15 分钟运行 10 次

从经典编辑器迁移

以下示例演示了如何将计划从经典编辑器迁移到 YAML。

示例:多个时区中的 Git 存储库的夜间生成

在此示例中,经典编辑器计划触发器有两个条目,可生成以下生成。

  • 每个星期一 - 星期五凌晨 3:00(UTC + 5:30 时区),生成符合 features/india/* 分支筛选条件的分支

    计划触发器 UTC + 5:30 时区

  • 每个星期一 - 星期五凌晨 3:00(UTC - 5:00 时区),生成符合 features/nc/* 分支筛选条件的分支

    计划触发器 UTC -5:00 时区

等效的 YAML 计划触发器如下:

schedules:
- cron: '30 21 * * Sun-Thu'
  displayName: M-F 3:00 AM (UTC + 5:30) India daily build
  branches:
    include:
    - /features/india/*
- cron: '0 8 * * Mon-Fri'
  displayName: M-F 3:00 AM (UTC - 5) NC daily build
  branches:
    include:
    - /features/nc/*

在第一个计划 M-F 3:00 AM (UTC + 5:30) 印度每日生成中,cron 语法 (mm HH DD MM DW) 为 30 21 * * Sun-Thu

  • 分钟数和小时数 - 30 21 这会映射到 21:30 UTC (9:30 PM UTC)。 由于经典编辑器中的指定时区是 UTC + 5:30,我们需要在所需的生成时间凌晨 3:00 的基础上减去 5 小时 30 分钟,才能得出为 YAML 触发器指定的所需 UTC 时间。
  • 天数和月数指定为通配符,因为此计划没有指定仅在该月的特定日期或特定月份运行。
  • 星期几 - Sun-Thu - 由于时区转换,要在 UTC + 5:30 印度时区的凌晨 3:00 运行生成,我们需要指定在 UTC 时间的前一天开始。 还可以将星期几指定为 0-40,1,2,3,4

在第二个计划 M-F 3:00 AM (UTC - 5) NC 每日生成中,cron 语法为 0 8 * * Mon-Fri

  • 分钟数和小时数 - 0 8 这会映射到 8:00 AM UTC。 由于经典编辑器中的指定时区是 UTC - 5:00,我们需要在所需的生成时间凌晨 3:00 的基础上增加 5 小时,才能得出为 YAML 触发器指定的所需 UTC 时间。
  • 天数和月数指定为通配符,因为此计划没有指定仅在该月的特定日期或特定月份运行。
  • 星期几 - Mon-Fri 由于时区转换不会根据所需的计划跨越一周中的多天,因此这里无需执行任何转换。 还可以将星期几指定为 1-51,2,3,4,5

重要

YAML 计划触发器中的 UTC 时区不考虑夏令时。

提示

如果使用 3 个字母来表示星期几,并且希望跨越多天一直到 Sun(周日),应将 Sun 视为一周中的第一天。例如,对于 EST 午夜的计划(星期四到星期日),cron 语法为 0 5 * * Sun,Thu-Sat

示例:采用不同频率的夜间生成

在此示例中,经典编辑器计划触发器有两个条目,可生成以下生成。

  • 每个星期一 - 星期五凌晨 3:00 UTC,生成符合 mainreleases/* 分支筛选条件的分支

    计划触发器频率 1。

  • 每个星期日凌晨 3:00 UTC,生成 releases/lastversion 分支,即使源或管道未更改

    计划触发器频率 2。

等效的 YAML 计划触发器如下:

schedules:
- cron: '0 3 * * Mon-Fri'
  displayName: M-F 3:00 AM (UTC) daily build
  branches:
    include:
    - main
    - /releases/*
- cron: '0 3 * * Sun'
  displayName: Sunday 3:00 AM (UTC) weekly latest version build
  branches:
    include:
    - /releases/lastversion
  always: true

在第一个计划 M-F 3:00 AM (UTC) 每日生成中,cron 语法为 0 3 * * Mon-Fri

  • 分钟数和小时数 - 0 3 这会映射到 3:00 AM UTC。 由于经典编辑器中的指定时区为 UTC,因此无需执行任何时区转换。
  • 天数和月数指定为通配符,因为此计划没有指定仅在该月的特定日期或特定月份运行。
  • 星期几 - Mon-Fri 由于没有时区转换,因此星期几将直接从经典编辑器计划映射。 还可以将星期几指定为 1,2,3,4,5

在第二个计划星期日凌晨 3:00 (UTC) 每周最新版本生成中,cron 语法为 0 3 * * Sun

  • 分钟数和小时数 - 0 3 这会映射到 3:00 AM UTC。 由于经典编辑器中的指定时区为 UTC,因此无需执行任何时区转换。
  • 天数和月数指定为通配符,因为此计划没有指定仅在该月的特定日期或特定月份运行。
  • 星期几 - Sun 由于时区转换不会根据所需的计划跨越一周中的多天,因此这里无需执行任何转换。 还可以将星期几指定为 0
  • 我们还要指定 always: true,因为无论源代码是否已更新,都会计划运行此生成。

常见问题

我希望管道仅按计划运行,而不是在有人将更改推送到分支时运行

如果希望管道仅按计划运行,而不是在有人将更改推送到分支或将更改合并到主分支时运行,则必须显式禁用管道上的默认 CI 和 PR 触发器。

要禁用默认 CI 和 PR 触发器,请将以下语句添加到 YAML 管道,并验证是否尚未使用 UI 触发器重写 YAML 管道触发器

trigger: none
pr: none

有关详细信息,请参阅 pr 定义触发器定义

我在 YAML 文件中定义了一个计划。 但它没有运行。 发生了什么情况?

  • 检查 Azure Pipelines 为管道计划的接下来几个运行。 可以通过在管道中选择计划运行操作来查找这些运行。 列表经过筛选后,只显示未来几天内即将执行的几个运行。 如果这不符合你的预期,可能是你键入 cron 计划时出错,或者你没有在正确的分支中定义计划。 请阅读上述主题,了解如何配置计划。 重新评估 cron 语法。 cron 计划的所有时间都是 UTC 时间。

  • 对 YAML 文件进行少量更改,并将该更新推送到存储库中。 如果此前从 YAML 文件读取计划时出现问题,现在应修复此问题。

  • 如果在 UI 中定义了任何计划,则不会遵循 YAML 计划。 通过导航到管道的编辑器,然后选择触发器,确保没有任何 UI 计划。

  • 可以为管道计划的运行数存在限制。 详细了解限制

  • 如果代码没有更改,Azure Pipelines 可能无法启动新的运行。 了解如何重写此行为。

我的 YAML 计划正常运行。 但是,它们现在停止工作了。 如何调试这个问题?

  • 如果未指定 always:true,除非代码有任何更新,否则不会计划管道。 检查是否有任何代码更改,并看看配置计划的方式。

  • 可以计划管道的次数存在限制。 检查是否超出了这些限制。

  • 检查是否有人在 UI 中启用了更多计划。 打开管道的编辑器,然后选择触发器。 如果他们在 UI 中定义了计划,则不会遵循 YAML 计划。

  • 检查管道是否已暂停或已禁用。 为管道选择设置

  • 检查 Azure Pipelines 为管道计划的接下来几个运行。 可以通过在管道中选择计划运行操作来查找这些运行。 如果看不到预期的计划,请对 YAML 文件进行少量更改,并将更新推送到存储库。 此操作应该会重新同步计划。

  • 如果你使用 GitHub 来存储代码,Azure Pipelines 在尝试启动新运行时可能会被 GitHub 施加限制。 检查是否可以手动启动新运行。

我的代码未更改,但计划生成已触发。 为什么?

  • 你可能已启用即使在没有代码更改的情况下仍始终运行计划生成的选项。 如果使用 YAML 文件,请验证 YAML 文件中计划的语法。 如果使用经典管道,请验证是否在计划触发器中选中了此选项。

  • 你可能已更新生成管道或管道的某个属性。 即使还没有更新源代码,这也会导致计划新运行。 使用经典编辑器验证管道中更改的历史记录

  • 你可能已更新用于连接到存储库的服务连接。 即使还没有更新源代码,这也会导致计划新运行。

  • Azure Pipelines 首先检查代码是否有任何更新。 如果 Azure Pipelines 无法访问存储库或获取此信息,它将创建信息性运行。 这是一个虚拟生成,可让你知道 Azure Pipelines 无法访问存储库。

  • 你的管道可能没有完全成功的生成。 为了确定是否计划新生成,Azure DevOps 会查找最后一个完全成功的计划生成。 如果找不到,就会触发新的计划生成。 部分成功的计划生成不被视为成功,因此,如果管道只有部分成功的生成,即使代码未更改,Azure DevOps 也会触发计划生成。

我在“计划运行”面板中看到了计划运行。 然而,它并没有在那个时间运行。 为什么?

  • 计划运行面板显示了所有可能的计划。 但是,除非你对代码进行了真正的更新,否则它可能不会实际运行。 要强制计划始终运行,请确保已在 YAML 管道中设置始终属性,或已选中始终在经典管道中运行的选项。

YAML 管道中定义的计划适用于一个分支,但对另一个分支无效。 如何修复此问题?

计划是在 YAML 文件中定义的,这些文件与分支相关联。 如果需要为特定分支(例如 features/X)计划管道,请确保该分支中的 YAML 文件具有在其中定义的 cron 计划,并且具有该计划的正确分支包含项。 在本示例中,features/X 分支中的 YAML 文件应具有以下 schedule

schedules: 
- cron: '0 12 * * 0'   # replace with your schedule
  branches: 
    include: 
    - features/X  

有关详细信息,请参阅计划触发器的分支注意事项