New Chat
Ctrl
K
Kimi+
Chat History

GitHub Actions 跨workflow文档合并部署

要“确保两个前置 workflow 都成功后才运行下一个 workflow”,GitHub Actions 的 workflow_run 事件本身不能直接声明“必须 A 且 B 都成功”,因为它每次只针对单个前置 workflow 触发。因此需要借助状态缓存 + 条件判断的组合技巧。

✅ 推荐实现步骤(官方可行方案)

场景示例

  • 前置 workflow:build.yml(name: build)
  • 前置 workflow:test.yml(name: test)
  • 后置 workflow:deploy.yml(仅当 build 与 test 均成功时运行)

🔧 步骤 1:让前置 workflows 把“成功标记”写成仓库状态

在每个前置 workflow 的末尾,加一个 job:把当前 workflow 的“成功”写成一个 commit status,以特定 context命名。

示例:build.yml

yaml
Copy
name: build
on:
  push:
    branches: [main]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: echo "build step"

  # 关键:写状态
  mark-success:
    runs-on: ubuntu-latest
    needs: build
    steps:
      - uses: actions/github-script@v7
        with:
          script: |
            await github.rest.repos.createCommitStatus({
              owner: context.repo.owner,
              repo: context.repo.repo,
              sha: context.sha,
              state: 'success',
              context: 'build/success',
              description: 'build passed',
            });

示例:test.yml(同理)

yaml
Copy
name: test
on:
  push:
    branches: [main]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: echo "test step"

  mark-success:
    runs-on: ubuntu-latest
    needs: test
    steps:
      - uses: actions/github-script@v7
        with:
          script: |
            await github.rest.repos.createCommitStatus({
              owner: context.repo.owner,
              repo: context.repo.repo,
              sha: context.sha,
              state: 'success',
              context: 'test/success',
              description: 'test passed',
            });

🔧 步骤 2:后置 workflow 检查两个状态是否都为 success

deploy.yml

yaml
Copy
name: deploy
on:
  workflow_run:
    workflows: [build, test]   # 任何一个完成后都会触发
    types: [completed]
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      # 关键:检查两个状态是否都是 success
      - name: Check both build and test success
        id: check
        uses: actions/github-script@v7
        with:
          script: |
            const { data: statuses } = await github.rest.repos.listCommitStatusesForRef({
              owner: context.repo.owner,
              repo: context.repo.repo,
              ref: context.sha,
            });

            const buildOk = statuses.some(s => s.context === 'build/success' && s.state === 'success');
            const testOk  = statuses.some(s => s.context === 'test/success' && s.state === 'success');

            if (!buildOk || !testOk) {
              core.setFailed('build or test not yet successful, skipping deploy');
              return;
            }
            console.log('✅ both build and test passed, proceeding to deploy');

      - run: echo "🚀 deploying now ..."

✅ 运行流程图

Text
Copy
push ──► build.yml ──► 写 status "build/success" ─┐
                 └-------------------------------┐
push ──► test.yml ──► 写 status "test/success" ──┤
                                               ▼
                     deploy.yml 每次被触发后检查两个 status
                     若都成功 → 真正执行 deploy;否则直接失败跳过

🧪 失败场景示例

Table
Copy
情况build/successtest/successdeploy 实际执行
build 成功, test 成功✅✅✅
build 失败, test 成功❌✅❌
build 成功, test 失败✅❌❌

🔒 额外安全建议

  • 将 deploy.yml 的触发限定在 main 分支,避免 PR 误触。
  • 可结合环境 environment 与 required reviewers 做二次人工确认。

✅ 一句话总结

用 commit status 作为“成功标记”,后置 workflow 每次触发后检查两个标记是否都成功,只有满足条件才真正执行部署步骤。
createCommitStatus 做了什么事情
GitHub createCommitStatus 用途
createCommitStatus 是 GitHub REST API 里的一个接口,用来给某一次 commit 打一条“状态记录”。
通俗地说,就是告诉 GitHub:
“这次提交在某个维度上是成功 / 失败 / 运行中 / 异常”,并把这条结论显示在 PR 或 commit 页面的小对勾/叉号列表里。

📌 它具体做了什么?

  1. 目标对象
    通过 commit SHA 指定某一次提交。
  2. 写入内容
    • state:必填,只能是 pending、success、failure、error 四个值之一
      。
    • context:可选,起到“标签”作用,比如 ci/build、test/unit。同一个 commit 可以有多个不同 context 的状态。
    • description / target_url:可选,补充说明和外链。
  3. 存储位置
    数据保存在 GitHub 后端,不可修改,只能追加。页面 UI 只展示每个 context 的最新一条。
  4. 可见效果
    • 在 PR 的 “Checks” 区域会出现对应条目。
    • 如果仓库设置了 “Require status checks to pass before merging”,这些状态会被当成门禁,未 success 就无法合并
      。

🧩 典型调用示例

bash
Copy
POST /repos/{owner}/{repo}/statuses/{sha}
Authorization: token <GITHUB_TOKEN>
Content-Type: application/json

{
  "state": "success",
  "context": "build/docker",
  "description": "Docker image built successfully",
  "target_url": "https://example.com/logs/123"
}

🎯 在 GitHub Actions 中的用法

官方 JavaScript 封装:
JavaScript
Copy
await github.rest.repos.createCommitStatus({
  owner: context.repo.owner,
  repo: context.repo.repo,
  sha: context.sha,
  state: 'success',
  context: 'my-custom-check',
  description: 'all good',
});

一句话总结
createCommitStatus 就是把“某次提交在某个检查点上是否通过”这条结论永久地贴在 GitHub 上,供 PR 合并门禁、开发者查看或后续 workflow 读取使用。