// CI 侧 commit message 校验:Conventional Commits + feat 须带 Feature-Confirmed trailer。 // 与 lefthook commit-msg 同一套规则的服务端硬补偿——agent 沙箱(如 DSH workspace-write) // 内 lefthook 会静默失效,本脚本保证机器校验层不缺位(dsh-takeover-readiness T2)。 // 环境变量:EVENT_NAME / BEFORE_SHA / BASE_SHA / HEAD_SHA(由 workflow 从 github context 注入) import { execSync } from 'node:child_process'; const git = (cmd) => execSync(`git ${cmd}`, { encoding: 'utf8' }).trim(); const CONVENTIONAL = /^(feat|fix|docs|chore|refactor|ci|perf|style|test|build|revert)(\(.+\))?!?: .+/; const ZERO_SHA = /^0+$/; const { EVENT_NAME, BEFORE_SHA, BASE_SHA, HEAD_SHA } = process.env; let range; if (EVENT_NAME === 'pull_request' && BASE_SHA) { range = `${BASE_SHA}..${HEAD_SHA}`; } else if (BEFORE_SHA && !ZERO_SHA.test(BEFORE_SHA)) { range = `${BEFORE_SHA}..${HEAD_SHA}`; } else { // 新分支首推等场景拿不到 before:与 master 比对兜底,再退化为仅查 HEAD try { git('fetch origin master --quiet'); range = `origin/master..${HEAD_SHA || 'HEAD'}`; } catch { range = `${HEAD_SHA || 'HEAD'} -1`; } } let shas; try { shas = git(`rev-list --no-merges ${range}`).split('\n').filter(Boolean); } catch { // force push 后旧 before 在 clone 里不存在等场景:退化为与 master 比对,再退化为仅查 HEAD try { git('fetch origin master --quiet'); range = `origin/master..${HEAD_SHA || 'HEAD'}`; shas = git(`rev-list --no-merges ${range}`).split('\n').filter(Boolean); } catch { range = 'HEAD -1'; shas = [git('rev-parse HEAD')]; } } console.log(`commit message 校验:范围 ${range},共 ${shas.length} 个 commit`); const errors = []; for (const sha of shas) { const subject = git(`log -1 --format=%s ${sha}`); if (!CONVENTIONAL.test(subject)) { errors.push(`${sha.slice(0, 8)} 首行不符合 Conventional Commits:${subject}`); continue; } if (/^feat/.test(subject)) { const body = git(`log -1 --format=%B ${sha}`); if (!body.includes('Feature-Confirmed: true')) { errors.push(`${sha.slice(0, 8)} feat 提交缺少 "Feature-Confirmed: true" trailer:${subject}`); } } } if (errors.length > 0) { console.error('\n❌ commit message 校验失败:'); for (const e of errors) console.error(` ${e}`); console.error('\n 规则:首行须为 (): ;feat 提交末尾须有 Feature-Confirmed: true'); process.exit(1); } console.log('✅ commit message 校验通过');