Spaces:
Paused
Paused
| ; | |
| 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.setCommenterContext = exports.repo = exports.context = void 0; | |
| // Removed @actions imports for Probot migration | |
| const octokit_1 = require("./octokit"); | |
| const context_1 = require("./context"); | |
| const info = console.log; | |
| const warning = console.warn; | |
| const getInput = (name) => process.env[name.toUpperCase()] || ''; | |
| 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.COMMENT_GREETING = `${getInput('bot_icon')} AI PR Reviewer`; | |
| 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 = `--- | |
| *This PR was generated by [Prix](https://prix.dev). [View on Prix](https://app.prix.dev)*`; | |
| exports.PLAN_BRANDING = `--- | |
| *This plan was generated by [Prix](https://prix.dev). [View on Prix](https://app.prix.dev)*`; | |
| 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.pulls.get({ | |
| owner: exports.repo.owner, | |
| repo: exports.repo.repo, | |
| // eslint-disable-next-line camelcase | |
| pull_number: pullNumber | |
| }); | |
| 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.pulls.update({ | |
| owner: exports.repo.owner, | |
| repo: exports.repo.repo, | |
| // eslint-disable-next-line camelcase | |
| pull_number: pullNumber, | |
| body: newDescription | |
| }); | |
| } | |
| catch (e) { | |
| warning(`Failed to get PR: ${e}, skipping adding release notes to description.`); | |
| } | |
| } | |
| reviewCommentsBuffer = []; | |
| async bufferReviewComment(path, startLine, endLine, message, verified, verificationFeedback) { | |
| // Premium UI Formatting: Convert "[LEVEL] | [TYPE]" to emoji badges | |
| const levelTypeRegex = /^(\w+)\s*\|\s*(\w+)/; | |
| const match = message.match(levelTypeRegex); | |
| let header = ''; | |
| if (match != null) { | |
| const level = match[1].toLowerCase(); | |
| const type = match[2]; | |
| let emoji = '⚠️'; | |
| let color = 'Major'; | |
| if (level === 'critical') { | |
| emoji = '🚨'; | |
| color = 'Critical'; | |
| } | |
| else if (level === 'major') { | |
| emoji = '🔴'; | |
| color = 'Major'; | |
| } | |
| else if (level === 'minor') { | |
| emoji = '🟠'; | |
| color = 'Minor'; | |
| } | |
| else if (level === 'info') { | |
| emoji = 'ℹ️'; | |
| color = 'Info'; | |
| } | |
| header = `**${emoji} Potential issue | ${color} (${type})**\n\n`; | |
| message = message.replace(levelTypeRegex, '').trim(); | |
| } | |
| 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`; | |
| } | |
| const formattedMessage = `${exports.COMMENT_GREETING} | |
| ${header}${message}${verificationBadge} | |
| ${exports.COMMENT_TAG}`; | |
| this.reviewCommentsBuffer.push({ | |
| path, | |
| startLine, | |
| endLine, | |
| message: formattedMessage, | |
| verified, | |
| verificationFeedback | |
| }); | |
| } | |
| async deletePendingReview(pullNumber) { | |
| try { | |
| const reviews = await octokit_1.octokit.pulls.listReviews({ | |
| owner: exports.repo.owner, | |
| repo: exports.repo.repo, | |
| // eslint-disable-next-line camelcase | |
| pull_number: pullNumber | |
| }); | |
| 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.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 | |
| }); | |
| } | |
| 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} | |
| `; | |
| if (this.reviewCommentsBuffer.length === 0) { | |
| // Submit empty review with statusMsg | |
| info(`Submitting empty review for PR #${pullNumber}`); | |
| try { | |
| await octokit_1.octokit.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 | |
| }); | |
| } | |
| 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.pulls.deleteReviewComment({ | |
| owner: exports.repo.owner, | |
| repo: exports.repo.repo, | |
| // eslint-disable-next-line camelcase | |
| comment_id: c.id | |
| }); | |
| } | |
| 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.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) | |
| }); | |
| info(`Submitting review for PR #${pullNumber}, total comments: ${pushableComments.length}, review id: ${review.data.id}`); | |
| await octokit_1.octokit.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 | |
| }); | |
| } | |
| 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.startLine}-${comment.endLine}: ${comment.message}`); | |
| 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.pulls.createReviewComment(commentData); | |
| } | |
| 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} | |
| `; | |
| try { | |
| // Post the reply to the user comment | |
| await octokit_1.octokit.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 | |
| }); | |
| } | |
| catch (error) { | |
| warning(`Failed to reply to the top-level comment ${error}`); | |
| try { | |
| await octokit_1.octokit.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 | |
| }); | |
| } | |
| 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.pulls.updateReviewComment({ | |
| owner: exports.repo.owner, | |
| repo: exports.repo.repo, | |
| // eslint-disable-next-line camelcase | |
| comment_id: topLevelComment.id, | |
| body: newBody | |
| }); | |
| } | |
| } | |
| 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.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 | |
| }); | |
| 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.issues.createComment({ | |
| owner: exports.repo.owner, | |
| repo: exports.repo.repo, | |
| // eslint-disable-next-line camelcase | |
| issue_number: target, | |
| body | |
| }); | |
| // 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.issues.updateComment({ | |
| owner: exports.repo.owner, | |
| repo: exports.repo.repo, | |
| // eslint-disable-next-line camelcase | |
| comment_id: cmt.id, | |
| body | |
| }); | |
| } | |
| 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.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 | |
| }); | |
| 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.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 | |
| }); | |
| 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 |