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
29 changes: 25 additions & 4 deletions __tests__/integration/ai-review.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,33 @@ import { getLogger } from '../../src/logger.js';
// ---------------------------------------------------------------------------

function createMockOctokit() {
// Production code now calls octokit.request(route, params) for issue comments
// (was octokit.issues.X — that namespace turned out to be undefined at runtime
// in Probot v14's pull_request.opened context). Existing tests assert against
// octokit.issues.X mocks, so we retrofit the shape: route the request mock
// into the namespaced jest.fn()s for the three relevant routes.
const issuesListComments = jest.fn().mockResolvedValue({ data: [] });
const issuesCreateComment = jest.fn().mockResolvedValue({ status: 201, data: {} });
const issuesUpdateComment = jest.fn().mockResolvedValue({ status: 200, data: {} });

const routeDispatch = {
'GET /repos/{owner}/{repo}/issues/{issue_number}/comments': issuesListComments,
'POST /repos/{owner}/{repo}/issues/{issue_number}/comments': issuesCreateComment,
'PATCH /repos/{owner}/{repo}/issues/comments/{comment_id}': issuesUpdateComment
};

const request = jest.fn((route, params) => {
const dispatch = routeDispatch[route];
if (dispatch) return dispatch(params);
return Promise.resolve({ status: 200, data: {} });
});

return {
request: jest.fn().mockResolvedValue({ status: 200, data: {} }),
request,
issues: {
createComment: jest.fn().mockResolvedValue({ status: 201, data: {} }),
listComments: jest.fn().mockResolvedValue({ data: [] }),
updateComment: jest.fn().mockResolvedValue({ status: 200, data: {} })
listComments: issuesListComments,
createComment: issuesCreateComment,
updateComment: issuesUpdateComment
}
};
}
Expand Down
40 changes: 21 additions & 19 deletions src/ai-review.js
Original file line number Diff line number Diff line change
Expand Up @@ -285,13 +285,14 @@ function formatReviewComment(aiResponse, prNumber, headSha, meta) {
*/
async function supersedePreviousReviews(octokit, owner, repo, prNumber) {
try {
// List all comments on the PR
const { data: comments } = await octokit.issues.listComments({
owner,
repo,
issue_number: prNumber,
per_page: 100
});
// Use octokit.request() form (not .issues.listComments) because Probot v14's
// bundled Octokit does not always expose the .issues namespace plugin in the
// pull_request.opened event context \u2014 that mismatch was silently breaking
// every auto AI review with "Cannot read properties of undefined".
const { data: comments } = await octokit.request(
'GET /repos/{owner}/{repo}/issues/{issue_number}/comments',
{ owner, repo, issue_number: prNumber, per_page: 100 }
);

const outdatedPrefix =
'> \u26a0\ufe0f **Outdated** \u2014 this review was for an earlier revision. See the latest review below.\n\n';
Expand All @@ -302,12 +303,15 @@ async function supersedePreviousReviews(octokit, owner, repo, prNumber) {
comment.body.includes(AI_REVIEW_SIGNATURE) &&
!comment.body.startsWith('>')
) {
await octokit.issues.updateComment({
owner,
repo,
comment_id: comment.id,
body: outdatedPrefix + comment.body
});
await octokit.request(
'PATCH /repos/{owner}/{repo}/issues/comments/{comment_id}',
{
owner,
repo,
comment_id: comment.id,
body: outdatedPrefix + comment.body
}
);
}
}
} catch (error) {
Expand Down Expand Up @@ -396,12 +400,10 @@ async function reviewPullRequest(octokit, owner, repo, prNumber) {
// Mark previous bot reviews as outdated
await supersedePreviousReviews(octokit, owner, repo, prNumber);

await octokit.issues.createComment({
owner,
repo,
issue_number: prNumber,
body: comment
});
await octokit.request(
'POST /repos/{owner}/{repo}/issues/{issue_number}/comments',
{ owner, repo, issue_number: prNumber, body: comment }
);

// Store the review record
storeReview({
Expand Down
Loading