iter(g104): 留痕校验回查提交真实性

This commit is contained in:
HIsheR
2026-10-26 13:55:18 +08:00
parent 10eb402c72
commit 8e2175df29
3 changed files with 38 additions and 1 deletions
+29
View File
@@ -1017,6 +1017,18 @@ function cmdCommitLint(args) {
console.log(`commit-lint OK (${type}${scope ? `(${scope})` : ''})`);
}
/*** 提交主题索引:一次 git log 换「短哈希 → 主题」表,供留痕回查,避免逐行起进程 ***/
function commitSubjects() {
const r = spawnSync('git', ['log', '--all', '--pretty=%h|%s'], { cwd: ROOT, encoding: 'utf8' });
if (r.status !== 0) return null; // 非 git 环境(打包分发等)跳过该维度,不让整条门禁失效
const pairs = [];
for (const line of String(r.stdout ?? '').split('\n')) {
const cut = line.indexOf('|');
if (cut > 0) pairs.push([line.slice(0, cut), line.slice(cut + 1)]);
}
return pairs;
}
/*** 迭代留痕校验:.ua/iterations.log 每行 JSON 字段与格式必须符合 ITERATION.md 规范 ***/
function cmdLintIterations() {
const file = path.join(INDEX_DIR, 'iterations.log');
@@ -1041,6 +1053,23 @@ function cmdLintIterations() {
if (o.result === 'aborted' && commit && !/^[0-9a-f]{7,40}$/.test(commit)) issues.push(`${tag} aborted 条目 commit 须为空或哈希`);
if (!String(o.summary ?? '').trim()) issues.push(`${tag} summary 不能为空`);
});
// —— 留痕 ↔ 提交双向核对:哈希必须真实存在,且主题要指向同一条目(防伪造 / 防抄错哈希)——
const pairs = commitSubjects();
if (pairs) {
lines.forEach((line, i) => {
const tag = `iterations.log:${i + 1}`;
let o;
try { o = JSON.parse(line); } catch { return; } // 行格式问题已在上轮报过
const hash = String(o.commit ?? '');
if (!hash) return; // aborted 允许留空
const hit = pairs.find(([h]) => h.startsWith(hash));
if (!hit) { issues.push(`${tag} commit ${hash} 不在仓库历史中`); return; }
const legacy = `iter: ${o.id}`; // 早期提交用「iter: <id> 描述」,无 scope
if (!hit[1].startsWith(`iter(${o.id})`) && !hit[1].startsWith(legacy)) {
issues.push(`${tag} commit ${hash} 的主题「${hit[1]}」没有指向条目 ${o.id}`);
}
});
}
if (issues.length) {
for (const it of issues) console.error('lint-iterations: ' + it);
console.error(`${issues.length} violation(s)`);