Post failure comment and unassign bot when review times out.
After a Cursor timeout, explain the failure on the PR and remove the bot from requested reviewers. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -29,3 +29,29 @@ export async function deleteProgressComment(input: {
|
|||||||
}): Promise<void> {
|
}): Promise<void> {
|
||||||
await input.gitea.deleteIssueComment(input.owner, input.repo, input.commentId);
|
await input.gitea.deleteIssueComment(input.owner, input.repo, input.commentId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const TIMEOUT_FAILURE_MARKER = "<!-- gitea-pr-review-bot-timeout -->";
|
||||||
|
|
||||||
|
export function buildTimeoutFailureBody(timeoutMs: number): string {
|
||||||
|
const timeoutMinutes = Math.max(1, Math.round(timeoutMs / 60_000));
|
||||||
|
return (
|
||||||
|
`${TIMEOUT_FAILURE_MARKER}\n\n` +
|
||||||
|
`🤖 **PR review failed:** the automated review timed out after ${timeoutMinutes} minute(s). ` +
|
||||||
|
"You can request the bot again as reviewer or review the changes manually."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function postTimeoutFailureComment(input: {
|
||||||
|
gitea: GiteaClient;
|
||||||
|
owner: string;
|
||||||
|
repo: string;
|
||||||
|
prNumber: number;
|
||||||
|
timeoutMs: number;
|
||||||
|
}): Promise<void> {
|
||||||
|
await input.gitea.createIssueComment(
|
||||||
|
input.owner,
|
||||||
|
input.repo,
|
||||||
|
input.prNumber,
|
||||||
|
buildTimeoutFailureBody(input.timeoutMs)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|||||||
@@ -4,7 +4,11 @@ import { runCursorReview } from "../cursor/review-agent.js";
|
|||||||
import { DedupeStore } from "../domain/dedupe-store.js";
|
import { DedupeStore } from "../domain/dedupe-store.js";
|
||||||
import { shouldProcessEvent } from "../domain/should-process-event.js";
|
import { shouldProcessEvent } from "../domain/should-process-event.js";
|
||||||
import { GiteaClient } from "../gitea/client.js";
|
import { GiteaClient } from "../gitea/client.js";
|
||||||
import { deleteProgressComment, postProgressComment } from "../gitea/comments-api.js";
|
import {
|
||||||
|
deleteProgressComment,
|
||||||
|
postProgressComment,
|
||||||
|
postTimeoutFailureComment
|
||||||
|
} from "../gitea/comments-api.js";
|
||||||
import { deletePriorBotReviews, postReview } from "../gitea/review-api.js";
|
import { deletePriorBotReviews, postReview } from "../gitea/review-api.js";
|
||||||
import { removeBotFromReviewers } from "../gitea/reviewer-api.js";
|
import { removeBotFromReviewers } from "../gitea/reviewer-api.js";
|
||||||
import { buildReviewPrompt } from "../prompt/build-review-prompt.js";
|
import { buildReviewPrompt } from "../prompt/build-review-prompt.js";
|
||||||
@@ -221,6 +225,19 @@ async function executeReview(params: {
|
|||||||
outcome: "success"
|
outcome: "success"
|
||||||
});
|
});
|
||||||
return "success";
|
return "success";
|
||||||
|
} catch (error) {
|
||||||
|
if (isTimeoutError(error)) {
|
||||||
|
await handleTimeoutFailure({
|
||||||
|
gitea,
|
||||||
|
owner,
|
||||||
|
repo,
|
||||||
|
prNumber,
|
||||||
|
botLogin: input.env.GITEA_BOT_LOGIN,
|
||||||
|
timeoutMs: input.env.REVIEW_TIMEOUT_MS,
|
||||||
|
correlationId: input.correlationId
|
||||||
|
});
|
||||||
|
}
|
||||||
|
throw error;
|
||||||
} finally {
|
} finally {
|
||||||
if (progressCommentId !== undefined) {
|
if (progressCommentId !== undefined) {
|
||||||
try {
|
try {
|
||||||
@@ -245,3 +262,53 @@ async function executeReview(params: {
|
|||||||
function isTimeoutError(error: unknown): boolean {
|
function isTimeoutError(error: unknown): boolean {
|
||||||
return error instanceof Error && error.message.toLowerCase().includes("timed out");
|
return error instanceof Error && error.message.toLowerCase().includes("timed out");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function handleTimeoutFailure(input: {
|
||||||
|
gitea: GiteaClient;
|
||||||
|
owner: string;
|
||||||
|
repo: string;
|
||||||
|
prNumber: number;
|
||||||
|
botLogin: string;
|
||||||
|
timeoutMs: number;
|
||||||
|
correlationId: string;
|
||||||
|
}): Promise<void> {
|
||||||
|
try {
|
||||||
|
await postTimeoutFailureComment({
|
||||||
|
gitea: input.gitea,
|
||||||
|
owner: input.owner,
|
||||||
|
repo: input.repo,
|
||||||
|
prNumber: input.prNumber,
|
||||||
|
timeoutMs: input.timeoutMs
|
||||||
|
});
|
||||||
|
log("info", "Posted timeout failure comment on PR", {
|
||||||
|
correlation_id: input.correlationId,
|
||||||
|
pr_number: input.prNumber
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
log("warn", "Failed to post timeout failure comment on PR", {
|
||||||
|
correlation_id: input.correlationId,
|
||||||
|
pr_number: input.prNumber,
|
||||||
|
error: error instanceof Error ? error.message : String(error)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await removeBotFromReviewers({
|
||||||
|
gitea: input.gitea,
|
||||||
|
owner: input.owner,
|
||||||
|
repo: input.repo,
|
||||||
|
prNumber: input.prNumber,
|
||||||
|
botLogin: input.botLogin
|
||||||
|
});
|
||||||
|
log("info", "Removed bot from reviewers after timeout", {
|
||||||
|
correlation_id: input.correlationId,
|
||||||
|
pr_number: input.prNumber
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
log("warn", "Failed to remove bot from reviewers after timeout", {
|
||||||
|
correlation_id: input.correlationId,
|
||||||
|
pr_number: input.prNumber,
|
||||||
|
error: error instanceof Error ? error.message : String(error)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user