@topgroup/diginext
Version:
A BUILD SERVER & CLI to deploy apps to any Kubernetes clusters.
181 lines (180 loc) • 10.9 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.WebhookService = void 0;
const humanize_duration_1 = __importDefault(require("humanize-duration"));
const app_config_1 = require("../app.config");
const Webhook_1 = require("../entities/Webhook");
const create_build_slug_1 = require("../modules/deploy/create-build-slug");
const mongodb_1 = require("../plugins/mongodb");
const BaseService_1 = __importDefault(require("./BaseService"));
const NotificationService_1 = require("./NotificationService");
class WebhookService extends BaseService_1.default {
constructor(ownership) {
super(Webhook_1.webhookSchema, ownership);
this.notiSvc = new NotificationService_1.NotificationService(ownership);
}
async create(data, options) {
if (!data.events)
throw new Error(`Webhook "events" (Array) is required.`);
if (!data.channels)
data.channels = ["email"];
if (!data.consumers)
data.consumers = [];
data.consumers.forEach((userId) => {
if (!mongodb_1.MongoDB.isValidObjectId(userId))
throw new Error(`Invalid "consumers" array, should be a valid list of user ID.`);
});
data.events.forEach((event) => {
switch (event) {
case "build_status":
if (!data.build)
throw new Error(`Missing a referenced "build" associated with the webhook event "${event}".`);
break;
case "deploy_status":
if (!data.release)
throw new Error(`Missing a referenced "release" associated with the webhook event "${event}".`);
break;
default:
break;
}
});
return super.create(data, options);
}
/**
* Trigger a webhook & send the notification
* @param id - Webhook ID
* @param status - Webhook event status
*/
async trigger(id, status, options) {
// validate
if (!id)
throw new Error(`Webhook "id" is required.`);
if (!status)
throw new Error(`Webhook "status" is required.`);
const webhook = await this.updateOne({ _id: id }, { status }, options);
if (!webhook)
throw new Error(`Webhook not found.`);
// process
const { DB } = await Promise.resolve().then(() => __importStar(require("../modules/api/DB")));
this.notiSvc.ownership = this.ownership;
return Promise.all(webhook.events.map((event) => {
switch (event) {
case "build_status":
if (webhook.status === "failed" || webhook.status === "success") {
return DB.findOne("build", { _id: webhook.build }, { populate: ["workspace", "owner", "project", "app"] })
.then((build) => {
if (!build)
throw new Error(`Build not found.`);
const { projectSlug, appSlug, tag: buildTag } = build;
const SOCKET_ROOM = (0, create_build_slug_1.createBuildSlug)({ projectSlug, appSlug, buildTag });
const logURL = `${app_config_1.Config.BASE_URL}/build/logs?build_slug=${SOCKET_ROOM}`;
const duration = (0, humanize_duration_1.default)(build.duration);
const owner = build.owner;
return this.notiSvc
.webhookSend(webhook, {
references: { build: mongodb_1.MongoDB.toString(build._id) },
url: logURL,
from: mongodb_1.MongoDB.toString(webhook.owner),
to: webhook.consumers.map((recipientId) => mongodb_1.MongoDB.toString(recipientId)),
title: webhook.status === "failed" ? `Build failed: ${build === null || build === void 0 ? void 0 : build.name}` : `Build success: ${build === null || build === void 0 ? void 0 : build.name}`,
message: `- Workspace: ${this.ownership.workspace.name}<br/>- Project: ${(build === null || build === void 0 ? void 0 : build.project).name}<br/>- App: ${(build === null || build === void 0 ? void 0 : build.app).name}<br/>- User: ${owner.name} (${owner.slug})<br/>- Duration: ${duration}<br/>- View logs: <a href="${logURL}">CLICK HERE</a><br/>- Container image: ${build === null || build === void 0 ? void 0 : build.image}`,
})
.catch((e) => {
console.error(`Unable to trigger webhook:`, e);
});
})
.catch((e) => {
console.error(`Build not found:`, e);
});
}
break;
case "deploy_status":
if (webhook.status === "failed" || webhook.status === "success") {
return DB.findOne("release", { _id: webhook.release }, { populate: ["workspace", "owner", "project", "app", "build"] })
.then((release) => {
if (!release)
throw new Error(`Release not found.`);
const { build } = release;
const { projectSlug, appSlug, tag: buildTag, duration: buildDuration } = build;
const SOCKET_ROOM = (0, create_build_slug_1.createBuildSlug)({ projectSlug, appSlug, buildTag });
const buildListPageUrl = `${app_config_1.Config.BASE_URL}/build`;
const logURL = `${app_config_1.Config.BASE_URL}/build/logs?build_slug=${SOCKET_ROOM}`;
const duration = (0, humanize_duration_1.default)(buildDuration);
const owner = release.owner;
return this.notiSvc
.webhookSend(webhook, {
references: { release: mongodb_1.MongoDB.toString(release._id) },
url: logURL,
from: mongodb_1.MongoDB.toString(webhook.owner),
to: webhook.consumers.map((recipientId) => mongodb_1.MongoDB.toString(recipientId)),
title: webhook.status === "failed" ? `Deploy failed: ${release === null || release === void 0 ? void 0 : release.name}` : `Deploy success: ${release === null || release === void 0 ? void 0 : release.name}`,
message: (webhook.status === "failed"
? `Failed to deploy "${release === null || release === void 0 ? void 0 : release.appSlug}" app of "${release === null || release === void 0 ? void 0 : release.projectSlug}" project to "${release === null || release === void 0 ? void 0 : release.env.toUpperCase()}" environment.<br/>- View build logs: <a href="${logURL}">CLICK HERE</a><br/>- Duration: ${duration}`
: `<strong>App has been deployed to "${release === null || release === void 0 ? void 0 : release.env.toUpperCase()}" environment successfully.</strong><br/><br/>- Workspace: ${(release === null || release === void 0 ? void 0 : release.workspace).name}<br/>- User: ${owner.name} (${owner.slug})<br/>- App: ${release === null || release === void 0 ? void 0 : release.appSlug}<br/>- Project: ${release === null || release === void 0 ? void 0 : release.projectSlug}<br/>- URL: <a href="https://${(release === null || release === void 0 ? void 0 : release.env) === "production" ? release === null || release === void 0 ? void 0 : release.prereleaseUrl : release === null || release === void 0 ? void 0 : release.productionUrl}">CLICK TO VIEW</a><br/>- View build logs: <a href="${logURL}">CLICK HERE</a><br/>- Duration: ${duration}<br/>- Container Image: ${release === null || release === void 0 ? void 0 : release.image}`) +
`<br/><br/>Go to <a href="${buildListPageUrl}">DXUP Dashboard</a>.<br/><br/>Best regards, <a href="https://dxup.dev">DXUP</a> Team.`,
})
.catch((e) => {
console.error(`Unable to trigger webhook:`, e);
});
})
.catch((e) => {
console.error(`Release not found:`, e);
});
}
break;
default:
throw new Error(`Invalid webhook event: "${event}".`);
break;
}
}));
}
/**
* Subscribe a consumer to a webhook
* @param id - Webhook ID
* @param data - Subscription data
*/
async subscribe(id, consumers, options) {
// validate
if (!id)
throw new Error(`Webhook ID is required.`);
if (!consumers)
throw new Error(`Webhook "consumers" (Array of UserID) is required.`);
const webhook = await this.updateOne({ id },
// add consumers to existing webhook if it's not exists
{
$addToSet: {
consumers: { $each: consumers },
},
}, { raw: true });
if (!webhook)
throw new Error(`Webhook not found.`);
return webhook;
}
}
exports.WebhookService = WebhookService;