PRIX / lib /src /commenter.js
Rachit-Tw's picture
Upload 169 files
9284ad7 verified
Raw
History Blame Contribute Delete
32 kB
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Commenter = exports.PLAN_BRANDING = exports.PRIX_BRANDING = exports.ISSUE_REPLY_TAG = exports.VERIFICATION_FAILED_TAG = exports.VERIFIED_TAG = exports.COMMIT_ID_END_TAG = exports.COMMIT_ID_START_TAG = exports.SHORT_SUMMARY_END_TAG = exports.SHORT_SUMMARY_START_TAG = exports.RAW_SUMMARY_END_TAG = exports.RAW_SUMMARY_START_TAG = exports.DESCRIPTION_END_TAG = exports.DESCRIPTION_START_TAG = exports.IN_PROGRESS_END_TAG = exports.IN_PROGRESS_START_TAG = exports.SUMMARIZE_TAG = exports.COMMENT_REPLY_TAG = exports.COMMENT_TAG = exports.COMMENT_GREETING = exports.LOGO_URL = exports.setCommenterContext = exports.repo = exports.context = void 0;
// Removed @actions imports for Probot migration
const octokit_1 = require("./octokit");
const context_1 = require("./context");
const pino_1 = __importDefault(require("pino"));
const p_retry_1 = __importDefault(require("p-retry"));
const logger = (0, pino_1.default)({ level: process.env.LOG_LEVEL || 'info' });
const info = (msg) => logger.info(msg);
const warning = (msg) => logger.warn(msg);
const getInput = (name) => process.env[name.toUpperCase()] || '';
// Retry configuration for GitHub API calls
const GITHUB_RETRY_OPTIONS = {
retries: 3,
minTimeout: 1000,
maxTimeout: 10000,
factor: 2,
onFailedAttempt: (error) => {
logger.warn({
attemptNumber: error.attemptNumber,
retriesLeft: error.retriesLeft,
error: error.message
}, 'GitHub API call failed, retrying...');
}
};
// Wrapper for retryable GitHub API calls
async function withRetry(fn) {
return (0, p_retry_1.default)(fn, GITHUB_RETRY_OPTIONS);
}
exports.context = new Proxy({}, {
get(target, prop) {
return (context_1.als.getStore()?.probotContext)[prop];
}
});
exports.repo = new Proxy({}, {
get(target, prop) {
return (context_1.als.getStore()?.repo)[prop];
}
});
const setCommenterContext = (newContext) => {
// context and repo are now Proxies
};
exports.setCommenterContext = setCommenterContext;
exports.LOGO_URL = 'https://www.prixai.xyz/logo.png';
exports.COMMENT_GREETING = `<div align="center">
<img src="${exports.LOGO_URL}" width="64" height="64" alt="PRIX Logo">
# 🤖 PRIX AI Code Review
</div>
---
Welcome! I'm PRIX, your AI code reviewer. I've analyzed this pull request and here are my findings:
---`;
exports.COMMENT_TAG = '<!-- This is an auto-generated comment by AI PR Reviewer -->';
exports.COMMENT_REPLY_TAG = '<!-- This is an auto-generated reply by AI PR Reviewer -->';
exports.SUMMARIZE_TAG = '<!-- This is an auto-generated comment: summarize by AI PR Reviewer -->';
exports.IN_PROGRESS_START_TAG = '<!-- This is an auto-generated comment: summarize review in progress by AI PR Reviewer -->';
exports.IN_PROGRESS_END_TAG = '<!-- end of auto-generated comment: summarize review in progress by AI PR Reviewer -->';
exports.DESCRIPTION_START_TAG = '<!-- This is an auto-generated comment: release notes by AI PR Reviewer -->';
exports.DESCRIPTION_END_TAG = '<!-- end of auto-generated comment: release notes by AI PR Reviewer -->';
exports.RAW_SUMMARY_START_TAG = `<!-- This is an auto-generated comment: raw summary by AI PR Reviewer -->
<!--
`;
exports.RAW_SUMMARY_END_TAG = `-->
<!-- end of auto-generated comment: raw summary by AI PR Reviewer -->`;
exports.SHORT_SUMMARY_START_TAG = `<!-- This is an auto-generated comment: short summary by AI PR Reviewer -->
<!--
`;
exports.SHORT_SUMMARY_END_TAG = `-->
<!-- end of auto-generated comment: short summary by OSS CodeRabbit -->`;
exports.COMMIT_ID_START_TAG = '<!-- commit_ids_reviewed_start -->';
exports.COMMIT_ID_END_TAG = '<!-- commit_ids_reviewed_end -->';
exports.VERIFIED_TAG = '<!-- verified_by_prix -->';
exports.VERIFICATION_FAILED_TAG = '<!-- verification_failed -->';
exports.ISSUE_REPLY_TAG = '<!-- This is an auto-generated issue analysis by PRIX -->';
exports.PRIX_BRANDING = `
---
<div align="center">
🚀 **[Get PRIX for your team](https://www.prixai.xyz/)** — AI-powered code reviews that catch bugs before they ship
</div>`;
exports.PLAN_BRANDING = `
---
<div align="center">
🚀 **[Get PRIX for your team](https://www.prixai.xyz/)** — AI-powered code reviews that catch bugs before they ship
</div>`;
class Commenter {
/**
* @param mode Can be "create", "replace". Default is "replace".
*/
async comment(message, tag, mode) {
let target;
if (exports.context.payload.pull_request != null) {
target = exports.context.payload.pull_request.number;
}
else if (exports.context.payload.issue != null) {
target = exports.context.payload.issue.number;
}
else {
warning('Skipped: context.payload.pull_request and context.payload.issue are both null');
return;
}
if (!tag) {
tag = exports.COMMENT_TAG;
}
const body = `${exports.COMMENT_GREETING}
${message}
${tag}${exports.PRIX_BRANDING}`;
if (mode === 'create') {
await this.create(body, target);
}
else if (mode === 'replace') {
await this.replace(body, tag, target);
}
else {
warning(`Unknown mode: ${mode}, use "replace" instead`);
await this.replace(body, tag, target);
}
}
getContentWithinTags(content, startTag, endTag) {
const start = content.indexOf(startTag);
const end = content.indexOf(endTag);
if (start >= 0 && end >= 0) {
return content.slice(start + startTag.length, end);
}
return '';
}
removeContentWithinTags(content, startTag, endTag) {
const start = content.indexOf(startTag);
const end = content.lastIndexOf(endTag);
if (start >= 0 && end >= 0) {
return content.slice(0, start) + content.slice(end + endTag.length);
}
return content;
}
getRawSummary(summary) {
return this.getContentWithinTags(summary, exports.RAW_SUMMARY_START_TAG, exports.RAW_SUMMARY_END_TAG);
}
getShortSummary(summary) {
return this.getContentWithinTags(summary, exports.SHORT_SUMMARY_START_TAG, exports.SHORT_SUMMARY_END_TAG);
}
getDescription(description) {
return this.removeContentWithinTags(description, exports.DESCRIPTION_START_TAG, exports.DESCRIPTION_END_TAG);
}
getReleaseNotes(description) {
const releaseNotes = this.getContentWithinTags(description, exports.DESCRIPTION_START_TAG, exports.DESCRIPTION_END_TAG);
return releaseNotes.replace(/(^|\n)> .*/g, '');
}
async updateDescription(pullNumber, message) {
// add this response to the description field of the PR as release notes by looking
// for the tag (marker)
try {
// get latest description from PR
const pr = await octokit_1.octokit.rest.pulls.get({
owner: exports.repo.owner,
repo: exports.repo.repo,
// eslint-disable-next-line camelcase
pull_number: pullNumber,
request: { timeout: 10000 }
});
let body = '';
if (pr.data.body) {
body = pr.data.body;
}
const description = this.getDescription(body);
const messageClean = this.removeContentWithinTags(message, exports.DESCRIPTION_START_TAG, exports.DESCRIPTION_END_TAG);
const newDescription = `${description}\n${exports.DESCRIPTION_START_TAG}\n${messageClean}\n${exports.DESCRIPTION_END_TAG}`;
await octokit_1.octokit.rest.pulls.update({
owner: exports.repo.owner,
repo: exports.repo.repo,
// eslint-disable-next-line camelcase
pull_number: pullNumber,
body: newDescription,
request: { timeout: 10000 }
});
}
catch (e) {
warning(`Failed to get PR: ${e}, skipping adding release notes to description.`);
}
}
reviewCommentsBuffer = [];
async bufferReviewComment(path, startLine, endLine, message, verified, verificationFeedback, testCase) {
// Premium UI Formatting: Convert "[LEVEL] | [TYPE]" to emoji badges
const levelTypeRegex = /^(\w+)\s*\|\s*(\w+)/;
const match = message.match(levelTypeRegex);
let level = 'info';
let type = 'General';
let severityEmoji = 'ℹ️';
let color = 'Info';
if (match != null) {
level = match[1].toLowerCase();
type = match[2];
if (level === 'critical') {
severityEmoji = '🚨';
color = 'Critical';
}
else if (level === 'major') {
severityEmoji = '🔴';
color = 'Major';
}
else if (level === 'minor') {
severityEmoji = '🟠';
color = 'Minor';
}
else if (level === 'info') {
severityEmoji = 'ℹ️';
color = 'Info';
}
message = message.replace(levelTypeRegex, '').trim();
}
// Generate AI Agent Prompt for actionable issues
let aiAgentSection = '';
if (level === 'critical' || level === 'major') {
const aiPrompt = this.generateAIAgentPrompt(path, startLine, endLine, message);
aiAgentSection = `
<details>
<summary>🤖 Prompt for AI Agents</summary>
Copy and paste this prompt into your AI IDE (Cursor, Windsurf, etc.) to auto-fix:
\`\`\`
${aiPrompt}
\`\`\`
</details>`;
}
let verificationBadge = '';
if (verified === true) {
verificationBadge =
'\n---\n✅ **Verified**: This suggestion passed syntax, lint, and AST validation.\n';
}
else if (verified === false && verificationFeedback) {
verificationBadge = `\n---\n⚠️ **Verification Failed**: ${verificationFeedback}\n`;
}
// Add test case section if available
const testCaseSection = testCase ? `\n\n${testCase}` : '';
// CodeRabbit-style formatted comment
const formattedMessage = `**${severityEmoji} Potential Issue | ${color} (${type})**
${message}${aiAgentSection}${testCaseSection}${verificationBadge}
${exports.COMMENT_TAG}`;
this.reviewCommentsBuffer.push({
path,
startLine,
endLine,
message: formattedMessage,
verified,
verificationFeedback,
level,
type
});
}
generateAIAgentPrompt(path, startLine, endLine, issue) {
return `Fix the following issue in ${path} around lines ${startLine}-${endLine}:
Issue: ${issue.split('\n')[0]}
Steps:
1. Read the file ${path}
2. Locate lines ${startLine}-${endLine}
3. Fix the issue described above
4. Ensure the fix follows the existing code style
5. Verify no other parts of the code are broken
Provide the complete fixed code block.`;
}
async deletePendingReview(pullNumber) {
try {
const reviews = await octokit_1.octokit.rest.pulls.listReviews({
owner: exports.repo.owner,
repo: exports.repo.repo,
// eslint-disable-next-line camelcase
pull_number: pullNumber,
request: { timeout: 10000 }
});
const pendingReview = reviews.data.find(review => review.state === 'PENDING');
if (pendingReview) {
info(`Deleting pending review for PR #${pullNumber} id: ${pendingReview.id}`);
try {
await octokit_1.octokit.rest.pulls.deletePendingReview({
owner: exports.repo.owner,
repo: exports.repo.repo,
// eslint-disable-next-line camelcase
pull_number: pullNumber,
// eslint-disable-next-line camelcase
review_id: pendingReview.id,
request: { timeout: 10000 }
});
}
catch (e) {
warning(`Failed to delete pending review: ${e}`);
}
}
}
catch (e) {
warning(`Failed to list reviews: ${e}`);
}
}
async submitReview(pullNumber, commitId, statusMsg) {
const bodyHeader = `${exports.COMMENT_GREETING}
${statusMsg}
${exports.PRIX_BRANDING}`;
if (this.reviewCommentsBuffer.length === 0) {
// Submit empty review with statusMsg
info(`Submitting empty review for PR #${pullNumber}`);
try {
await octokit_1.octokit.rest.pulls.createReview({
owner: exports.repo.owner,
repo: exports.repo.repo,
// eslint-disable-next-line camelcase
pull_number: pullNumber,
// eslint-disable-next-line camelcase
commit_id: commitId,
event: 'COMMENT',
body: bodyHeader,
request: { timeout: 10000 }
});
}
catch (e) {
warning(`Failed to submit empty review: ${e}`);
}
return;
}
// De-duplicate and clear existing bot comments in the same range
for (const comment of this.reviewCommentsBuffer) {
const comments = await this.getCommentsAtRange(pullNumber, comment.path, comment.startLine, comment.endLine);
for (const c of comments) {
if (c.body.includes(exports.COMMENT_TAG)) {
try {
await octokit_1.octokit.rest.pulls.deleteReviewComment({
owner: exports.repo.owner,
repo: exports.repo.repo,
// eslint-disable-next-line camelcase
comment_id: c.id,
request: { timeout: 10000 }
});
}
catch (e) {
warning(`Failed to delete review comment: ${e}`);
}
}
}
}
await this.deletePendingReview(pullNumber);
// Unified Review: All comments are standalone threads to support suggestions
const pushableComments = this.reviewCommentsBuffer.map(comment => this.generateCommentData(comment));
try {
const review = await octokit_1.octokit.rest.pulls.createReview({
owner: exports.repo.owner,
repo: exports.repo.repo,
// eslint-disable-next-line camelcase
pull_number: pullNumber,
// eslint-disable-next-line camelcase
commit_id: commitId,
comments: pushableComments.map(comment => comment),
request: { timeout: 10000 }
});
info(`Submitting review for PR #${pullNumber}, total comments: ${pushableComments.length}, review id: ${review.data.id}`);
await octokit_1.octokit.rest.pulls.submitReview({
owner: exports.repo.owner,
repo: exports.repo.repo,
// eslint-disable-next-line camelcase
pull_number: pullNumber,
// eslint-disable-next-line camelcase
review_id: review.data.id,
event: 'COMMENT',
body: bodyHeader,
request: { timeout: 10000 }
});
}
catch (e) {
warning(`Failed to create review: ${e}. Falling back to individual comments.`);
await this.deletePendingReview(pullNumber);
let commentCounter = 0;
for (const comment of pushableComments) {
info(`Creating new review comment for ${comment.path}:${comment.start_line || comment.line}-${comment.line}: ${comment.body}`);
const commentData = {
owner: exports.repo.owner,
repo: exports.repo.repo,
// eslint-disable-next-line camelcase
pull_number: pullNumber,
// eslint-disable-next-line camelcase
commit_id: commitId,
...comment
};
try {
await octokit_1.octokit.rest.pulls.createReviewComment({ ...commentData, request: { timeout: 10000 } });
}
catch (ee) {
warning(`Failed to create review comment: ${ee}`);
}
commentCounter++;
info(`Comment ${commentCounter}/${pushableComments.length} posted`);
}
}
}
generateCommentData(comment) {
const commentData = {
path: comment.path,
body: comment.message,
line: comment.endLine
};
if (comment.startLine !== comment.endLine) {
// eslint-disable-next-line camelcase
commentData.start_line = comment.startLine;
// eslint-disable-next-line camelcase
commentData.start_side = 'RIGHT';
}
return commentData;
}
async reviewCommentReply(pullNumber, topLevelComment, message) {
const reply = `${exports.COMMENT_GREETING}
${message}
${exports.COMMENT_REPLY_TAG}${exports.PRIX_BRANDING}
`;
try {
// Post the reply to the user comment
await octokit_1.octokit.rest.pulls.createReplyForReviewComment({
owner: exports.repo.owner,
repo: exports.repo.repo,
// eslint-disable-next-line camelcase
pull_number: pullNumber,
body: reply,
// eslint-disable-next-line camelcase
comment_id: topLevelComment.id,
request: { timeout: 10000 }
});
}
catch (error) {
warning(`Failed to reply to the top-level comment ${error}`);
try {
await octokit_1.octokit.rest.pulls.createReplyForReviewComment({
owner: exports.repo.owner,
repo: exports.repo.repo,
// eslint-disable-next-line camelcase
pull_number: pullNumber,
body: `Could not post the reply to the top-level comment due to the following error: ${error}`,
// eslint-disable-next-line camelcase
comment_id: topLevelComment.id,
request: { timeout: 10000 }
});
}
catch (e) {
warning(`Failed to reply to the top-level comment ${e}`);
}
}
try {
if (topLevelComment.body.includes(exports.COMMENT_TAG)) {
// replace COMMENT_TAG with COMMENT_REPLY_TAG in topLevelComment
const newBody = topLevelComment.body.replace(exports.COMMENT_TAG, exports.COMMENT_REPLY_TAG);
await octokit_1.octokit.rest.pulls.updateReviewComment({
owner: exports.repo.owner,
repo: exports.repo.repo,
// eslint-disable-next-line camelcase
comment_id: topLevelComment.id,
body: newBody,
request: { timeout: 10000 }
});
}
}
catch (error) {
warning(`Failed to update the top-level comment ${error}`);
}
}
async getCommentsWithinRange(pullNumber, path, startLine, endLine) {
const comments = await this.listReviewComments(pullNumber);
return comments.filter((comment) => comment.path === path &&
comment.body !== '' &&
((comment.start_line !== undefined &&
comment.start_line >= startLine &&
comment.line <= endLine) ||
(startLine === endLine && comment.line === endLine)));
}
async getCommentsAtRange(pullNumber, path, startLine, endLine) {
const comments = await this.listReviewComments(pullNumber);
return comments.filter((comment) => comment.path === path &&
comment.body !== '' &&
((comment.start_line !== undefined &&
comment.start_line === startLine &&
comment.line === endLine) ||
(startLine === endLine && comment.line === endLine)));
}
async getCommentChainsWithinRange(pullNumber, path, startLine, endLine, tag = '') {
const existingComments = await this.getCommentsWithinRange(pullNumber, path, startLine, endLine);
// find all top most comments
const topLevelComments = [];
for (const comment of existingComments) {
if (!comment.in_reply_to_id) {
topLevelComments.push(comment);
}
}
let allChains = '';
let chainNum = 0;
for (const topLevelComment of topLevelComments) {
// get conversation chain
const chain = await this.composeCommentChain(existingComments, topLevelComment);
if (chain && chain.includes(tag)) {
chainNum += 1;
allChains += `Conversation Chain ${chainNum}:
${chain}
---
`;
}
}
return allChains;
}
async composeCommentChain(reviewComments, topLevelComment) {
const conversationChain = reviewComments
.filter((cmt) => cmt.in_reply_to_id === topLevelComment.id)
.map((cmt) => `${cmt.user.login}: ${cmt.body}`);
conversationChain.unshift(`${topLevelComment.user.login}: ${topLevelComment.body}`);
return conversationChain.join('\n---\n');
}
async getCommentChain(pullNumber, comment) {
try {
const reviewComments = await this.listReviewComments(pullNumber);
const topLevelComment = await this.getTopLevelComment(reviewComments, comment);
const chain = await this.composeCommentChain(reviewComments, topLevelComment);
return { chain, topLevelComment };
}
catch (e) {
warning(`Failed to get conversation chain: ${e}`);
return {
chain: '',
topLevelComment: null
};
}
}
async getTopLevelComment(reviewComments, comment) {
let topLevelComment = comment;
while (topLevelComment.in_reply_to_id) {
const parentComment = reviewComments.find((cmt) => cmt.id === topLevelComment.in_reply_to_id);
if (parentComment) {
topLevelComment = parentComment;
}
else {
break;
}
}
return topLevelComment;
}
reviewCommentsCache = {};
async listReviewComments(target) {
if (this.reviewCommentsCache[target]) {
return this.reviewCommentsCache[target];
}
const allComments = [];
let page = 1;
try {
for (;;) {
const { data: comments } = await octokit_1.octokit.rest.pulls.listReviewComments({
owner: exports.repo.owner,
repo: exports.repo.repo,
// eslint-disable-next-line camelcase
pull_number: target,
page,
// eslint-disable-next-line camelcase
per_page: 100,
request: { timeout: 10000 }
});
allComments.push(...comments);
page++;
if (!comments || comments.length < 100) {
break;
}
}
this.reviewCommentsCache[target] = allComments;
return allComments;
}
catch (e) {
warning(`Failed to list review comments: ${e}`);
return allComments;
}
}
async create(body, target) {
try {
// get comment ID from the response
const response = await octokit_1.octokit.rest.issues.createComment({
owner: exports.repo.owner,
repo: exports.repo.repo,
// eslint-disable-next-line camelcase
issue_number: target,
body,
request: { timeout: 10000 }
});
// add comment to issueCommentsCache
if (this.issueCommentsCache[target]) {
this.issueCommentsCache[target].push(response.data);
}
else {
this.issueCommentsCache[target] = [response.data];
}
}
catch (e) {
warning(`Failed to create comment: ${e}`);
}
}
async replace(body, tag, target) {
try {
const cmt = await this.findCommentWithTag(tag, target);
if (cmt) {
await octokit_1.octokit.rest.issues.updateComment({
owner: exports.repo.owner,
repo: exports.repo.repo,
// eslint-disable-next-line camelcase
comment_id: cmt.id,
body,
request: { timeout: 10000 }
});
}
else {
await this.create(body, target);
}
}
catch (e) {
warning(`Failed to replace comment: ${e}`);
}
}
async findCommentWithTag(tag, target) {
try {
const comments = await this.listComments(target);
for (const cmt of comments) {
if (cmt.body && cmt.body.includes(tag)) {
return cmt;
}
}
return null;
}
catch (e) {
warning(`Failed to find comment with tag: ${e}`);
return null;
}
}
issueCommentsCache = {};
async listComments(target) {
if (this.issueCommentsCache[target]) {
return this.issueCommentsCache[target];
}
const allComments = [];
let page = 1;
try {
for (;;) {
const { data: comments } = await octokit_1.octokit.rest.issues.listComments({
owner: exports.repo.owner,
repo: exports.repo.repo,
// eslint-disable-next-line camelcase
issue_number: target,
page,
// eslint-disable-next-line camelcase
per_page: 100,
request: { timeout: 10000 }
});
allComments.push(...comments);
page++;
if (!comments || comments.length < 100) {
break;
}
}
this.issueCommentsCache[target] = allComments;
return allComments;
}
catch (e) {
warning(`Failed to list comments: ${e}`);
return allComments;
}
}
// function that takes a comment body and returns the list of commit ids that have been reviewed
// commit ids are comments between the commit_ids_reviewed_start and commit_ids_reviewed_end markers
// <!-- [commit_id] -->
getReviewedCommitIds(commentBody) {
const start = commentBody.indexOf(exports.COMMIT_ID_START_TAG);
const end = commentBody.indexOf(exports.COMMIT_ID_END_TAG);
if (start === -1 || end === -1) {
return [];
}
const ids = commentBody.substring(start + exports.COMMIT_ID_START_TAG.length, end);
// remove the <!-- and --> markers from each id and extract the id and remove empty strings
return ids
.split('<!--')
.map(id => id.replace('-->', '').trim())
.filter(id => id !== '');
}
// get review commit ids comment block from the body as a string
// including markers
getReviewedCommitIdsBlock(commentBody) {
const start = commentBody.indexOf(exports.COMMIT_ID_START_TAG);
const end = commentBody.indexOf(exports.COMMIT_ID_END_TAG);
if (start === -1 || end === -1) {
return '';
}
return commentBody.substring(start, end + exports.COMMIT_ID_END_TAG.length);
}
// add a commit id to the list of reviewed commit ids
// if the marker doesn't exist, add it
addReviewedCommitId(commentBody, commitId) {
const start = commentBody.indexOf(exports.COMMIT_ID_START_TAG);
const end = commentBody.indexOf(exports.COMMIT_ID_END_TAG);
if (start === -1 || end === -1) {
return `${commentBody}\n${exports.COMMIT_ID_START_TAG}\n<!-- ${commitId} -->\n${exports.COMMIT_ID_END_TAG}`;
}
const ids = commentBody.substring(start + exports.COMMIT_ID_START_TAG.length, end);
return `${commentBody.substring(0, start + exports.COMMIT_ID_START_TAG.length)}${ids}<!-- ${commitId} -->\n${commentBody.substring(end)}`;
}
// given a list of commit ids provide the highest commit id that has been reviewed
getHighestReviewedCommitId(commitIds, reviewedCommitIds) {
for (let i = commitIds.length - 1; i >= 0; i--) {
if (reviewedCommitIds.includes(commitIds[i])) {
return commitIds[i];
}
}
return '';
}
async getAllCommitIds() {
const allCommits = [];
let page = 1;
let commits;
if (exports.context && exports.context.payload && exports.context.payload.pull_request != null) {
do {
commits = await octokit_1.octokit.rest.pulls.listCommits({
owner: exports.repo.owner,
repo: exports.repo.repo,
// eslint-disable-next-line camelcase
pull_number: exports.context.payload.pull_request.number,
// eslint-disable-next-line camelcase
per_page: 100,
page,
request: { timeout: 10000 }
});
allCommits.push(...commits.data.map(commit => commit.sha));
page++;
} while (commits.data.length > 0);
}
return allCommits;
}
// add in-progress status to the comment body
addInProgressStatus(commentBody, statusMsg) {
const start = commentBody.indexOf(exports.IN_PROGRESS_START_TAG);
const end = commentBody.indexOf(exports.IN_PROGRESS_END_TAG);
// add to the beginning of the comment body if the marker doesn't exist
// otherwise do nothing
if (start === -1 || end === -1) {
return `${exports.IN_PROGRESS_START_TAG}
Currently reviewing new changes in this PR...
${statusMsg}
${exports.IN_PROGRESS_END_TAG}
---
${commentBody}`;
}
return commentBody;
}
// remove in-progress status from the comment body
removeInProgressStatus(commentBody) {
const start = commentBody.indexOf(exports.IN_PROGRESS_START_TAG);
const end = commentBody.indexOf(exports.IN_PROGRESS_END_TAG);
// remove the in-progress status if the marker exists
// otherwise do nothing
if (start !== -1 && end !== -1) {
return (commentBody.substring(0, start) +
commentBody.substring(end + exports.IN_PROGRESS_END_TAG.length));
}
return commentBody;
}
}
exports.Commenter = Commenter;
//# sourceMappingURL=commenter.js.map