-
Notifications
You must be signed in to change notification settings - Fork 110
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
12 changed files
with
261 additions
and
106 deletions.
There are no files selected for viewing
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
name: Comment on review | ||
|
||
on: | ||
workflow_run: | ||
workflows: [Generate comment body on review] | ||
types: [completed] | ||
|
||
|
||
jobs: | ||
comment: | ||
runs-on: ubuntu-latest | ||
if: ${{ github.event.workflow_run.conclusion == 'success' }} | ||
permissions: | ||
pull-requests: write | ||
actions: read | ||
steps: | ||
- name: Download artifact | ||
uses: actions/download-artifact@v4 | ||
with: | ||
name: comment_body_on_review | ||
run-id: ${{ github.event.workflow_run.id}} | ||
github-token: ${{ secrets.GITHUB_TOKEN }} | ||
- name: Send a comment | ||
env: | ||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
GH_REPO: ${{ github.repository }} | ||
run: | ||
gh pr comment "$(cat PR_NUMBER)" --body "$(cat COMMENT_BODY.txt)" --repo "$GH_REPO" | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
# This workflow generates a comment body on an approval. | ||
# It generates the body and saves it as an artifact. | ||
# A following workflow called from `workflow_run` event uses the artifact. | ||
# | ||
# These workflows are separated due to GITHUB_TOKEN's permission. | ||
# GitHub does not allow `write` permission on public fork repositories on `pull_request_review` event. | ||
# Therefore we need to use `workflow_run` event to permit `write` actions to the token. | ||
|
||
name: 'Generate comment body on review' | ||
|
||
on: | ||
pull_request_review: | ||
types: [submitted] | ||
|
||
jobs: | ||
create_comment: | ||
if: github.event.review.state != 'CHANGES_REQUESTED' | ||
runs-on: 'ubuntu-latest' | ||
env: | ||
BASE_SHA: ${{ github.event.pull_request.base.sha }} | ||
HEAD_SHA: ${{ github.event.pull_request.head.sha }} | ||
PR_AUTHOR: ${{ github.event.pull_request.user.login }} | ||
GH_REPO: ${{ github.repository }} | ||
steps: | ||
- uses: actions/checkout@v4 | ||
with: | ||
filter: 'blob:none' | ||
fetch-depth: 0 | ||
ref: main | ||
- uses: ruby/setup-ruby@v1 | ||
with: | ||
ruby-version: '3.3' | ||
bundler-cache: true | ||
- name: Changed gems and non gem files | ||
id: changes | ||
run: | | ||
ruby .github/workflows/pr_bot/changed_files.rb | ||
- name: Prepare comment body | ||
id: comment-body | ||
env: | ||
CHANGED_GEMS: ${{ steps.changes.outputs.gems }} | ||
CHANGED_NON_GEMS: ${{ steps.changes.outputs.non_gems }} | ||
PR_NUMBER: ${{ github.event.pull_request.number }} | ||
REVIEWED_BY: ${{ github.event.review.user.login }} | ||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
run: | | ||
ruby .github/workflows/pr_bot/review_result_comment_body.rb "$CHANGED_GEMS" "$CHANGED_NON_GEMS" "$PR_NUMBER" COMMENT_BODY.txt | ||
echo "$PR_NUMBER" > PR_NUMBER | ||
- name: Store comment body | ||
uses: actions/upload-artifact@v4 | ||
with: | ||
name: comment_body_on_review | ||
path: | | ||
COMMENT_BODY.txt | ||
PR_NUMBER | ||
retention-days: 1 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,17 +1,34 @@ | ||
require_relative "./utils" | ||
require_relative "./merge_ability" | ||
|
||
def can_merge?(commented_by, author, gem_reviewers) | ||
return true if commented_by == author | ||
return true if administorators.include?(commented_by) | ||
return true if gem_reviewers.include?(commented_by) | ||
return false | ||
def comment_to_github(body, pr_number) | ||
sh! 'gh', 'pr', 'comment', pr_number, '--body', body, '--repo', GH_REPO | ||
end | ||
|
||
def all_gem_reviewers(changed_gems) | ||
changed_gems.flat_map { |gem| gem_reviewers(gem, BASE_SHA) } | ||
changed_gems = JSON.parse(ARGV[0]) | ||
changed_non_gems = JSON.parse(ARGV[1]) | ||
pr_number = ARGV[2] | ||
|
||
ability = MergeAbility.new(changed_gems:, changed_non_gems:, pr_number:) | ||
|
||
unless ability.can_merge_by?(ENV['COMMENTED_BY'], PR_AUTHOR) | ||
body = <<~BODY | ||
`/merge` command failed. | ||
You do not have permission to merge this PR. | ||
PR author, reviewers, and administrators can merge this PR. | ||
BODY | ||
comment_to_github(body, pr_number) | ||
exit 1 | ||
end | ||
|
||
reviewers = all_gem_reviewers(JSON.parse(ARGV[0])) | ||
return if can_merge?(ENV['COMMENTED_BY'], PR_AUTHOR, reviewers) | ||
unless ability.approved? | ||
body = <<~BODY | ||
`/merge` command failed. | ||
raise "You do not have permission to merge this PR." | ||
This PR is not approved yet by the reviewers. Please get approval from the reviewers. | ||
See the Actions tab for detail. | ||
BODY | ||
comment_to_github(body, pr_number) | ||
exit 1 | ||
end |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
require_relative "./utils" | ||
|
||
class MergeAbility | ||
attr_reader :changed_gems, :changed_non_gems, :pr_number | ||
|
||
def initialize(changed_gems:, changed_non_gems:, pr_number:) | ||
@changed_gems = changed_gems | ||
@changed_non_gems = changed_non_gems | ||
@pr_number = pr_number | ||
end | ||
|
||
def approved? | ||
is_approved = true | ||
|
||
# Check gem files | ||
unless not_approved_gems.empty? | ||
log "The following gems are not approved yet:" | ||
log not_approved_gems.join("\n") | ||
is_approved = false | ||
end | ||
|
||
# Check non gem files | ||
if waiting_admin_approval? | ||
log "The following files are changed, but not approved by the admin yet:" | ||
log changed_non_gems.join("\n") | ||
is_approved = false | ||
end | ||
|
||
is_approved | ||
end | ||
|
||
def can_merge_by?(commented_by, author) | ||
return true if commented_by == author | ||
return true if administorators.include?(commented_by) | ||
return true if all_gem_reviewers.include?(commented_by) | ||
return false | ||
end | ||
|
||
def not_approved_gems | ||
@not_approved_gems ||= changed_gems.reject { |gem| gem_accepted?(gem) } | ||
end | ||
|
||
def waiting_admin_approval? | ||
return false if changed_non_gems.empty? | ||
|
||
admins = administorators.map { _1['login'] } | ||
(approvers & admins).empty? | ||
end | ||
|
||
private | ||
|
||
def all_gem_reviewers | ||
@all_gem_reviewers ||= changed_gems.flat_map { |gem| gem_reviewers(gem, BASE_SHA) } | ||
end | ||
|
||
def gem_accepted?(gem) | ||
reviewers = gem_reviewers(gem, BASE_SHA) | ||
|
||
# If reviewers is empty, it means that anyone cannot approve this PR. | ||
# So, we can merge this PR without approval. | ||
return true if reviewers.empty? | ||
|
||
# If the author is a reviewer, they can merge this PR themselves. | ||
return true if reviewers.include?(PR_AUTHOR) | ||
|
||
not (reviewers & approvers).empty? | ||
end | ||
|
||
def approvers | ||
@approvers ||= approvements(HEAD_SHA, pr_number).map { _1['user']['login'] } | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
require_relative "./merge_ability" | ||
|
||
changed_gems = JSON.parse(ARGV[0]) | ||
changed_non_gems = JSON.parse(ARGV[1]) | ||
pr_number = ARGV[2] | ||
file = ARGV[3] | ||
|
||
ability = MergeAbility.new(changed_gems:, changed_non_gems:, pr_number:) | ||
|
||
reviewer = ENV['REVIEWED_BY'] | ||
|
||
msg = "Thanks for your review, @#{reviewer}!\n\n" | ||
|
||
if ability.approved? | ||
msg << <<~MSG | ||
@#{PR_AUTHOR}, @#{reviewer} This PR is ready to be merged. | ||
Just comment `/merge` to merge this PR. | ||
MSG | ||
else | ||
unless ability.not_approved_gems.empty? | ||
msg << <<~MSG | ||
This PR still needs approval from the reviewers of the following gems. | ||
#{ability.not_approved_gems.map { "* `#{_1}`" }.join("\n")} | ||
MSG | ||
end | ||
if ability.waiting_admin_approval? | ||
msg << <<~MSG | ||
This PR still needs approval from the administrators. | ||
MSG | ||
end | ||
|
||
msg << "Please get approval from the reviewers." | ||
end | ||
|
||
File.write(file, msg) |
Oops, something went wrong.