SC Core Dev Approval Check #1137
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
# - Smart Contract Core Dev Approval checker | |
# - makes sure that every pull_request is at least reviewed by one Smart Contract Core Developer | |
# (member of group https://github.com/orgs/lifinance/teams/smart-contract-core) | |
name: SC Core Dev Approval Check | |
on: | |
pull_request_review: | |
types: [submitted] | |
jobs: | |
core-dev-approval: | |
if: ${{ github.event.pull_request.draft == false }} # will only run once the PR is in "Ready for Review" state | |
runs-on: ubuntu-latest | |
steps: | |
- name: Get smart-contract-core Team Members | |
env: | |
GH_PAT: ${{ secrets.GIT_TOKEN }} | |
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
run: | | |
##### unset the default git token (does not have sufficient rights to get team members) | |
unset GITHUB_TOKEN | |
##### use the Personal Access Token to log into git CLI | |
echo $GH_PAT | gh auth login --with-token | |
##### Function that uses github's REST API via CLI to get team members | |
getTeamMembers() { | |
local org=$1 | |
local team=$2 | |
gh api \ | |
-H "Accept: application/vnd.github+json" \ | |
-H "X-GitHub-Api-Version: 2022-11-28" \ | |
"/orgs/$org/teams/$team/members" | jq -r '.[].login' | |
} | |
ORG_NAME="lifinance" | |
TEAM_SLUG="smart-contract-core" | |
# Get members of each group | |
echo "Fetching members of $TEAM_SLUG..." | |
MEMBERS=$(getTeamMembers $ORG_NAME $TEAM_SLUG) | |
#### check if any members were returned | |
if [[ -z $MEMBERS ]]; then | |
echo -e "\033[31mERROR: Could not retrieve team members of group $TEAM_SLUG\033[0m" | |
echo "CONTINUE=false" >> "$GITHUB_ENV" | |
exit 1 | |
fi | |
echo "The following Github users are members of team smart-contract-core: " | |
echo "$MEMBERS" | |
echo -e "$MEMBERS" > sc_core_dev_members.txt | |
echo "CONTINUE=true" >> "$GITHUB_ENV" | |
- name: Check if PR is approved by at least one SC core dev | |
id: check-core-dev-approval | |
if: env.CONTINUE == 'true' | |
uses: actions/github-script@v7 | |
env: | |
PR_NUMBER: ${{ github.event.pull_request.number || github.event.review.pull_request.number }} | |
with: | |
script: | | |
const fs = require('fs'); | |
// ANSI escape codes for colors (used for colored output in Git action console) | |
const colors = { | |
reset: "\033[0m", | |
red: "\033[31m", | |
green: "\033[32m", | |
}; | |
const coreDevsFile = 'sc_core_dev_members.txt'; | |
// Read handles from file | |
const coreDevs = fs.readFileSync(coreDevsFile, 'utf-8').split(/\r?\n/).filter(Boolean); | |
const pullNumber = process.env.PR_NUMBER; | |
if (!pullNumber) { | |
console.log(`${colors.red}No PR number found in context.${colors.reset}`); | |
core.setFailed("PR number is missing."); | |
return; | |
} | |
// get all reviewers that have approved this PR | |
const { data: reviews } = await github.rest.pulls.listReviews({ | |
owner: context.repo.owner, | |
repo: context.repo.repo, | |
pull_number: pullNumber, | |
}); | |
// make sure that reviews are available | |
if(!reviews || reviews.length === 0) { | |
console.log(`${colors.red}Could not get reviewers of this PR from Github. Are there any reviews yet?${colors.reset}`); | |
console.log(`${colors.red}Check failed.${colors.reset}`); | |
core.setFailed("Required approval is missing"); | |
return | |
} | |
// Filter to only include reviews that have "APPROVED" status | |
console.log(JSON.stringify(reviews,null,2)); | |
const approvedReviews = reviews.filter(review => review.state === 'APPROVED'); | |
if(!approvedReviews.length) { | |
console.log(`${colors.red}Could not find any reviews with approval.${colors.reset}`); | |
console.log(`${colors.red}Cannot continue. Check failed.${colors.reset}`); | |
core.setFailed("Required approval is missing"); | |
return | |
} | |
// extract the git login handles of all reviewers that approved this PR | |
const reviewerHandles = approvedReviews.map(review => review.user.login); | |
if(approvedReviews.length === 0) | |
console.log(`${colors.red}This PR has no approvals${colors.reset}`); | |
else | |
console.log(`This PR has been approved by the following git members: ${reviewerHandles}`); | |
// check if at least one of these reviewers is member in smart-contract-core group | |
if (reviewerHandles.some((handle) => coreDevs.includes(handle))) { | |
console.log(`${colors.green}The current PR is approved by a member of the smart-contract-core group.${colors.reset}`); | |
console.log(`${colors.green}Check passed.${colors.reset}`); | |
core.setOutput('approved', 'true'); | |
} else { | |
console.log(`${colors.red}The PR requires a missing approval by a member of the smart-contract-core group (https://github.com/orgs/lifinance/teams/smart-contract-core).${colors.reset}`); | |
console.log(`${colors.red}Check failed.${colors.reset}`); | |
core.setFailed("Required approval is missing"); | |
} |