diff --git a/README.md b/README.md
index 1b09677f..a9267f60 100644
--- a/README.md
+++ b/README.md
@@ -3,8 +3,8 @@
[](https://opensource.org/licenses/MIT)
@@ -47,7 +47,7 @@ FAQs, you can refer to the sections below.
- [Overview](#overview)
- [Install instructions](#install-instructions)
-- [Conversation with OpenAI](#conversation-with-openai)
+- [Conversation with CodeRabbit](#conversation-with-coderabbit)
- [Examples](#examples)
- [Contribute](#contribute)
- [FAQs](#faqs)
@@ -55,7 +55,7 @@ FAQs, you can refer to the sections below.
## Install instructions
`ai-pr-reviewer` runs as a GitHub Action. Add the below file to your repository
-at `.github/workflows/openai-pr-reviewer.yml`
+at `.github/workflows/ai-pr-reviewer.yml`
```yaml
name: Code Review
@@ -123,7 +123,7 @@ value. For example, to review docs/blog posts, you can use the following prompt:
```yaml
system_message: |
- You are `@openai` (aka `github-actions[bot]`), a language model
+ You are `@coderabbitai` (aka `github-actions[bot]`), a language model
trained by OpenAI. Your purpose is to act as a highly experienced
DevRel (developer relations) professional with focus on cloud-native
infrastructure.
@@ -150,15 +150,15 @@ system_message: |
-## Conversation with OpenAI
+## Conversation with CodeRabbit
You can reply to a review comment made by this action and get a response based
on the diff context. Additionally, you can invite the bot to a conversation by
-tagging it in the comment (`@openai`).
+tagging it in the comment (`@coderabbitai`).
Example:
-> @openai Please generate a test plan for this file.
+> @coderabbitai Please generate a test plan for this file.
Note: A review comment is a comment made on a diff or a file in the pull
request.
@@ -170,7 +170,7 @@ to review documentation, you can ignore PRs that only change the documentation.
To ignore a PR, add the following keyword in the PR description:
```text
-@openai: ignore
+@coderabbitai: ignore
```
## Examples
diff --git a/action.yml b/action.yml
index 06fbea67..c66695cf 100644
--- a/action.yml
+++ b/action.yml
@@ -1,9 +1,9 @@
-name: 'OpenAI ChatGPT based PR Reviewer & Summarizer'
-description: 'OpenAI ChatGPT based PR Reviewer and Summarizer'
+name: 'AI-based PR Reviewer & Summarizer with Chat Capabilities'
+description: 'AI-based PR Reviewer & Summarizer with Chat Capabilities'
branding:
- icon: 'aperture'
+ icon: 'git-merge'
color: 'orange'
-author: 'FluxNinja, Inc.'
+author: 'CodeRabbit LLC'
inputs:
debug:
required: false
@@ -148,7 +148,7 @@ inputs:
required: false
description: 'System message to be sent to OpenAI'
default: |
- You are `@openai` (aka `github-actions[bot]`), a language model
+ You are `@coderabbitai` (aka `github-actions[bot]`), a language model
trained by OpenAI. Your purpose is to act as a highly experienced
software engineer and provide a thorough review of the code hunks
and suggest code snippets to improve key areas such as:
diff --git a/dist/index.js b/dist/index.js
index 55ab8cdd..2cc2b1fb 100644
--- a/dist/index.js
+++ b/dist/index.js
@@ -3895,7 +3895,7 @@ Current date: ${currentDate}`;
/* harmony export */ "oi": () => (/* binding */ RAW_SUMMARY_START_TAG),
/* harmony export */ "rV": () => (/* binding */ RAW_SUMMARY_END_TAG)
/* harmony export */ });
-/* unused harmony exports COMMENT_GREETING, DESCRIPTION_START_TAG, DESCRIPTION_END_TAG, COMMIT_ID_START_TAG, COMMIT_ID_END_TAG */
+/* unused harmony exports COMMENT_GREETING, IN_PROGRESS_START_TAG, IN_PROGRESS_END_TAG, DESCRIPTION_START_TAG, DESCRIPTION_END_TAG, COMMIT_ID_START_TAG, COMMIT_ID_END_TAG */
/* harmony import */ var _actions_core__WEBPACK_IMPORTED_MODULE_0__ = __nccwpck_require__(2186);
/* harmony import */ var _actions_core__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__nccwpck_require__.n(_actions_core__WEBPACK_IMPORTED_MODULE_0__);
/* harmony import */ var _actions_github__WEBPACK_IMPORTED_MODULE_1__ = __nccwpck_require__(5438);
@@ -3908,23 +3908,25 @@ Current date: ${currentDate}`;
// eslint-disable-next-line camelcase
const context = _actions_github__WEBPACK_IMPORTED_MODULE_1__.context;
const repo = context.repo;
-const COMMENT_GREETING = ':robot: OpenAI';
-const COMMENT_TAG = '';
-const COMMENT_REPLY_TAG = '';
-const SUMMARIZE_TAG = '';
+const COMMENT_GREETING = `
CodeRabbit`;
+const COMMENT_TAG = '';
+const COMMENT_REPLY_TAG = '';
+const SUMMARIZE_TAG = '';
+const IN_PROGRESS_START_TAG = '';
+const IN_PROGRESS_END_TAG = '';
const DESCRIPTION_START_TAG = `
-`;
-const DESCRIPTION_END_TAG = '';
-const RAW_SUMMARY_START_TAG = `
+`;
+const DESCRIPTION_END_TAG = '';
+const RAW_SUMMARY_START_TAG = `
-`;
-const SHORT_SUMMARY_START_TAG = `
+`;
+const SHORT_SUMMARY_START_TAG = `
-`;
+`;
const COMMIT_ID_START_TAG = '';
const COMMIT_ID_END_TAG = '';
class Commenter {
@@ -4315,13 +4317,20 @@ ${chain}
async create(body, target) {
try {
// get comment ID from the response
- await _octokit__WEBPACK_IMPORTED_MODULE_2__/* .octokit.issues.createComment */ .K.issues.createComment({
+ const response = await _octokit__WEBPACK_IMPORTED_MODULE_2__/* .octokit.issues.createComment */ .K.issues.createComment({
owner: repo.owner,
repo: 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) {
(0,_actions_core__WEBPACK_IMPORTED_MODULE_0__.warning)(`Failed to create comment: ${e}`);
@@ -4461,6 +4470,42 @@ ${chain}
}
return allCommits;
}
+ // add in-progress status to the comment body
+ addInProgressStatus(commentBody, headCommitId, highestReviewedCommitId) {
+ const start = commentBody.indexOf(IN_PROGRESS_START_TAG);
+ const end = commentBody.indexOf(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 `${IN_PROGRESS_START_TAG}
+
+Currently reviewing new changes in this PR...
+
+
+Details
+The files that changed from the \`base\` of the PR and between \`${highestReviewedCommitId}\` and \`${headCommitId}\` commits are being reviewed.
+
+
+${IN_PROGRESS_END_TAG}
+
+---
+
+${commentBody}`;
+ }
+ return commentBody;
+ }
+ // remove in-progress status from the comment body
+ removeInProgressStatus(commentBody) {
+ const start = commentBody.indexOf(IN_PROGRESS_START_TAG);
+ const end = commentBody.indexOf(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 + IN_PROGRESS_END_TAG.length));
+ }
+ return commentBody;
+ }
}
@@ -6981,7 +7026,7 @@ $comment
// eslint-disable-next-line camelcase
const context = _actions_github__WEBPACK_IMPORTED_MODULE_1__.context;
const repo = context.repo;
-const ASK_BOT = '@openai';
+const ASK_BOT = '@coderabbitai';
const handleReviewComment = async (heavyBot, options, prompts) => {
const commenter = new _commenter__WEBPACK_IMPORTED_MODULE_2__/* .Commenter */ .Es();
const inputs = new _inputs__WEBPACK_IMPORTED_MODULE_5__/* .Inputs */ .k();
@@ -7277,7 +7322,7 @@ var tokenizer = __nccwpck_require__(652);
// eslint-disable-next-line camelcase
const context = github.context;
const repo = context.repo;
-const ignoreKeyword = '@openai: ignore';
+const ignoreKeyword = '@coderabbitai: ignore';
const codeReview = async (lightBot, heavyBot, options, prompts) => {
const commenter = new lib_commenter/* Commenter */.Es();
const openaiConcurrencyLimit = pLimit(options.openaiConcurrencyLimit);
@@ -7306,10 +7351,12 @@ const codeReview = async (lightBot, heavyBot, options, prompts) => {
// get SUMMARIZE_TAG message
const existingSummarizeCmt = await commenter.findCommentWithTag(lib_commenter/* SUMMARIZE_TAG */.Rp, context.payload.pull_request.number);
let existingCommitIdsBlock = '';
+ let existingSummarizeCmtBody = '';
if (existingSummarizeCmt != null) {
- inputs.rawSummary = commenter.getRawSummary(existingSummarizeCmt.body);
- inputs.shortSummary = commenter.getShortSummary(existingSummarizeCmt.body);
- existingCommitIdsBlock = commenter.getReviewedCommitIdsBlock(existingSummarizeCmt.body);
+ existingSummarizeCmtBody = existingSummarizeCmt.body;
+ inputs.rawSummary = commenter.getRawSummary(existingSummarizeCmtBody);
+ inputs.shortSummary = commenter.getShortSummary(existingSummarizeCmtBody);
+ existingCommitIdsBlock = commenter.getReviewedCommitIdsBlock(existingSummarizeCmtBody);
}
const allCommitIds = await commenter.getAllCommitIds();
// find highest reviewed commit id
@@ -7351,11 +7398,6 @@ const codeReview = async (lightBot, heavyBot, options, prompts) => {
(0,core.warning)('Skipped: files is null');
return;
}
- const commits = incrementalDiff.data.commits;
- if (commits.length === 0) {
- (0,core.warning)('Skipped: ommits is null');
- return;
- }
// skip files if they are filtered out
const filterSelectedFiles = [];
const filterIgnoredFiles = [];
@@ -7368,6 +7410,15 @@ const codeReview = async (lightBot, heavyBot, options, prompts) => {
filterSelectedFiles.push(file);
}
}
+ if (filterSelectedFiles.length === 0) {
+ (0,core.warning)('Skipped: filterSelectedFiles is null');
+ return;
+ }
+ const commits = incrementalDiff.data.commits;
+ if (commits.length === 0) {
+ (0,core.warning)('Skipped: commits is null');
+ return;
+ }
// find hunks to review
const filteredFiles = await Promise.all(filterSelectedFiles.map(file => githubConcurrencyLimit(async () => {
// retrieve file contents
@@ -7439,6 +7490,10 @@ ${hunks.oldHunk}
(0,core.error)('Skipped: no files to review');
return;
}
+ // update the existing comment with in progress status
+ const inProgressSummarizeCmt = commenter.addInProgressStatus(existingSummarizeCmtBody, context.payload.pull_request.head.sha, highestReviewedCommitId);
+ // add in progress status to the summarize comment
+ await commenter.comment(`${inProgressSummarizeCmt}`, lib_commenter/* SUMMARIZE_TAG */.Rp, 'replace');
const summariesFailed = [];
const doSummary = async (filename, fileContent, fileDiff) => {
(0,core.info)(`summarize: ${filename}`);
@@ -7536,7 +7591,7 @@ ${filename}: ${summary}
(0,core.info)('release notes: nothing obtained from openai');
}
else {
- let message = '### Summary by OpenAI\n\n';
+ let message = '### Summary by CodeRabbit\n\n';
message += releaseNotesResponse;
try {
await commenter.updateDescription(context.payload.pull_request.number, message);
@@ -7556,20 +7611,24 @@ ${lib_commenter/* RAW_SUMMARY_END_TAG */.rV}
${lib_commenter/* SHORT_SUMMARY_START_TAG */.O$}
${inputs.shortSummary}
${lib_commenter/* SHORT_SUMMARY_END_TAG */.Zb}
+
---
-### Chat with 🤖 OpenAI Bot (\`@openai\`)
+
+Notes
+
+### Chat with
CodeRabbit Bot (\`@coderabbitai\`)
- Reply on review comments left by this bot to ask follow-up questions. A review comment is a comment on a diff or a file.
-- Invite the bot into a review comment chain by tagging \`@openai\` in a reply.
+- Invite the bot into a review comment chain by tagging \`@coderabbitai\` in a reply.
### Code suggestions
- The bot may make code suggestions, but please review them carefully before committing since the line number ranges may be misaligned.
- You can edit the comment made by the bot and manually tweak the suggestion if it is slightly off.
### Ignoring further reviews
-- Type \`@openai: ignore\` anywhere in the PR description to ignore further reviews from the bot.
+- Type \`@coderabbitai: ignore\` anywhere in the PR description to ignore further reviews from the bot.
----
+
${filterIgnoredFiles.length > 0
? `
@@ -7735,9 +7794,6 @@ ${commentChain}
}
await Promise.all(reviewPromises);
summarizeComment += `
----
-In the recent run, only the files that changed from the \`base\` of the PR and between \`${highestReviewedCommitId}\` and \`${context.payload.pull_request.head.sha}\` commits were reviewed.
-
${reviewsFailed.length > 0
? `
Files not reviewed due to errors in the recent run (${reviewsFailed.length})
diff --git a/src/commenter.ts b/src/commenter.ts
index 1b8a4770..9aa036f5 100644
--- a/src/commenter.ts
+++ b/src/commenter.ts
@@ -7,34 +7,40 @@ import {octokit} from './octokit'
const context = github_context
const repo = context.repo
-export const COMMENT_GREETING = ':robot: OpenAI'
+export const COMMENT_GREETING = `
CodeRabbit`
export const COMMENT_TAG =
- ''
+ ''
export const COMMENT_REPLY_TAG =
- ''
+ ''
export const SUMMARIZE_TAG =
- ''
+ ''
+
+export const IN_PROGRESS_START_TAG =
+ ''
+
+export const IN_PROGRESS_END_TAG =
+ ''
export const DESCRIPTION_START_TAG = `
-`
+`
export const DESCRIPTION_END_TAG =
- ''
+ ''
-export const RAW_SUMMARY_START_TAG = `
+export const RAW_SUMMARY_START_TAG = `
-`
+`
-export const SHORT_SUMMARY_START_TAG = `
+export const SHORT_SUMMARY_START_TAG = `
-`
+`
export const COMMIT_ID_START_TAG = ''
export const COMMIT_ID_END_TAG = ''
@@ -557,13 +563,19 @@ ${chain}
async create(body: string, target: number) {
try {
// get comment ID from the response
- await octokit.issues.createComment({
+ const response = await octokit.issues.createComment({
owner: repo.owner,
repo: 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}`)
}
@@ -718,4 +730,48 @@ ${chain}
return allCommits
}
+
+ // add in-progress status to the comment body
+ addInProgressStatus(
+ commentBody: string,
+ headCommitId: string,
+ highestReviewedCommitId: string
+ ): string {
+ const start = commentBody.indexOf(IN_PROGRESS_START_TAG)
+ const end = commentBody.indexOf(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 `${IN_PROGRESS_START_TAG}
+
+Currently reviewing new changes in this PR...
+
+
+Details
+The files that changed from the \`base\` of the PR and between \`${highestReviewedCommitId}\` and \`${headCommitId}\` commits are being reviewed.
+
+
+${IN_PROGRESS_END_TAG}
+
+---
+
+${commentBody}`
+ }
+ return commentBody
+ }
+
+ // remove in-progress status from the comment body
+ removeInProgressStatus(commentBody: string): string {
+ const start = commentBody.indexOf(IN_PROGRESS_START_TAG)
+ const end = commentBody.indexOf(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 + IN_PROGRESS_END_TAG.length)
+ )
+ }
+ return commentBody
+ }
}
diff --git a/src/review-comment.ts b/src/review-comment.ts
index 1a5b0b17..f42c53db 100644
--- a/src/review-comment.ts
+++ b/src/review-comment.ts
@@ -17,7 +17,7 @@ import {getTokenCount} from './tokenizer'
// eslint-disable-next-line camelcase
const context = github_context
const repo = context.repo
-const ASK_BOT = '@openai'
+const ASK_BOT = '@coderabbitai'
export const handleReviewComment = async (
heavyBot: Bot,
diff --git a/src/review.ts b/src/review.ts
index 9d73d34b..867f7b0a 100644
--- a/src/review.ts
+++ b/src/review.ts
@@ -22,7 +22,7 @@ import {getTokenCount} from './tokenizer'
const context = github_context
const repo = context.repo
-const ignoreKeyword = '@openai: ignore'
+const ignoreKeyword = '@coderabbitai: ignore'
export const codeReview = async (
lightBot: Bot,
@@ -72,11 +72,13 @@ export const codeReview = async (
context.payload.pull_request.number
)
let existingCommitIdsBlock = ''
+ let existingSummarizeCmtBody = ''
if (existingSummarizeCmt != null) {
- inputs.rawSummary = commenter.getRawSummary(existingSummarizeCmt.body)
- inputs.shortSummary = commenter.getShortSummary(existingSummarizeCmt.body)
+ existingSummarizeCmtBody = existingSummarizeCmt.body
+ inputs.rawSummary = commenter.getRawSummary(existingSummarizeCmtBody)
+ inputs.shortSummary = commenter.getShortSummary(existingSummarizeCmtBody)
existingCommitIdsBlock = commenter.getReviewedCommitIdsBlock(
- existingSummarizeCmt.body
+ existingSummarizeCmtBody
)
}
@@ -140,13 +142,6 @@ export const codeReview = async (
return
}
- const commits = incrementalDiff.data.commits
-
- if (commits.length === 0) {
- warning('Skipped: ommits is null')
- return
- }
-
// skip files if they are filtered out
const filterSelectedFiles = []
const filterIgnoredFiles = []
@@ -159,6 +154,18 @@ export const codeReview = async (
}
}
+ if (filterSelectedFiles.length === 0) {
+ warning('Skipped: filterSelectedFiles is null')
+ return
+ }
+
+ const commits = incrementalDiff.data.commits
+
+ if (commits.length === 0) {
+ warning('Skipped: commits is null')
+ return
+ }
+
// find hunks to review
const filteredFiles: Array<
[string, string, string, Array<[number, number, string]>] | null
@@ -255,6 +262,16 @@ ${hunks.oldHunk}
return
}
+ // update the existing comment with in progress status
+ const inProgressSummarizeCmt = commenter.addInProgressStatus(
+ existingSummarizeCmtBody,
+ context.payload.pull_request.head.sha,
+ highestReviewedCommitId
+ )
+
+ // add in progress status to the summarize comment
+ await commenter.comment(`${inProgressSummarizeCmt}`, SUMMARIZE_TAG, 'replace')
+
const summariesFailed: string[] = []
const doSummary = async (
@@ -385,7 +402,7 @@ ${filename}: ${summary}
if (releaseNotesResponse === '') {
info('release notes: nothing obtained from openai')
} else {
- let message = '### Summary by OpenAI\n\n'
+ let message = '### Summary by CodeRabbit OSS\n\n'
message += releaseNotesResponse
try {
await commenter.updateDescription(
@@ -412,20 +429,24 @@ ${RAW_SUMMARY_END_TAG}
${SHORT_SUMMARY_START_TAG}
${inputs.shortSummary}
${SHORT_SUMMARY_END_TAG}
+
---
-### Chat with 🤖 OpenAI Bot (\`@openai\`)
+
+Notes
+
+### Chat with
CodeRabbit Bot (\`@coderabbitai\`)
- Reply on review comments left by this bot to ask follow-up questions. A review comment is a comment on a diff or a file.
-- Invite the bot into a review comment chain by tagging \`@openai\` in a reply.
+- Invite the bot into a review comment chain by tagging \`@coderabbitai\` in a reply.
### Code suggestions
- The bot may make code suggestions, but please review them carefully before committing since the line number ranges may be misaligned.
- You can edit the comment made by the bot and manually tweak the suggestion if it is slightly off.
### Ignoring further reviews
-- Type \`@openai: ignore\` anywhere in the PR description to ignore further reviews from the bot.
+- Type \`@coderabbitai: ignore\` anywhere in the PR description to ignore further reviews from the bot.
----
+
${
filterIgnoredFiles.length > 0
@@ -653,11 +674,6 @@ ${commentChain}
await Promise.all(reviewPromises)
summarizeComment += `
----
-In the recent run, only the files that changed from the \`base\` of the PR and between \`${highestReviewedCommitId}\` and \`${
- context.payload.pull_request.head.sha
- }\` commits were reviewed.
-
${
reviewsFailed.length > 0
? `