Skip to content
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ const REVIEWABILITY = [{ pr: "acme/widgets#1" }];
const BASE_PREVIEW = {
repoFullName: "acme/widgets",
generatedAt: "2026-07-05T00:00:00.000Z",
currentGateMode: "off" as const,
currentReviewCheckMode: "disabled" as const,
aiReviewConfigured: false,
evaluatedCount: 3,
withFindingsCount: 2,
Expand Down Expand Up @@ -106,7 +106,7 @@ describe("ActivationPreview", () => {
// Reload after activation reports the gate is now on — the button should disappear.
apiFetch.mockResolvedValueOnce({
ok: true,
data: { ...BASE_PREVIEW, currentGateMode: "enabled", recommendedAction: null },
data: { ...BASE_PREVIEW, currentReviewCheckMode: "required", recommendedAction: null },
});

fireEvent.click(activateButton);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ type ActivationSample = {
type ActivationPreviewResponse = {
repoFullName: string;
generatedAt: string;
currentGateMode: "off" | "enabled";
currentReviewCheckMode: "required" | "visible" | "disabled";
aiReviewConfigured: boolean;
evaluatedCount: number;
withFindingsCount: number;
Expand Down Expand Up @@ -140,7 +140,7 @@ export function ActivationPreview({ reviewability }: { reviewability: Array<{ pr
</div>
{preview ? (
<StatusPill status={preview.recommendedAction === null ? "ready" : "info"}>
gate {preview.currentGateMode}
gate {preview.currentReviewCheckMode}
</StatusPill>
) : null}
</div>
Expand Down
1 change: 0 additions & 1 deletion src/api/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2551,7 +2551,6 @@ export function createApp() {
const updated = await upsertRepositorySettings(c.env, { ...current, ...recommendedAdvisoryActivationSettings() });
return c.json({
repoFullName: fullName,
gateCheckMode: updated.gateCheckMode,
reviewCheckMode: updated.reviewCheckMode,
checkRunMode: updated.checkRunMode,
linkedIssueGateMode: updated.linkedIssueGateMode,
Expand Down
10 changes: 5 additions & 5 deletions src/services/maintainer-activation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ export type MaintainerActivationSample = {
export type MaintainerActivationPreview = {
repoFullName: string;
generatedAt: string;
// What's on today, so the UI can show the current state next to the one-click ramp.
/** @deprecated (#4618, tracked for removal in #5373) sourced from the computed read-back
* `RepositorySettings["gateCheckMode"]` -- kept only for API/dashboard back-compat display. */
currentGateMode: RepositorySettings["gateCheckMode"];
// What's on today, so the UI can show the current state next to the one-click ramp. Sourced from
// reviewCheckMode (#2852), the real publish authority -- not the deprecated gateCheckMode read-back
// (#5373), which never carried more information than reviewCheckMode already does.
currentReviewCheckMode: RepositorySettings["reviewCheckMode"];
aiReviewConfigured: boolean;
evaluatedCount: number;
withFindingsCount: number;
Expand Down Expand Up @@ -91,7 +91,7 @@ export function buildMaintainerActivationPreview(args: {
return {
repoFullName: args.repoFullName,
generatedAt: args.generatedAt,
currentGateMode: args.settings.gateCheckMode,
currentReviewCheckMode: args.settings.reviewCheckMode,
aiReviewConfigured: args.settings.aiReviewMode !== "off",
evaluatedCount: samples.length,
withFindingsCount,
Expand Down
12 changes: 6 additions & 6 deletions test/integration/maintainer-activation.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,21 +41,21 @@ describe("maintainer activation routes", () => {

const preview = await app.request(PATH_PREVIEW, { headers }, env);
expect(preview.status).toBe(200);
const previewBody = (await preview.json()) as { repoFullName: string; recommendedAction: string | null; currentGateMode: string; evaluatedCount: number };
expect(previewBody).toMatchObject({ repoFullName: FULL_NAME, recommendedAction: "enable_advisory", currentGateMode: "off", evaluatedCount: 0 });
const previewBody = (await preview.json()) as { repoFullName: string; recommendedAction: string | null; currentReviewCheckMode: string; evaluatedCount: number };
expect(previewBody).toMatchObject({ repoFullName: FULL_NAME, recommendedAction: "enable_advisory", currentReviewCheckMode: "disabled", evaluatedCount: 0 });

const activate = await app.request(PATH_ACTIVATE, { method: "POST", headers, body: "{}" }, env);
expect(activate.status).toBe(200);
expect(await activate.json()).toMatchObject({
repoFullName: FULL_NAME,
gateCheckMode: "enabled",
reviewCheckMode: "required",
linkedIssueGateMode: "advisory",
duplicatePrGateMode: "advisory",
qualityGateMode: "advisory",
});

// The flip persisted, and the preview now reports nothing left to enable.
expect((await getRepositorySettings(env, FULL_NAME)).gateCheckMode).toBe("enabled");
expect((await getRepositorySettings(env, FULL_NAME)).reviewCheckMode).toBe("required");
const afterPreview = await app.request(PATH_PREVIEW, { headers }, env);
expect((await afterPreview.json() as { recommendedAction: string | null }).recommendedAction).toBeNull();
});
Expand Down Expand Up @@ -86,7 +86,7 @@ describe("maintainer activation routes", () => {
const activate = await app.request(PATH_ACTIVATE, { method: "POST", headers, body: "{}" }, env);
expect(activate.status).toBe(403);
expect(await activate.json()).toMatchObject({ error: "insufficient_repo_permission" });
expect((await getRepositorySettings(env, FULL_NAME)).gateCheckMode).toBe("off");
expect((await getRepositorySettings(env, FULL_NAME)).reviewCheckMode).toBe("disabled");
});

it("allows a session with GitHub write permission to activate advisory checks", async () => {
Expand All @@ -98,7 +98,7 @@ describe("maintainer activation routes", () => {
const { token } = await createSessionForGitHubUser(env, { login: "owner", id: 201 });
const response = await app.request(PATH_ACTIVATE, { method: "POST", headers: { cookie: `gittensory_session=${token}`, "content-type": "application/json" }, body: "{}" }, env);
expect(response.status).toBe(200);
expect(await response.json()).toMatchObject({ repoFullName: FULL_NAME, gateCheckMode: "enabled" });
expect(await response.json()).toMatchObject({ repoFullName: FULL_NAME, reviewCheckMode: "required" });
});

it("forbids read-only repo collaborators from writing agent settings", async () => {
Expand Down
20 changes: 10 additions & 10 deletions test/unit/maintainer-activation.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ describe("buildMaintainerActivationPreview", () => {
expect(preview.withFindingsCount).toBe(1);
expect(preview.recommendedAction).toBe("enable_advisory");
expect(preview.aiReviewConfigured).toBe(false);
expect(preview.currentGateMode).toBe("off");
expect(preview.currentReviewCheckMode).toBe("disabled");
expect(preview.findingCodeCounts).toContainEqual({ code: "missing_linked_issue", count: 1 });

const flagged = preview.samples.find((sample) => sample.number === 1)!;
Expand Down Expand Up @@ -116,29 +116,29 @@ describe("buildMaintainerActivationPreview", () => {
const preview = buildMaintainerActivationPreview({
repoFullName: repo.fullName,
repo,
settings: settings({ gateCheckMode: "enabled", reviewCheckMode: "required", aiReviewMode: "advisory" }),
settings: settings({ reviewCheckMode: "required", aiReviewMode: "advisory" }),
pullRequests: [pr(1, { linkedIssues: [] })],
generatedAt: "2026-06-14T00:00:00.000Z",
});
expect(preview.recommendedAction).toBeNull();
expect(preview.aiReviewConfigured).toBe(true);
expect(preview.currentGateMode).toBe("enabled");
expect(preview.currentReviewCheckMode).toBe("required");
expect(preview.summary).toContain("already enabled");
});

it("still recommends activation when gateCheckMode is enabled but reviewCheckMode is disabled (#2852 legacy-yml mismatch)", () => {
// Reachable via .gittensory.yml's independent settings.gateCheckMode/settings.reviewCheckMode keys (or any
// caller that sets one without the other) -- currentGateMode echoes the legacy field for display, but
// recommendedAction/currentlyActive must follow reviewCheckMode, the actual check-run publish authority,
// not the legacy field, since the check genuinely is not publishing in this state.
it("recommendedAction/currentlyActive follow only reviewCheckMode (#2852), regardless of any other settings (#5373)", () => {
// reviewCheckMode is the sole publish authority; the legacy gateCheckMode echo this test used to guard
// against (a maintainer-activation display that could diverge from the real activation decision) was
// removed in #5373 -- currentReviewCheckMode IS reviewCheckMode now, so there is no separate field left
// to drift. Kept as a plain reviewCheckMode invariant check.
const preview = buildMaintainerActivationPreview({
repoFullName: repo.fullName,
repo,
settings: settings({ gateCheckMode: "enabled", reviewCheckMode: "disabled" }),
settings: settings({ reviewCheckMode: "disabled" }),
pullRequests: [pr(1, { linkedIssues: [] })],
generatedAt: "2026-06-14T00:00:00.000Z",
});
expect(preview.currentGateMode).toBe("enabled");
expect(preview.currentReviewCheckMode).toBe("disabled");
expect(preview.recommendedAction).toBe("enable_advisory");
expect(preview.summary).not.toContain("already enabled");
});
Expand Down
Loading