Skip to content
This repository was archived by the owner on Mar 6, 2024. It is now read-only.

Commit 7751de6

Browse files
authored
provide option to review simple changes (#232)
1 parent 85a79e3 commit 7751de6

File tree

7 files changed

+131
-59
lines changed

7 files changed

+131
-59
lines changed

README.md

Lines changed: 46 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,47 @@
55
## Overview
66

77
This [OpenAI ChatGPT-based](https://platform.openai.com/docs/guides/chat) GitHub
8-
Action provides a summary, release notes and review of pull requests. The
9-
prompts have been tuned for a concise response. To prevent excessive
10-
notifications, this action can be configured to skip adding review comments when
11-
the changes look good for the most part.
12-
13-
In addition, this action can also reply to the user comments made on the review
14-
by this action.
8+
Action provides a summary, release notes and review of pull requests. The unique
9+
features of this action are:
10+
11+
- Unlike other approaches that provide a simple summary and/or conversation,
12+
this action reviews the changes line by line and provides code change
13+
suggestions that can be directly committed from the GitHub UI. The prompts
14+
have been tuned carefully to comment on exact lines within changed hunks of
15+
code.
16+
- Continuous, yet incremental, reviews on each commit with a pull request. This
17+
is unlike other approaches that provide a one-time review on the entire pull
18+
request when requested by the user.
19+
- Incremental reviews save on OpenAI costs while also reducing noise. Changed
20+
files are tracked between commits and the base of the pull request
21+
- The action is designed to be used with a "light" summarization model (e.g.
22+
`gpt-3.5-turbo`) and a "heavy" review model (e.g. `gpt-4`). This allows for a
23+
cheaper and faster summarization process and a more accurate review process.
24+
**For best results, setting `gpt-4` as the "heavy" model instead of the
25+
`gpt-3.5-turbo` (default) is highly recommended.**
26+
- This action supports a conversation with the bot in the context of lines of
27+
code or entire files. Useful for providing further context to the bot for its
28+
next review, to generate test cases, to reduce complexity of the code and so
29+
on.
30+
- By default, the action is configured to skip more in-depth review when the
31+
changes are simple (e.g. typo fixes). This is based on the triage done during
32+
the summarization stage. This feature can be disabled by setting
33+
`review_simple_changes` to `true`.
34+
- By default, the action is configured to skip adding review comments when the
35+
changes look good for the most part. This feature can be disabled by setting
36+
`review_comment_lgtm` to `true`.
37+
- You can tailor the following prompts:
38+
- `system_message`: Defines the objective and the personality of the bot. You
39+
can change this prompt to focus on or ignore certain aspects of the review
40+
process, e.g. documentation, code quality, etc. Furthermore, you can even
41+
change the bot to do marketing material review instead of code review.
42+
- `summarize`: Summarizes the pull request into a table of changes etc.
43+
- `summarize_release_notes`: Summarize the changes in the pull request for
44+
release notes purposes.
45+
- You can altogether skip the reviews, setting the `summary_only` to `true`. But
46+
that defeats the main purpose of this action. Other tools such as GitHub's
47+
[Copliot for Pull Requests](https://githubnext.com/projects/copilot-for-pull-requests)
48+
may be a cheaper and good enough alternative in that case.
1549

1650
NOTES:
1751

@@ -58,6 +92,7 @@ jobs:
5892
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
5993
with:
6094
debug: false
95+
review_simple_changes: false
6196
review_comment_lgtm: false
6297
```
6398
@@ -101,7 +136,9 @@ To ignore a PR, add the following keyword in the PR description:
101136
- `OPENAI_API_KEY`: use this to authenticate with OpenAI API. You can get one
102137
[here](https://platform.openai.com/account/api-keys). Please add this key to
103138
your GitHub Action secrets.
104-
- `OPENAI_API_ORG`: (optional) use this to use the specified organisation with OpenAI API if you have multiple. Please add this key to your GitHub Action secrets.
139+
- `OPENAI_API_ORG`: (optional) use this to use the specified organisation with
140+
OpenAI API if you have multiple. Please add this key to your GitHub Action
141+
secrets.
105142

106143
### Models: `gpt-4` and `gpt-3.5-turbo`
107144

@@ -217,6 +254,7 @@ jobs:
217254
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
218255
with:
219256
debug: false
257+
review_simple_changes: false
220258
review_comment_lgtm: false
221259
```
222260

action.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@ inputs:
1515
'Max files to summarize and review. Less than or equal to 0 means no
1616
limit.'
1717
default: '150'
18+
review_simple_changes:
19+
required: false
20+
description: 'Review even when the changes are simple'
21+
default: 'false'
1822
review_comment_lgtm:
1923
required: false
2024
description: 'Leave comments even if the patch is LGTM'

dist/index.js

Lines changed: 36 additions & 26 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/main.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ async function run(): Promise<void> {
1616
getBooleanInput('debug'),
1717
getBooleanInput('summary_only'),
1818
getInput('max_files'),
19+
getBooleanInput('review_simple_changes'),
1920
getBooleanInput('review_comment_lgtm'),
2021
getMultilineInput('path_filters'),
2122
getInput('system_message'),

src/options.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ export class Options {
66
debug: boolean
77
summaryOnly: boolean
88
maxFiles: number
9+
reviewSimpleChanges: boolean
910
reviewCommentLGTM: boolean
1011
pathFilters: PathFilter
1112
systemMessage: string
@@ -22,6 +23,7 @@ export class Options {
2223
debug: boolean,
2324
summaryOnly: boolean,
2425
maxFiles = '0',
26+
reviewSimpleChanges = false,
2527
reviewCommentLGTM = false,
2628
pathFilters: string[] | null = null,
2729
systemMessage = '',
@@ -35,6 +37,7 @@ export class Options {
3537
this.debug = debug
3638
this.summaryOnly = summaryOnly
3739
this.maxFiles = parseInt(maxFiles)
40+
this.reviewSimpleChanges = reviewSimpleChanges
3841
this.reviewCommentLGTM = reviewCommentLGTM
3942
this.pathFilters = new PathFilter(pathFilters)
4043
this.systemMessage = systemMessage
@@ -53,6 +56,7 @@ export class Options {
5356
info(`debug: ${this.debug}`)
5457
info(`summary_only: ${this.summaryOnly}`)
5558
info(`max_files: ${this.maxFiles}`)
59+
info(`review_simple_changes: ${this.reviewSimpleChanges}`)
5660
info(`review_comment_lgtm: ${this.reviewCommentLGTM}`)
5761
info(`path_filters: ${this.pathFilters}`)
5862
info(`system_message: ${this.systemMessage}`)

src/prompts.ts

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@ $file_diff
2323
\`\`\`
2424
2525
I would like you to summarize the diff within 50 words.
26-
27-
Below the summary, I would also like you to triage the diff as \`NEEDS_REVIEW\` or
26+
`
27+
triageFileDiff = `Below the summary, I would also like you to triage the diff as \`NEEDS_REVIEW\` or
2828
\`APPROVED\` based on the following criteria:
2929
3030
- If the diff involves any modifications to the logic or functionality, even if they
@@ -248,8 +248,15 @@ $patches
248248
this.summarizeReleaseNotes = summarizeReleaseNotes
249249
}
250250

251-
renderSummarizeFileDiff(inputs: Inputs): string {
252-
return inputs.render(this.summarizeFileDiff)
251+
renderSummarizeFileDiff(
252+
inputs: Inputs,
253+
reviewSimpleChanges: boolean
254+
): string {
255+
let prompt = this.summarizeFileDiff
256+
if (reviewSimpleChanges === false) {
257+
prompt += this.triageFileDiff
258+
}
259+
return inputs.render(prompt)
253260
}
254261

255262
renderSummarizeChangesets(inputs: Inputs): string {

src/review.ts

Lines changed: 29 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,9 @@ ${hunks.oldHunk}
261261
ins.filename = filename
262262

263263
// render prompt based on inputs so far
264-
let tokens = getTokenCount(prompts.renderSummarizeFileDiff(ins))
264+
let tokens = getTokenCount(
265+
prompts.renderSummarizeFileDiff(ins, options.reviewSimpleChanges)
266+
)
265267

266268
const diffTokens = getTokenCount(fileDiff)
267269
if (tokens + diffTokens > options.lightTokenLimits.requestTokens) {
@@ -291,7 +293,7 @@ ${hunks.oldHunk}
291293
// summarize content
292294
try {
293295
const [summarizeResp] = await lightBot.chat(
294-
prompts.renderSummarizeFileDiff(ins),
296+
prompts.renderSummarizeFileDiff(ins, options.reviewSimpleChanges),
295297
{}
296298
)
297299

@@ -300,23 +302,24 @@ ${hunks.oldHunk}
300302
summariesFailed.push(`${filename} (nothing obtained from openai)`)
301303
return null
302304
} else {
303-
// parse the comment to look for triage classification
304-
// Format is : [TRIAGE]: <NEEDS_REVIEW or APPROVED>
305-
// if the change needs review return true, else false
306-
const triageRegex = /\[TRIAGE\]:\s*(NEEDS_REVIEW|APPROVED)/
307-
const triageMatch = summarizeResp.match(triageRegex)
308-
309-
if (triageMatch != null) {
310-
const triage = triageMatch[1]
311-
const needsReview = triage === 'NEEDS_REVIEW'
312-
313-
// remove this line from the comment
314-
const summary = summarizeResp.replace(triageRegex, '').trim()
315-
info(`filename: ${filename}, triage: ${triage}`)
316-
return [filename, summary, needsReview]
317-
} else {
318-
return [filename, summarizeResp, true]
305+
if (options.reviewSimpleChanges === false) {
306+
// parse the comment to look for triage classification
307+
// Format is : [TRIAGE]: <NEEDS_REVIEW or APPROVED>
308+
// if the change needs review return true, else false
309+
const triageRegex = /\[TRIAGE\]:\s*(NEEDS_REVIEW|APPROVED)/
310+
const triageMatch = summarizeResp.match(triageRegex)
311+
312+
if (triageMatch != null) {
313+
const triage = triageMatch[1]
314+
const needsReview = triage === 'NEEDS_REVIEW'
315+
316+
// remove this line from the comment
317+
const summary = summarizeResp.replace(triageRegex, '').trim()
318+
info(`filename: ${filename}, triage: ${triage}`)
319+
return [filename, summary, needsReview]
320+
}
319321
}
322+
return [filename, summarizeResp, true]
320323
}
321324
} catch (e: any) {
322325
warning(`summarize: error from openai: ${e as string}`)
@@ -653,14 +656,19 @@ ${commentChain}
653656
await Promise.all(reviewPromises)
654657

655658
summarizeComment += `
659+
---
660+
In the recent run, only the files that changed from the \`base\` of the PR and between \`${highestReviewedCommitId}\` and \`${
661+
context.payload.pull_request.head.sha
662+
}\` commits were reviewed.
663+
656664
${
657665
reviewsFailed.length > 0
658666
? `<details>
659-
<summary>Files not reviewed due to errors in this run (${
667+
<summary>Files not reviewed due to errors in the recent run (${
660668
reviewsFailed.length
661669
})</summary>
662670
663-
### Failed to review
671+
### Failed to review in the last run
664672
665673
* ${reviewsFailed.join('\n* ')}
666674
@@ -676,7 +684,7 @@ ${
676684
reviewsSkipped.length
677685
})</summary>
678686
679-
### Skipped review
687+
### Skipped review in the recent run
680688
681689
* ${reviewsSkipped.join('\n* ')}
682690

0 commit comments

Comments
 (0)