Files
Genarrative/.codex/hooks/pre-submit-compile-check.mjs
T
kdletters 271b153308 统一Rust格式化工具链与构建门禁
固定Rust 1.96.0与rustfmt格式配置

接入本地lint、Codex提交前检查和Jenkins构建门禁

提交server-rs全workspace一次性格式化基线

同步开发运维文档与production-ops防回退检查
2026-07-15 21:06:05 +08:00

148 lines
3.5 KiB
JavaScript

#!/usr/bin/env node
import { spawnSync } from 'node:child_process';
import { readFileSync } from 'node:fs';
import { dirname, resolve } from 'node:path';
import { fileURLToPath } from 'node:url';
const scriptDir = dirname(fileURLToPath(import.meta.url));
const repoRoot = resolve(scriptDir, '..', '..');
const npmCommand = process.platform === 'win32' ? 'cmd' : 'npm';
const hookInput = readHookInput();
if (hookInput && !isGitCommitCommand(extractShellCommand(hookInput))) {
process.exit(0);
}
const validationSteps = [
{
label: 'Rust format check',
command: npmCommand,
args:
process.platform === 'win32'
? ['/d', '/s', '/c', 'npm run check:rustfmt']
: ['run', 'check:rustfmt'],
},
{
label: 'TypeScript typecheck',
command: npmCommand,
args:
process.platform === 'win32'
? ['/d', '/s', '/c', 'npm run typecheck']
: ['run', 'typecheck'],
},
{
label: 'Admin web typecheck',
command: npmCommand,
args:
process.platform === 'win32'
? ['/d', '/s', '/c', 'npm run admin-web:typecheck']
: ['run', 'admin-web:typecheck'],
},
{
label: 'Rust api-server compile check',
command: 'cargo',
args: [
'check',
'-p',
'api-server',
'--manifest-path',
'server-rs/Cargo.toml',
],
},
];
for (const step of validationSteps) {
const result = runStep(step);
if (!result.ok) {
const reason = `[codex-hook] 提交前编译检查失败:${step.label}。请修复编译错误后再提交。`;
console.error(reason);
if (hookInput) {
console.log(JSON.stringify({ decision: 'block', reason }));
process.exit(0);
}
process.exit(result.status ?? 1);
}
}
console.error('[codex-hook] 提交前编译检查通过。');
function runStep(step) {
console.error(`[codex-hook] ${step.label}`);
const result = spawnSync(step.command, step.args, {
cwd: repoRoot,
shell: false,
encoding: 'utf8',
env: {
...process.env,
NO_COLOR: process.env.NO_COLOR ?? '1',
},
});
if (result.stdout) {
process.stderr.write(result.stdout);
}
if (result.stderr) {
process.stderr.write(result.stderr);
}
if (result.error) {
console.error(
`[codex-hook] ${step.label} 启动失败:${result.error.message}`,
);
return { ok: false, status: 1 };
}
if (result.signal) {
console.error(`[codex-hook] ${step.label} 被信号终止:${result.signal}`);
return { ok: false, status: 1 };
}
return {
ok: (result.status ?? 0) === 0,
status: result.status ?? 1,
};
}
function readHookInput() {
try {
const rawInput = readFileSync(0, 'utf8').trim();
if (!rawInput) {
return null;
}
return JSON.parse(rawInput);
} catch {
return null;
}
}
function extractShellCommand(input) {
const candidates = [
input?.tool_input?.command,
input?.toolInput?.command,
input?.tool_args?.command,
input?.toolArgs?.command,
input?.arguments?.command,
input?.params?.command,
input?.command,
];
const command = candidates.find(
(value) => typeof value === 'string' && value.trim().length > 0,
);
if (command) {
return command;
}
const shellCommand =
input?.tool_input?.cmd ?? input?.toolInput?.cmd ?? input?.arguments?.cmd;
if (Array.isArray(shellCommand)) {
return shellCommand.join(' ');
}
return '';
}
function isGitCommitCommand(command) {
return /(^|[;&|]\s*)git(?:\.exe)?\b[\s\S]{0,200}\bcommit\b/iu.test(command);
}