ccc47e70fa
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Frontend Lint (push) Successful in 1m6s
CI Build & Deploy Pipeline / Build Production API Image (push) Has been skipped
CI Build & Deploy Pipeline / Build Production Web Image (push) Has been skipped
CI Build & Deploy Pipeline / Build Production Worker Image (push) Has been skipped
CI Build & Deploy Pipeline / Deploy Production (push) Has been skipped
CI Build & Deploy Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Validate Code Quality And Tests (push) Successful in 2m54s
CI/CD Pipeline / Unit Tests (push) Successful in 3m45s
CI/CD Pipeline / Integration Tests (push) Successful in 1m34s
CI Build & Deploy Pipeline / Build Staging Web Image (push) Successful in 4m26s
CI Build & Deploy Pipeline / Build Staging API Image (push) Successful in 6m15s
CI Build & Deploy Pipeline / Build Staging Worker Image (push) Successful in 8m20s
CI Build & Deploy Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 1m14s
CI Build & Deploy Pipeline / Staging E2E Tests (push) Successful in 2m15s
CI Build & Deploy Pipeline / Staging API Integration Tests (push) Successful in 3m18s
Co-authored-by: xiaoxia <dev@xiaoxiajianji.com> Co-committed-by: xiaoxia <dev@xiaoxiajianji.com>
168 lines
6.7 KiB
YAML
168 lines
6.7 KiB
YAML
name: Auto Approve CI PRs
|
||
|
||
on:
|
||
pull_request:
|
||
types: [synchronize, opened, ready_for_review]
|
||
|
||
jobs:
|
||
auto-approve:
|
||
name: Auto Approve on CI Green
|
||
runs-on: ci-check
|
||
if: github.event_name == 'pull_request' && !github.event.pull_request.draft
|
||
timeout-minutes: 20
|
||
steps:
|
||
- name: Checkout code
|
||
uses: actions/checkout@v3
|
||
|
||
- name: Auto approve when CI passes
|
||
shell: bash
|
||
env:
|
||
GITHUB_TOKEN: ${{ github.token }}
|
||
REVIEW_TOKEN: ${{ secrets.REVIEW_GITEA_TOKEN }}
|
||
PR_NUMBER: ${{ github.event.pull_request.number }}
|
||
PR_HEAD_SHA: ${{ github.event.pull_request.head.sha }}
|
||
run: |
|
||
set -eu
|
||
|
||
echo "PR #${PR_NUMBER} - 检查CI状态并自动审批"
|
||
|
||
# 检查是否纯前端改动
|
||
API_URL="${GITHUB_API_URL}/repos/${GITHUB_REPOSITORY}/pulls/${PR_NUMBER}/files?limit=300"
|
||
FILES=$(curl -s -H "Authorization: token ${GITHUB_TOKEN}" "$API_URL" | python3 -c "import sys,json; [print(f['filename']) for f in json.load(sys.stdin)]")
|
||
FRONTEND_COUNT=$(echo "$FILES" | grep -c '^apps/web/' || true)
|
||
BACKEND_COUNT=$(echo "$FILES" | grep -cv '^apps/web/' || true)
|
||
TOTAL=$(echo "$FILES" | grep -cv '^$' || true)
|
||
echo "变更文件: ${TOTAL} 个 (前端: ${FRONTEND_COUNT}, 后端/公共: ${BACKEND_COUNT})"
|
||
|
||
if [ "$BACKEND_COUNT" = "0" ] && [ "$FRONTEND_COUNT" -gt "0" ]; then
|
||
SKIP_BACKEND=true
|
||
echo "✅ 纯前端改动,只检查Frontend Lint"
|
||
else
|
||
SKIP_BACKEND=false
|
||
echo "🔧 包含后端/公共变更,检查全部CI"
|
||
fi
|
||
|
||
# 定义需要检查的context
|
||
if [ "$SKIP_BACKEND" = "true" ]; then
|
||
CONTEXTS=("CI/CD Pipeline / Frontend Lint (pull_request)")
|
||
else
|
||
CONTEXTS=(
|
||
"CI/CD Pipeline / Validate Code Quality And Tests (pull_request)"
|
||
"CI/CD Pipeline / Unit Tests (pull_request)"
|
||
"CI/CD Pipeline / Frontend Lint (pull_request)"
|
||
)
|
||
fi
|
||
|
||
echo "需要通过的CI检查: ${#CONTEXTS[@]} 项"
|
||
for ctx in "${CONTEXTS[@]}"; do
|
||
echo " - $ctx"
|
||
done
|
||
echo
|
||
|
||
# 轮询等待,最多20分钟(120次x10秒)
|
||
for attempt in $(seq 1 120); do
|
||
ALL_SUCCESS=true
|
||
ANY_FAILED=false
|
||
ANY_PENDING=false
|
||
|
||
echo "--- 第${attempt}次检查 ($(date '+%H:%M:%S')) ---"
|
||
|
||
# 调用辅助脚本检查每个context状态
|
||
for ctx in "${CONTEXTS[@]}"; do
|
||
STATE=$(python3 scripts/check_ci_status.py "$GITHUB_TOKEN" "$GITHUB_REPOSITORY" "$PR_HEAD_SHA" "$ctx")
|
||
echo " $ctx: $STATE"
|
||
|
||
if [ "$STATE" != "success" ]; then
|
||
ALL_SUCCESS=false
|
||
fi
|
||
if [ "$STATE" = "failure" ] || [ "$STATE" = "error" ]; then
|
||
ANY_FAILED=true
|
||
fi
|
||
if [ "$STATE" = "pending" ] || [ "$STATE" = "null" ]; then
|
||
ANY_PENDING=true
|
||
fi
|
||
done
|
||
|
||
if [ "$ALL_SUCCESS" = "true" ]; then
|
||
echo
|
||
echo "✅ 所有CI检查通过,自动审批 PR #${PR_NUMBER}"
|
||
|
||
# 检查是否已有审批(任何用户的APPROVED都算,避免重复审批)
|
||
EXISTING=$(curl -s -H "Authorization: token ${REVIEW_TOKEN}" \
|
||
"${GITHUB_API_URL}/repos/${GITHUB_REPOSITORY}/pulls/${PR_NUMBER}/reviews" \
|
||
| python3 -c "import sys,json; reviews=json.load(sys.stdin); print('yes' if any(r.get('state')=='APPROVED' for r in reviews) else 'no')")
|
||
|
||
if [ "$EXISTING" = "yes" ]; then
|
||
echo "ℹ️ PR #${PR_NUMBER} 已有审批,跳过"
|
||
exit 0
|
||
fi
|
||
|
||
# 第一步:创建PENDING review(Gitea API需要先创建再提交)
|
||
echo "创建review..."
|
||
REVIEW_CREATE=$(curl -s -X POST \
|
||
-H "Authorization: token ${REVIEW_TOKEN}" \
|
||
-H "Content-Type: application/json" \
|
||
-d '{"event": "PENDING", "body": "CI全绿,自动审批通过。"}' \
|
||
"${GITHUB_API_URL}/repos/${GITHUB_REPOSITORY}/pulls/${PR_NUMBER}/reviews")
|
||
|
||
REVIEW_ID=$(echo "$REVIEW_CREATE" | python3 -c "import sys,json; print(json.load(sys.stdin).get('id',''))")
|
||
REVIEW_STATE=$(echo "$REVIEW_CREATE" | python3 -c "import sys,json; print(json.load(sys.stdin).get('state',''))")
|
||
echo "创建结果: id=$REVIEW_ID state=$REVIEW_STATE"
|
||
|
||
if [ -z "$REVIEW_ID" ]; then
|
||
echo "❌ 创建review失败"
|
||
echo "$REVIEW_CREATE"
|
||
exit 1
|
||
fi
|
||
|
||
# 如果已经是APPROVED就不用再submit了(兼容不同Gitea版本)
|
||
if [ "$REVIEW_STATE" = "APPROVED" ]; then
|
||
echo "✅ 自动审批成功(直接创建为APPROVED)"
|
||
exit 0
|
||
fi
|
||
|
||
# 第二步:submit review为APPROVED
|
||
echo "提交review审批..."
|
||
SUBMIT_CODE=$(curl -s -o /tmp/submit_resp.json -w "%{http_code}" \
|
||
-X POST \
|
||
-H "Authorization: token ${REVIEW_TOKEN}" \
|
||
-H "Content-Type: application/json" \
|
||
-d '{"event": "APPROVED", "body": "CI全绿,自动审批通过。"}' \
|
||
"${GITHUB_API_URL}/repos/${GITHUB_REPOSITORY}/pulls/${PR_NUMBER}/reviews/${REVIEW_ID}")
|
||
|
||
echo "提交API HTTP状态: $SUBMIT_CODE"
|
||
cat /tmp/submit_resp.json 2>/dev/null || true
|
||
echo
|
||
|
||
if [ "$SUBMIT_CODE" = "200" ] || [ "$SUBMIT_CODE" = "201" ]; then
|
||
FINAL_STATE=$(python3 -c "import json; print(json.load(open('/tmp/submit_resp.json')).get('state',''))" 2>/dev/null || echo "?")
|
||
echo "✅ 自动审批成功 (state: $FINAL_STATE)"
|
||
exit 0
|
||
else
|
||
echo "❌ 提交审批失败"
|
||
exit 1
|
||
fi
|
||
fi
|
||
|
||
# 还有CI在跑(pending状态)→ 继续等
|
||
if [ "$ANY_PENDING" = "true" ]; then
|
||
echo "⏳ CI仍在运行中,继续等待(第${attempt}/120次轮询)..."
|
||
sleep 10
|
||
continue
|
||
fi
|
||
|
||
# 所有CI都跑完了但有失败 → 退出
|
||
if [ "$ANY_FAILED" = "true" ]; then
|
||
echo
|
||
echo "❌ CI检查有失败项,不自动审批"
|
||
exit 0
|
||
fi
|
||
|
||
# 其他情况继续等
|
||
sleep 10
|
||
done
|
||
|
||
echo
|
||
echo "⏰ 等待超时(20分钟),CI尚未全部完成"
|
||
exit 0
|