-
Notifications
You must be signed in to change notification settings - Fork 3
/
gmail-gitlab-filtering.gs
153 lines (128 loc) · 4.4 KB
/
gmail-gitlab-filtering.gs
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
/* SPDX-License-Identifier: BSD-2-Clause */
const personalLabelName = "mattst88"
const unprocessedLabels = ["freedesktop"];
const maxThreads = 240;
let personalLabel;
function processInbox() {
updateUserLabels();
personalLabel = GmailApp.getUserLabelByName(personalLabelName);
for (const label of unprocessedLabels) {
processLabel(userLabels[label]);
}
}
let toInboxThreads = [];
let toRemoveThreads = new Map();
let toAddThreads = new Map();
function processLabel(unprocessedLabel) {
let threads = GmailApp.search("label:" + unprocessedLabel.getName(), 0, maxThreads);
if (threads.length < 1) {
Logger.log("No threads to process with label:" + unprocessedLabel.getName());
return;
} else {
Logger.log("Processing threads with label:" + unprocessedLabel.getName());
}
for (const i in threads) {
Logger.log("Processing thread " + i);
processThread(unprocessedLabel, threads[i]);
}
/* the GmailLabel.addToThreads/removeFromThreads functions
* only process 100 threads at a time */
const chunk_size = 100;
/* Apply labels to threads */
for (const [label, threads] of toAddThreads) {
Logger.log("Adding " + label.getName() + " label to " + threads.length + " threads");
for (let i = 0; i < threads.length; i += chunk_size) {
const end = Math.min(i+chunk_size, threads.length);
label.addToThreads(threads.slice(i, end));
Logger.log("\t... " + end + " done");
}
}
/* Move threads to Inbox */
Logger.log("Moving " + toInboxThreads.length + " to Inbox");
for (let i = 0; i < toInboxThreads.length; i += chunk_size) {
const end = Math.min(i+chunk_size, toInboxThreads.length);
GmailApp.moveThreadsToInbox(toInboxThreads.slice(i, end));
Logger.log("\t... " + end + " done")
}
/* Remove labels from threads */
for (const label of [personalLabel, unprocessedLabel]) {
const threads = toRemoveThreads.get(label);
if (!threads)
continue;
Logger.log("Removing " + label.getName() + " label from " + threads.length + " threads");
for (let i = 0; i < threads.length; i += chunk_size) {
const end = Math.min(i+chunk_size, threads.length);
label.removeFromThreads(threads.slice(i, end));
Logger.log("\t... " + end + " done");
}
}
}
function processThread(unprocessedLabel, thread) {
let moveToInbox = false;
let labelNames = [];
let messages = thread.getMessages();
for (const message of messages) {
/* If the X-GitLab-NotificationReason header exists in any message
* in the thread, it was sent to us because we were mentioned, we participated, etc.
* We want to move those threads to the Inbox. */
let notificationReason = message.getHeader("X-GitLab-NotificationReason")
if (notificationReason) {
moveToInbox = true;
}
/* Push the project path to a list. We'll deduplicate later. */
const projectPath = message.getHeader("X-GitLab-Project-Path");
if (projectPath) {
labelNames.push(projectPath);
}
}
/* Deduplicate labels list */
labelNames = labelNames.filter(onlyUnique);
for (const labelName of labelNames) {
/* Get/create a label nested under our unprocessed label */
const label = getLabel(unprocessedLabel.getName() + "/" + labelName);
if (!toAddThreads.has(label)) {
toAddThreads.set(label, []);
}
toAddThreads.get(label).push(thread);
}
if (moveToInbox) {
toInboxThreads.push(thread);
} else {
if (!toRemoveThreads.has(personalLabel)) {
toRemoveThreads.set(personalLabel, []);
}
toRemoveThreads.get(personalLabel).push(thread);
}
if (!toRemoveThreads.has(unprocessedLabel)) {
toRemoveThreads.set(unprocessedLabel, []);
}
toRemoveThreads.get(unprocessedLabel).push(thread);
}
/* Makes a hash table of "name" -> label */
function makeNameToLabelTbl(labels) {
let table = [];
for (const label of labels) {
table[label.getName()] = label;
}
return table;
}
/* Cache of user labels, indexed by name string */
let userLabels = [];
function updateUserLabels() {
userLabels = makeNameToLabelTbl(GmailApp.getUserLabels());
}
/* Returns a GmailLabel given a name string.
* If it doesn't exist, it creates it. */
function getLabel(name) {
let label;
if (!userLabels[name]) {
label = GmailApp.createLabel(name);
updateUserLabels();
} else {
label = userLabels[name];
}
return label;
}
function onlyUnique(value, index, self) {
return self.indexOf(value) === index;
}