Last active
April 1, 2022 15:05
-
-
Save jeromepl/02e70f3ea4a4e8103da6f96f14eb213c to your computer and use it in GitHub Desktop.
Mark as "Ready for review" and assign reviewers on GitHub pull requests after test suite passes
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
#!/bin/bash | |
set -eou pipefail | |
# This script was partially inspired by https://arturdryomov.dev/posts/auto-github-pull-requests/ | |
# Few notes about some of the decisions that led to the code below: | |
# - The GitHub REST API does not support the marking PRs as ready for review. | |
# Instead, this has to be done through the GraphQL API, **and** requires a | |
# personal access token since the Github Action default token cannot have | |
# the required permission | |
# - It would have been cleaner to split up all the queries in this file as | |
# different "steps" in the workflow file. However, I found that to be | |
# massively more painful to test and debug, as you cannot run the whole | |
# flow locally easily. Having it all in this single bash script makes it | |
# really easy to test. Simply generate a personal access token in your | |
# GitHub account settings! | |
# - The only dependency is currently `jq`, to help with parsing the JSON | |
# output of GitHub API queries. Note that we could consider also using | |
# `gh` (the GitHub cli) in the future as it could simplify this code | |
# quite a bit | |
TOKEN="${1}" | |
PR_NUMBERS="${2}" | |
LABEL="autoready" | |
REPO="your-repository" | |
ORGANIZATION="potloc" | |
# Split the numbers string (comma-delimited) | |
for pr_number in $(echo $PR_NUMBERS | tr "," "\n"); do | |
# Get the node_id (and labels) from the PR number | |
# - https://docs.github.com/en/graphql/guides/using-global-node-ids | |
# - https://docs.github.com/en/rest/reference/pulls#get-a-pull-request | |
out=$(curl \ | |
--fail \ | |
--silent \ | |
--show-error \ | |
--header "Accept: application/vnd.github.v3+json" \ | |
--header "Authorization: token ${TOKEN}" \ | |
--request "GET" \ | |
--url "https://api.github.com/repos/${ORGANIZATION}/${REPO}/pulls/${pr_number}" | |
) | |
node_id=$(jq -r '.node_id' <<< $out) | |
contains_label=$(jq "any(.labels[].name == \"${LABEL}\"; .)" <<< $out) | |
comments_url=$(jq -r ".comments_url" <<< $out) | |
# Check if the PR contains the label we want | |
if [ "$contains_label" == "true" ]; then | |
# Mark the PR as ready for review | |
curl \ | |
--fail \ | |
--silent \ | |
--show-error \ | |
--header "Content-Type: application/json" \ | |
--header "Authorization: token ${TOKEN}" \ | |
--request "POST" \ | |
--data "{ \"query\": \"mutation { markPullRequestReadyForReview(input: { pullRequestId: \\\"${node_id}\\\" }) { pullRequest { id } } }\" }" \ | |
--url https://api.github.com/graphql | |
# Remove the label | |
curl \ | |
--request "DELETE" \ | |
--header "Accept: application/vnd.github.v3+json" \ | |
--header "Authorization: token ${TOKEN}" \ | |
--url "https://api.github.com/repos/${ORGANIZATION}/${REPO}/issues/${pr_number}/labels/${LABEL}" | |
# Get the comments on the PR | |
comments_out=$(curl \ | |
--fail \ | |
--silent \ | |
--show-error \ | |
--header "Content-Type: application/vnd.github.v3+json" \ | |
--header "Authorization: token ${TOKEN}" \ | |
--request "GET" \ | |
--url $comments_url) | |
# Look for a comment matching the 'autoready-reviewers: ' pattern | |
# If found, assign the mentionned reviewers to review this PR | |
jq -r ".[].body" <<< $comments_out | while IFS='' read comment; do | |
if [[ $comment =~ autoready-reviewers:[[:space:]]([a-zA-Z0-9,\-\/]+) ]]; then | |
all_reviewers=${BASH_REMATCH[1]} | |
# Split the reviewers between teams and individuals | |
reviewers_array=() | |
team_reviewers_array=() | |
for reviewer in $(echo $all_reviewers | tr "," "\n"); do | |
if [[ $reviewer =~ [a-zA-Z0-9,\-]+\/[a-zA-Z0-9,\-]+ ]]; then | |
# In the case of a team reviewer, only take the part of the username after the '/': | |
slug_array=(${reviewer//\// }) | |
team_slug=${slug_array[1]} | |
team_reviewers_array+=("\"$team_slug\"") | |
else | |
reviewers_array+=("\"$reviewer\"") | |
fi | |
done | |
# Join the array elements into a single comma-separated string: | |
reviewers=$(IFS=, ; echo "${reviewers_array[*]}") | |
team_reviewers=$(IFS=, ; echo "${team_reviewers_array[*]}") | |
# Assign reviewers | |
curl \ | |
--fail \ | |
--silent \ | |
--show-error \ | |
--output /dev/null \ | |
--header "Accept: application/vnd.github.v3+json" \ | |
--header "Authorization: token ${TOKEN}" \ | |
--request "POST" \ | |
--url "https://api.github.com/repos/${ORGANIZATION}/${REPO}/pulls/${pr_number}/requested_reviewers" \ | |
--data "{\"reviewers\":[${reviewers}], \"team_reviewers\":[${team_reviewers}]}" | |
break | |
fi | |
done | |
fi | |
done |
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
name: Ready For Review | |
on: | |
workflow_run: | |
workflows: ["Test"] # Change this to the name of your own workflow | |
branches-ignore: [main] | |
types: | |
- completed | |
jobs: | |
mark_as_ready_for_review: | |
runs-on: self-hosted | |
if: ${{ github.event.workflow_run.conclusion == 'success' }} | |
steps: | |
- name: Checkout Code | |
uses: actions/checkout@v3 | |
- name: Mark as Ready for Review | |
run: bash .github/workflows/mark_as_ready_for_review.sh "${{ secrets.ACCESS_TOKEN }}" "${{ join(github.event.workflow_run.pull_requests.*.number) }}" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment