scripts: validate-changelog-frontmatter 增加 --files 提交前自检模式(与 pre-push 门禁同规则,供作者/Agent 与 hl-workflow lint 复用)
changelog-filename-gate / validate (push) Successful in 2s
changelog-filename-gate / validate (push) Successful in 2s
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XYL5S9SsBtkg7aGyFAbrrQ
这个提交包含在:
@@ -447,8 +447,51 @@ export function runFrontmatterValidation(records, root = process.cwd()) {
|
||||
return { checkedCount: documents.length, errors };
|
||||
}
|
||||
|
||||
/**
|
||||
* 提交前自检模式:`--files a.md b.md`(或逗号分隔)按「新增文件」口径校验工作区里的 changelog,
|
||||
* 让作者/Agent 不用先 commit 就能跑到与 pre-push 门禁完全相同的规则(hl-workflow changelog_workflow.py lint 也走这里)。
|
||||
*/
|
||||
export function runFilesValidation(files, root = process.cwd()) {
|
||||
const errors = [];
|
||||
let checkedCount = 0;
|
||||
for (const raw of files) {
|
||||
const absolute = path.resolve(root, raw);
|
||||
const relative = path.relative(root, absolute).split(path.sep).join('/');
|
||||
if (!controlledRootForPath(relative) || !relative.endsWith('.md')) {
|
||||
errors.push(ruleError('E_PATH', relative, '不在受控 changelog 目录内(changelogs/ 或 changelogs-v2/)'));
|
||||
continue;
|
||||
}
|
||||
let text;
|
||||
try {
|
||||
text = readFileSync(absolute, 'utf8');
|
||||
} catch (error) {
|
||||
errors.push(ruleError('E_READ', relative, `无法读取文件: ${error.message}`));
|
||||
continue;
|
||||
}
|
||||
checkedCount += 1;
|
||||
errors.push(...validateV2Document(relative, text, { requireV2: true }));
|
||||
}
|
||||
return { checkedCount, errors };
|
||||
}
|
||||
|
||||
export function main(argv = process.argv.slice(2)) {
|
||||
try {
|
||||
if (argv[0] === '--files') {
|
||||
const files = argv.slice(1).flatMap((item) => item.split(',')).filter(Boolean);
|
||||
if (files.length === 0) {
|
||||
throw new Error('--files 需要至少一个文件路径');
|
||||
}
|
||||
const result = runFilesValidation(files);
|
||||
if (result.errors.length > 0) {
|
||||
for (const error of result.errors) {
|
||||
console.error(`[${error.code}] ${error.path}: ${error.message}`);
|
||||
}
|
||||
console.error(`FAIL: ${result.errors.length} frontmatter error(s) in ${result.checkedCount} changelog file(s).`);
|
||||
return 1;
|
||||
}
|
||||
console.log(`PASS: validated frontmatter for ${result.checkedCount} changelog file(s) (--files).`);
|
||||
return 0;
|
||||
}
|
||||
const options = parseArguments(argv);
|
||||
const records = parseNameStatusZ(diffFromOptions(options));
|
||||
const result = runFrontmatterValidation(records);
|
||||
|
||||
在新工单中引用
屏蔽一个用户