You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

145 lines
4.3 KiB
JavaScript

const debug = require("debug")("action-dashboard:webhooks");
const { Webhooks, createNodeMiddleware } = require("@octokit/webhooks");
const http = require("http");
class WebHooks {
constructor(
sitePort,
secret,
webhookPort,
webhookPath,
gitHub,
actions,
expressApp
) {
if (secret) {
this._secret = secret;
this._webhookPort = webhookPort;
this._sitePort = sitePort;
this._gitHub = gitHub;
this._actions = actions;
if (sitePort === webhookPort) {
this._defaultPath = "/webhook";
} else {
this._defaultPath = "/";
}
this._path = webhookPath || this._defaultPath;
// Fail in the case that the ports for the main site and webhooks
// are the same and the path is explicitly set to /
if (sitePort === webhookPort && this._path === "/") {
throw new Error(
"Path cannot be / when the webhooks are running on the same port as the main site"
);
}
this._expressApp = expressApp;
this._enabled = true;
}
}
start() {
if (this._enabled) {
debug(
`Setting up webhooks port: ${this._webhookPort}, path: ${this._path}`
);
// OctoKit webhooks, not this module
const webhooks = new Webhooks({
secret: this._secret,
});
webhooks.onError((error) => {
console.dir(error);
// console.error(
// `Webhook error occured in "${error.event.name} handler: ${error.stack}"`
// );
});
const middleware = createNodeMiddleware(webhooks, { path: this._path });
webhooks.on("workflow_run", this.workflowRun);
if (this._sitePort !== this._webhookPort) {
this._server = http
.createServer((req, res) => {
debug(`received request path: ${req.url}`);
if (req.url === "/ping") {
debug("ping");
res.statusCode = 200;
res.end();
} else {
middleware(req, res);
}
})
.listen({ port: this._webhookPort }, () => {
console.log(
`Listening for webhooks on ${this._webhookPort} at ${this._path}`
);
});
} else {
this._expressApp.use(this._path, middleware);
console.log(
`Listening for webhooks on ${this._webhookPort} at ${this._path}`
);
}
} else {
debug("Webhooks disabled");
}
}
// Mainly used by testing functions to cleanly shutdown web server
stop() {
if (this._enabled && this._server && this._server.listening) {
this._server.close();
}
}
workflowRun = async ({ id, name, payload }) => {
try {
debug(`workflow_run received id: ${id}, name: ${name}`, payload);
let usage = null;
if (payload.workflow_run.status === "completed") {
debug(`getting usage for id: ${id}, name: ${name}`);
usage = await this._gitHub.getUsage(
payload.workflow_run.repository.owner.login,
payload.workflow_run.repository.name,
payload.workflow_run.workflow_id,
payload.workflow_run.id
);
}
debug(`merging runs for id: ${id}, name: ${name}`);
this._actions.mergeRuns([
{
runId: payload.workflow_run.id,
repo: payload.workflow_run.repository.name,
owner: payload.workflow_run.repository.owner.login,
workflowId: payload.workflow_run.workflow_id,
runNumber: payload.workflow_run.run_number,
workflow: payload.workflow_run.name,
branch: payload.workflow_run.head_branch,
sha: payload.workflow_run.head_sha,
message: payload.workflow_run.head_commit.message,
committer: payload.workflow_run.head_commit.committer.name,
status:
payload.workflow_run.status === "completed"
? payload.workflow_run.conclusion
: payload.workflow_run.status,
createdAt: payload.workflow_run.created_at,
updatedAt: payload.workflow_run.updated_at,
durationMs: usage?.run_duration_ms,
},
]);
debug(`runs merged for id: ${id}, name: ${name}`);
} catch (e) {
console.dir(e);
console.error(
`Error processing workflow_run received id: ${id}, name: ${name}`,
payload
);
}
};
}
module.exports = WebHooks;