Skip to main content
Skip to content

优化堆叠式 PR 的 CI

了解堆栈的GitHub Actions工作流如何运行、访问工作流中的堆栈元数据以及减少冗余 CI 使用情况。

堆栈中的每个拉取请求都会被评估,就好像它以堆栈的基数为目标,例如 main。 这可以跨每一层保持质量一致,但这也意味着工作流可以针对单个堆栈运行多次。 本文介绍了工作流如何在堆栈中运行,以及如何减少冗余 CI 使用情况。

堆栈中的工作流如何运行

GitHub Actions 工作流会触发,就像堆栈中的每个拉取请求都以该堆栈的基底为目标一样。 配置为在针对main的pull_request事件上运行的工作流会对堆栈中的每个拉取请求运行,而不只是底部的那个,因此无需更改工作流,你的检查即可在整个堆栈中运行。

由于每个拉取请求都会运行一次工作流,因此较大的 PR 堆栈会成倍增加 CI 用量。 但是,可以使用堆栈元数据仅在需要时运行昂贵的作业。

访问堆栈元数据

堆栈元数据可在工作流表达式中通过 github.event.pull_request.stack 获取。 仅当拉取请求属于堆栈时,此属性才存在,因此请确保工作流在读取其任何字段之前先筛选出包含该属性的项。

表达式Description
github.event.pull_request.stack.number堆栈的编号,以存储库为作用域。
github.event.pull_request.stack.size堆栈中的拉取请求总数。
github.event.pull_request.stack.position此拉取请求在堆栈中基于 1 的位置(1 为底部)。
github.event.pull_request.stack.base.ref整个堆栈最终面向的分支,例如 main。
github.event.pull_request.stack.base.sha堆栈基分支的 HEAD SHA。

例如,以下工作流读取堆栈元数据,仅当堆栈以名称开头为 release/ 的分支为目标时,才会运行第二步。

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v6

      - name: Show stack info
        if: github.event.pull_request.stack != null
        run: |
          echo "Stack base ref: ${{ github.event.pull_request.stack.base.ref }}"
          echo "PR ${{ github.event.pull_request.stack.position }} of ${{ github.event.pull_request.stack.size }} in the stack"

      - name: Run only when the stack targets a release branch
        if: github.event.pull_request.stack != null && startsWith(github.event.pull_request.stack.base.ref, 'release/')
        run: echo "This stack targets a release branch"

减少 CI 使用量

由于工作流会针对堆栈中的每个拉取请求运行,因此可以使用 stack 参数仅在重要位置运行昂贵的作业。 两个条件特别有用:

  • 最低未合并拉取请求 — 当前位于剩余堆栈底部的拉取请求,直接以该堆栈的基底为目标。 这是 github.event.pull_request.stack.base.ref 等于 github.event.pull_request.base.ref 的拉取请求。
  • 顶部拉取请求(PR) — 堆栈中最后一个拉取请求(PR),其中包含完整的更改集。 这是 github.event.pull_request.stack.position 等于 github.event.pull_request.stack.size 的拉取请求。
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v6

      - name: Run for the lowest unmerged pull request in the stack
        if: github.event.pull_request.stack != null && github.event.pull_request.stack.base.ref == github.event.pull_request.base.ref
        run: echo "Lowest unmerged pull request in the stack"

      - name: Run for the top pull request in the stack
        if: github.event.pull_request.stack != null && github.event.pull_request.stack.position == github.event.pull_request.stack.size
        run: echo "Top pull request in the stack"

当拉取请求自下而上合并时,最下面的未合并拉取请求会发生变化。 最底部的拉取请求合并后,下一个拉取请求将重新变基,直接以堆栈基部为目标,因此它会在下一次工作流运行中成为新的最低未合并拉取请求。

还可以使用 github.event.pull_request.stack.position == 1 对原始拉取请求进行门控,或使用 position 对任何特定层进行门控。