Rocket.Chat SaaS
GitLab
Add GitLab notifications via a new WebHook in Rocket.Chat
  1. 1.
    In Rocket.Chat go to "Administration"->"Integrations" and create "New Integration".
  2. 2.
    Choose Incoming WebHook.
  3. 3.
    Follow all instructions like Enable, give it a name, link to channel etc. Set "Enable Script" to true and enter the javascript in the "Script" box.
  4. 4.
    Press Save changes and copy the Webhook URL (added just below the script box).
  5. 5.
    Go to your GitLab project, ie. https://gitlab.com/< username >/< project >/hooks . It's in the project "settings" under Webhooks menu GitLab.
  6. 6.
    Add a new webhook by pasting the Rocket.Chat url you've copied in step 4, select at least 1 checkbox and press the button (conveniently called "Add Webhook").
  7. 7.
    Test the webhook with the "Test Hook" button in GitLab, a topbar should appear with more info (success or failure).
Paste this in javascript in the "Script" text area on Rocket.Chat webhook settings
1
/* eslint no-console:0, max-len:0 */
2
// see <https://gitlab.com/help/web_hooks/web_hooks> for full json posted by GitLab
3
const MENTION_ALL_ALLOWED = false; // <- check that bot permission allow has mention-all before passing this to true.
4
const NOTIF_COLOR = '#6498CC';
5
const IGNORE_CONFIDENTIAL = true;
6
const refParser = (ref) => ref.replace(/^refs\/(?:tags|heads)\/(.+)$/, '$1');
7
const displayName = (name) => (name && name.toLowerCase().replace(/\s+/g, '.'));
8
const atName = (user) => (user && user.name ? '@' + displayName(user.name) : '');
9
const makeAttachment = (author, text, color) => {
10
return {
11
author_name: author ? displayName(author.name) : '',
12
author_icon: author ? author.avatar_url : '',
13
text,
14
color: color || NOTIF_COLOR
15
};
16
};
17
const pushUniq = (array, val) => ~array.indexOf(val) || array.push(val); // eslint-disable-line
18
19
class Script { // eslint-disable-line
20
process_incoming_request({ request }) {
21
try {
22
let result = null;
23
const channel = request.url.query.channel;
24
const event = request.headers['x-gitlab-event'];
25
switch (event) {
26
case 'Push Hook':
27
result = this.pushEvent(request.content);
28
break;
29
case 'Merge Request Hook':
30
result = this.mergeRequestEvent(request.content);
31
break;
32
case 'Note Hook':
33
result = this.commentEvent(request.content);
34
break;
35
case 'Confidential Issue Hook':
36
case 'Issue Hook':
37
result = this.issueEvent(request.content, event);
38
break;
39
case 'Tag Push Hook':
40
result = this.tagEvent(request.content);
41
break;
42
case 'Pipeline Hook':
43
result = this.pipelineEvent(request.content);
44
break;
45
case 'Build Hook': // GitLab < 9.3
46
result = this.buildEvent(request.content);
47
break;
48
case 'Job Hook': // GitLab >= 9.3.0
49
result = this.buildEvent(request.content);
50
break;
51
case 'Wiki Page Hook':
52
result = this.wikiEvent(request.content);
53
break;
54
default:
55
result = this.unknownEvent(request, event);
56
break;
57
}
58
if (result && result.content && channel) {
59
result.content.channel = '#' + channel;
60
}
61
return result;
62
} catch (e) {
63
console.log('gitlabevent error', e);
64
return this.createErrorChatMessage(e);
65
}
66
}
67
68
createErrorChatMessage(error) {
69
return {
70
content: {
71
username: 'Rocket.Cat ErrorHandler',
72
text: 'Error occured while parsing an incoming webhook request. Details attached.',
73
icon_url: '',
74
attachments: [
75
{
76
text: `Error: '${error}', \n Message: '${error.message}', \n Stack: '${error.stack}'`,
77
color: NOTIF_COLOR
78
}
79
]
80
}
81
};
82
}
83
84
unknownEvent(data, event) {
85
return {
86
content: {
87
username: data.user ? data.user.name : (data.user_name || 'Unknown user'),
88
text: `Unknown event '${event}' occured. Data attached.`,
89
icon_url: data.user ? data.user.avatar_url : (data.user_avatar || ''),
90
attachments: [
91
{
92
text: `${JSON.stringify(data, null, 4)}`,
93
color: NOTIF_COLOR
94
}
95
]
96
}
97
};
98
}
99
issueEvent(data, event) {
100
if (event === 'Confidential Issue Hook' && IGNORE_CONFIDENTIAL) {
101
return false;
102
}
103
const project = data.project || data.repository;
104
const state = data.object_attributes.state;
105
const action = data.object_attributes.action;
106
let user_action = state;
107
let assigned = '';
108
109
if (action === 'update') {
110
user_action = 'updated';
111
}
112
113
if (data.assignee) {
114
assigned = `*Assigned to*: @${data.assignee.username}\n`;
115
}
116
117
return {
118
content: {
119
username: 'gitlab/' + project.name,
120
icon_url: project.avatar_url || data.user.avatar_url || '',
121
text: (data.assignee && data.assignee.name !== data.user.name) ? atName(data.assignee) : '',
122
attachments: [
123
makeAttachment(
124
data.user, `${user_action} an issue _${data.object_attributes.title}_ on ${project.name}.
125
*Description:* ${data.object_attributes.description}.
126
${assigned}
127
See: ${data.object_attributes.url}`
128
)
129
]
130
}
131
};
132
}
133
134
commentEvent(data) {
135
const project = data.project || data.repository;
136
const comment = data.object_attributes;
137
const user = data.user;
138
const at = [];
139
let text;
140
if (data.merge_request) {
141
const mr = data.merge_request;
142
const lastCommitAuthor = mr.last_commit && mr.last_commit.author;
143
if (mr.assignee && mr.assignee.name !== user.name) {
144
at.push(atName(mr.assignee));
145
}
146
if (lastCommitAuthor && lastCommitAuthor.name !== user.name) {
147
pushUniq(at, atName(lastCommitAuthor));
148
}
149
text = `commented on MR [#${mr.id} ${mr.title}](${comment.url})`;
150
} else if (data.commit) {
151
const commit = data.commit;
152
const message = commit.message.replace(/\n[^\s\S]+/, '...').replace(/\n$/, '');
153
if (commit.author && commit.author.name !== user.name) {
154
at.push(atName(commit.author));
155
}
156
text = `commented on commit [${commit.id.slice(0, 8)} ${message}](${comment.url})`;
157
} else if (data.issue) {
158
const issue = data.issue;
159
text = `commented on issue [#${issue.id} ${issue.title}](${comment.url})`;
160
} else if (data.snippet) {
161
const snippet = data.snippet;
162
text = `commented on code snippet [#${snippet.id} ${snippet.title}](${comment.url})`;
163
}
164
return {
165
content: {
166
username: 'gitlab/' + project.name,
167
icon_url: project.avatar_url || user.avatar_url || '',
168
text: at.join(' '),
169
attachments: [
170
makeAttachment(user, `${text}\n${comment.note}`)
171
]
172
}
173
};
174
}
175
176
mergeRequestEvent(data) {
177
const user = data.user;
178
const mr = data.object_attributes;
179
const assignee = mr.assignee;
180
let at = [];
181
182
if (mr.action === 'open' && assignee) {
183
at = '\n' + atName(assignee);
184
} else if (mr.action === 'merge') {
185
const lastCommitAuthor = mr.last_commit && mr.last_commit.author;
186
if (assignee && assignee.name !== user.name) {
187
at.push(atName(assignee));
188
}
189
if (lastCommitAuthor && lastCommitAuthor.name !== user.name) {
190
pushUniq(at, atName(lastCommitAuthor));
191
}
192
}
193
return {
194
content: {
195
username: `gitlab/${mr.target.name}`,
196
icon_url: mr.target.avatar_url || mr.source.avatar_url || user.avatar_url || '',
197
text: at.join(' '),
198
attachments: [
199
makeAttachment(user, `${mr.action} MR [#${mr.iid} ${mr.title}](${mr.url})\n${mr.source_branch} into ${mr.target_branch}`)
200
]
201
}
202
};
203
}
204
205
pushEvent(data) {
206
const project = data.project || data.repository;
207
const web_url = project.web_url || project.homepage;
208
const user = {
209
name: data.user_name,
210
avatar_url: data.user_avatar
211
};
212
// branch removal
213
if (data.checkout_sha === null && !data.commits.length) {
214
return {
215
content: {
216
username: `gitlab/${project.name}`,
217
icon_url: project.avatar_url || data.user_avatar || '',
218
attachments: [
219
makeAttachment(user, `removed branch ${refParser(data.ref)} from [${project.name}](${web_url})`)
220
]
221
}
222
};
223
}
224
// new branch
225
if (data.before == 0) { // eslint-disable-line
226
return {
227
content: {
228
username: `gitlab/${project.name}`,
229
icon_url: project.avatar_url || data.user_avatar || '',
230
attachments: [
231
makeAttachment(user, `pushed new branch [${refParser(data.ref)}](${web_url}/commits/${refParser(data.ref)}) to [${project.name}](${web_url}), which is ${data.total_commits_count} commits ahead of master`)
232
]
233
}
234
};
235
}
236
return {
237
content: {
238
username: `gitlab/${project.name}`,
239
icon_url: project.avatar_url || data.user_avatar || '',
240
attachments: [
241
makeAttachment(user, `pushed ${data.total_commits_count} commits to branch [${refParser(data.ref)}](${web_url}/commits/${refParser(data.ref)}) in [${project.name}](${web_url})`),
242
{
243
text: data.commits.map((commit) => ` - ${new Date(commit.timestamp).toUTCString()} [${commit.id.slice(0, 8)}](${commit.url}) by ${commit.author.name}: ${commit.message.replace(/\s*$/, '')}`).join('\n'),
244
color: NOTIF_COLOR
245
}
246
]
247
}
248
};
249
}
250
251
tagEvent(data) {
252
const project = data.project || data.repository;
253
const web_url = project.web_url || project.homepage;
254
const tag = refParser(data.ref);
255
const user = {
256
name: data.user_name,
257
avatar_url: data.user_avatar
258
};
259
let message;
260
if (data.checkout_sha === null) {
261
message = `deleted tag [${tag}](${web_url}/tags/)`;
262
} else {
263
message = `pushed tag [${tag} ${data.checkout_sha.slice(0, 8)}](${web_url}/tags/${tag})`;
264
}
265
return {
266
content: {
267
username: `gitlab/${project.name}`,
268
icon_url: project.avatar_url || data.user_avatar || '',
269
text: MENTION_ALL_ALLOWED ? '@all' : '',
270
attachments: [
271
makeAttachment(user, message)
272
]
273
}
274
};
275
}
276
277
createColor(status) {
278
switch (status) {
279
case 'success':
280
return '#2faa60';
281
case 'pending':
282
return '#e75e40';
283
case 'failed':
284
return '#d22852';
285
case 'canceled':
286
return '#5c5c5c';
287
case 'created':
288
return '#ffc107';
289
case 'running':
290
return '#607d8b';
291
default:
292
return null;
293
}
294
}
295
296
pipelineEvent(data) {
297
const project = data.project || data.repository;
298
const commit = data.commit;
299
const user = {
300
name: data.user_name,
301
avatar_url: data.user_avatar
302
};
303
const pipeline = data.object_attributes;
304
305
return {
306
content: {
307
username: `gitlab/${project.name}`,
308
icon_url: project.avatar_url || data.user_avatar || '',
309
attachments: [
310
makeAttachment(user, `pipeline returned *${pipeline.status}* for commit [${commit.id.slice(0, 8)}](${commit.url}) made by *${commit.author.name}*`, this.createColor(pipeline.status))
311
]
312
}
313
};
314
}
315
316
buildEvent(data) {
317
const user = {
318
name: data.user_name,
319
avatar_url: data.user_avatar
320
};
321
322
return {
323
content: {
324
username: `gitlab/${data.repository.name}`,
325
icon_url: '',
326
attachments: [
327
makeAttachment(user, `build named *${data.build_name}* returned *${data.build_status}* for [${data.project_name}](${data.repository.homepage})`, this.createColor(data.build_status))
328
]
329
}
330
};
331
}
332
333
wikiPageTitle(wiki_page) {
334
if (wiki_page.action === 'delete') {
335
return wiki_page.title;
336
}
337
338
return `[${wiki_page.title}](${wiki_page.url})`;
339
}
340
341
wikiEvent(data) {
342
const user_name = data.user.name;
343
const project = data.project;
344
const project_path = project.path_with_namespace;
345
const wiki_page = data.object_attributes;
346
const wiki_page_title = this.wikiPageTitle(wiki_page);
347
const action = wiki_page.action;
348
349
let user_action = 'modified';
350
351
if (action === 'create') {
352
user_action = 'created';
353
} else if (action === 'update') {
354
user_action = 'edited';
355
} else if (action === 'delete') {
356
user_action = 'deleted';
357
}
358
359
return {
360
content: {
361
username: project_path,
362
icon_url: project.avatar_url || data.user.avatar_url || '',
363
text: `The wiki page ${wiki_page_title} was ${user_action} by ${user_name}`
364
}
365
};
366
}
367
}
Copied!
This example contains code for several hooks. It can easily be extended with more. Source: https://github.com/malko/rocketchat-gitlab-hook.
Export as PDF
Copy link