#!/usr/bin/env python # -*- coding: utf-8 -*- """ 清理 e2e-m0.py 产生的测试数据。 E2E 每跑一次就新建一个租户(编码 e2e######)并给它建角色与账号, 反复跑会把开发库堆满。这个脚本把 e2e* 租户及其关联数据清掉。 用法 ---- python scripts/dev-clean-e2e.py # 只看会删什么(默认 dry-run) python scripts/dev-clean-e2e.py --apply # 真删 ⚠️ 只在开发库上跑,不要对生产执行。 """ from __future__ import annotations import argparse import subprocess import sys if hasattr(sys.stdout, "reconfigure"): sys.stdout.reconfigure(encoding="utf-8") # 子表在前、主表在后(无外键约束,顺序只为可读性与排查方便) STEPS = [ ("角色授权", "sys_role_permission"), ("用户角色", "sys_user_role"), ("登录日志", "sys_login_log"), ("组织", "sys_org"), ("角色", "sys_role"), ("用户", "sys_user"), ] TENANT_FILTER = "tenant_code LIKE 'e2e%'" SUB_FILTER = f"tenant_id IN (SELECT id FROM sys_tenant WHERE {TENANT_FILTER})" class Db: def __init__(self, container: str, user: str, name: str): self.container = container self.user = user self.name = name def scalar_rows(self, sql: str) -> list[str]: cmd = ["docker", "exec", self.container, "psql", "-U", self.user, "-d", self.name, "-v", "ON_ERROR_STOP=1", "-t", "-A", "-F", "|", "-c", sql] r = subprocess.run(cmd, capture_output=True, text=True, encoding="utf-8") if r.returncode != 0: print(r.stderr.strip(), file=sys.stderr) sys.exit(1) return [x for x in r.stdout.split("\n") if x.strip()] def main() -> int: ap = argparse.ArgumentParser() ap.add_argument("--apply", action="store_true", help="真正执行删除(默认只预览)") ap.add_argument("--container", default="xt-pg") ap.add_argument("--user", default="fill") ap.add_argument("--db", default="filldb") args = ap.parse_args() db = Db(args.container, args.user, args.db) tenants = db.scalar_rows( f"SELECT id || '|' || tenant_code || '|' || tenant_name " f"FROM sys_tenant WHERE {TENANT_FILTER} ORDER BY id") if not tenants: print("没有 e2e 测试租户,无需清理") return 0 print(f"找到 {len(tenants)} 个 e2e 测试租户:") for r in tenants[:15]: p = r.split("|") print(" id=%-5s code=%-14s %s" % (p[0], p[1], p[2] if len(p) > 2 else "")) if len(tenants) > 15: print(f" ... 另有 {len(tenants) - 15} 个") if not args.apply: print("\n这是预览。加 --apply 才会真正删除。") return 0 print("\n开始清理:") total = 0 for label, table in STEPS: rows = db.scalar_rows(f"DELETE FROM {table} WHERE {SUB_FILTER} RETURNING id") total += len(rows) print(" %-8s %-20s 删除 %d 行" % (label, table, len(rows))) rows = db.scalar_rows(f"DELETE FROM sys_tenant WHERE {TENANT_FILTER} RETURNING id") total += len(rows) print(" %-8s %-20s 删除 %d 行" % ("租户", "sys_tenant", len(rows))) print(f"\n完成,共删除 {total} 行。") return 0 if __name__ == "__main__": raise SystemExit(main())