chore(clean): 测试数据三本账清完(库 / 磁盘 / 七牛桶)+ 100 条问题全部核销
一、dev-clean-e2e.py:加「在用组织保护」后执行
· 先算「仍被存活任务引用的组织」并保留 —— 当前演示态就挂在其中一个
「E2E 24数控1班」上,删了它演示态就坏(保留 3 个,演示态完好:
任务 1449 / 名册 3 人 / 组织 43 都在)
· 已执行 --apply --demo-tasks --orphan-files:
49 个 e2e 租户 + 147 个测试组织 + 84 个【演示·旧】任务,
共 3714 行 / 27 个文件(业务表按 information_schema 动态枚举,不写死清单)
二、dev-clean-qiniu.py(新增):清真实桶里本项目前缀的测试对象
· 只动 xiaotutongxue/ 前缀;默认 dry-run;删前核实库中零引用、
数量异常(>5000)直接停
· 已执行:2036 个对象 / 116 MB 全部删除,删后复验 0 个(F-93「删库不删桶」)
· 签名按官方文档逐字核对 —— 踩了两个 401 才对:旧 QBox 格式(一个换行 +
"QBox " 前缀)不对,是「两个换行 + Qiniu 前缀」;batch 的 Body 必须进
签名串(列举无 Body 能过、批删全 401 —— 同一签名函数一好一坏,线索在 Body)
· 列举在 rsf.qiniuapi.com,不在 rs(打错 host 报「Bad method: list」)
三、xt-minio 容器已删(F-2)—— 代码早已不用 S3,deploy 里也没有它
四、文档核销与记录
· docs/08:F-3/4/7/10(小节)与 F-14/26/29/30/31/38/51/57/64/65/71/72/93
(表格行)全部标「已闭环」;F-5 补执行记录;F-28 备案维持两级(→D-11);
变更记录补两行 —— **F-1~F-100 至此无未决项**,剩余全部等外部输入
· docs/01:新增 E4「国标职业库数据来源待客户确认」(F-34,字典页如实显示 0 项)
· 交接摘要:新增 §一·三十一(17 项决策执行记录)
· AGENTS.md:清理一节写清三个工具与「在用组织保护」
验证:python scripts/verify-all.py --with-e2e →
通过 8 / 失败 0 / 跳过 0(37 个 E2E 脚本 / 1577 条断言 / 0 失败,291s;
prodguard 9/9;test profile 能起)
This commit is contained in:
@@ -117,6 +117,27 @@ def db_file_paths(db: Db) -> set[str]:
|
||||
return known
|
||||
|
||||
|
||||
def orgs_referenced_by_live_tasks(db: Db) -> set[int]:
|
||||
"""
|
||||
仍被**存活任务**引用的组织 id —— 这些组织绝不能删。
|
||||
|
||||
⚠️ 为什么必须有它:当前演示态就挂在其中一个 "E2E 24数控1班" 上
|
||||
(历史原因:演示种子当时用了 E2E 建的班)。删了组织 = 演示态的审核范围、
|
||||
导出目录全部失去归属,而**界面上一句话都不会提示**。
|
||||
引用判断用任务表的 deleted(collect_task_org 没有 deleted 列,不能用它判活)。
|
||||
"""
|
||||
keep: set[int] = set()
|
||||
for r in db.rows(
|
||||
"SELECT DISTINCT cto.org_id FROM collect_task_org cto "
|
||||
"JOIN collect_task t ON t.id = cto.task_id AND t.deleted = 0 "
|
||||
"WHERE cto.org_id IS NOT NULL"):
|
||||
try:
|
||||
keep.add(int(r.split("|")[0]))
|
||||
except ValueError:
|
||||
pass
|
||||
return keep
|
||||
|
||||
|
||||
def scan_orphans(db: Db) -> tuple[list[str], int]:
|
||||
"""磁盘上有、而库里没有任何一行指向的文件。"""
|
||||
known = db_file_paths(db)
|
||||
@@ -155,9 +176,16 @@ def main() -> int:
|
||||
tenants = [] if args.only_orphan_files else db.rows(
|
||||
f"SELECT id || '|' || tenant_code || '|' || tenant_name "
|
||||
f"FROM sys_tenant WHERE {TENANT_FILTER} ORDER BY id")
|
||||
demo_orgs = [] if args.only_orphan_files else db.rows(
|
||||
f"SELECT id || '|' || org_name FROM sys_org "
|
||||
f"WHERE deleted = 0 AND ({DEMO_ORG_FILTER}) ORDER BY id")
|
||||
# 在用组织保护:先算好(任何删除发生之前),删除阶段只动"没被引用的"
|
||||
keep_orgs = orgs_referenced_by_live_tasks(db) if not args.only_orphan_files else set()
|
||||
demo_orgs = [] if args.only_orphan_files else [
|
||||
r for r in db.rows(
|
||||
f"SELECT id || '|' || org_name FROM sys_org "
|
||||
f"WHERE deleted = 0 AND ({DEMO_ORG_FILTER}) ORDER BY id")
|
||||
if int(r.split("|")[0]) not in keep_orgs
|
||||
]
|
||||
kept_note = ("(另有 %d 个测试组织被存活任务引用,**保留**:其中就有当前演示态挂着的班)"
|
||||
% len(keep_orgs)) if keep_orgs else ""
|
||||
demo_tasks = (db.rows(f"SELECT id || '|' || task_name FROM collect_task "
|
||||
f"WHERE deleted = 0 AND {DEMO_TASK_FILTER} ORDER BY id")
|
||||
if (args.demo_tasks and not args.only_orphan_files) else [])
|
||||
@@ -176,7 +204,7 @@ def main() -> int:
|
||||
print(f" ... 另有 {len(tenants) - 15} 个")
|
||||
|
||||
if demo_orgs:
|
||||
print(f"\n② 其它租户下的 e2e 测试组织 {len(demo_orgs)} 个:")
|
||||
print(f"\n② 其它租户下的 e2e 测试组织 {len(demo_orgs)} 个{kept_note}:")
|
||||
for r in demo_orgs[:15]:
|
||||
p = r.split("|")
|
||||
print(" id=%-5s %s" % (p[0], p[1] if len(p) > 1 else ""))
|
||||
@@ -228,9 +256,22 @@ def main() -> int:
|
||||
total += n
|
||||
print(" %-10s %-22s 删除 %d 行" % ("租户", "sys_tenant", n))
|
||||
|
||||
n = len(db.rows(f"DELETE FROM sys_org WHERE {DEMO_ORG_FILTER} RETURNING id"))
|
||||
total += n
|
||||
print(" %-10s %-22s 删除 %d 行" % ("测试组织", "sys_org", n))
|
||||
# 测试组织:按 id 删(keep_orgs 已在预览阶段剔除;这里再校验一次,
|
||||
# 因为上面可能刚删过任务,引用集合应该只减不增 —— 双保险,宁可少删)
|
||||
keep_orgs = orgs_referenced_by_live_tasks(db) if not args.only_orphan_files else set()
|
||||
org_ids = [int(r.split("|")[0]) for r in db.rows(
|
||||
f"SELECT id FROM sys_org WHERE deleted = 0 AND ({DEMO_ORG_FILTER}) ORDER BY id")
|
||||
if int(r.split("|")[0]) not in keep_orgs]
|
||||
if org_ids:
|
||||
# 一次 IN 里塞太多 id 会撑爆语句,分批(144 个一批也行,但分批无成本)
|
||||
for i in range(0, len(org_ids), 200):
|
||||
batch = org_ids[i:i + 200]
|
||||
n = len(db.rows("DELETE FROM sys_org WHERE id IN (%s) RETURNING id"
|
||||
% ",".join(map(str, batch))))
|
||||
total += n
|
||||
print(" %-10s %-22s 删除 %d 行" % ("测试组织", "sys_org", n))
|
||||
else:
|
||||
print(" %-10s %-22s 没有可删的(都在用或已清)" % ("测试组织", "sys_org"))
|
||||
|
||||
if args.demo_tasks:
|
||||
# 先按任务 id 删子表(同样动态枚举"带 task_id 的表")
|
||||
|
||||
Reference in New Issue
Block a user