如何在外部测试失败时阻止PR合并并获取结果通知
更优实现方案推荐
方案一:基于GitHub Checks API的回调式触发(首选)
这个方案无需创建GitHub App,仅通过GitHub Actions+API回调即可实现,完美解决长时间测试的资源占用问题,同时满足阻止PR合并+结果通知的需求。
核心逻辑
- 分支保护锁死合并条件:给目标分支branchB设置分支保护规则,要求必须通过指定的检查项才能合并。
- Action触发外部任务并标记pending状态:PR创建/同步时,触发GitHub Action,调用外部工具API启动测试任务,同时通过GitHub Checks API创建一个
pending状态的检查项(与分支保护规则要求的名称一致),随后Action直接结束,无需持续运行。 - 外部工具回调更新检查状态:配置外部工具,在测试任务完成后(成功/失败/中断),调用GitHub Checks API更新检查项的状态为
success/failure/cancelled,同时附上测试结果详情。 - 自动通知:GitHub会自动在检查状态变更时,向PR作者、评审人发送通知,无需额外配置。
具体实现步骤
1. 设置分支保护规则
- 进入仓库
Settings > Branches > Branch protection rules,针对branchB创建规则:- 勾选「Require status checks to pass before merging」
- 添加检查项名称(比如
External Long-Running Test),后续Action和外部工具都要使用这个名称。
2. 编写GitHub Action工作流(触发外部任务)
创建.github/workflows/trigger-external-test.yml:
name: Trigger External Long-Running Test on: pull_request: branches: [branchB] types: [opened, synchronize] permissions: checks: write # 赋予操作Checks API的权限 jobs: trigger-test: runs-on: ubuntu-latest steps: - name: Create external test task id: create-task run: | # 调用外部工具API创建测试任务,替换成实际的API地址和参数 TASK_RESPONSE=$(curl -X POST https://your-external-tool/api/tasks \ -H "Authorization: Bearer ${{ secrets.EXTERNAL_TOOL_TOKEN }}" \ -d '{"branchA": "${{ github.head_ref }}", "branchB": "${{ github.base_ref }}", "pr_number": ${{ github.event.number }} }') # 解析出任务ID,假设返回的JSON里有task_id字段 TASK_ID=$(echo $TASK_RESPONSE | jq -r '.task_id') echo "task_id=$TASK_ID" >> $GITHUB_OUTPUT - name: Create pending check run run: | gh api repos/${{ github.repository }}/check-runs \ -X POST \ -f name="External Long-Running Test" \ -f head_sha="${{ github.head_sha }}" \ -f status="pending" \ -f output='{"title":"External Test in Progress","summary":"Long-duration test is running, please wait for completion..."}' env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
3. 配置外部工具的回调逻辑
当外部测试任务完成时,调用GitHub Checks API更新检查状态:
# 替换以下变量为实际值 OWNER="你的仓库所属组织/个人" REPO="仓库名称" CHECK_RUN_NAME="External Long-Running Test" HEAD_SHA="PR头分支的提交SHA" # 可以在创建任务时传给外部工具 TEST_RESULT="success" # 或failure/cancelled TEST_DETAILS="测试通过,耗时3小时20分" # 先查询对应的检查运行ID CHECK_RUN_ID=$(gh api repos/$OWNER/$REPO/check-runs \ -f name=$CHECK_RUN_NAME \ -f head_sha=$HEAD_SHA \ | jq -r '.check_runs[0].id') # 更新检查状态 gh api repos/$OWNER/$REPO/check-runs/$CHECK_RUN_ID \ -X PATCH \ -f status="completed" \ -f conclusion="$TEST_RESULT" \ -f output='{"title":"External Test Completed","summary":"'"$TEST_DETAILS"'"}'
注意:外部工具需要持有具有checks:write权限的GitHub令牌(可以用仓库令牌或个人访问令牌PAT)。
方案优势
- 无需长时间运行GitHub Action,避免资源浪费和超时风险(GitHub Action默认超时6小时,虽可调整但没必要)
- 逻辑清晰,依赖GitHub原生能力,稳定性高
- 无需创建GitHub App,仅需简单的API调用即可实现
方案二:改进版轮询方案(备选)
如果外部工具不支持回调,可以采用定时轮询的方式,但需优化资源占用:
- 初始Action创建外部任务后,将任务ID存储在GitHub Secrets或仓库的临时文件(比如
task-id.txt提交到临时分支) - 创建另一个定时触发的Action(比如每30分钟运行一次),读取任务ID,轮询外部工具的任务状态
- 一旦获取到最终结果,立即更新PR的检查状态,随后停止轮询(可通过删除任务ID标记实现)
这个方案比原始轮询更高效,但仍不如回调方案灵活,仅适用于外部工具无法配置回调的场景。
内容的提问来源于stack exchange,提问作者guilhermecgs
相关产品推荐
相关产品推荐

