Skip to content

Check PR Approvals #677

Check PR Approvals

Check PR Approvals #677

Workflow file for this run

name: Check PR Approvals
# For now, the workflow gets triggered only when a review is submitted
# This technically means, a PR with zero approvals can be merged by the rules of this workflow alone
# To protect against that scenario, we can turn on number of approvals required to 2 in the github settings
# of the repository
on:
pull_request_review:
types: [submitted]
jobs:
check-approvals:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v2
- name: Install TOML parser
run: npm install @iarna/toml
- name: Check PR Relevance and Approvals
uses: actions/github-script@v6
with:
script: |
const fs = require('fs');
const toml = require('@iarna/toml');
const { owner, repo } = context.repo;
let pull_number;
if (github.event_name === 'workflow_dispatch') {
const branch = github.ref.replace('refs/heads/', '');
const prs = await github.rest.pulls.list({
owner,
repo,
head: `${owner}:${branch}`,
state: 'open'
});
if (prs.data.length === 0) {
console.log('No open PR found for this branch.');
return;
}
pull_number = prs.data[0].number;
} else {
pull_number = context.issue.number;
}
// Get parsed data
try {
const tomlContent = fs.readFileSync('.github/pull_requests.toml', 'utf8');
console.log('TOML content:', tomlContent);
const tomlData = toml.parse(tomlContent);
console.log('Parsed TOML data:', JSON.stringify(tomlData, null, 2));
if (!tomlData.committee || !Array.isArray(tomlData.committee.members)) {
throw new Error('committee.members is not an array in the TOML file');
}
requiredApprovers = tomlData.committee.members;
} catch (error) {
console.error('Error reading or parsing TOML file:', error);
core.setFailed('Failed to read required approvers list');
return;
}
// Get all reviews
const reviews = await github.rest.pulls.listReviews({
owner,
repo,
pull_number
});
// Example: approvers = ["celina", "zyad"]
const approvers = new Set(
reviews.data
.filter(review => review.state === 'APPROVED')
.map(review => review.user.login)
);
const requiredApprovals = 2;
const currentCountfromCommittee = Array.from(approvers)
.filter(approver => requiredApprovers.includes(approver))
.length;
// TODO: Improve logging and messaging to the user
console.log('PR Approvers:', Array.from(approvers));
console.log('Required Approvers:', requiredApprovals);
// Core logic that checks if the approvers are in the committee
const checkName = 'PR Approval Status';
const conclusion = (approvers.size >= requiredApprovals && currentCountfromCommittee >= 2) ? 'success' : 'failure';
const output = {
title: checkName,
summary: `PR has ${approvers.size} total approvals and ${requiredApprovals} required approvals.`,
text: `Approvers: ${Array.from(approvers).join(', ')}\nRequired Approvers: ${requiredApprovers.join(', ')}`
};
if (conclusion === 'failure') {
core.setFailed(`PR needs at least ${requiredApprovals} total approvals and 2 required approvals. Current approvals: ${approvers.size}, Required approvals: ${requiredApprovals}`);
}