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
21 changes: 15 additions & 6 deletions src/db/repositories.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4119,12 +4119,21 @@ export async function getLatestPublishedAiReview(
};
}

/** Count distinct PR head SHAs that already received a published AI review — used by `review.auto_review.auto_pause_after_reviewed_commits`. (#2042) */
export async function countPublishedAiReviewHeads(env: Env, repoFullName: string, pullNumber: number): Promise<number> {
const row = await env.DB.prepare(
"SELECT COUNT(DISTINCT head_sha) AS cnt FROM ai_review_cache WHERE repo_full_name = ? AND pull_number = ? AND published_at IS NOT NULL",
)
.bind(repoFullName, pullNumber)
/** Count distinct prior PR head SHAs that already received a published AI review — used by `review.auto_review.auto_pause_after_reviewed_commits`. (#2042) */
export async function countPublishedAiReviewHeads(
env: Env,
repoFullName: string,
pullNumber: number,
currentHeadSha?: string | null | undefined,
): Promise<number> {
const currentHeadClause = currentHeadSha ? " AND head_sha != ?" : "";
const row = await env.DB
.prepare(
`SELECT COUNT(DISTINCT head_sha) AS cnt FROM ai_review_cache WHERE repo_full_name = ? AND pull_number = ? AND published_at IS NOT NULL${currentHeadClause}`,
)
.bind(
...(currentHeadSha ? [repoFullName, pullNumber, currentHeadSha] : [repoFullName, pullNumber]),
)
.first<{ cnt: number }>();
/* v8 ignore next -- SQL aggregate count always returns one row; fallback protects D1 driver anomalies. */
return row?.cnt ?? 0;
Expand Down
2 changes: 1 addition & 1 deletion src/queue/processors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6352,7 +6352,7 @@ export async function resolveAutoReviewSkipForPullRequest(
if (args.authorBlacklisted || args.isFrozenForManualReview) {
return { skipReason: null, reviewManifest };
}
const reviewedCommitCount = await countPublishedAiReviewHeads(env, args.repoFullName, args.pr.number).catch(() => 0);
const reviewedCommitCount = await countPublishedAiReviewHeads(env, args.repoFullName, args.pr.number, args.headSha).catch(() => 0);
const skipReason = resolvePullRequestAutoReviewSkipReason({
forceAiReview: args.forceAiReview,
manifest: reviewManifest,
Expand Down
11 changes: 11 additions & 0 deletions test/unit/ai-review-cache.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -485,6 +485,17 @@ describe("AI review cache (#1)", () => {
expect(await countPublishedAiReviewHeads(env, "o/r", 61)).toBe(2);
});

it("excludes the current published head from the pause threshold (regression for cached blocker suppression)", async () => {
const env = createTestEnv();
await putCachedAiReview(env, "o/r", 63, "sha1", "block", { notes: "first", reviewerCount: 1 });
await markAiReviewPublished(env, "o/r", 63, "sha1");
await putCachedAiReview(env, "o/r", 63, "sha2", "block", { notes: "current", reviewerCount: 1 });
await markAiReviewPublished(env, "o/r", 63, "sha2");

expect(await countPublishedAiReviewHeads(env, "o/r", 63, "sha2")).toBe(1);
expect(await countPublishedAiReviewHeads(env, "o/r", 63, null)).toBe(2);
});

it("returns 0 when the count query yields no row (fail-safe)", async () => {
const env = createTestEnv();
const prepareSpy = vi.spyOn(env.DB, "prepare").mockReturnValue({
Expand Down
2 changes: 1 addition & 1 deletion test/unit/auto-review-wiring.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -352,7 +352,7 @@ describe("review.auto_review wiring (#1954)", () => {
headSha: "sha5",
}),
).resolves.toEqual({ skipReason: "review paused (commit threshold)", reviewManifest: manifest });
expect(countSpy).toHaveBeenCalledWith(expect.anything(), "acme/widgets", 5);
expect(countSpy).toHaveBeenCalledWith(expect.anything(), "acme/widgets", 5, "sha5");
expect(auditSpy).toHaveBeenCalledWith(
expect.anything(),
expect.objectContaining({ detail: "review paused (commit threshold)" }),
Expand Down
Loading