From 4481bd78eeae116aa5d9d961574c1a6d2ef82c6a Mon Sep 17 00:00:00 2001 From: iphydf Date: Sat, 8 Feb 2025 00:41:04 +0000 Subject: [PATCH] chore: Add in-repo reviewable config. This is better than manually maintaining it in the reviewable settings. This way, any contributor can make changes to this logic. --- .github/workflows/ci.yml | 2 -- .reviewable/completion.js | 58 +++++++++++++++++++++++++++++++++++++++ .reviewable/settings.yaml | 4 +++ 3 files changed, 62 insertions(+), 2 deletions(-) create mode 100644 .reviewable/completion.js create mode 100644 .reviewable/settings.yaml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 517dbda..85fe41e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,8 +1,6 @@ name: ci on: - push: - branches: [master] pull_request: branches: [master] diff --git a/.reviewable/completion.js b/.reviewable/completion.js new file mode 100644 index 0000000..d1c7ab5 --- /dev/null +++ b/.reviewable/completion.js @@ -0,0 +1,58 @@ +// jshint esversion: 6 + +// This code will check that the pull request has been approved via GitHub review approval by a +// minimum number of reviewers and by all assignees, and that no changes were requested by any +// reviewers. Only reviewers with write access to the repository are considered. +// +// This is very similar to GitHub's built-in branch protection option to require pull request +// reviews before merging, but allows for much more flexibility and customization. + +// dependencies: lodash4 + +// The number of approvals required to merge. +let numApprovalsRequired = 1; + +const approvals = review.pullRequest.approvals; + +let numApprovals = _.filter(approvals, (x) => x === 'approved').length; +const numRejections = _.filter(approvals, (x) => x === 'changes_requested').length; + +const discussionBlockers = _(review.discussions) + .filter((x) => !x.resolved) + .flatMap('participants') + .filter((x) => !x.resolved) + .map(user => _.pick(user, 'username')) + .value(); + +let pendingReviewers = _(discussionBlockers) + .map(user => _.pick(user, 'username')) + .concat(review.pullRequest.requestedReviewers) + .value(); + +const required = _.map(review.pullRequest.assignees, 'username'); +_.pull(required, review.pullRequest.author.username); +if (required.length) { + numApprovalsRequired = _.max([required.length, numApprovalsRequired]); + numApprovals = + (_(approvals).pick(required).filter('approved').size()) + + _.min([numApprovals, numApprovalsRequired - required.length]); + pendingReviewers = _(required) + .reject(username => approvals[username] === 'approved') + .reject(username => pendingReviewers.length && approvals[username]) + .map(username => ({username})) + .concat(pendingReviewers) + .value(); +} + +pendingReviewers = _.uniqBy(pendingReviewers, 'username'); + +const description = + (numRejections ? `${numRejections} change requests, ` : '') + + `${numApprovals} of ${numApprovalsRequired} approvals obtained`; +const shortDescription = + (numRejections ? `${numRejections} ✗, ` : '') + `${numApprovals} of ${numApprovalsRequired} ✓`; + +return { + completed: numApprovals >= numApprovalsRequired, + description, shortDescription, pendingReviewers +}; diff --git a/.reviewable/settings.yaml b/.reviewable/settings.yaml new file mode 100644 index 0000000..361886f --- /dev/null +++ b/.reviewable/settings.yaml @@ -0,0 +1,4 @@ +# Reviewable settings file. Read the docs at https://docs.reviewable.io/repositories.html#store-repository-settings-using-the-reviewable-directory +approval-text: ":lgtm_strong:" +github-status: + updates: always