b846f04dab
目的:不再用 Werror,改为「推送前 + CI」的显式检查,并且只拦**基线之外的新增**告警, 这样上游新代码的存量不会挡住任何人,本地开发构建也不会因为告警变红。 单一真源(本地与 CI 调同一份实现): - 新增 `scripts/check-rust-warnings.mjs` + `npm run check:rust-warnings`: 用 `cargo check --message-format=json` 收集告警,键 = `路径|符号|lint`(**不含行号**,抗上游行号漂移), 与 `scripts/warning-baseline.json` 比对:新增 → 退出码 1 并逐条打印;存量减少 → 只提示可更新; 更新用 `--profile=<name> --update-baseline`。 - 新增 `scripts/pre-push-rust-warnings.mjs`:读 pre-push 的 ref 行,**只在本次推送触碰 `*.rs`/`Cargo.toml`/`Cargo.lock`** 时才跑(无关推送不受影响);Windows 跑 `agc-windows`+`server-rs`, Linux/macOS 只跑 `server-rs`。 - `.husky/pre-push`:把 ref 行落一份临时文件供两段检查共用,然后调用上面的脚本(原有的 `check:pre-push-master` 保持不变)。 - `.gitea/workflows/project-ci.yml`:新增 `rust-warning-check` job(`runs-on: genarrative-ci`,Linux), 跑 `--profile=server-rs --profile=agc-linux`,复用 Rust lane 的隔离编译缓存,只 `cargo check` 不 build。 - `scripts/warning-baseline.json`:`agc-windows` 14 条(上游 `b04aceb57` 等引入,逐条见 `local://commit-1a86675f4-inventory.md`);`agc-linux` 433 条(从 CI lane 日志抽取去重,**刻意取超集**, 含测试实例产物,首轮 CI 的多余项只显示为「存量减少」不判失败);`server-rs` 0 条。 - 文档:dev 运维「Rust 编译告警门禁」改写为现役口径(目的/命令/基线更新/覆盖分工与缺口/局限), 旧 Werror 段落标注为历史;development-workflow 的门禁句同步改写。 覆盖分工:CI 覆盖 `server-rs` + AGC 壳 **Linux** 档;AGC 壳 **Windows 生产口径**(GTK/ring 无法在 Linux 交叉编译)**只由本地 pre-push 覆盖**。局限:`--no-verify` 可绕过;本机 target 目录污染要先 `cargo clean -p`;CI 不跑 clippy;基线只保证「不新增」。
78 lines
2.9 KiB
JavaScript
78 lines
2.9 KiB
JavaScript
#!/usr/bin/env node
|
||
// pre-push 的 Rust 告警检查入口:只在「本次推送的提交确实碰了 Rust 代码」时才跑,
|
||
// 避免无关推送(纯文档/前端)被编译检查拖慢。
|
||
//
|
||
// 与 CI 共用同一份检查实现:scripts/check-rust-warnings.mjs(单一真源)。
|
||
// 平台差异:Windows 跑 `agc-windows` + `server-rs`;Linux/macOS 只跑 `server-rs`
|
||
// (AGC 壳的 Windows 生产口径只能在 Windows 上编;Linux 档由 CI 的 Rust warning check job 覆盖)。
|
||
//
|
||
// 用法(由 .husky/pre-push 调用,stdin 为 `local_ref local_sha remote_ref remote_sha` 行):
|
||
// node scripts/pre-push-rust-warnings.mjs < changes.txt
|
||
|
||
import { spawnSync } from 'node:child_process';
|
||
import { readFileSync } from 'node:fs';
|
||
import { dirname, resolve } from 'node:path';
|
||
import { fileURLToPath } from 'node:url';
|
||
|
||
const repoRoot = resolve(dirname(fileURLToPath(import.meta.url)), '..');
|
||
const ZERO = /^0+$/u;
|
||
const RUST_RELEVANT = /(\.rs$|Cargo\.toml$|Cargo\.lock$)/u;
|
||
|
||
const stdin = readFileSync(0, 'utf8');
|
||
const pushed = [];
|
||
for (const line of stdin.split('\n')) {
|
||
const [localRef, localSha, remoteRef, remoteSha] = line.trim().split(/\s+/u);
|
||
if (!localRef || !localSha || ZERO.test(localSha)) continue;
|
||
pushed.push({ localRef, localSha, remoteRef, remoteSha });
|
||
}
|
||
|
||
function git(...args) {
|
||
const result = spawnSync('git', args, { cwd: repoRoot, encoding: 'utf8' });
|
||
return result.status === 0 ? (result.stdout ?? '').trim() : '';
|
||
}
|
||
|
||
const changed = new Set();
|
||
for (const { localSha, remoteSha } of pushed) {
|
||
let base = ZERO.test(remoteSha ?? '') ? '' : remoteSha;
|
||
if (!base) {
|
||
// 新分支/首次推送:用与 origin/master 的合并基点作为比较基线;取不到就用该提交的父提交。
|
||
base =
|
||
git('merge-base', 'origin/master', localSha) ||
|
||
git('rev-parse', `${localSha}^`);
|
||
}
|
||
if (!base) continue;
|
||
for (const path of git('diff', '--name-only', `${base}..${localSha}`).split(
|
||
'\n',
|
||
)) {
|
||
if (path) changed.add(path);
|
||
}
|
||
}
|
||
|
||
const relevant = [...changed].filter((path) => RUST_RELEVANT.test(path));
|
||
if (relevant.length === 0) {
|
||
console.log(
|
||
`[rust-warnings] 本次推送未触碰 Rust 代码(${changed.size} 个文件),跳过告警检查。`,
|
||
);
|
||
process.exit(0);
|
||
}
|
||
|
||
const profiles =
|
||
process.platform === 'win32' ? ['agc-windows', 'server-rs'] : ['server-rs'];
|
||
console.log(
|
||
`[rust-warnings] 本次推送触碰 Rust 文件 ${relevant.length} 个,检查 profile: ${profiles.join(', ')}`,
|
||
);
|
||
const args = [
|
||
'scripts/check-rust-warnings.mjs',
|
||
...profiles.map((name) => `--profile=${name}`),
|
||
];
|
||
const result = spawnSync(process.execPath, args, {
|
||
cwd: repoRoot,
|
||
stdio: 'inherit',
|
||
});
|
||
if (result.status !== 0) {
|
||
console.error(
|
||
'[rust-warnings] 推送被拦下:请先处理上面的新增告警(详见 dev 运维文档「Rust 编译告警门禁」)。',
|
||
);
|
||
process.exit(result.status ?? 1);
|
||
}
|