要“确保两个前置 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
复制
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
复制
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
复制
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
复制
push ──► build.yml ──► 写 status "build/success" ─┐
└-------------------------------┐
push ──► test.yml ──► 写 status "test/success" ──┤
▼
deploy.yml 每次被触发后检查两个 status
若都成功 → 真正执行 deploy;否则直接失败跳过🧪 失败场景示例
复制
| 情况 | build/success | test/success | deploy 实际执行 |
|---|---|---|---|
| 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 页面的小对勾/叉号列表里。
📌 它具体做了什么?
- 目标对象
通过 commit SHA 指定某一次提交。 - 写入内容
- state:必填,只能是
pending、success、failure、error四个值之一。 - context:可选,起到“标签”作用,比如
ci/build、test/unit。同一个 commit 可以有多个不同 context 的状态。 - description / target_url:可选,补充说明和外链。
- 存储位置
数据保存在 GitHub 后端,不可修改,只能追加。页面 UI 只展示每个 context 的最新一条。 - 可见效果
- 在 PR 的 “Checks” 区域会出现对应条目。
- 如果仓库设置了 “Require status checks to pass before merging”,这些状态会被当成门禁,未 success 就无法合并。
🧩 典型调用示例
bash
复制
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
复制
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 读取使用。