Files
Genarrative/scripts/lint-staged-rustfmt.test.ts
T
kdletters 3fc3399032
Project CI / AI game creator shell Rust shard 1/4 (pull_request) Successful in 6m41s
Project CI / AI game creator shell Rust shard 3/4 (pull_request) Successful in 7m8s
Project CI / AI game creator shell Rust shard 2/4 (pull_request) Successful in 7m16s
Project CI / AI game creator shell Rust shard 4/4 (pull_request) Successful in 7m38s
Project CI / AI game creator shell Rust smoke (pull_request) Successful in 2m11s
Project CI / AI game creator shell Rust crates (pull_request) Successful in 3m11s
Project CI / Repository checks (pull_request) Successful in 4m22s
Project CI / Frontend tests (pull_request) Successful in 5m52s
Project CI / Native shell tests (pull_request) Successful in 9m52s
Project CI / Backend tests (pull_request) Successful in 11m3s
Project CI / AI game creator shell web tests (pull_request) Successful in 6m41s
接入 DotCraft Unity 编辑器插件
新增内置 Unity 插件与自包含 Attach helper,固定上游版本并保留许可证
统一 Runner 执行归属、项目身份校验、回执确认和不确定结果阻断
接入 Unity 工程导入、Agent 工具目录及 Windows 构建分发
补齐插件测试、CI 执行入口和 Windows .NET 10 工具链检查
记录真实 Unity 连接、执行、重载恢复及 Runner 边界验证
2026-09-18 19:44:36 +08:00

116 lines
4.3 KiB
TypeScript

import { readFileSync } from 'node:fs';
import { dirname, resolve } from 'node:path';
import { fileURLToPath } from 'node:url';
import { describe, expect, test } from 'vitest';
import {
RUSTFMT_EXCLUDED_WORKSPACES,
RUSTFMT_WORKSPACES,
selectRustfmtWorkspaces,
} from './lint-staged-rustfmt-workspaces.mjs';
const repoRoot = resolve(dirname(fileURLToPath(import.meta.url)), '..');
function selectedManifests(stagedFiles: string[], root = repoRoot) {
return selectRustfmtWorkspaces({
stagedFiles,
repoRoot: root,
}).workspaces.map((workspace) => workspace.manifestPath);
}
describe('lint-staged Rust 格式检查的 workspace 选择', () => {
test('只暂存 server-rs 时不再连带检查 src-tauri', () => {
// 回归判据:`cargo fmt --all` 会连未暂存的在改文件一起查,全量跑两个 workspace
// 会让「只暂存了 server-rs 干净文件」的提交被别人的 src-tauri 改动挡下来。
expect(
selectedManifests([
'server-rs/crates/api-server/src/editor_project.rs',
'server-rs/crates/shared-contracts/src/game_creation_app.rs',
]),
).toEqual(['server-rs/Cargo.toml']);
});
test('只暂存 src-tauri 时不再连带检查 server-rs', () => {
expect(
selectedManifests(['apps/ai-game-creator-shell/src-tauri/src/assets.rs']),
).toEqual(['apps/ai-game-creator-shell/src-tauri/Cargo.toml']);
});
test('多个 workspace 都有暂存文件时分别检查', () => {
expect(
selectedManifests([
'server-rs/crates/api-server/src/editor_project.rs',
'apps/ai-game-creator-shell/src-tauri/src/assets.rs',
'plugins/agc-unity-editor/native/unity-editor-bridge/src/lib.rs',
]),
).toEqual([
'server-rs/Cargo.toml',
'apps/ai-game-creator-shell/src-tauri/Cargo.toml',
'plugins/agc-unity-editor/native/unity-editor-bridge/Cargo.toml',
]);
});
test('手工执行(没有暂存列表)时保持全量检查语义', () => {
const selection = selectRustfmtWorkspaces({ stagedFiles: [], repoRoot });
expect(selection.usedStagedList).toBe(false);
expect(selection.workspaces).toEqual(RUSTFMT_WORKSPACES);
});
test('排除的 workspace 与未登记路径都会被显式报出,不静默通过', () => {
const selection = selectRustfmtWorkspaces({
stagedFiles: [
'apps/desktop-shell/src-tauri/src/host_bridge/mod.rs',
'somewhere-new/src/lib.rs',
],
repoRoot,
});
// desktop-shell 当前整体未过 `cargo fmt --check`,所以它不参与检查……
expect(selection.workspaces).toEqual([]);
// ……但必须被点名,否则「glob 命中了、谁都没查」就是静默通过。
expect(selection.excluded).toEqual([
'apps/desktop-shell/src-tauri/src/host_bridge/mod.rs',
]);
expect(selection.unmanaged).toEqual(['somewhere-new/src/lib.rs']);
});
test('Windows 反斜杠与绝对路径都归一化成仓库相对路径', () => {
const root = 'C:\\repo\\genarrative';
expect(
selectedManifests(
[
'server-rs\\crates\\api-server\\src\\editor_project.rs',
`${root}\\apps\\ai-game-creator-shell\\src-tauri\\src\\assets.rs`,
],
root,
),
).toEqual([
'server-rs/Cargo.toml',
'apps/ai-game-creator-shell/src-tauri/Cargo.toml',
]);
});
test('检查清单与 package.json 的 check:rustfmt 保持同一份 workspace 表', () => {
// 两处各写一份 workspace 列表就会漂移:hook 查的与 `npm run check:rustfmt` 查的必须同集。
const packageJson = JSON.parse(
readFileSync(resolve(repoRoot, 'package.json'), 'utf8'),
) as { scripts: Record<string, string> };
const manifests = Array.from(
packageJson.scripts['check:rustfmt']!.matchAll(
/--manifest-path\s+(\S+)\s+--\s+--check/gu,
),
).map((match) => match[1]!);
expect(manifests).toEqual(
RUSTFMT_WORKSPACES.map((workspace) => workspace.manifestPath),
);
// 排除项必须是「检查清单之外」的,否则这段注释与实际行为不符。
for (const excluded of RUSTFMT_EXCLUDED_WORKSPACES) {
expect(
RUSTFMT_WORKSPACES.some((workspace) =>
workspace.prefix.startsWith(excluded.prefix),
),
).toBe(false);
}
});
});