Skip to content

Commit 8278e9c

Browse files
committed
chore: Add release issue template and workflow.
1 parent a9bb3a1 commit 8278e9c

File tree

5 files changed

+133
-6
lines changed

5 files changed

+133
-6
lines changed

Diff for: .github/ISSUE_TEMPLATE/release.yml

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
name: 🚀 Release
2+
description: Build and deploy a new release
3+
title: Release tracking issue
4+
labels: [chore]
5+
type: Task
6+
body:
7+
- type: textarea
8+
id: release-notes
9+
attributes:
10+
label: Release notes
11+
description: Write something nice about the new release.
12+
placeholder: "Here's our latest awesome release!"
13+
validations:
14+
required: true
15+
- type: dropdown
16+
id: production
17+
attributes:
18+
label: Release type
19+
description: Whether this is a production release or a release candidate.
20+
options:
21+
- Release candidate
22+
- Production release
23+
validations:
24+
required: true

Diff for: .github/workflows/draft.yml

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
name: draft
2+
3+
on:
4+
push:
5+
branches: [master]
6+
pull_request_target:
7+
branches: [master]
8+
types: [opened, reopened, synchronize]
9+
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+
15+
jobs:
16+
release:
17+
uses: TokTok/ci-tools/.github/workflows/release-drafter.yml@master

Diff for: .github/workflows/release.yml

+12-6
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,18 @@
11
name: release
22

33
on:
4-
push:
5-
branches: [master]
6-
pull_request_target:
7-
branches: [master]
8-
types: [opened, reopened, synchronize]
4+
issues:
5+
types: [assigned]
6+
7+
concurrency:
8+
group: release-${{ github.event.issue.number }}
9+
cancel-in-progress: true
910

1011
jobs:
1112
release:
12-
uses: TokTok/ci-tools/.github/workflows/release-drafter.yml@master
13+
name: Release
14+
uses: TokTok/ci-tools/.github/workflows/release-deploy.yml@master
15+
with:
16+
production: true
17+
secrets:
18+
TOKEN_RELEASES: ${{ secrets.TOKEN_RELEASES }}

Diff for: .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+
};

Diff for: .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)