Skip to content

Commit 17ee7ee

Browse files
committed
chore: Add reviewable config; rename release workflow to draft.
1 parent 30db545 commit 17ee7ee

File tree

3 files changed

+86
-1
lines changed

3 files changed

+86
-1
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
name: release
1+
name: draft
22

33
on:
44
push:
@@ -7,6 +7,11 @@ on:
77
branches: [master]
88
types: [opened, reopened, synchronize]
99

10+
# Cancel old builds when pushing new commits.
11+
concurrency:
12+
group: draft-${{ github.event.pull_request.number || github.ref }}
13+
cancel-in-progress: true
14+
1015
jobs:
1116
release:
1217
uses: TokTok/ci-tools/.github/workflows/release-drafter.yml@master

.reviewable/completion.js

+76
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
// jshint esversion: 6
2+
3+
// This code will check that the pull request has been approved via GitHub
4+
// review approval by a minimum number of reviewers and by all assignees, and
5+
// that no changes were requested by any reviewers. Only reviewers with write
6+
// access to the repository are considered.
7+
//
8+
// This is very similar to GitHub's built-in branch protection option to require
9+
// pull request reviews before merging, but allows for much more flexibility and
10+
// customization.
11+
12+
// dependencies: lodash4
13+
14+
// Helper function to check if a user is a bot.
15+
function isBotAuthor(author) {
16+
return (
17+
author.username.endsWith("[bot]") || author.username.startsWith("toktok-")
18+
);
19+
}
20+
21+
function equals(a) {
22+
return (b) => a === b;
23+
}
24+
25+
// The number of approvals required to merge: at least 2 humans must approve the
26+
// code. If the author is a bot, then 2 approvals are required; otherwise, only
27+
// 1 approval is required (because 1 human wrote the code, so they approve).
28+
let numApprovalsRequired = isBotAuthor(review.pullRequest.author) ? 2 : 1;
29+
30+
const approvals = review.pullRequest.approvals;
31+
32+
let numApprovals = _.filter(approvals, equals("approved")).length;
33+
const numRejections = _.filter(approvals, equals("changes_requested")).length;
34+
35+
const discussionBlockers = _(review.discussions)
36+
.filter((x) => !x.resolved)
37+
.flatMap("participants")
38+
.filter((x) => !x.resolved)
39+
.map((user) => _.pick(user, "username"))
40+
.value();
41+
42+
let pendingReviewers = _(discussionBlockers)
43+
.map((user) => _.pick(user, "username"))
44+
.concat(review.pullRequest.requestedReviewers)
45+
.value();
46+
47+
const required = _.map(review.pullRequest.assignees, "username");
48+
_.pull(required, review.pullRequest.author.username);
49+
if (required.length) {
50+
numApprovalsRequired = _.max([required.length, numApprovalsRequired]);
51+
numApprovals =
52+
_(approvals).pick(required).filter(equals("approved")).size() +
53+
_.min([numApprovals, numApprovalsRequired - required.length]);
54+
pendingReviewers = _(required)
55+
.reject((username) => approvals[username] === "approved")
56+
.reject((username) => pendingReviewers.length && approvals[username])
57+
.map((username) => ({ username }))
58+
.concat(pendingReviewers)
59+
.value();
60+
}
61+
62+
pendingReviewers = _.uniqBy(pendingReviewers, "username");
63+
64+
const description =
65+
(numRejections ? `${numRejections} change requests, ` : "") +
66+
`${numApprovals} of ${numApprovalsRequired} approvals obtained`;
67+
const shortDescription =
68+
(numRejections ? `${numRejections} ✗, ` : "") +
69+
`${numApprovals} of ${numApprovalsRequired} ✓`;
70+
71+
return {
72+
completed: numApprovals >= numApprovalsRequired,
73+
description,
74+
shortDescription,
75+
pendingReviewers,
76+
};

.reviewable/settings.yaml

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# Reviewable settings file. Read the docs at https://docs.reviewable.io/repositories.html#store-repository-settings-using-the-reviewable-directory
2+
approval-text: ":lgtm_strong:"
3+
github-status:
4+
updates: always

0 commit comments

Comments
 (0)