UNPKG

@topgroup/diginext

Version:

A BUILD SERVER & CLI to deploy apps to any Kubernetes clusters.

221 lines (220 loc) 9.51 kB
"use strict"; 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.requestBuild = void 0; const chalk_1 = __importDefault(require("chalk")); const log_1 = require("diginext-utils/dist/xconsole/log"); const socket_io_client_1 = require("socket.io-client"); const config_1 = require("../../config/config"); const fetchApi_1 = require("../../modules/api/fetchApi"); const plugins_1 = require("../../plugins"); const ask_project_and_app_1 = require("../apps/ask-project-and-app"); const update_git_config_1 = require("../apps/update-git-config"); const create_build_slug_1 = require("../deploy/create-build-slug"); const git_utils_1 = require("../git/git-utils"); const ask_for_registry_1 = require("../registry/ask-for-registry"); const generate_build_tag_1 = require("./generate-build-tag"); /** * Request the build server to start building & deploying */ async function requestBuild(options) { var _a; if (process.env.CLI_MODE === "server") { (0, log_1.logError)(`This command is only available at CLIENT MODE.`); return; } const { DB } = await Promise.resolve().then(() => __importStar(require("../../modules/api/DB"))); if (!options.targetDirectory) options.targetDirectory = process.cwd(); // ask for project & app information let project, app; if (!options.appSlug) { let { project: _project, app: _app } = await (0, ask_project_and_app_1.askForProjectAndApp)(options.targetDirectory, options); project = _project; app = _app; if (options.isDebugging) console.log("askForDeployEnvironmentInfo > app :>> ", app); if (options.isDebugging) console.log("askForDeployEnvironmentInfo > project :>> ", project); options.appSlug = app.slug; options.projectSlug = app.projectSlug; } // verify if this app's directory has any git remote integrated const gitInfo = await (0, plugins_1.getCurrentGitRepoData)(options.targetDirectory); if (options.isDebugging) console.log("askForDeployEnvironmentInfo > gitInfo :>> ", gitInfo); if (!gitInfo) { (0, log_1.logError)(`This app's directory doesn't have any git remote integrated.`); return; } const gitBranch = gitInfo.branch; if (!app.git || !app.git.provider || !app.git.repoSSH || !app.git.repoURL) { const updateGitInfo = { provider: gitInfo.provider, repoSSH: gitInfo.repoSSH, repoURL: gitInfo.repoURL }; if (options.isDebugging) console.log("askForDeployEnvironmentInfo > updateGitInfo :>> ", updateGitInfo); app = await (0, update_git_config_1.updateAppGitInfo)(app, updateGitInfo); if (options.isDebugging) console.log("askForDeployEnvironmentInfo > app :>> ", app); } // container registry let registry; if (typeof options.registry === "boolean" || typeof options.registry === "undefined") { registry = await (0, ask_for_registry_1.askForRegistry)(); options.registry = registry.slug; } else { registry = await DB.findOne("registry", { slug: options.registry }, { subpath: "/all" }); } if (!registry) { (0, log_1.logError)(`Container Registry "${options.registry}" not found.`); return; } // const { buildServerUrl } = (0, config_1.getCliConfig)(); const { env, targetDirectory } = options; const START_BUILD_API_PATH = `${buildServerUrl}/api/v1/build/start`; // check Dockerfile -> no dockerfile, no build -> failed let dockerFile = (0, plugins_1.resolveDockerfilePath)({ targetDirectory, env }); if (!dockerFile) return; /** * Generate build number & build image as docker image tag */ const imageURL = `${registry.imageBaseURL}/${app.projectSlug}-${app.slug}`; const tagInfo = await (0, generate_build_tag_1.generateBuildTagBySourceDir)(options.targetDirectory, { branch: options.gitBranch }); if (options.isDebugging) console.log("tagInfo :>> ", tagInfo); options.buildTag = tagInfo.tag; options.buildImage = `${imageURL}:${options.buildTag}`; if (options.isDebugging) console.log("options.buildTag :>> ", options.buildTag); const SOCKET_ROOM = (0, create_build_slug_1.createBuildSlug)({ projectSlug: project.slug, appSlug: app.slug, buildTag: options.buildTag }); /** * Stage, commit & push configuration files (dx.json) to GIT repository: */ try { await (0, git_utils_1.stageCommitAndPushAll)({ directory: options.targetDirectory, message: `build(${env}): ${options.buildImage}`, }); } catch (e) { // Stop the process if this throws any errors (0, log_1.logError)(`Can't commit files for building this app: ${e}`); return; } /** * [5] Notify the commander & call API to request server build: */ (0, log_1.log)(`Requesting Diginext Server to build this app: "${app.projectSlug}/${app.slug}" (branch: "${gitBranch}")`); // const deployOptions = JSON.stringify(options); const requestBuildData = { gitBranch: gitBranch, buildTag: options.buildTag, buildNumber: tagInfo.number, registrySlug: registry.slug, appSlug: app.slug, }; if (options.isDebugging) { console.log("Request build data :>> "); console.dir(requestBuildData, { depth: 10 }); } try { const requestResult = await (0, fetchApi_1.fetchApi)({ url: START_BUILD_API_PATH, method: "POST", data: requestBuildData, }); if (options.isDebugging) { console.log("Request build result :>> "); console.dir(requestResult, { depth: 10 }); } if (!requestResult.status) (0, log_1.logError)(requestResult.messages[0] || `Unable to process Request Build API.`); (0, log_1.log)(`-> Check build status here: ${(_a = requestResult.data) === null || _a === void 0 ? void 0 : _a.logURL} `); } catch (e) { (0, log_1.logError)(`Unable to call Build Deploy API:`, e); return; } // update the project so it can be sorted on top try { await DB.updateOne("project", { slug: app.projectSlug }, { lastUpdatedBy: options.username }); } catch (e) { (0, log_1.logWarn)(e); } // friendly reminder if (env == "prod") (0, log_1.log)(chalk_1.default.red(`⚠️⚠️⚠️ REMEMBER TO CREATE PULL REQUEST TO "master" (or "main") BRANCH ⚠️⚠️⚠️`)); if (options.isTail) { let socketURL = buildServerUrl.replace(/https/gi, "wss"); socketURL = buildServerUrl.replace(/http/gi, "ws"); const socket = (0, socket_io_client_1.io)(socketURL, { transports: ["websocket"], timeout: 60000 }); socket.on("error", (e) => (0, log_1.logError)(e)); socket.on("connect_error", (e) => (0, log_1.logError)(e)); socket.on("disconnect", () => { // log("[CLI Server] Disconnected"); socket.emit("leave", { room: SOCKET_ROOM }); }); socket.on("connect", () => { // log("[CLI Server] Connected"); socket.emit("join", { room: SOCKET_ROOM }); }); return new Promise((resolve, reject) => { socket.on("message", ({ action, message, type }) => { if (message) { const errorWordIndex = message.toLowerCase().indexOf("error"); if (errorWordIndex > -1) { (0, log_1.logWarn)(message); } else { (0, log_1.log)(message); } } if (action == "end") { socket.disconnect(); if (type === "error") { // process.exit(1); reject(message); } else { // process.exit(0); resolve(true); } } }); // Max build duration: 30 mins setTimeout(() => reject(`Request timeout (30 minutes)`), 30 * 60 * 1000); }); } else { return true; } } exports.requestBuild = requestBuild;