You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
72 lines
3.1 KiB
72 lines
3.1 KiB
|
2 days ago
|
# -*- coding: utf-8 -*-
|
||
|
|
r"""票 06 续跑步骤 4:对账 verify(HANDOFF-2026-09-04 §3.4)。
|
||
|
|
- 正则扫 9 个 crm-customer Controller + crm-rule CustomerReminderRuleController
|
||
|
|
的 class @RequestMapping + method @XxxMapping,得 (METHOD, path) 钥匙集(应 57)
|
||
|
|
- 与生成 .bru 的 docs 首行钥匙 `METHOD path` 双向比对,全命中收口(防笔误漏端点)
|
||
|
|
- crm-preference 6 端点不生成副本(源码 tag 挂 A3),不参与本对账
|
||
|
|
"""
|
||
|
|
import io, sys, os, re
|
||
|
|
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
|
||
|
|
|
||
|
|
WS = r'd:\code\crm-backend-matt'
|
||
|
|
CONTROLLERS = [
|
||
|
|
WS + r'\crm-customer\src\main\java\com\crm\customer\controller\%s' % n
|
||
|
|
for n in ('CustomerController.java', 'CustomerWorkspaceController.java',
|
||
|
|
'CustomerOwnershipController.java', 'CustomerDetailController.java',
|
||
|
|
'CustomerContactController.java', 'CustomerFocusController.java',
|
||
|
|
'CustomerTransferController.java', 'CustomerImportController.java',
|
||
|
|
'CustomerPingController.java')
|
||
|
|
] + [WS + r'\crm-rule\src\main\java\com\crm\rule\controller\CustomerReminderRuleController.java']
|
||
|
|
|
||
|
|
DOCS = r'D:\code\crm-api-docs'
|
||
|
|
SCAN_ROOTS = [os.path.join(DOCS, 'A4 客户管理'), os.path.join(DOCS, '客户管理')]
|
||
|
|
|
||
|
|
# ---- 源码钥匙集 ----
|
||
|
|
re_class = re.compile(r'@RequestMapping\(\s*"([^"]+)"')
|
||
|
|
re_method = re.compile(r'@(Get|Post|Put|Delete)Mapping(?:\(\s*(?:"([^"]*)")?[^)]*\))?')
|
||
|
|
src_keys = set()
|
||
|
|
for f in CONTROLLERS:
|
||
|
|
txt = open(f, encoding='utf-8').read()
|
||
|
|
m = re_class.search(txt)
|
||
|
|
base = m.group(1) if m else ''
|
||
|
|
for mm in re_method.finditer(txt):
|
||
|
|
verb = mm.group(1).upper()
|
||
|
|
sub = mm.group(2) or ''
|
||
|
|
path = (base + sub) if not sub.startswith(base) else sub
|
||
|
|
path = re.sub(r'/{2,}', '/', path)
|
||
|
|
src_keys.add(f'{verb} {path}')
|
||
|
|
print(f'source keys: {len(src_keys)} (expect 57)')
|
||
|
|
|
||
|
|
# ---- .bru 钥匙集 ----
|
||
|
|
re_key = re.compile(r'`\s*(GET|POST|PUT|DELETE) (/\S+?)`')
|
||
|
|
bru_keys = {}
|
||
|
|
for root in SCAN_ROOTS:
|
||
|
|
for dp, dn, fn in os.walk(root):
|
||
|
|
for f in fn:
|
||
|
|
if not f.endswith('.bru') or f == 'folder.bru':
|
||
|
|
continue
|
||
|
|
p = os.path.join(dp, f)
|
||
|
|
txt = open(p, encoding='utf-8').read()
|
||
|
|
m = re_key.search(txt)
|
||
|
|
if not m:
|
||
|
|
print(f' !! no key line: {os.path.relpath(p, DOCS)}')
|
||
|
|
continue
|
||
|
|
bru_keys.setdefault(f'{m.group(1)} {m.group(2)}', []).append(os.path.relpath(p, DOCS))
|
||
|
|
print(f'bru keys: {len(bru_keys)} (expect 57)')
|
||
|
|
|
||
|
|
missing = sorted(src_keys - set(bru_keys))
|
||
|
|
extra = sorted(k for k in bru_keys if k not in src_keys)
|
||
|
|
dupes = {k: v for k, v in bru_keys.items() if len(v) > 1}
|
||
|
|
print(f'missing in bru (source has, doc lacks): {len(missing)}')
|
||
|
|
for k in missing:
|
||
|
|
print(' -', k)
|
||
|
|
print(f'extra in bru (doc has, source lacks): {len(extra)}')
|
||
|
|
for k in extra:
|
||
|
|
print(' -', k, '->', bru_keys[k])
|
||
|
|
print(f'duplicate keys: {len(dupes)}')
|
||
|
|
for k, v in dupes.items():
|
||
|
|
print(' -', k, '->', v)
|
||
|
|
|
||
|
|
ok = not missing and not extra and not dupes and len(src_keys) == 57 and len(bru_keys) == 57
|
||
|
|
print('VERIFY:', 'PASS ✅ 全命中收口' if ok else 'FAIL ❌')
|