snapshot of https://github.com/marmelab/atomic-crm.git (main, 2026-09-18; blobs > 131072B omitted)
Some checks failed
✅ Check / 🔬 ESLint (push) Failing after 21s
✅ Check / 🏷️ Typecheck (push) Failing after 11s
✅ Check / 🔎 Test (push) Failing after 11s
✅ Check / e2e-test (push) Failing after 11s
✅ Check / 🔨 Build (push) Failing after 11s
🚀 Deploy / 🚀 Deploy (doc) (push) Failing after 12s
🚀 Deploy / 🚀 Deploy (demo) (push) Failing after 12s
🚀 Deploy / 🚀 Deploy (supabase) (push) Failing after 18s
Some checks failed
✅ Check / 🔬 ESLint (push) Failing after 21s
✅ Check / 🏷️ Typecheck (push) Failing after 11s
✅ Check / 🔎 Test (push) Failing after 11s
✅ Check / e2e-test (push) Failing after 11s
✅ Check / 🔨 Build (push) Failing after 11s
🚀 Deploy / 🚀 Deploy (doc) (push) Failing after 12s
🚀 Deploy / 🚀 Deploy (demo) (push) Failing after 12s
🚀 Deploy / 🚀 Deploy (supabase) (push) Failing after 18s
This commit is contained in:
90
.claude/hooks/test/block-merger-without-review.test.mjs
Normal file
90
.claude/hooks/test/block-merger-without-review.test.mjs
Normal file
@@ -0,0 +1,90 @@
|
||||
// Tests for block-merger-without-review.mjs — the PreToolUse(Agent) gate that
|
||||
// blocks a per-ticket merger until the quality-reviewer recorded APPROVED (flags
|
||||
// under <sessionDir>/reviews/<TASK>-<role>, written by record-review-verdict.mjs). The
|
||||
// gate exits 2 to block and 0 to allow. Skipped for promotion-only / MIGRATION /
|
||||
// ROLLBACK dispatches and when the ticket id can't be parsed (fail open).
|
||||
|
||||
import { mkdtempSync, mkdirSync, writeFileSync, rmSync } from "node:fs";
|
||||
import { tmpdir } from "node:os";
|
||||
import { dirname, join } from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { spawnSync } from "node:child_process";
|
||||
import { describe, test, expect, beforeAll, afterAll } from "vitest";
|
||||
import { sanitizePath } from "../lib/paths.mjs";
|
||||
|
||||
const HERE = dirname(fileURLToPath(import.meta.url));
|
||||
const HOOK = join(HERE, "..", "block-merger-without-review.mjs");
|
||||
const SS = "ab12cd34";
|
||||
const SESSION_ID = `${SS}-1111-2222-3333-444455556666`;
|
||||
|
||||
let TMP;
|
||||
let APP_DIR;
|
||||
let env;
|
||||
let reviewsDir;
|
||||
|
||||
const run = (prompt, subagentType = "merger") =>
|
||||
spawnSync("node", [HOOK], {
|
||||
input: JSON.stringify({
|
||||
session_id: SESSION_ID,
|
||||
tool_input: { subagent_type: subagentType, prompt },
|
||||
}),
|
||||
env,
|
||||
encoding: "utf8",
|
||||
}).status;
|
||||
|
||||
const approve = (task, role) =>
|
||||
writeFileSync(join(reviewsDir, `${task}-${role}`), "");
|
||||
|
||||
beforeAll(() => {
|
||||
TMP = mkdtempSync(join(tmpdir(), "block-merger-test-"));
|
||||
APP_DIR = join(TMP, "app");
|
||||
const CRM_TMP_ROOT = join(TMP, "scratch");
|
||||
reviewsDir = join(CRM_TMP_ROOT, sanitizePath(APP_DIR), SESSION_ID, "reviews");
|
||||
mkdirSync(reviewsDir, { recursive: true });
|
||||
env = { ...process.env, APP_DIR, CRM_TMP_ROOT };
|
||||
// Neutralise an ambient CHAT_SESSION_DIR: reviewsDir() prefers it over
|
||||
// ctx.sessionDir (managed-launcher path), which would point the verdict flag
|
||||
// away from this test's CRM_TMP_ROOT fixture. See reviews.test.mjs for the
|
||||
// CHAT_SESSION_DIR-present behaviour.
|
||||
delete env.CHAT_SESSION_DIR;
|
||||
});
|
||||
|
||||
afterAll(() => rmSync(TMP, { recursive: true, force: true }));
|
||||
|
||||
describe("block-merger-without-review", () => {
|
||||
test("blocks a per-ticket merger when no reviewer flags exist", () => {
|
||||
expect(
|
||||
run(`ROLE: merger\nTASK_ID: TASK-001\nBRANCH_NAME: ${SS}/TASK-001`),
|
||||
).toBe(2);
|
||||
});
|
||||
|
||||
test("allows the merger once the reviewer approved", () => {
|
||||
approve("TASK-003", "quality-reviewer");
|
||||
expect(
|
||||
run(`ROLE: merger\nTASK_ID: TASK-003\nBRANCH_NAME: ${SS}/TASK-003`),
|
||||
).toBe(0);
|
||||
});
|
||||
|
||||
test("ignores the promotion-only merger (MODE: promote)", () => {
|
||||
expect(run(`ROLE: merger\nMODE: promote\nSESSION_SHORT_ID: ${SS}`)).toBe(0);
|
||||
});
|
||||
|
||||
test("ignores the MIGRATION merger (no per-ticket review)", () => {
|
||||
expect(
|
||||
run(`ROLE: merger\nTASK_ID: MIGRATION\nBRANCH_NAME: ${SS}/simple`),
|
||||
).toBe(0);
|
||||
});
|
||||
|
||||
test("ignores a non-merger dispatch", () => {
|
||||
expect(
|
||||
run(
|
||||
`ROLE: developer\nTASK_ID: TASK-001\nWORKTREE_PATH: /wt`,
|
||||
"developer",
|
||||
),
|
||||
).toBe(0);
|
||||
});
|
||||
|
||||
test("fails open when the ticket id can't be parsed (no TASK_ID line)", () => {
|
||||
expect(run(`ROLE: merger\nBRANCH_NAME: ${SS}/whatever`)).toBe(0);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user