Files
Genarrative/scripts/pre-push-rust-warnings.mjs
T
suzmii b846f04dab chore: 加 Rust 告警的 pre-push + CI 基线感知检查(单一脚本 + 基线)
目的:不再用 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;基线只保证「不新增」。
2026-10-07 19:22:29 +08:00

78 lines
2.9 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/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);
}