forked from raycast/extensions
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpr-bot.js
149 lines (124 loc) · 4.32 KB
/
pr-bot.js
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
const fs = require("fs");
const path = require("path");
module.exports = async ({ github, context, core, changedFiles }) => {
const codeowners = getCodeOwners();
const touchedExtensions = new Set(
changedFiles
.filter((x) => x.startsWith("extensions"))
.map((x) => {
const parts = x.split("/");
return `/extensions/${parts[1]}`;
})
);
if (touchedExtensions.size > 1) {
console.log("We only notify people when updating a single extension");
return;
}
const sender = context.payload.sender.login;
if (sender === "raycastbot") {
console.log("We don't notify people when raycastbot is doing its stuff (usually merging the PR)");
return;
}
const opts = github.rest.issues.listForRepo.endpoint.merge({
...context.issue,
creator: sender,
state: "all",
});
const issues = await github.paginate(opts);
const isFirstContribution = issues.every((issue) => issue.number === context.issue.number || !issue.pull_request);
for (const ext of touchedExtensions) {
const owners = codeowners[ext];
if (!owners) {
// it's a new extension
console.log(`cannot find existing extension ${ext}`);
await github.rest.issues.addLabels({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
labels: ["new extension"],
});
await comment({
github,
context,
comment: `Congratulation on your new Raycast extension! :rocket:\n\nWe will review it shortly. Once the PR is approved and merged, the extension will be available on the Store.`,
});
return;
}
await github.rest.issues.addLabels({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
labels: ["extension fix / improvement", limitLabelLength(`extension: ${findExtensionName(ext)}`)],
});
if (owners[0] === sender) {
await github.rest.issues.addLabels({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
labels: ["OP is author"],
});
return;
}
if (owners.indexOf(sender) !== -1) {
await github.rest.issues.addLabels({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
labels: ["OP is contributor"],
});
}
await comment({
github,
context,
comment: `Thank you for your ${isFirstContribution ? "first " : ""} contribution! :tada:\n\n🔔 ${owners
.filter((x) => x !== sender)
.map((x) => `@${x}`)
.join(" ")} you might want to have a look.`,
});
return;
}
};
function getCodeOwners() {
const codeowners = fs.readFileSync(path.join(__dirname, "../.github/CODEOWNERS"), "utf8");
const regex = /(\/extensions\/[\w-]+) +(.+)/g;
const matches = codeowners.matchAll(regex);
return Array.from(matches).reduce((prev, match) => {
prev[match[1]] = match[2].split(" ").map((x) => x.replace(/^@/, ""));
return prev;
}, {});
}
function findExtensionName(ext) {
const map = JSON.parse(fs.readFileSync(path.join(__dirname, "../.github/extensionName2Folder.json"), "utf8"));
const folder = ext.replace("/extensions/", "");
const foundExtension = Object.entries(map).find(([name, _folder]) => _folder === folder);
return foundExtension ? foundExtension[0] : undefined;
}
// Create a new comment or update the existing one
async function comment({ github, context, comment }) {
// Get the existing comments on the PR
const { data: comments } = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
});
// Find any comment already made by the bot
const botComment = comments.find((comment) => comment.user.login === "raycastbot");
if (botComment) {
await github.rest.issues.updateComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: botComment.id,
body: comment,
});
} else {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body: comment,
});
}
}
function limitLabelLength(label) {
return label.length > 50 ? label.substring(0, 49) + "…" : label;
}