-
Notifications
You must be signed in to change notification settings - Fork 169
/
Copy pathindex.js
114 lines (98 loc) · 4.49 KB
/
index.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
'use strict';
const joi = require('joi');
const logger = require('screwdriver-logger');
const boom = require('@hapi/boom');
const { ValidationError } = require('joi');
const { startHookEvent } = require('./helper');
const DEFAULT_MAX_BYTES = 1048576;
/**
* Webhook API Plugin
* - Validates that webhook events came from the specified scm provider
* - Opening a PR should sync the pipeline (creating the job) and start the new PR job
* - Syncing a PR should stop the existing PR job and start a new one
* - Closing a PR should stop the PR job and sync the pipeline (disabling the job)
* @method register
* @param {Hapi} server Hapi Server
* @param {Object} options Configuration
* @param {String} options.username Generic scm username
* @param {Array} options.ignoreCommitsBy Ignore commits made by these usernames
* @param {Array} options.restrictPR Restrict PR setting
* @param {Boolean} options.chainPR Chain PR flag
* @param {Integer} options.maxBytes Upper limit on incoming uploads to builds
* @param {Function} next Function to call when done
*/
const webhooksPlugin = {
name: 'webhooks',
async register(server, options) {
const pluginOptions = joi.attempt(
options,
joi.object().keys({
username: joi.string().required(),
ignoreCommitsBy: joi.array().items(joi.string()).optional(),
restrictPR: joi
.string()
.valid('all', 'none', 'branch', 'fork', 'all-admin', 'none-admin', 'branch-admin', 'fork-admin')
.optional(),
chainPR: joi.boolean().optional(),
maxBytes: joi.number().integer().optional()
}),
'Invalid config for plugin-webhooks'
);
server.route({
method: 'POST',
path: '/webhooks',
options: {
description: 'Handle webhook events',
notes: 'Acts on pull request, pushes, comments, etc.',
tags: ['api', 'webhook'],
plugins: {
'hapi-rate-limit': {
enabled: false
}
},
payload: {
maxBytes: parseInt(pluginOptions.maxBytes, 10) || DEFAULT_MAX_BYTES
},
handler: async (request, h) => {
const { pipelineFactory, queueWebhook } = request.server.app;
const { scm } = pipelineFactory;
const { executor, queueWebhookEnabled } = queueWebhook;
const message = 'Unable to process this kind of event';
let hookId;
try {
const parsed = await scm.parseHook(request.headers, request.payload);
if (!parsed) {
// for all non-matching events or actions
return h.response({ message }).code(204);
}
parsed.pluginOptions = pluginOptions;
const { type } = parsed;
hookId = parsed.hookId;
request.log(['webhook', hookId], `Received event type ${type}`);
if (queueWebhookEnabled) {
parsed.token = request.server.plugins.auth.generateToken({
scope: ['sdapi']
});
try {
return await executor.enqueueWebhook(parsed);
} catch (err) {
// if enqueueWebhook is not implemented, an event starts without enqueuing
if (err.message !== 'Not implemented') {
throw err;
}
}
}
return await startHookEvent(request, h, parsed);
} catch (err) {
logger.error(`[${hookId}]: ${err}`);
if (err instanceof ValidationError) {
throw boom.badData(err);
}
throw boom.boomify(err, { statusCode: err.statusCode });
}
}
}
});
}
};
module.exports = webhooksPlugin;