fix(ci): 修复auto-merge checkout缓存损坏 + 清理老合并脚本 #484

Merged
auto-approve-bot merged 3 commits from fix/auto-merge-checkout-and-legacy-cleanup into develop 2026-07-17 20:22:43 +08:00
3 changed files with 8 additions and 110 deletions
+4 -1
View File
@@ -12,7 +12,10 @@ jobs:
timeout-minutes: 20
steps:
- name: Checkout code
uses: actions/checkout@v3
shell: sh
env:
GITHUB_TOKEN: ${{ github.token }}
run: "set -eu\npython3 - <<'PY'\nimport io, os, tarfile, time, urllib.request, urllib.error\nurl = f\"{os.environ['GITHUB_API_URL']}/repos/{os.environ['GITHUB_REPOSITORY']}/archive/{os.environ['GITHUB_SHA']}.tar.gz\"\nrequest = urllib.request.Request(url, headers={\"Authorization\": f\"token {os.environ['GITHUB_TOKEN']}\"})\nlast_err = None\nfor attempt in range(5):\n try:\n with urllib.request.urlopen(request, timeout=120) as response:\n archive = response.read()\n break\n except urllib.error.HTTPError as e:\n last_err = e\n if e.code >= 500 and attempt < 4:\n wait = 2 ** attempt\n print(f\"Checkout HTTP {e.code}, retrying in {wait}s (attempt {attempt+1}/5)...\")\n time.sleep(wait)\n continue\n raise\n except Exception as e:\n last_err = e\n if attempt < 4:\n wait = 2 ** attempt\n print(f\"Checkout error: {e}, retrying in {wait}s (attempt {attempt+1}/5)...\")\n time.sleep(wait)\n continue\n raise\nelse:\n raise last_err\nwith tarfile.open(fileobj=io.BytesIO(archive), mode='r:gz') as tar:\n root_prefix = tar.getmembers()[0].name.split('/', 1)[0] + '/'\n for member in tar.getmembers():\n name = member.name\n if name == root_prefix[:-1]:\n continue\n if name.startswith(root_prefix):\n member.name = name[len(root_prefix):]\n if member.name:\n tar.extract(member, '.')\nPY\n"
- name: Auto approve when CI passes
shell: bash
+4 -1
View File
@@ -12,7 +12,10 @@ jobs:
timeout-minutes: 30
steps:
- name: Checkout code
uses: actions/checkout@v3
shell: sh
env:
GITHUB_TOKEN: ${{ github.token }}
run: "set -eu\npython3 - <<'PY'\nimport io, os, tarfile, time, urllib.request, urllib.error\nurl = f\"{os.environ['GITHUB_API_URL']}/repos/{os.environ['GITHUB_REPOSITORY']}/archive/{os.environ['GITHUB_SHA']}.tar.gz\"\nrequest = urllib.request.Request(url, headers={\"Authorization\": f\"token {os.environ['GITHUB_TOKEN']}\"})\nlast_err = None\nfor attempt in range(5):\n try:\n with urllib.request.urlopen(request, timeout=120) as response:\n archive = response.read()\n break\n except urllib.error.HTTPError as e:\n last_err = e\n if e.code >= 500 and attempt < 4:\n wait = 2 ** attempt\n print(f\"Checkout HTTP {e.code}, retrying in {wait}s (attempt {attempt+1}/5)...\")\n time.sleep(wait)\n continue\n raise\n except Exception as e:\n last_err = e\n if attempt < 4:\n wait = 2 ** attempt\n print(f\"Checkout error: {e}, retrying in {wait}s (attempt {attempt+1}/5)...\")\n time.sleep(wait)\n continue\n raise\nelse:\n raise last_err\nwith tarfile.open(fileobj=io.BytesIO(archive), mode='r:gz') as tar:\n root_prefix = tar.getmembers()[0].name.split('/', 1)[0] + '/'\n for member in tar.getmembers():\n name = member.name\n if name == root_prefix[:-1]:\n continue\n if name.startswith(root_prefix):\n member.name = name[len(root_prefix):]\n if member.name:\n tar.extract(member, '.')\nPY\n"
- name: Auto merge when CI passes and approved
shell: bash
-108
View File
@@ -1,108 +0,0 @@
#!/bin/bash
# 自动合并通过 CI 检查的 PR
# 用法: ./scripts/auto_merge_prs.sh [target_branch]
#
# 合并前必须验证的 CI 检查项:
# - CI/CD Pipeline / Validate Code Quality And Tests (push)
# - CI/CD Pipeline / Frontend Lint (push)
# 只有两个检查项均为 success 状态才允许合并
GITEA_API="${GITEA_API_URL:-https://git.xiaoxiajianji.com/api/v1}"
TOKEN="${GITEA_API_TOKEN:?Please set GITEA_API_TOKEN environment variable}"
REPO="xiaoxia/xiaoxia-saas"
TARGET_BRANCH="${1:-develop}"
# 必需的 CI 检查项(context 名称前缀匹配,避免 pipeline 名称变化导致匹配失败)
REQUIRED_CHECKS=(
"Validate Code Quality And Tests"
"Frontend Lint"
)
echo "=== Checking open PRs targeting $TARGET_BRANCH ==="
# 获取所有 open PR
PRS=$(curl -s -H "Authorization: token $TOKEN" \
"$GITEA_API/repos/$REPO/pulls?state=open&sort=updated&direction=desc" | python3 -c "
import json, sys
data = json.load(sys.stdin)
for pr in data:
if pr.get('base', {}).get('ref') == '$TARGET_BRANCH':
head_sha = pr.get('head', {}).get('sha', '')
print(f\"{pr['number']}|{pr['title']}|{head_sha}\")
")
if [ -z "$PRS" ]; then
echo "No open PRs found for $TARGET_BRANCH"
exit 0
fi
merge_count=0
skip_count=0
echo "$PRS" | while IFS='|' read -r number title head_sha; do
echo ""
echo "--- PR #$number: $title ---"
echo " Head SHA: $head_sha"
# 获取该 commit 的 combined CI 状态
STATUS_JSON=$(curl -s -H "Authorization: token $TOKEN" \
"$GITEA_API/repos/$REPO/commits/$head_sha/status")
# 检查每个必需的 CI 项是否通过
all_passed=true
failed_checks=""
for check_pattern in "${REQUIRED_CHECKS[@]}"; do
state=$(echo "$STATUS_JSON" | python3 -c "
import json, sys
d = json.load(sys.stdin)
pattern = '$check_pattern'
# 在 statuses 中找到匹配的最新状态
target = None
for s in d.get('statuses', []):
if pattern in s.get('context', ''):
target = s
break # status 接口返回的是每个 context 的最新状态,取第一个匹配即可
if target:
print(target.get('state', 'unknown'))
else:
print('not_found')
")
if [ "$state" = "success" ]; then
echo "$check_pattern: $state"
else
echo "$check_pattern: $state"
all_passed=false
failed_checks="$failed_checks $check_pattern($state)"
fi
done
if [ "$all_passed" != "true" ]; then
echo " ⏭️ Skipping - CI not passed:$failed_checks"
skip_count=$((skip_count + 1))
continue
fi
# CI 全部通过,执行合并
echo " 🚀 All CI checks passed, merging..."
RESULT=$(curl -s -X POST \
-H "Authorization: token $TOKEN" \
-H "Content-Type: application/json" \
"$GITEA_API/repos/$REPO/pulls/$number/merge" \
-d '{"Do": "merge"}')
if echo "$RESULT" | python3 -c "import json,sys; d=json.load(sys.stdin); sys.exit(0 if d.get('merged', False) or 'id' in d else 1)" 2>/dev/null; then
echo " ✅ PR #$number merged successfully"
merge_count=$((merge_count + 1))
else
echo " ❌ PR #$number merge failed"
# 提取错误信息
err_msg=$(echo "$RESULT" | python3 -c "import json,sys; d=json.load(sys.stdin); print(d.get('message', str(d)[:200]))" 2>/dev/null)
echo " Error: $err_msg"
fi
done
echo ""
echo "=== Done ==="
echo "Merged: $merge_count | Skipped: $skip_count"