108 lines
2.7 KiB
JavaScript
108 lines
2.7 KiB
JavaScript
|
#!/usr/bin/env node
|
||
|
|
||
|
/**
|
||
|
* Usage (cli):
|
||
|
* ```
|
||
|
* node create-preview <build-number> <job-name> <webhook-url>
|
||
|
* ```
|
||
|
*
|
||
|
* Usage (JS):
|
||
|
* ```js
|
||
|
* require('./trigger-webhook').
|
||
|
* triggerWebhook(buildNumber, jobName, webhookUrl).
|
||
|
* then(...);
|
||
|
* ```
|
||
|
*
|
||
|
* Triggers a notification webhook with CircleCI specific info.
|
||
|
*
|
||
|
* It can be used for notifying external servers and trigger operations based on CircleCI job status
|
||
|
* (e.g. triggering the creation of a preview based on previously stored build atrifacts).
|
||
|
*
|
||
|
* The body of the sent payload is of the form:
|
||
|
* ```json
|
||
|
* {
|
||
|
* "payload": {
|
||
|
* "build_num": ${buildNumber}
|
||
|
* "build_parameters": {
|
||
|
* "CIRCLE_JOB": "${jobName}"
|
||
|
* }
|
||
|
* }
|
||
|
* }
|
||
|
* ```
|
||
|
*
|
||
|
* When used from JS, it returns a promise which resolves to an object of the form:
|
||
|
* ```json
|
||
|
* {
|
||
|
* "statucCode": ${statusCode},
|
||
|
* "responseText": "${responseText}"
|
||
|
* }
|
||
|
* ```
|
||
|
*
|
||
|
* NOTE:
|
||
|
* - When used from the cli, the command will exit with an error code if the response's status code
|
||
|
* is outside the [200, 400) range.
|
||
|
* - When used from JS, the returned promise will be resolved, even if the response's status code is
|
||
|
* outside the [200, 400) range. It is up to the caller to decide how this should be handled.
|
||
|
*/
|
||
|
|
||
|
// Imports
|
||
|
const {request} = require('https');
|
||
|
|
||
|
// Exports
|
||
|
module.exports = {
|
||
|
triggerWebhook,
|
||
|
};
|
||
|
|
||
|
// Run
|
||
|
if (require.resolve === module) {
|
||
|
_main(process.argv.slice(2));
|
||
|
}
|
||
|
|
||
|
// Helpers
|
||
|
function _main(args) {
|
||
|
triggerWebhook(...args).
|
||
|
then(({statusCode, responseText}) => (200 <= statusCode && statusCode < 400) ?
|
||
|
console.log(`Status: ${statusCode}\n${responseText}`) :
|
||
|
Promise.reject(new Error(`Request failed (status: ${statusCode}): ${responseText}`))).
|
||
|
catch(err => {
|
||
|
console.error(err);
|
||
|
process.exit(1);
|
||
|
});
|
||
|
}
|
||
|
|
||
|
function postJson(url, data) {
|
||
|
return new Promise((resolve, reject) => {
|
||
|
const opts = {method: 'post', headers: {'Content-Type': 'application/json'}};
|
||
|
const onResponse = res => {
|
||
|
const statusCode = res.statusCode || -1;
|
||
|
let responseText = '';
|
||
|
|
||
|
res.
|
||
|
on('error', reject).
|
||
|
on('data', d => responseText += d).
|
||
|
on('end', () => resolve({statusCode, responseText}));
|
||
|
};
|
||
|
|
||
|
request(url, opts, onResponse).
|
||
|
on('error', reject).
|
||
|
end(JSON.stringify(data));
|
||
|
});
|
||
|
}
|
||
|
|
||
|
async function triggerWebhook(buildNumber, jobName, webhookUrl) {
|
||
|
if (!buildNumber || !jobName || !webhookUrl || isNaN(buildNumber)) {
|
||
|
throw new Error(
|
||
|
'Missing or invalid arguments.\n' +
|
||
|
'Expected: buildNumber (number), jobName (string), webhookUrl (string)');
|
||
|
}
|
||
|
|
||
|
const data = {
|
||
|
payload: {
|
||
|
build_num: +buildNumber,
|
||
|
build_parameters: {CIRCLE_JOB: jobName},
|
||
|
},
|
||
|
};
|
||
|
|
||
|
return postJson(webhookUrl, data);
|
||
|
}
|