Reads the diff of each open pull request, has AI note the obvious problems, and posts them as a comment.
Uses
GitHub
OpenAI
AI first-pass review on open pull requests
repositoryOwner to blank.Set repositoryOwner to blank.repositoryName to blank.Set repositoryName to blank.repositoryReadToken to blank.Set repositoryReadToken to blank.reviewedLabel to first-pass-reviewed.Set reviewedLabel to first-pass-reviewed.maxPullRequestsPerRun to 5.Set maxPullRequestsPerRun to 5.maxFilesPerReview to 20.Set maxFilesPerReview to 20.maxDiffCharactersPerFile to 3000.Set maxDiffCharactersPerFile to 3000.githubHeaders to a record of Authorization, Accept, and X-GitHub-Api-Version.Set githubHeaders to a record of Authorization, Accept, and X-GitHub-Api-Version.https://api.github.com/repos/, repositoryOwner, /, repositoryName] with nothing and save it as repositoryApiUrl.Join a list of [https://api.github.com/repos/, repositoryOwner, /, repositoryName] with nothing and save it as repositoryApiUrl.repositoryApiUrl, /pulls] with nothing and save it as openPullRequestsUrl.Join a list of [repositoryApiUrl, /pulls] with nothing and save it as openPullRequestsUrl.openPullRequests.Start an empty list and save it as openPullRequests.pullRequestListErrorIf a step below fails, save the error as pullRequestListErrorTry
openPullRequests to <expr>.body.Change openPullRequests to <expr>.body.On error
Could not read the open pull requests from GitHub: , pullRequestListError.message with openPullRequestsUrl replaced by the GitHub API address, Check the repository details and the token in the 'repositoryReadToken' step.] joined by nothing.Stop and report a problem: a list of [Could not read the open pull requests from GitHub: , pullRequestListError.message with openPullRequestsUrl replaced by the GitHub API address, Check the repository details and the token in the 'repositoryReadToken' step.] joined by nothing.reviewedThisRun to 0.Set reviewedThisRun to 0.pullRequest in openPullRequests:For each pullRequest in openPullRequests:reviewedThisRun is greater than or equal to maxPullRequestsPerRunIf reviewedThisRun is greater than or equal to maxPullRequestsPerRunYes
Reviewed , maxPullRequestsPerRun, pull requests, which is this run's limit. The rest keep their place in the queue and are picked up on the next run.] joined by nothing.Show in the output: a list of [Reviewed , maxPullRequestsPerRun, pull requests, which is this run's limit. The rest keep their place in the queue and are picked up on the next run.] joined by nothing.No
No steps
pullNumber to pullRequest.number.Set pullNumber to pullRequest.number.pullNumber is noIf pullNumber is noYes
Skipped a pull request that GitHub returned without a number, so there was nothing to comment on..Show in the output: Skipped a pull request that GitHub returned without a number, so there was nothing to comment on..No
No steps
pullRequest.draft is yesIf pullRequest.draft is yesYes
Pull request #, pullNumber, is still a draft, so it was left alone.] joined by nothing.Show in the output: a list of [Pull request #, pullNumber, is still a draft, so it was left alone.] joined by nothing.No
No steps
alreadyReviewed to false.Set alreadyReviewed to false.pullRequestLabel in pullRequest.labels:For each pullRequestLabel in pullRequest.labels:pullRequestLabel.name is reviewedLabelIf pullRequestLabel.name is reviewedLabelYes
alreadyReviewed to true.Change alreadyReviewed to true.No
No steps
alreadyReviewed is yesIf alreadyReviewed is yesYes
No
No steps
repositoryApiUrl, /pulls/, pullNumber, /files] with nothing and save it as changedFilesUrl.Join a list of [repositoryApiUrl, /pulls/, pullNumber, /files] with nothing and save it as changedFilesUrl.changedFiles.Start an empty list and save it as changedFiles.changedFilesErrorIf a step below fails, save the error as changedFilesErrorTry
changedFiles to <expr>.body.Change changedFiles to <expr>.body.On error
Could not read the changed files for pull request #, pullNumber, : , changedFilesError.message with changedFilesUrl replaced by the GitHub API address] joined by nothing.Show in the output: a list of [Could not read the changed files for pull request #, pullNumber, : , changedFilesError.message with changedFilesUrl replaced by the GitHub API address] joined by nothing.changedFiles is noIf changedFiles is noYes
Pull request #, pullNumber, has no changed files this workflow can read, so it was left for a human.] joined by nothing.Show in the output: a list of [Pull request #, pullNumber, has no changed files this workflow can read, so it was left for a human.] joined by nothing.No
No steps
changedFiles and save it as changedFileCount.Count the items in changedFiles and save it as changedFileCount.maxFilesPerReview items of changedFiles and save it as filesToReview.Take the first maxFilesPerReview items of changedFiles and save it as filesToReview.filesToReview and save it as reviewedFileCount.Count the items in filesToReview and save it as reviewedFileCount.diffBlocks.Start an empty list and save it as diffBlocks.changedFile in filesToReview:For each changedFile in filesToReview:changedFileName to blank.Set changedFileName to blank.fileNameErrorIf a step below fails, save the error as fileNameErrorTry
changedFile.filename and save it as changedFileName.Trim changedFile.filename and save it as changedFileName.On error
changedFileName to blank.Change changedFileName to blank.changedFileName is emptyIf changedFileName is emptyYes
Skipped a changed file in pull request #, pullNumber, because GitHub returned it without a filename.] joined by nothing.Show in the output: a list of [Skipped a changed file in pull request #, pullNumber, because GitHub returned it without a filename.] joined by nothing.No
No steps
changedFilePatch to blank.Set changedFilePatch to blank.filePatchErrorIf a step below fails, save the error as filePatchErrorTry
changedFile.patch and save it as changedFilePatch.Trim changedFile.patch and save it as changedFilePatch.On error
changedFilePatch to blank.Change changedFilePatch to blank.diffBlockBody to (GitHub sent no text diff for this file - it may be binary, a pure rename, or too large to display.).Set diffBlockBody to (GitHub sent no text diff for this file - it may be binary, a pure rename, or too large to display.).changedFilePatch isn't emptyIf changedFilePatch isn't emptyYes
changedFilePatch to maxDiffCharactersPerFile characters and save it as diffBlockBody.Shorten changedFilePatch to maxDiffCharactersPerFile characters and save it as diffBlockBody.No
No steps
File: , changedFileName, "Add a list of [File: , changedFileName,
, diffBlockBody] joined by nothing to the end of diffBlocks and save it as diffBlocks.diffBlocks is noIf diffBlocks is noYes
None of the changed files in pull request #, pullNumber, could be read, so it was left for a human.] joined by nothing.Show in the output: a list of [None of the changed files in pull request #, pullNumber, could be read, so it was left for a human.] joined by nothing.No
No steps
coverageNote to blank.Set coverageNote to blank.changedFileCount is greater than reviewedFileCountIf changedFileCount is greater than reviewedFileCountYes
This pull request changes , changedFileCount, files. This first pass read only the first , reviewedFileCount, of them, in the order GitHub lists them - the rest have not been looked at.] with nothing and save it as coverageNote.Join a list of [This pull request changes , changedFileCount, files. This first pass read only the first , reviewedFileCount, of them, in the order GitHub lists them - the rest have not been looked at.] with nothing and save it as coverageNote.No
This first pass read all , changedFileCount, changed files.] with nothing and save it as coverageNote.Join a list of [This first pass read all , changedFileCount, changed files.] with nothing and save it as coverageNote.You are giving a pull request a first-pass read for a human reviewer who has not opened it yet.
, Repository: , repositoryOwner, /, repositoryName,
Pull request #, pullNumber, : , pullRequest.title,
Opened by: , pullRequest.user.login,
, coverageNote,
The changed files and their diffs follow. Lines starting with + or - are the change itself.
, diffBlocks joined by a blank line,
Write short markdown bullet points about what is plainly visible in the diff above:
- error handling that looks missing, such as an unchecked failure or a swallowed exception
- names that do not say what the thing is
- new behaviour that arrives without a test
- anything else obviously risky, such as a hardcoded secret or an unbounded loop
Group the points by file and quote the identifier or the line you mean. Make at most eight points, most important first. If nothing stands out, reply with the single sentence: Nothing obvious stood out in this first pass. Do not approve the pull request, do not say LGTM, and do not suggest merging - a human decides that. Do not comment on anything that is not in the diff above.] with nothing and save it as reviewPrompt.reviewText to blank.Set reviewText to blank.reviewErrorIf a step below fails, save the error as reviewErrorTry
reviewText.Trim the response text from the OpenAI “Ask OpenAI” step and save it as reviewText.On error
Could not get a first-pass review for pull request #, pullNumber, : , reviewError.message] joined by nothing.Show in the output: a list of [Could not get a first-pass review for pull request #, pullNumber, : , reviewError.message] joined by nothing.reviewText is emptyIf reviewText is emptyYes
The model returned nothing for pull request #, pullNumber, , so no comment was posted and it stays unlabelled for the next run.] joined by nothing.Show in the output: a list of [The model returned nothing for pull request #, pullNumber, , so no comment was posted and it stays unlabelled for the next run.] joined by nothing.No
No steps
### Automated first-pass review
, coverageNote,
, reviewText,
This is a first pass, meant to give a human reviewer somewhere to start. It is not an approval, and this workflow never approves, merges or closes anything. Remove the ', reviewedLabel, ' label from this pull request to have it looked at again.] with nothing and save it as commentBody.pullNumber in repositoryOwner/repositoryName.Comment on issue pullNumber in repositoryOwner/repositoryName.commentBodylabelErrorIf a step below fails, save the error as labelErrorTry
reviewedLabel to issue pullNumber in repositoryOwner/repositoryName.Add label reviewedLabel to issue pullNumber in repositoryOwner/repositoryName.On error
Commented on pull request #, pullNumber, but could not add the ', reviewedLabel, ' label, so the next run will comment on it again. Add the label by hand to stop that: , labelError.message] joined by nothing.Show in the output: a list of [Commented on pull request #, pullNumber, but could not add the ', reviewedLabel, ' label, so the next run will comment on it again. Add the label by hand to stop that: , labelError.message] joined by nothing.reviewedThisRun.Add 1 to reviewedThisRun.First-pass review finished. Commented on , reviewedThisRun, pull request(s).] joined by nothing.Show in the output: a list of [First-pass review finished. Commented on , reviewedThisRun, pull request(s).] joined by nothing.