1
0

chore: 强化代码质量与风格检查体系

ESLint 升级到 recommended-type-checked + stylistic-type-checked,
引入 perfectionist 导入排序和 import 插件导入验证。

Prettier 显式声明全部格式化参数,消除跨环境差异。
TypeScript 启用 noUnusedLocals 和 noPropertyAccessFromIndexSignature。
完善 ignore 列表,排除 .agents/、bun.lock、data/ 等。
引入 husky + lint-staged(pre-commit)+ commitlint(commit-msg)。
更新 DEVELOPMENT.md 代码质量章节。
修复所有新增规则检测到的类型和风格违规。
This commit is contained in:
2026-05-12 18:44:59 +08:00
parent ce8baae3d1
commit a5cf6065c2
83 changed files with 2654 additions and 1824 deletions

View File

@@ -1,31 +1,11 @@
import { describe, expect, test } from "bun:test";
import { CommandChecker } from "../../../../../src/server/checker/runner/command/runner";
import type { CheckerContext } from "../../../../../src/server/checker/runner/types";
import type { ResolvedCommandTarget } from "../../../../../src/server/checker/types";
const checker = new CommandChecker();
import { CommandChecker } from "../../../../../src/server/checker/runner/command/runner";
function makeTarget(
command: Partial<ResolvedCommandTarget["command"]>,
overrides?: Partial<ResolvedCommandTarget>,
): ResolvedCommandTarget {
return {
type: "command",
name: "test-cmd",
group: "default",
command: {
exec: "echo",
args: ["hello"],
cwd: "/tmp",
env: {},
maxOutputBytes: 1024 * 1024,
...command,
},
intervalMs: 60000,
timeoutMs: 5000,
...overrides,
};
}
const checker = new CommandChecker();
function makeCtx(timeoutMs = 5000): CheckerContext {
const controller = new AbortController();
@@ -33,23 +13,48 @@ function makeCtx(timeoutMs = 5000): CheckerContext {
return { signal: controller.signal };
}
function makeTarget(
command: Partial<ResolvedCommandTarget["command"]>,
overrides?: Partial<ResolvedCommandTarget>,
): ResolvedCommandTarget {
return {
command: {
args: ["hello"],
cwd: "/tmp",
env: {},
exec: "echo",
maxOutputBytes: 1024 * 1024,
...command,
},
group: "default",
intervalMs: 60000,
name: "test-cmd",
timeoutMs: 5000,
type: "command",
...overrides,
};
}
describe("CommandChecker", () => {
test("exitCode=0 成功", async () => {
const result = await checker.execute(makeTarget({ exec: "true", args: [] }), makeCtx());
const result = await checker.execute(makeTarget({ args: [], exec: "true" }), makeCtx());
expect(result.matched).toBe(true);
expect(result.statusDetail).toBe("exitCode=0");
expect(result.failure).toBeNull();
});
test("exitCode=1 不匹配默认 [0]", async () => {
const result = await checker.execute(makeTarget({ exec: "false", args: [] }), makeCtx());
const result = await checker.execute(makeTarget({ args: [], exec: "false" }), makeCtx());
expect(result.matched).toBe(false);
expect(result.statusDetail).toBe("exitCode=1");
expect(result.failure!.phase).toBe("exitCode");
});
test("exitCode=1 匹配自定义 [1]", async () => {
const result = await checker.execute(makeTarget({ exec: "false", args: [] }, { expect: { exitCode: [1] } }), makeCtx());
const result = await checker.execute(
makeTarget({ args: [], exec: "false" }, { expect: { exitCode: [1] } }),
makeCtx(),
);
expect(result.matched).toBe(true);
expect(result.statusDetail).toBe("exitCode=1");
});
@@ -62,54 +67,69 @@ describe("CommandChecker", () => {
});
test("超时返回错误", async () => {
const result = await checker.execute(makeTarget({ exec: "sleep", args: ["10"] }, { timeoutMs: 100 }), makeCtx(100));
const result = await checker.execute(makeTarget({ args: ["10"], exec: "sleep" }, { timeoutMs: 100 }), makeCtx(100));
expect(result.matched).toBe(false);
expect(result.failure!.message).toContain("超时");
});
test("stdout 输出捕获", async () => {
const result = await checker.execute(makeTarget({ exec: "echo", args: ["hello world"] }), makeCtx());
const result = await checker.execute(makeTarget({ args: ["hello world"], exec: "echo" }), makeCtx());
expect(result.matched).toBe(true);
});
test("stdout 匹配 expect", async () => {
const result = await checker.execute(makeTarget({ exec: "echo", args: ["hello"] }, { expect: { stdout: [{ contains: "hello" }] } }), makeCtx());
const result = await checker.execute(
makeTarget({ args: ["hello"], exec: "echo" }, { expect: { stdout: [{ contains: "hello" }] } }),
makeCtx(),
);
expect(result.matched).toBe(true);
});
test("stdout 不匹配 expect", async () => {
const result = await checker.execute(makeTarget({ exec: "echo", args: ["hello"] }, { expect: { stdout: [{ contains: "nonexistent" }] } }), makeCtx());
const result = await checker.execute(
makeTarget({ args: ["hello"], exec: "echo" }, { expect: { stdout: [{ contains: "nonexistent" }] } }),
makeCtx(),
);
expect(result.matched).toBe(false);
expect(result.failure!.phase).toBe("stdout");
});
test("stderr 匹配 expect", async () => {
const result = await checker.execute(makeTarget({ exec: "bash", args: ["-c", "echo error >&2"] }, { expect: { stderr: [{ contains: "error" }] } }), makeCtx());
const result = await checker.execute(
makeTarget({ args: ["-c", "echo error >&2"], exec: "bash" }, { expect: { stderr: [{ contains: "error" }] } }),
makeCtx(),
);
expect(result.matched).toBe(true);
});
test("输出超过 maxOutputBytes", async () => {
const result = await checker.execute(makeTarget({ exec: "bash", args: ["-c", "yes | head -1000"], maxOutputBytes: 10 }), makeCtx());
const result = await checker.execute(
makeTarget({ args: ["-c", "yes | head -1000"], exec: "bash", maxOutputBytes: 10 }),
makeCtx(),
);
expect(result.matched).toBe(false);
expect(result.failure!.message).toContain("超过限制");
});
test("durationMs 非空", async () => {
const result = await checker.execute(makeTarget({ exec: "true", args: [] }), makeCtx());
const result = await checker.execute(makeTarget({ args: [], exec: "true" }), makeCtx());
expect(result.durationMs).not.toBeNull();
expect(result.durationMs!).toBeGreaterThanOrEqual(0);
});
test("不使用 shell通配符不被展开", async () => {
const result = await checker.execute(makeTarget({ exec: "echo", args: ["*"] }, { expect: { stdout: [{ contains: "*" }] } }), makeCtx());
const result = await checker.execute(
makeTarget({ args: ["*"], exec: "echo" }, { expect: { stdout: [{ contains: "*" }] } }),
makeCtx(),
);
expect(result.matched).toBe(true);
});
test("serialize 返回命令摘要和 config JSON", () => {
const target = makeTarget({ exec: "echo", args: ["hello"] });
const target = makeTarget({ args: ["hello"], exec: "echo" });
const s = checker.serialize(target);
expect(s.target).toBe("exec echo hello");
const config = JSON.parse(s.config);
const config = JSON.parse(s.config) as { args: string[]; exec: string };
expect(config.exec).toBe("echo");
expect(config.args).toEqual(["hello"]);
});