-
Notifications
You must be signed in to change notification settings - Fork 165
Expand file tree
/
Copy pathmaintainer-approval.js
More file actions
83 lines (73 loc) · 2.34 KB
/
maintainer-approval.js
File metadata and controls
83 lines (73 loc) · 2.34 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
const path = require("path");
const {
parseOwnersFile,
findOwners,
getCoreTeam,
} = require("../scripts/owners");
// Check if the PR author is exempted.
// If ALL changed files are owned by non-core-team owners that include the
// author, the PR can merge with any approval (not necessarily core team).
function isExempted(authorLogin, files, rules, coreTeam) {
if (files.length === 0) return false;
const coreSet = new Set(coreTeam);
for (const { filename } of files) {
const owners = findOwners(filename, rules);
const nonCoreOwners = owners.filter((o) => !coreSet.has(o));
if (nonCoreOwners.length === 0 || !nonCoreOwners.includes(authorLogin)) {
return false;
}
}
return true;
}
module.exports = async ({ github, context, core }) => {
const ownersPath = path.join(
process.env.GITHUB_WORKSPACE,
".github",
"OWNERS"
);
const rules = parseOwnersFile(ownersPath);
const coreTeam = getCoreTeam(rules);
if (coreTeam.length === 0) {
core.setFailed(
"Could not determine core team from .github/OWNERS (no * rule found)."
);
return;
}
const reviews = await github.paginate(github.rest.pulls.listReviews, {
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: context.issue.number,
});
const coreTeamApproved = reviews.some(
({ state, user }) =>
state === "APPROVED" && user && coreTeam.includes(user.login)
);
if (coreTeamApproved) {
const approver = reviews.find(
({ state, user }) =>
state === "APPROVED" && user && coreTeam.includes(user.login)
);
core.info(`Core team approval from @${approver.user.login}`);
return;
}
// Check exemption rules based on file ownership.
const { pull_request: pr } = context.payload;
const authorLogin = pr?.user?.login;
const files = await github.paginate(github.rest.pulls.listFiles, {
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: context.issue.number,
});
if (authorLogin && isExempted(authorLogin, files, rules, coreTeam)) {
const hasAnyApproval = reviews.some(({ state }) => state === "APPROVED");
if (!hasAnyApproval) {
core.setFailed(
"PR from exempted author still needs at least one approval."
);
}
return;
}
core.setFailed(
`Requires approval from a core team member: ${coreTeam.join(", ")}.`
);
};