Skip to content
Open
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
48 changes: 31 additions & 17 deletions src/github.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1119,17 +1119,21 @@ export async function getPRReviewComments(repo: string, prNumber: number): Promi
}
}

// Check which inline comments already have a 👍 from Yeti
for (const comment of comments) {
// Check for existing 👍 reaction from Yeti
let hasYetiReaction = false;
try {
const reactionsRaw = await gh(["api", `repos/${repo}/pulls/comments/${comment.id}/reactions`]);
const reactions = JSON.parse(reactionsRaw) as Reaction[];
hasYetiReaction = reactions.some((r) => r.user.login === selfLogin && r.content === "+1");
} catch { /* treat as no reaction */ }
if (hasYetiReaction) continue;
// Check which inline comments already have a 👍 from Yeti (parallel)
const inlineReactionChecks = await Promise.all(
comments.map(async (comment) => {
let hasYetiReaction = false;
try {
const reactionsRaw = await gh(["api", `repos/${repo}/pulls/comments/${comment.id}/reactions`]);
const reactions = JSON.parse(reactionsRaw) as Reaction[];
hasYetiReaction = reactions.some((r) => r.user.login === selfLogin && r.content === "+1");
} catch { /* treat as no reaction */ }
return { comment, hasYetiReaction };
}),
);

for (const { comment, hasYetiReaction } of inlineReactionChecks) {
if (hasYetiReaction) continue;
const location = comment.line ? `${comment.path}:${comment.line}` : comment.path;
parts.push(
`Inline comment by @${comment.user.login} on ${location}:\n` +
Expand All @@ -1139,6 +1143,8 @@ export async function getPRReviewComments(repo: string, prNumber: number): Promi
}

// Add non-Yeti, non-bot issue-tab comments without 👍 from Yeti
// Separate comments that need reaction checks from those that don't
const humanIssueComments: typeof issueComments = [];
for (const comment of issueComments) {
if (!comment.body?.trim()) continue;
if (comment.body.trim().toUpperCase() === "LGTM") continue;
Expand All @@ -1147,15 +1153,23 @@ export async function getPRReviewComments(repo: string, prNumber: number): Promi
continue;
}
if (comment.user.login.endsWith("[bot]")) continue;
humanIssueComments.push(comment);
}

// Check for existing 👍 reaction from Yeti
let hasYetiReaction = false;
try {
const reactions = await getCommentReactions(repo, comment.id);
hasYetiReaction = reactions.some((r) => r.user.login === selfLogin && r.content === "+1");
} catch { /* treat as no reaction */ }
if (hasYetiReaction) continue;
// Check reactions in parallel for human issue comments
const issueReactionChecks = await Promise.all(
humanIssueComments.map(async (comment) => {
let hasYetiReaction = false;
try {
const reactions = await getCommentReactions(repo, comment.id);
hasYetiReaction = reactions.some((r) => r.user.login === selfLogin && r.content === "+1");
} catch { /* treat as no reaction */ }
return { comment, hasYetiReaction };
}),
);

for (const { comment, hasYetiReaction } of issueReactionChecks) {
if (hasYetiReaction) continue;
parts.push(`Comment by @${comment.user.login}:\n${comment.body}`);
commentIds.push(comment.id);
}
Expand Down
32 changes: 19 additions & 13 deletions src/jobs/issue-auditor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,20 +49,26 @@ export async function classifyIssue(
const selfLogin = await gh.getSelfLogin();
const commentsAfterPlan = comments.slice(lastPlanIdx + 1);

for (const comment of commentsAfterPlan) {
if (gh.isYetiComment(comment.body)) continue;
if (comment.login.endsWith("[bot]")) continue;
const humanComments = commentsAfterPlan.filter(
(comment) => !gh.isYetiComment(comment.body) && !comment.login.endsWith("[bot]"),
);

try {
const reactions = await gh.getCommentReactions(fullName, comment.id);
const hasReaction = reactions.some(
(r) => r.user.login === selfLogin && r.content === "+1",
);
if (!hasReaction) return "needs-refinement";
} catch {
// Treat as unreacted to be safe
return "needs-refinement";
}
const reactionResults = await Promise.all(
humanComments.map(async (comment) => {
try {
const reactions = await gh.getCommentReactions(fullName, comment.id);
return reactions.some(
(r) => r.user.login === selfLogin && r.content === "+1",
);
} catch {
// Treat as unreacted to be safe
return false;
}
}),
);

if (reactionResults.some((hasReaction) => !hasReaction)) {
return "needs-refinement";
}

// Plan has blocking clarifying questions awaiting user response
Expand Down
34 changes: 18 additions & 16 deletions src/jobs/issue-refiner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -485,23 +485,25 @@ async function findUnreactedHumanComments(
commentsAfterPlan: gh.IssueComment[],
selfLogin: string,
): Promise<gh.IssueComment[]> {
const unreacted: gh.IssueComment[] = [];
for (const comment of commentsAfterPlan) {
if (gh.isYetiComment(comment.body)) continue;
if (comment.login.endsWith("[bot]")) continue;
try {
const reactions = await gh.getCommentReactions(fullName, comment.id);
const hasReaction = reactions.some(
(r) => r.user.login === selfLogin && r.content === "+1",
);
if (!hasReaction) {
unreacted.push(comment);
const humanComments = commentsAfterPlan.filter(
(comment) => !gh.isYetiComment(comment.body) && !comment.login.endsWith("[bot]"),
);

const results = await Promise.all(
humanComments.map(async (comment) => {
try {
const reactions = await gh.getCommentReactions(fullName, comment.id);
const hasReaction = reactions.some(
(r) => r.user.login === selfLogin && r.content === "+1",
);
return hasReaction ? null : comment;
} catch {
return comment;
}
} catch {
unreacted.push(comment);
}
}
return unreacted;
}),
);

return results.filter((c): c is gh.IssueComment => c !== null);
}

export async function run(repos: Repo[]): Promise<void> {
Expand Down
Loading