Public: anyone can read this; the crew can change it.

The fast check cannot see a pull's commit messages, so the gate's Why-now rule always fails there #8883

Merged opened this

Check · Review · Land · Live done — Landed and live in production.

Merged

mason/forge:mason/8882-the-fast-check-cannot-see-a-pull-s-commi → main 1 commit fork

  • Merged. mason/8882-the-fast-check-cannot-see-a-pull-s-commi was merged into main as 066d408.

Review

Sign in to review this change.
2 files changed +27 −1
src/checks/merged.ts +18
@@ -22,6 +22,22 @@ export type Merged =
2222 | { ok: true; commit: string; line: string }
2323 | { ok: false; error: string };
2424
25 /** How many of the pull's commits the merge commit carries. */
26 const MESSAGE_CAP = 200;
27
28 /**
29 * The pull's own commit messages, so rules that read `git log base..HEAD`
30 * (the gate's Why-now) still see them in a history cut to the merge commit.
31 * Best effort: a history too shallow to walk yields none.
32 */
33 async function pullMessages(dir: string, baseTip: string, head: string): Promise<string> {
34 const log = await runGit(
35 ["log", "-n", String(MESSAGE_CAP), "--format=%B", `${baseTip}..${head}`],
36 { cwd: dir, env: IDENTITY },
37 );
38 return log.ok ? log.value.trim() : "";
39 }
40
2541 export async function mergeForCheck(
2642 dir: string,
2743 baseBranch: string,
@@ -37,6 +53,7 @@ export async function mergeForCheck(
3753 };
3854 return { ok: false, error: "the pull could not be merged with its base" };
3955 }
56 const pull = await pullMessages(dir, baseTip, head);
4057 const made = await runGit(
4158 [
4259 "commit-tree",
@@ -47,6 +64,7 @@ export async function mergeForCheck(
4764 head,
4865 "-m",
4966 `check of ${head.slice(0, 7)} merged into ${baseBranch}`,
67 ...(pull ? ["-m", pull] : []),
5068 ],
5169 { cwd: dir, env: IDENTITY },
5270 );
test/merged-check.test.ts +9 −1
@@ -55,7 +55,7 @@ describe("mergeForCheck: the pull as it would land on today's base", () => {
5555 const work = join(root, "work");
5656 await git(root, "clone", pullDir, work);
5757 await git(work, "checkout", "-b", "pull");
58 head = await commit(work, "pull.txt", "b\n", "pull change");
58 head = await commit(work, "pull.txt", "b\n", "pull change\n\nWhy now: the owner asked for it today");
5959 await git(work, "checkout", "-b", "clash", forkPoint);
6060 conflicting = await commit(work, "shared.txt", "theirs\n", "clash");
6161 await git(work, "push", "origin", "pull", "clash");
@@ -86,6 +86,14 @@ describe("mergeForCheck: the pull as it would land on today's base", () => {
8686 expect([await refs(pullDir), await refs(baseDir)]).toEqual(before);
8787 });
8888
89 test("the merge commit message carries the pull's own commit messages", async () => {
90 const m = await mergeForCheck(pullDir, "main", baseTip, head);
91 if (!m.ok) throw new Error(m.error);
92 const body = await git(pullDir, "log", "-n1", "--format=%B", m.commit);
93 expect(body).toContain(`check of ${head.slice(0, 7)} merged into main`);
94 expect(body).toMatch(/^Why now: the owner asked for it today$/m);
95 });
96
8997 test("the merge commit lives in the pull's repository, not the base's", async () => {
9098 const m = await mergeForCheck(pullDir, "main", baseTip, head);
9199 if (!m.ok) throw new Error(m.error);

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs