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.
 
 
 
 
 

71 lines
3.1 KiB

# -*- 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 ❌')