Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion src/github/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -977,6 +977,11 @@ async function createOrUpdateNamedCheckRun(
const legacyNames = check.supersedeLegacyNames ?? [];
if (legacyNames.length === 0 || check.checkRunId) return;
for (const legacyName of legacyNames) {
const legacyConclusion =
legacyName === GITTENSORY_LEGACY_ORB_GATE_CHECK_NAME
? check.conclusion
: "neutral";
if (!legacyConclusion) continue;
try {
const existing = await octokit.request(
"GET /repos/{owner}/{repo}/commits/{ref}/check-runs",
Expand Down Expand Up @@ -1005,7 +1010,7 @@ async function createOrUpdateNamedCheckRun(
check_run_id: legacyRun.id,
name: legacyName,
status: "completed",
conclusion: "neutral",
conclusion: legacyConclusion,
output: outputForCheckRunUpdate({
title: `${LOOPOVER_GATE_CHECK_NAME} superseded this legacy check`,
summary:
Expand Down
6 changes: 2 additions & 4 deletions src/review/check-names.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,8 @@ export const LOOPOVER_GATE_CHECK_NAME = "LoopOver Orb Review Agent";
* finishes. Keep this until self-hosters can no longer be upgrading across that rename boundary. */
export const GITTENSORY_LEGACY_GATE_CHECK_NAME = "Gittensory Gate";
/** Pre-rebrand check-run name ("Gittensory Orb Review Agent"), retired by the LoopOver rebrand's hard
* cutover (#5327 — no dual-emit window). Same NOT-dead-code reasoning as
* {@link GITTENSORY_LEGACY_GATE_CHECK_NAME}: `finalizeLegacyPendingCheckRuns` also supersedes any run still
* pending under THIS name so a self-hoster mid-flight across the rebrand deploy never sees a permanently-
* pending status. */
* cutover (#5327 — no dual-emit window). This was once the active required Gate name, so legacy
* finalization must mirror the renamed Gate's terminal conclusion rather than neutralizing it early. */
export const GITTENSORY_LEGACY_ORB_GATE_CHECK_NAME = "Gittensory Orb Review Agent";
/** Pre-rebrand check-run name ("Gittensory Context"), retired by the LoopOver rebrand's hard cutover
* (#5327). Unlike the two Gate-check legacy names above, this one is NOT fed into
Expand Down
128 changes: 128 additions & 0 deletions test/unit/github-app.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1433,6 +1433,134 @@ describe("GitHub check runs", () => {
);
});

it("does not neutralize the legacy Orb gate name while the renamed gate is still pending", async () => {
const privateKey = await generatePrivateKeyPem();
const patchedIds: number[] = [];
let newCheckBody: { name?: string; status?: string; conclusion?: string } = {};
vi.stubGlobal(
"fetch",
async (input: RequestInfo | URL, init?: RequestInit) => {
const url = input.toString();
const method = init?.method ?? "GET";
if (url.includes("/access_tokens"))
return Response.json({ token: "installation-token" });
if (url.includes("/commits/legacy-orb-pending/check-runs")) {
const checkName = new URL(url).searchParams.get("check_name");
if (checkName === "LoopOver Orb Review Agent")
return Response.json({ total_count: 0, check_runs: [] });
if (checkName === "Gittensory Gate")
return Response.json({ total_count: 0, check_runs: [] });
if (checkName === "Gittensory Orb Review Agent")
return Response.json({
total_count: 1,
check_runs: [
{
id: 421,
name: "Gittensory Orb Review Agent",
status: "in_progress",
},
],
});
}
if (url.includes("/check-runs/421") && method === "PATCH") {
patchedIds.push(421);
return Response.json({ id: 421 });
}
if (url.includes("/check-runs") && method === "POST") {
newCheckBody = JSON.parse(String(init?.body)) as typeof newCheckBody;
return Response.json({ id: 89 }, { status: 201 });
}
return new Response("not found", { status: 404 });
},
);

const result = await createOrUpdatePendingGateCheckRun(
createTestEnv({ GITHUB_APP_PRIVATE_KEY: privateKey }),
123,
"JSONbored/gittensory",
gateAdvisory("legacy-orb-pending"),
);

expect(result).toMatchObject({ kind: "published", id: 89 });
expect(newCheckBody).toMatchObject({
name: "LoopOver Orb Review Agent",
status: "in_progress",
});
expect(newCheckBody).not.toHaveProperty("conclusion");
expect(patchedIds).toEqual([]);
});

it("mirrors a failed renamed gate verdict to the legacy Orb gate name", async () => {
const privateKey = await generatePrivateKeyPem();
let legacyPatchBody: { name?: string; status?: string; conclusion?: string } = {};
vi.stubGlobal(
"fetch",
async (input: RequestInfo | URL, init?: RequestInit) => {
const url = input.toString();
const method = init?.method ?? "GET";
if (url.includes("/access_tokens"))
return Response.json({ token: "installation-token" });
if (url.includes("/commits/legacy-orb-failure/check-runs")) {
const checkName = new URL(url).searchParams.get("check_name");
if (checkName === "LoopOver Orb Review Agent")
return Response.json({ total_count: 0, check_runs: [] });
if (checkName === "Gittensory Gate")
return Response.json({ total_count: 0, check_runs: [] });
if (checkName === "Gittensory Orb Review Agent")
return Response.json({
total_count: 1,
check_runs: [
{
id: 422,
name: "Gittensory Orb Review Agent",
status: "in_progress",
},
],
});
}
if (url.includes("/check-runs/422") && method === "PATCH") {
legacyPatchBody = JSON.parse(String(init?.body)) as typeof legacyPatchBody;
return Response.json({ id: 422 });
}
if (url.includes("/check-runs") && method === "POST")
return Response.json({ id: 90 }, { status: 201 });
return new Response("not found", { status: 404 });
},
);

const result = await createOrUpdateGateCheckRun(
createTestEnv({ GITHUB_APP_PRIVATE_KEY: privateKey }),
123,
"JSONbored/gittensory",
gateAdvisory("legacy-orb-failure"),
{},
{
gate: {
enabled: true,
conclusion: "failure",
title: "LoopOver Orb Review Agent failed",
summary: "A configured hard blocker was found.",
blockers: [
{
code: "duplicate_pr",
severity: "warning",
title: "Duplicate pull request",
detail: "Another pull request already claims this work.",
},
],
warnings: [],
},
},
);

expect(result).toMatchObject({ kind: "published", id: 90 });
expect(legacyPatchBody).toMatchObject({
name: "Gittensory Orb Review Agent",
status: "completed",
conclusion: "failure",
});
});

it("leaves an already-completed legacy Gate check alone while posting the renamed review-agent check", async () => {
const privateKey = await generatePrivateKeyPem();
const calls: string[] = [];
Expand Down