Compare commits

..

2 Commits

Author SHA1 Message Date
lanrtop
35df41f2b5 probe illegal message for CI gate test
Some checks failed
Push & PR Check / check (push) Failing after 40s
2026-09-11 21:16:04 +09:00
lanrtop
1c3133c1dd ci: 服务端 commit message 校验(Conventional + Feature-Confirmed trailer)
All checks were successful
Push & PR Check / check (push) Successful in 54s
lefthook 在 agent 沙箱(DSH workspace-write)内静默失效的机器层硬补偿,
dsh-takeover-readiness T2。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-09-11 21:16:01 +09:00
2 changed files with 78 additions and 0 deletions

View File

@ -0,0 +1,67 @@
// 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 规则:首行须为 <type>(<scope>): <subject>feat 提交末尾须有 Feature-Confirmed: true');
process.exit(1);
}
console.log('✅ commit message 校验通过');

View File

@ -12,6 +12,8 @@ jobs:
runs-on: windows
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: pnpm/action-setup@v4
with:
@ -23,6 +25,15 @@ jobs:
node-version: '20'
cache: 'pnpm'
# 服务端 commit message 校验lefthook 在 agent 沙箱内会静默失效,此为机器层硬补偿)
- name: Commit message 校验
env:
EVENT_NAME: ${{ github.event_name }}
BEFORE_SHA: ${{ github.event.before }}
BASE_SHA: ${{ github.event.pull_request.base.sha }}
HEAD_SHA: ${{ github.sha }}
run: node .gitea/scripts/check-commit-msg.mjs
- run: pnpm install --frozen-lockfile
- run: pnpm typecheck
- run: pnpm test