From c1a5f52004556d5cbf2fee01f611f5fed824a8c1 Mon Sep 17 00:00:00 2001 From: xiaoxia Date: Thu, 23 Jul 2026 18:46:11 +0800 Subject: [PATCH] =?UTF-8?q?fix(ci):=20=E4=BF=AE=E5=A4=8Dintegration-tests?= =?UTF-8?q?=20needs=E4=BE=9D=E8=B5=96=20+=20push=E4=BA=8B=E4=BB=B6auto-fix?= =?UTF-8?q?=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitea/workflows/ci-pipeline.yml | 4 +- scripts/ci/auto_fix_formatting.py | 144 +++++++++++++++++++++--------- 2 files changed, 106 insertions(+), 42 deletions(-) diff --git a/.gitea/workflows/ci-pipeline.yml b/.gitea/workflows/ci-pipeline.yml index baec97761..db1da1ead 100755 --- a/.gitea/workflows/ci-pipeline.yml +++ b/.gitea/workflows/ci-pipeline.yml @@ -395,7 +395,9 @@ jobs: if: always() && needs.check-frontend-only.outputs.skip_backend != 'true' needs: - check-frontend-only - - validate + - validate-code-quality + - validate-type-check + - validate-migration env: DATABASE_URL: postgresql+psycopg://postgres:postgres@host.docker.internal:5432/xiaoxia_saas USE_IN_MEMORY_DB: 'false' diff --git a/scripts/ci/auto_fix_formatting.py b/scripts/ci/auto_fix_formatting.py index 4edd97f1c..f4e493e3d 100755 --- a/scripts/ci/auto_fix_formatting.py +++ b/scripts/ci/auto_fix_formatting.py @@ -1,8 +1,9 @@ #!/usr/bin/env python3 -"""CI中自动修复代码格式(Python: black + isort | Frontend: prettier),并推送回PR分支。 +"""CI中自动修复代码格式(Python: black + isort | Frontend: prettier),并推送回原分支。 -只在PR事件中执行,避免直接修改主干。 -当code quality检查因格式问题失败时触发,自动修复后push回原分支。 +- PR事件:自动修复并push回PR源分支(Agent提交的PR自动修,人提交的仅诊断) +- Push事件(develop/main):自动修复并push回原分支,保持主干格式永远正确 +当code quality检查因格式问题失败时触发。 """ import json @@ -74,6 +75,45 @@ def ensure_git_repo(api_url, repo, token, pr_number): return head_branch +def ensure_git_repo_for_push(api_url, repo, token, branch_name): + """push事件下确保git仓库可用,并切换到目标分支。 + + checkout脚本用tarball方式下载代码,没有.git目录。 + 这里自动初始化git仓库,fetch目标分支并checkout。 + """ + if os.path.exists(".git"): + # 已有git,确认在正确分支 + result = run("git rev-parse --abbrev-ref HEAD", check=False) + if result.stdout.strip() == branch_name: + return + # 不在目标分支,切换 + run(f"git checkout {branch_name}", check=False) + return + + print(f"检测到tarball checkout(无.git目录),初始化git仓库(push模式,分支: {branch_name})...") + + server_url = api_url.rsplit("/api/v1", 1)[0] + remote_url = f"{server_url.replace('https://', f'https://x-access-token:{token}@')}/{repo}.git" + + run("git init -q") + run(f"git remote add origin {remote_url}") + run('git config user.name "CI Bot"') + run('git config user.email "ci-bot@xiaoxiajianji.com"') + + print(f"fetch {branch_name} 分支...") + run(f"git fetch --depth=1 origin {branch_name}") + + print(f"切换到 {branch_name} 分支...") + run(f"git checkout -f -B {branch_name} FETCH_HEAD") + + result = run("git status --porcelain") + if result.stdout.strip(): + n = len(result.stdout.strip().splitlines()) + print(f"⚠️ 工作区有 {n} 个未追踪文件") + else: + print("✅ git仓库就绪,工作区clean") + + def get_changed_files(pr_number, api_url, token): """获取PR中变更的文件列表""" url = f"{api_url}/pulls/{pr_number}/files?limit=100" @@ -155,43 +195,11 @@ def fix_frontend(target_fe_files, scan_mode, repo_root): def main(): - # 只在PR事件中执行 event_name = os.environ.get("GITHUB_EVENT_NAME", "") - if event_name != "pull_request": - print("非PR事件,跳过自动修复") - return - github_ref = os.environ.get("GITHUB_REF", "") - pr_number = github_ref.split("/")[2] if github_ref.startswith("refs/pull/") else "" - if not pr_number: - print("无法获取PR号,跳过自动修复") - return - api_url = os.environ.get("GITHUB_API_URL", "") repo = os.environ.get("GITHUB_REPOSITORY", "") token = os.environ.get("REVIEW_TOKEN", "") or os.environ.get("GITHUB_TOKEN", "") - - # 获取PR作者信息,判断是人还是Agent提交的 - pr_info_url = f"{api_url}/repos/{repo}/pulls/{pr_number}" - req_pr = urllib.request.Request(pr_info_url, headers={"Authorization": f"token {token}"}) - with urllib.request.urlopen(req_pr) as resp: - pr_info = json.loads(resp.read()) - pr_author = pr_info.get("user", {}).get("login", "") - print(f"PR作者: {pr_author}") - - # 判断是否为Agent提交的PR - # Agent账号:actions, auto-approve-bot 等bot用户 - # 人提交的PR(如xiaoxia):只诊断不自动修 - agent_authors = {"actions", "auto-approve-bot", "gitea-actions"} - is_agent_pr = pr_author in agent_authors or "bot" in pr_author.lower() - - if is_agent_pr: - print(f"检测到Agent提交的PR(作者: {pr_author}),将自动修复并推送") - fix_mode = "auto_fix_and_push" - else: - print(f"检测到人提交的PR(作者: {pr_author}),仅诊断不自动修改") - print("(如需自动修复,请用Agent账号提交PR,或手动运行格式化脚本)") - fix_mode = "diagnose_only" scan_mode = os.environ.get("SCAN_MODE", "full") changed_files_env = os.environ.get("CHANGED_FILES", "") @@ -201,13 +209,67 @@ def main(): repo_root = os.getcwd() - # 确保git仓库可用(tarball checkout模式下自动初始化) - # 返回PR源分支名,供后续推送使用 - head_branch = ensure_git_repo(api_url, repo, token, pr_number) + # ====== Push事件处理(develop/main等受保护分支) ====== + if event_name == "push": + # 从 refs/heads/xxx 提取分支名 + if not github_ref.startswith("refs/heads/"): + print(f"push事件但refs格式异常: {github_ref},跳过") + return + branch_name = github_ref.replace("refs/heads/", "") - print("=== 检测到代码格式问题,尝试自动修复 ===") - print(f"PR #{pr_number}") - print(f"扫描模式: {scan_mode}") + # 只在受保护分支(develop/main)上自动修复并推送 + protected_branches = {"develop", "main", "master"} + if branch_name not in protected_branches: + print(f"push事件,分支 {branch_name} 不是受保护分支,跳过自动修复") + return + + print("=== Push事件:检测到格式问题,自动修复并推送回原分支 ===") + print(f"分支: {branch_name}") + print(f"扫描模式: {scan_mode}") + + # 初始化git仓库 + ensure_git_repo_for_push(api_url, repo, token, branch_name) + head_branch = branch_name + fix_mode = "auto_fix_and_push" + + # ====== PR事件处理 ====== + elif event_name == "pull_request": + pr_number = github_ref.split("/")[2] if github_ref.startswith("refs/pull/") else "" + if not pr_number: + print("无法获取PR号,跳过自动修复") + return + + # 获取PR作者信息,判断是人还是Agent提交的 + pr_info_url = f"{api_url}/repos/{repo}/pulls/{pr_number}" + req_pr = urllib.request.Request(pr_info_url, headers={"Authorization": f"token {token}"}) + with urllib.request.urlopen(req_pr) as resp: + pr_info = json.loads(resp.read()) + pr_author = pr_info.get("user", {}).get("login", "") + print(f"PR作者: {pr_author}") + + # 判断是否为Agent提交的PR + agent_authors = {"actions", "auto-approve-bot", "gitea-actions"} + is_agent_pr = pr_author in agent_authors or "bot" in pr_author.lower() + + if is_agent_pr: + print(f"检测到Agent提交的PR(作者: {pr_author}),将自动修复并推送") + fix_mode = "auto_fix_and_push" + else: + print(f"检测到人提交的PR(作者: {pr_author}),仅诊断不自动修改") + print("(如需自动修复,请用Agent账号提交PR,或手动运行格式化脚本)") + fix_mode = "diagnose_only" + + print("=== 检测到代码格式问题,尝试自动修复 ===") + print(f"PR #{pr_number}") + print(f"扫描模式: {scan_mode}") + + # 确保git仓库可用(tarball checkout模式下自动初始化) + head_branch = ensure_git_repo(api_url, repo, token, pr_number) + + # ====== 其他事件跳过 ====== + else: + print(f"事件 {event_name} 不支持自动修复,跳过") + return # 前端文件扩展名 fe_extensions = ( -- 2.54.0