-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathCode.gs
More file actions
119 lines (104 loc) · 4.43 KB
/
Copy pathCode.gs
File metadata and controls
119 lines (104 loc) · 4.43 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
/**
* Scans recent emails for GitHub Pull Request headers and body content to apply labels.
* Designed to run on a time-based trigger (e.g., every 5-10 minutes).
*
* Source & Bug Reports: https://github.com/varvashenya/gas-github-labels/issues
*/
function markGitHubPullRequests() {
// Look back 1 hour to ensure no messages are missed.
const threads = GmailApp.search('newer_than:1h');
// Define label paths using forward slashes for nesting (folder/label)
const ROOT_LABELS = {
GITHUB: "GitHub",
CLOSED: "GitHub/Closed",
MERGED: "GitHub/Merged",
CLOSED_BY_ME: "GitHub/Closed by me",
MERGED_BY_ME: "GitHub/Merged by me",
APPROVED_BY_ME: "GitHub/Approved by me",
CHANGES_BY_ME: "GitHub/Requested changes by me"
};
// Regex for headers
const RE_STATUS_CLOSED = /X-GitHub-PullRequestStatus:\s*closed/i;
const RE_STATUS_MERGED = /X-GitHub-PullRequestStatus:\s*merged/i;
const RE_REASON_YOUR_ACTIVITY = /X-GitHub-Reason:\s*your_activity/i;
const RE_LIST_ARCHIVE = /List-Archive:\s*https:\/\/github\.com\/([^\s>]+)/i;
// Regex for body content
const RE_BODY_APPROVED = /approved this pull request/i;
const RE_BODY_CHANGES = /requested changes on this pull request/i;
// Cache all existing labels once for performance
const labelCache = {};
GmailApp.getUserLabels().forEach(label => {
labelCache[label.getName()] = label;
});
// Helper function to get or create a label with caching
function getOrCreateLabel(name) {
if (!labelCache[name]) {
labelCache[name] = GmailApp.createLabel(name);
}
return labelCache[name];
}
// Initialize root label objects
const rootLabelObjects = {};
for (let key in ROOT_LABELS) {
rootLabelObjects[key] = getOrCreateLabel(ROOT_LABELS[key]);
}
for (let i = 0; i < threads.length; i++) {
const thread = threads[i];
const messages = thread.getMessages();
const lastMessage = messages[messages.length - 1];
const rawContent = lastMessage.getRawContent();
const bodyContent = lastMessage.getPlainBody();
const currentLabelsSet = new Set(thread.getLabels().map(l => l.getName()));
const subject = lastMessage.getSubject();
const isYourActivity = RE_REASON_YOUR_ACTIVITY.test(rawContent);
// 1. Handle dynamic Company/Repo label
const archiveMatch = rawContent.match(RE_LIST_ARCHIVE);
if (archiveMatch && archiveMatch[1]) {
// Add root "GitHub" label
if (!currentLabelsSet.has(ROOT_LABELS.GITHUB)) {
thread.addLabel(rootLabelObjects.GITHUB);
console.log(`GITHUB: Added [${ROOT_LABELS.GITHUB}] to "${subject}"`);
}
// Add dynamic repo label
const repoPath = "GitHub/" + archiveMatch[1].replace(/\/$/, "");
if (!currentLabelsSet.has(repoPath)) {
const repoLabel = getOrCreateLabel(repoPath);
thread.addLabel(repoLabel);
console.log(`REPO LABEL: Added [${repoPath}] to "${subject}"`);
}
}
// 2. Process original Status labels (Root folder)
// Status: CLOSED
if (RE_STATUS_CLOSED.test(rawContent)) {
if (!currentLabelsSet.has(ROOT_LABELS.CLOSED)) {
thread.addLabel(rootLabelObjects.CLOSED);
console.log(`STATUS: Added [${ROOT_LABELS.CLOSED}] to "${subject}"`);
}
if (isYourActivity && !currentLabelsSet.has(ROOT_LABELS.CLOSED_BY_ME)) {
thread.addLabel(rootLabelObjects.CLOSED_BY_ME);
console.log(`ACTIVITY: Added [${ROOT_LABELS.CLOSED_BY_ME}] to "${subject}"`);
}
}
// Status: MERGED
if (RE_STATUS_MERGED.test(rawContent)) {
if (!currentLabelsSet.has(ROOT_LABELS.MERGED)) {
thread.addLabel(rootLabelObjects.MERGED);
console.log(`STATUS: Added [${ROOT_LABELS.MERGED}] to "${subject}"`);
}
if (isYourActivity && !currentLabelsSet.has(ROOT_LABELS.MERGED_BY_ME)) {
thread.addLabel(rootLabelObjects.MERGED_BY_ME);
console.log(`ACTIVITY: Added [${ROOT_LABELS.MERGED_BY_ME}] to "${subject}"`);
}
}
if (isYourActivity) {
if (RE_BODY_APPROVED.test(bodyContent) && !currentLabelsSet.has(ROOT_LABELS.APPROVED_BY_ME)) {
thread.addLabel(rootLabelObjects.APPROVED_BY_ME);
console.log(`REVIEW: Added [${ROOT_LABELS.APPROVED_BY_ME}] to "${subject}"`);
}
if (RE_BODY_CHANGES.test(bodyContent) && !currentLabelsSet.has(ROOT_LABELS.CHANGES_BY_ME)) {
thread.addLabel(rootLabelObjects.CHANGES_BY_ME);
console.log(`REVIEW: Added [${ROOT_LABELS.CHANGES_BY_ME}] to "${subject}"`);
}
}
}
}