-
-
Notifications
You must be signed in to change notification settings - Fork 107
181 lines (162 loc) · 8.84 KB
/
maintainers-tsc-changes-verification.yaml
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
173
174
175
176
177
178
179
180
181
name: Verify tsc and maintainers changes by human and bot
on:
pull_request:
types: [synchronize, opened, reopened]
paths:
- "MAINTAINERS.yaml"
env:
GITHUB_TOKEN: ${{ secrets.GH_TOKEN }}
jobs:
verify-changes-if-tsc-if-maintainers:
# if statement to check if the PR is open.
if: github.event.pull_request.state == 'open'
runs-on: ubuntu-latest
steps:
- name: Checkout main branch
uses: actions/checkout@v3
with:
ref: master
path: community-main
- name: Checkout PR branch
uses: actions/checkout@v3
with:
ref: ${{github.event.pull_request.head.ref}}
repository: ${{github.event.pull_request.head.repo.full_name}}
path: pr-branch
- name: Install js-yaml
run: npm install js-yaml@4.1.0
- name: Verify changes in MAINTAINERS.yaml
id: verify-changes
uses: actions/github-script@v6
with:
github-token: ${{ env.GITHUB_TOKEN }}
script: |
const yaml = require("js-yaml");
const fs = require("fs");
const mainFile = yaml.load(fs.readFileSync("./community-main/MAINTAINERS.yaml", "utf8"));
const prFile = yaml.load(fs.readFileSync("./pr-branch/MAINTAINERS.yaml", "utf8"));
const beforeMaintainers = new Map(mainFile.map((maintainer) => [maintainer.name, {github: maintainer.github, repos: maintainer.repos || []}]));
let errorMessages = [];
const owner = context.repo.owner;
const repo = context.repo.repo;
const pull_number = context.issue.number;
const author = context.payload.pull_request.user.login;
let removedTscMembers = [];
// If the PR is made by the bot.
if (author === 'asyncapi-bot') {
core.info('Changes made by asyncapi-bot')
core.setOutput('errorMessages', JSON.stringify(errorMessages));
const removedMaintainers = mainFile.filter(
(mainMaintainer) => !prFile.some((maintainer) => mainMaintainer.github === maintainer.github)
);
removedTscMembers = removedMaintainers.filter(maintainer => maintainer.isTscMember);
if (removedTscMembers.length > 0) {
core.setOutput("removedTscMembers", JSON.stringify(removedTscMembers));
}
else {
return
}
}
// detecting if changes in the PR contain removal of maintainer object
if (prFile.length < mainFile.length) {
errorMessages.push('A maintainer has been removed from `MAINTAINERS.yaml` file. Only `asyncapi-bot` can make such changes. Maintainers are removed from the file in an automated way only if they are no longer mentioned in `CODEOWNERS` file in any repository under AsyncAPI GitHub organization.');
}
for (const maintainer of prFile) {
// retrieve the previous data of the maintainer from the main file
const previousData = beforeMaintainers.get(maintainer.name);
// if the maintainer is not found in the previous data, it is a new maintainer
if (!previousData) {
errorMessages.push(`A new maintainer, ${maintainer.name}, has been added to MAINTAINERS.yaml. Only asyncapi-bot can make such changes. Maintainers are added to the file in an automated way only if they are mentioned in the CODEOWNERS file in any repository under AsyncAPI GitHub organization.`);
} else {
// retrieve the previous GitHub key and repositories of the maintainer
const previousGithub = previousData.github;
const previousRepos = previousData.repos;
// check if the GitHub key for the maintainer has been modified
if (previousGithub !== maintainer.github) {
errorMessages.push(`GitHub key for ${maintainer.name} has been modified in MAINTAINERS.yaml. Only asyncapi-bot can make such changes. This information is derived from the CODEOWNERS file located in any repository under AsyncAPI GitHub organization.`);
}
// check if the repositories list for the maintainer has been modified
if (previousRepos.toString() !== (maintainer.repos || []).toString()) {
// Check if a human added a repo to the maintainer's repository list
const previousReposLength = previousData.repos.length;
const currentReposLength = (maintainer.repos || []).length;
// Check if a repository is added by a human
if (currentReposLength > previousReposLength) {
const addedRepos = (maintainer.repos || []).slice(previousReposLength);
errorMessages.push(`New repositories (${addedRepos.join(', ')}) have been added to ${maintainer.name}'s repository list in MAINTAINERS.yaml. Only asyncapi-bot can make such changes. This information is derived from the CODEOWNERS file located in any repository under AsyncAPI GitHub organization.`);
}
// Check if a repository is removed by a human
if (currentReposLength < previousReposLength) {
const removedRepos = previousData.repos.slice(currentReposLength);
errorMessages.push(`Repositories (${removedRepos.join(', ')}) have been removed from ${maintainer.name}'s repository list in MAINTAINERS.yaml. Only asyncapi-bot can make such changes. This information is derived from the CODEOWNERS file located in any repository under AsyncAPI GitHub organization.`);
}
}
}
}
// Console log the error messages
core.info('Error messages:', errorMessages);
// Set the error messages as an output
core.info('Setting error messages output...');
core.setOutput('errorMessages', JSON.stringify(errorMessages));
outputs:
errorMessages: ${{ steps.verify-changes.outputs.errorMessages }}
removedTscMembers: ${{ steps.verify-changes.outputs.removedTscMembers }}
block-human-made-critical-changes:
needs: verify-changes-if-tsc-if-maintainers
if: needs.verify-changes-if-tsc-if-maintainers.outputs.errorMessages != '[]'
runs-on: ubuntu-latest
steps:
- name: Comment and close the PR if there are any critical changes done by human
uses: actions/github-script@v6
with:
github-token: ${{ env.GITHUB_TOKEN }}
script: |
const errorMessagesString = `${{ needs.verify-changes-if-tsc-if-maintainers.outputs.errorMessages }}`;
const errorMessages = errorMessagesString ? JSON.parse(errorMessagesString) : [];
console.log('Parsed errorMessages:', errorMessages);
if (errorMessages && Array.isArray(errorMessages) && errorMessages.length > 0) {
const owner = context.repo.owner;
const repo = context.repo.repo;
const pull_number = context.issue.number;
const commentBody = errorMessages[0];
const commentContext = {
owner: owner,
repo: repo,
issue_number: pull_number,
body: commentBody
};
github.rest.issues.createComment(commentContext);
github.rest.pulls.update({
owner: owner,
repo: repo,
pull_number: pull_number,
state: 'closed'
});
} else {
console.info('errorMessages is empty.');
}
block-bot-from-tsc-removal:
needs: verify-changes-if-tsc-if-maintainers
if: needs.verify-changes-if-tsc-if-maintainers.outputs.removedTscMembers != ''
runs-on: ubuntu-latest
steps:
- name: Comment on PR if TSC member is removed by asyncapi-bot
if: steps.verify-changes-if-tsc-if-maintainers.outputs.removedTscMembers != ''
uses: actions/github-script@v6
with:
github-token: ${{ env.GITHUB_TOKEN }}
script: |
const issueComment = {
owner: github.context.repo.owner,
repo: github.context.repo.repo,
issue_number: github.context.issue.number,
body: 'A TSC member has been removed in this PR. Maintainers of this repository need to review and approve this PR.'
}
const addLabel = {
owner: github.context.repo.owner,
repo: github.context.repo.repo,
issue_number: github.context.issue.number,
labels: ['do-not-merge']
}
github.rest.issues.createComment(issueComment);
github.rest.issues.addLabels(addLabel);