From e149f0c9e294b58c078a00a953541aa0e34559a9 Mon Sep 17 00:00:00 2001 From: xiaoxia Date: Fri, 17 Jul 2026 19:54:22 +0800 Subject: [PATCH 1/3] =?UTF-8?q?fix(ci):=20auto-approve=20checkout=E6=94=B9?= =?UTF-8?q?=E7=94=A8tar.gz=E6=96=B9=E5=BC=8F=EF=BC=8C=E9=81=BF=E5=85=8D?= =?UTF-8?q?=E7=BC=93=E5=AD=98=E6=8D=9F=E5=9D=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitea/workflows/auto-approve.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.gitea/workflows/auto-approve.yml b/.gitea/workflows/auto-approve.yml index 5400caf0c..16533c602 100644 --- a/.gitea/workflows/auto-approve.yml +++ b/.gitea/workflows/auto-approve.yml @@ -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 -- 2.54.0 From bff13f4c2205ac26b0d793158b33228d89fe24c7 Mon Sep 17 00:00:00 2001 From: xiaoxia Date: Fri, 17 Jul 2026 19:54:22 +0800 Subject: [PATCH 2/3] =?UTF-8?q?fix(ci):=20auto-merge=20checkout=E6=94=B9?= =?UTF-8?q?=E7=94=A8tar.gz=E6=96=B9=E5=BC=8F=EF=BC=8C=E9=81=BF=E5=85=8D?= =?UTF-8?q?=E7=BC=93=E5=AD=98=E6=8D=9F=E5=9D=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitea/workflows/auto-merge.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.gitea/workflows/auto-merge.yml b/.gitea/workflows/auto-merge.yml index d1998dec6..d7214a570 100644 --- a/.gitea/workflows/auto-merge.yml +++ b/.gitea/workflows/auto-merge.yml @@ -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 -- 2.54.0 From 0d743e2511277590f2cef7aa0000ffa8541fe521 Mon Sep 17 00:00:00 2001 From: xiaoxia Date: Fri, 17 Jul 2026 19:54:23 +0800 Subject: [PATCH 3/3] =?UTF-8?q?cleanup(ci):=20=E5=88=A0=E9=99=A4=E8=80=81?= =?UTF-8?q?=E7=9A=84auto=5Fmerge=5Fprs.sh=E8=84=9A=E6=9C=AC=EF=BC=8C?= =?UTF-8?q?=E5=B7=B2=E7=94=B1auto-merge.yml=E5=AE=8C=E5=85=A8=E6=8E=A5?= =?UTF-8?q?=E7=AE=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- scripts/auto_merge_prs.sh | 108 -------------------------------------- 1 file changed, 108 deletions(-) delete mode 100755 scripts/auto_merge_prs.sh diff --git a/scripts/auto_merge_prs.sh b/scripts/auto_merge_prs.sh deleted file mode 100755 index 91253a200..000000000 --- a/scripts/auto_merge_prs.sh +++ /dev/null @@ -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" -- 2.54.0