forked from ton-org/docs
-
Notifications
You must be signed in to change notification settings - Fork 0
172 lines (161 loc) · 7.82 KB
/
bouncer.yml
File metadata and controls
172 lines (161 loc) · 7.82 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
name: 🏀 Bouncer
# aka 🚪 Supervisor
env:
# additions only
MAX_ADDITIONS_FORKS: 500
# on rare occasions maintainers need to edit a lot of things at once
MAX_ADDITIONS_DIRECT_BRANCHES: 1000
# many target issues usually mean bigger pull requests
MAX_ISSUES_PER_PR: 3
on:
pull_request_target: # do NOT use actions/checkout!
# any branches
branches: ["**"]
# on creation, on new commits, and description edits
types: [opened, synchronize, edited]
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}-bouncer
cancel-in-progress: true
permissions:
contents: read
pull-requests: write
jobs:
enforce-smaller-requests:
name: "PR is manageable"
if: github.event.action != 'edited'
runs-on: ubuntu-latest
steps:
- name: Set MAX_ADDITIONS for forks
if: |
github.event_name == 'pull_request_target' &&
github.event.pull_request.head.repo.fork == true ||
github.event.pull_request.head.repo.full_name != github.repository
uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7.1.0
with:
script: core.exportVariable('MAX_ADDITIONS', '${{ env.MAX_ADDITIONS_FORKS }}')
- name: Set MAX_ADDITIONS for direct branches
if: |
github.event.pull_request.head.repo.fork != true ||
github.event.pull_request.head.repo.full_name == github.repository
uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7.1.0
with:
script: core.exportVariable('MAX_ADDITIONS', '${{ env.MAX_ADDITIONS_DIRECT_BRANCHES }}')
- name: Check if a number of additions modulo filtered files is within the threshold
id: stats
uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7.1.0
with:
script: |
const maxAdditions = Number(process.env.MAX_ADDITIONS ?? '500');
await exec.exec('sleep 0.5s');
const { data: files } = await github.rest.pulls.listFiles({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: context.payload.pull_request.number,
per_page: 100,
});
const filtered = files.filter(
(f) =>
![
'package-lock.json',
'ecosystem/api/toncenter/v2.json',
'ecosystem/api/toncenter/v3.yaml',
'ecosystem/api/toncenter/smc-index.json',
'tvm/instructions.mdx',
].includes(f.filename) && !f.filename.endsWith('.py') && !f.filename.startsWith('snippets'),
);
const additions = filtered.reduce((acc, it) => acc + it.additions, 0);
if (additions > maxAdditions) {
core.setOutput('trigger', 'true');
} else {
core.setOutput('trigger', 'false');
}
- name: ${{ steps.stats.outputs.trigger == 'true' && 'An opened PR is too big to be reviewed at once!' || 'No comments' }}
if: github.event.action == 'opened' && steps.stats.outputs.trigger == 'true'
uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7.1.0
with:
script: |
await exec.exec('sleep 0.5s');
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.payload.pull_request.number,
body: [
'Thank you for the contribution!',
[
'Unfortunately, it is too large, with over ${{ env.MAX_ADDITIONS }} added lines,',
'excluding some generated or otherwise special files.',
'Thus, this pull request is challenging to review and iterate on.',
].join(' '),
[
'Please split the PR into several smaller ones and consider',
'reverting any unrelated changes, writing less, or approaching',
'the problem in the issue from a different angle.',
].join(' '),
[
'I look forward to your next submissions.',
'If you still intend to proceed as is, then you are at the mercy of the reviewers.',
].join(' '),
].join('\n\n'),
});
process.exit(1);
- name: ${{ steps.stats.outputs.trigger == 'true' && 'Some change in the PR made it too big!' || 'No comments' }}
if: github.event.action == 'synchronize' && steps.stats.outputs.trigger == 'true'
uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7.1.0
with:
script: |
core.setFailed([
[
'This pull request has gotten over ${{ env.MAX_ADDITIONS }} added lines,',
'which can be challenging to review and iterate on',
'Please, decrease the size of this PR or consider splitting it into several smaller requests.'
].join(' '),
[
'Until then, the CI will be soft-marked as failed.',
'If you still intend to proceed as is, then you are at the mercy of the reviewers.',
].join(' '),
].join('\n\n'));
process.exit(1);
enforce-better-descriptions:
name: "Title and description"
runs-on: ubuntu-latest
steps:
# pr title check
- name: "Check that the title conforms to the simplified version of Conventional Commits"
if: ${{ !cancelled() }}
uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7.1.0
with:
script: |
const title = context.payload.pull_request.title;
const types = 'feat|fix|chore|refactor|test';
const pattern = new RegExp(`^(revert: )?(${types})(?:\\/(${types}))?!?(\\([^\\)]+\\))?!?: [a-zA-Z].{1,200}`);
const matches = title.match(pattern) !== null;
if (!matches) {
core.setFailed([
'Title of this pull request does not conform to the simplified version of Conventional Commits used in the documentation',
`Received: ${title}`,
'Expected to find a type of: feat, fix, chore, refactor, or test, followed by the parts outlined here: https://www.conventionalcommits.org/en/v1.0.0/',
].join('\n'));
process.exit(1);
}
# pr close issue limits
- name: "Check that there is no more than ${{ env.MAX_ISSUES_PER_PR }} linked issues"
if: ${{ !cancelled() && github.event.pull_request.user.login != 'dependabot[bot]' }}
uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7.1.0
with:
script: |
const maxIssuesAllowed = Number(process.env.MAX_ISSUES_PER_PR ?? '3');
const body = context.payload.pull_request.body || '';
const closePatterns = /\b(?:close[sd]?|fixes|fixed|resolve[sd]?|towards)\s+(?:https?:\/\/github\.com\/|[a-z0-9\-\_\/]*#\d+)/gi;
const issueCount = [...body.matchAll(closePatterns)].length;
if (issueCount > maxIssuesAllowed) {
core.setFailed(`This pull request attempts to close ${issueCount} issues, while the maximum number allowed is ${maxIssuesAllowed}.`);
process.exit(1);
}
if (issueCount === 0) {
core.setFailed([
'This pull request does not resolve any issues — no close patterns found in the description.',
'Please, specify an issue by writing `Closes #that-issue-number` in the description of this PR.',
'If there is no such issue, create a new one: https://github.com/ton-org/docs/issues/1366#issuecomment-3560650817',
].join(' '));
process.exit(1);
}