UNPKG

@topgroup/diginext

Version:

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

1,092 lines (1,091 loc) 47 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.resolveDockerfilePath = exports.resolveFilePath = exports.sequentialExec = exports.objToEnv = exports.getDiginextEnvVars = exports.strToArray = exports.objectToDeploymentYaml = exports.kubeEnvToDotenv = exports.getValueOfKubeEnvVarsByName = exports.loadEnvFileAsContainerEnvVars = exports.objectToDotenv = exports.objectToKubeEnvVars = exports.trimFirstSlash = exports.getReplicasFromYaml = exports.getImageFromYaml = exports.getCurrentFramework = exports.isUsingStaticHtmlFramework = exports.isUsingDiginestAPIFramework = exports.isUsingDiginextFramework = exports.isUsingNodejsFramework = exports.isUsingExpressjsFramework = exports.getGitProviderFromRepoSSH = exports.getCurrentGitRepoData = exports.pullOrCloneGitRepo = exports.cloneGitRepo = exports.installPackages = exports.savePackageConfig = exports.getPackageConfig = exports.updateAppConfig = exports.saveAppConfig = exports.getAppConfig = exports.flattenObjectPaths = exports.flattenObjectToPost = exports.deleteFolderRecursive = exports.parseRepoSlugFromUrl = exports.shouldNotifyCliUpdate = exports.getLatestCliVersion = exports.currentVersion = exports.execCmd = exports.progressCmd = exports.logVersion = exports.replaceInFile = exports.getLongEnv = exports.stringToArray = exports.createTmpFile = exports.showDocs = exports.saveJson = exports.readJson = exports.waitUntil = exports.nowStr = void 0; exports.generateWorkspaceApiAccessToken = exports.getUnexpiredAccessToken = exports.extractWorkspaceIdFromUser = exports.extractWorkspaceSlugFromUrl = exports.wait = exports.toBase64 = exports.logHelp = exports.logBitbucketError = exports.logBitbucket = exports.getCurrentContainerEnvs = exports.getCurrentImageName = exports.getCurrentDeployment = exports.getIngressIP = exports.getIngressEndpoint = exports.getIngress = exports.getClusterIP = exports.getIPFromDomain = exports.cliContainerExec = exports.resolveEnvFilePath = void 0; // import { execa } from "execa"; const fs = __importStar(require("node:fs")); const chalk_1 = __importDefault(require("chalk")); const crypto_1 = require("crypto"); // import { compareVersions } from "compare-versions"; const dayjs_1 = __importDefault(require("dayjs")); const makeDaySlug_1 = require("diginext-utils/dist/string/makeDaySlug"); const log_1 = require("diginext-utils/dist/xconsole/log"); const dns_1 = __importDefault(require("dns")); const dotenv_1 = __importDefault(require("dotenv")); const execa_1 = require("execa"); const afs = __importStar(require("fs/promises")); const js_yaml_1 = __importDefault(require("js-yaml")); const lodash_1 = __importStar(require("lodash")); const m = __importStar(require("marked")); const marked_terminal_1 = __importDefault(require("marked-terminal")); const path_1 = __importDefault(require("path")); const simple_git_1 = require("simple-git"); const package_json_1 = __importDefault(require("../../package.json")); const config_1 = require("../config/config"); const git_utils_1 = require("../modules/git/git-utils"); const const_1 = require("../config/const"); const mongodb_1 = require("./mongodb"); const monorepo_1 = require("./monorepo"); const number_1 = require("./number"); const os_1 = require("./os"); const { marked } = m; marked.setOptions({ renderer: new marked_terminal_1.default() }); function nowStr() { return (0, dayjs_1.default)().format("YYYY-MM-DD HH:mm:ss"); } exports.nowStr = nowStr; /** * Delay/wait a specific miliseconds * @param i - waiting time in miliseconds * @param exec - callback function */ const wait = async function (i = 100, exec) { return new Promise((resolve, reject) => { setTimeout(() => { try { if (exec) exec(); resolve(true); } catch (e) { reject(e); } }, i); }); }; exports.wait = wait; /** * Wait until a condition is matched * @param condition - Condition * @param interval - Re-check interval in seconds @default 10 * @param maxWaitingTime - Max waiting time in seconds @default 30 minutes (30 * 60 = 1.800 seconds) */ async function waitUntil(condition, interval = 10, maxWaitTime = 30 * 60 * 1000) { let timeWaited = 0; while (timeWaited < maxWaitTime) { const conditionMet = await condition(); if (conditionMet) { return true; } await new Promise((resolve) => setTimeout(resolve, interval * 1000)); timeWaited += interval; } return false; } exports.waitUntil = waitUntil; async function logBitbucket(title, message, delay) { if (delay) await wait(delay); console.log(chalk_1.default.yellow("====== [BITBUCKET: " + title + "] ======")); console.log(message); process.exit(1); } exports.logBitbucket = logBitbucket; const readJson = (filePath) => { const jsonContent = fs.readFileSync(filePath).toString(); return JSON.parse(jsonContent); }; exports.readJson = readJson; const saveJson = (data, filePath, options = {}) => { const { overwrite = false, beautify = true } = options; let jsonContent = typeof data == "string" ? data : JSON.stringify(data); if (beautify) jsonContent = JSON.stringify(JSON.parse(jsonContent), null, 4); const fileExisted = fs.existsSync(filePath); if (fileExisted && !overwrite) { try { return JSON.parse(fs.readFileSync(filePath).toString()); } catch (e) { (0, log_1.logWarn)(`FILE_EXISTED >`, e); return {}; } } fs.writeFileSync(filePath, jsonContent, "utf8"); return JSON.parse(jsonContent); }; exports.saveJson = saveJson; const showDocs = async (filePath) => { // const cliMd = await importEsm("cli-markdown", module); // console.log("cliMd :>> ", cliMd); const content = await afs.readFile(filePath, "utf8"); (0, log_1.log)(marked(content)); // log(cliMd(content)); return content; }; exports.showDocs = showDocs; /** * Create temporary file with provided content * @param fileName - File name (include the extension) * @param content - Content of the file * @returns Path to the file */ const createTmpFile = (fileName, content, options = { recursive: true, encoding: "utf8" }) => { const { encoding, recursive } = options; const tmpDir = path_1.default.resolve(const_1.HOME_DIR, `tmp/${(0, makeDaySlug_1.makeDaySlug)({ divider: "" })}`); if (!fs.existsSync(tmpDir)) fs.mkdirSync(tmpDir, { recursive }); const tmpFilePath = path_1.default.resolve(tmpDir, fileName); fs.writeFileSync(tmpFilePath, content, encoding); return tmpFilePath; }; exports.createTmpFile = createTmpFile; /** * Convert string-array-like to array * @example "1" -> ["1"] | "123,555,abc,def" -> ["123","555","abc","def"] */ const stringToArray = (str, options = { typeTransform: false, divider: "," }) => { const { typeTransform = false, divider = "," } = options; const arr = str.indexOf(divider) === -1 ? [str] : str.split(divider); return typeTransform ? arr.map((item) => ((0, number_1.isNumeric)(item) ? (0, lodash_1.toNumber)(item) : item)) : arr; }; exports.stringToArray = stringToArray; /** * Get full name of the environment, such as: `development`, `production` (instead of `dev`, `prod`) * @param {String} env * @returns {String} */ const getLongEnv = (env) => { if (env == "dev") { return "development"; } else if (env == "prod") { return "production"; } else if (env == "cana") { return "canary"; } else if (env == "stag") { return "staging"; } else { return env; } }; exports.getLongEnv = getLongEnv; /** * @param {String} filePath * @param {[{keyword:(RegExp|String), replacement:String}]} replacement=[] * @return {String} - New content */ const replaceInFile = async (filePath, replacement = []) => { let fileContent = fs.readFileSync(filePath, "utf-8"); replacement.forEach(({ keyword, replacement: replaceWith }) => { fileContent = fileContent.replace(keyword, replaceWith); }); fs.writeFileSync(filePath, fileContent, "utf8"); return fileContent; }; exports.replaceInFile = replaceInFile; function toBase64(str) { return Buffer.from(str).toString("base64"); } exports.toBase64 = toBase64; function logVersion() { console.warn(chalk_1.default.bgWhite(chalk_1.default.bold(chalk_1.default.black(` [ Diginext CLI - v${package_json_1.default.version} | ${nowStr()} ] `)))); } exports.logVersion = logVersion; const progressCmd = async (command, options) => { if (options === null || options === void 0 ? void 0 : options.isDebugging) console.log("Processing command :>> ", command); const stream = (0, execa_1.execaCommand)(command); let stdout = ""; stream.stdio.forEach((_stdio) => { if (_stdio) { _stdio.on("data", (data) => { let logMsg = data.toString(); stdout += logMsg; if ((options === null || options === void 0 ? void 0 : options.isDebugging) && logMsg) console.log(logMsg); if ((options === null || options === void 0 ? void 0 : options.onProgress) && logMsg) options === null || options === void 0 ? void 0 : options.onProgress(logMsg); }); } }); const end = await stream; return stdout || end.stdout; }; exports.progressCmd = progressCmd; async function execCmd(cmd, errorMsgOrCallback = "") { try { let { stdout } = await (0, execa_1.execaCommand)(cmd, config_1.cliOpts); // console.log(`[execCmd]`, { stdout }); return stdout; } catch (e) { if (typeof errorMsgOrCallback == "string") { const errorMsg = errorMsgOrCallback; if (errorMsg != "") { (0, log_1.logError)(`${errorMsg} > ${e.stack}`); } else { (0, log_1.logWarn)(`[FAILED_BUT_IGNORE] ${e.message}`); } return; } else { // if it's a callback function try { errorMsgOrCallback(e); } catch (f) { (0, log_1.logWarn)(`[FAILED_BUT_IGNORE] ${f.message}`); return; } } } } exports.execCmd = execCmd; /** * Get current CLI version */ function currentVersion() { return package_json_1.default.version; } exports.currentVersion = currentVersion; /** * Get latest version of the CLI from NPM */ async function getLatestCliVersion() { const latestVersion = await execCmd(`npm show ${package_json_1.default.name} version`); return latestVersion; } exports.getLatestCliVersion = getLatestCliVersion; /** * Check if CLI version is latest or not, if not -> return FALSE */ async function shouldNotifyCliUpdate() { const curVersion = currentVersion(); if (curVersion.indexOf("prerelease") > -1) return false; const latestVersion = await getLatestCliVersion(); let [lastestBreaking, lastestFeature, lastestPatch] = latestVersion.split(".").map((num) => (0, lodash_1.toInteger)(num)); let [curBreaking, curFeature, curPatch] = curVersion.split(".").map((num) => (0, lodash_1.toInteger)(num)); if (lastestBreaking > curBreaking) return false; // no need to notify when there is a new breaking change version if (lastestBreaking === curBreaking && lastestFeature > curFeature) return true; if (lastestBreaking === curBreaking && lastestFeature === curFeature && lastestPatch > curPatch) return true; return false; } exports.shouldNotifyCliUpdate = shouldNotifyCliUpdate; async function logBitbucketError(error, delay, location, shouldExit = false) { if (delay) await wait(delay); try { delete error.request.request; } catch (e) { } console.error(error); const errMsg = error.message ? error.message : error.error.message; const reason = error.error && error.error.error && error.error.error.fields ? error.error.error.fields : error.error.error.message; console.error(chalk_1.default.red(`[ERROR ${error.status}: ${errMsg} | ${nowStr()}]`)); console.error(chalk_1.default.yellow("[REASON]"), reason); if (location) console.error(chalk_1.default.yellow("[LOCATION]"), location); console.error(error.request); if (shouldExit) process.exit(1); } exports.logBitbucketError = logBitbucketError; const parseRepoSlugFromUrl = (url) => { // https://digitop-duynguyen@bitbucket.org/digitopvn/diginext-cli.git let n = url.split("/").pop().split(".").shift(); return n; }; exports.parseRepoSlugFromUrl = parseRepoSlugFromUrl; const deleteFolderRecursive = async (dir) => { if (fs.existsSync(dir)) { // for (let entry of await afs.readdir(dir)) { // const filePath = path.resolve(dir, entry); // // use "unlink" to delete every single file // if ((await afs.lstat(filePath)).isDirectory()) await deleteFolderRecursive(filePath); // else await afs.unlink(filePath); // } // remove the directory itself await afs.rm(dir, { recursive: true, force: true }); } }; exports.deleteFolderRecursive = deleteFolderRecursive; /** * Flatten the object into 1-level-object (with key paths) * @example {a: {b: [{c: 1}, {c: 2}]}, e: 3} -> {"a.b[0].c": 1, "a.b[1].c": 2, "e": 3} */ function flattenObjectToPost(object = {}, initialPathPrefix = "") { if (!object || typeof object !== "object") return [{ [initialPathPrefix]: object }]; const prefix = initialPathPrefix ? (Array.isArray(object) ? initialPathPrefix : `${initialPathPrefix}`) : ""; const _arr = Object.entries(object).flatMap(([key]) => flattenObjectToPost(object[key], Array.isArray(object) ? `${prefix}[${key}]` : `${prefix}[${key}]`)); // console.log("_arr :>> ", _arr); if ((0, lodash_1.isEmpty)(_arr)) return {}; const res = _arr.reduce((acc, _path) => ({ ...acc, ..._path })); // console.log("res :>> ", res); return res; } exports.flattenObjectToPost = flattenObjectToPost; /** * Flatten the object into 1-level-object (with key paths) * @example {a: {b: [{c: 1}, {c: 2}]}, e: 3} -> {"a.b.0.c": 1, "a.b.1.c": 2, "e": 3} */ function flattenObjectPaths(object = {}, initialPathPrefix = "") { if (!object || typeof object !== "object") return [{ [initialPathPrefix]: object }]; const prefix = initialPathPrefix ? (Array.isArray(object) ? initialPathPrefix : `${initialPathPrefix}.`) : ""; const _arr = Object.entries(object).flatMap(([key]) => flattenObjectPaths(object[key], Array.isArray(object) ? `${prefix}.${key}` : `${prefix}${key}`)); // console.log("_arr :>> ", _arr); if ((0, lodash_1.isEmpty)(_arr)) return {}; const res = _arr.reduce((acc, _path) => ({ ...acc, ..._path })); // console.log("res :>> ", res); return res; } exports.flattenObjectPaths = flattenObjectPaths; /** * Get object of project configuration from "dx.json" * @param {String} [directory] - Absolute path to project directory */ const getAppConfig = (directory) => { const filePath = path_1.default.resolve(directory || process.cwd(), "dx.json"); if (!fs.existsSync(filePath)) return; const cfg = (0, exports.readJson)(filePath); return cfg; }; exports.getAppConfig = getAppConfig; /** * Save object of project configuration to "dx.json" * @param {Object} appConfig - Object data of the config * @param {SaveOpts} [options] - Save options * @param {String} [options.directory] - Absolute path to project directory @default process.cwd() * @param {Boolean} [options.create] - TRUE will create new file if not existed. @default false */ const saveAppConfig = (appConfig, options = { directory: process.cwd(), create: false }) => { const { directory, create } = options; const filePath = path_1.default.resolve(directory || process.cwd(), "dx.json"); if (!create && !fs.existsSync(filePath)) (0, log_1.logError)(`Không tìm thấy "dx.json"`); if (fs.existsSync(filePath)) fs.unlinkSync(filePath); const content = JSON.stringify(appConfig, null, 2); fs.writeFileSync(filePath, content, "utf8"); return (0, exports.getAppConfig)(directory); }; exports.saveAppConfig = saveAppConfig; /** * Update values of app config ("dx.json") * @param updatedData - updated data */ const updateAppConfig = (updatedData, options = {}) => { const { directory = process.cwd() } = options; const currentAppConfig = (0, exports.getAppConfig)(directory); const updatedDataMap = flattenObjectPaths(updatedData); Object.entries(updatedDataMap).map(([keyPath, value]) => { lodash_1.default.set(currentAppConfig, keyPath, value); }); (0, exports.saveAppConfig)(currentAppConfig, { directory }); return currentAppConfig; }; exports.updateAppConfig = updateAppConfig; /** * Get object of project configuration from "../../package.json" * @param {Object} [options] - Options * @param {String} [options.directory] - Absolute path to project directory * @param {Boolean} [options.ignoreIfNotExisted] - TRUE ignore the error if not existed. * @return {Object} */ const getPackageConfig = (options) => { const { directory, ignoreIfNotExisted = true } = options; let shouldReturn = true; const filePath = path_1.default.resolve(directory || process.cwd(), "package.json"); if (!fs.existsSync(filePath)) { if (ignoreIfNotExisted) { shouldReturn = false; } else { (0, log_1.logError)(`Không tìm thấy "package.json"`); } } return shouldReturn ? (0, exports.readJson)(filePath) : {}; }; exports.getPackageConfig = getPackageConfig; /** * Save object of project configuration to "package.json" * @param {Object} _config - Object data of the config * @param {SaveOpts} [options] - Options * @param {String} [options.directory] - Absolute path to project directory * @param {Boolean} [options.create] - TRUE will create new file if not existed. * @param {Boolean} [options.ignoreIfNotExisted] - TRUE ignore the error if not existed. */ const savePackageConfig = (_config, options) => { const { directory, ignoreIfNotExisted } = options; let shouldWriteFile = true; const filePath = path_1.default.resolve(directory || process.cwd(), "package.json"); if (!options.create && !fs.existsSync(filePath) && !ignoreIfNotExisted) { (0, log_1.logError)(`Không tìm thấy "package.json"`); shouldWriteFile = false; } if (shouldWriteFile) { const content = JSON.stringify(_config, null, 2); return fs.writeFileSync(filePath, content, "utf8"); } }; exports.savePackageConfig = savePackageConfig; /** * Process `npm install` or `yarn install` or `pnpm install` on current directory */ const installPackages = async () => { (0, log_1.log)(`Đang tiến hành cài đặt "package.json" mới...`); let areDependenciesInstalled = false; // Install dependencies try { await (0, execa_1.execa)("yarn", ["install"]); // console.log(stdout); areDependenciesInstalled = true; } catch (e) { (0, log_1.logWarn)("YARN not found, switch to `npm install` instead."); } if (!areDependenciesInstalled) { let isOk; try { await (0, execa_1.execa)("npm", ["install"]); isOk = true; } catch (e) { (0, log_1.logError)("NPM not found -> ", e); isOk = false; } return isOk; } else { return true; } }; exports.installPackages = installPackages; const cloneGitRepo = async (repoSSH, dir, options = {}) => { // let git; const { onUpdate } = options; const onProgress = ({ method, stage, progress }) => { const message = `git.${method} ${stage} stage ${progress}% complete`; if (onUpdate) onUpdate(message, progress); }; if (fs.existsSync(dir)) { try { git = (0, simple_git_1.simpleGit)(dir, { progress: onProgress }); await git.clone(repoSSH, dir, ["--depth", "1"]); console.log("\ndone"); } catch (e) { } } }; exports.cloneGitRepo = cloneGitRepo; // const pullOrCloneGitRepo = async (repoSSH, dir, branch, options = {}) => { var _a; let git; let success = false; if (options === null || options === void 0 ? void 0 : options.isDebugging) console.log("pullOrCloneGitRepo() > repoSSH :>> ", repoSSH); if (options === null || options === void 0 ? void 0 : options.isDebugging) console.log("pullOrCloneGitRepo() > dir :>> ", dir); if (options === null || options === void 0 ? void 0 : options.isDebugging) console.log("pullOrCloneGitRepo() > options :>> ", options); const onProgress = ({ method, stage, progress }) => { const message = `git.${method} ${stage} stage ${progress}% complete`; if (options === null || options === void 0 ? void 0 : options.onUpdate) options === null || options === void 0 ? void 0 : options.onUpdate(message, progress); }; if (options === null || options === void 0 ? void 0 : options.isDebugging) console.log("pullOrCloneGitRepo() > repoSSH :>> ", repoSSH); // TMP DIRECTORY NOT EXISTS if (!fs.existsSync(dir)) { if (options === null || options === void 0 ? void 0 : options.isDebugging) console.log("pullOrCloneGitRepo() > directory NOT exists :>> try to CLONE..."); if (options === null || options === void 0 ? void 0 : options.onUpdate) options === null || options === void 0 ? void 0 : options.onUpdate(`Cache source code not found. Cloning "${repoSSH}" (${branch}) to "${dir}" directory.`); try { git = (0, simple_git_1.simpleGit)({ progress: onProgress }); await git.clone(repoSSH, dir, [`--branch=${branch}`, "--single-branch", "--depth=1"]); if (options === null || options === void 0 ? void 0 : options.isDebugging) console.log("✅ pullOrCloneGitRepo() > Success to CLONE !"); // remove git on finish if (options === null || options === void 0 ? void 0 : options.removeGitOnFinish) await (0, exports.deleteFolderRecursive)(path_1.default.join(dir, ".git")); if (options === null || options === void 0 ? void 0 : options.removeCIOnFinish) await (0, exports.deleteFolderRecursive)(path_1.default.join(dir, ".github")); success = true; return success; } catch (e) { if (options === null || options === void 0 ? void 0 : options.isDebugging) console.log("pullOrCloneGitRepo() > Failed to CLONE !"); if (options === null || options === void 0 ? void 0 : options.onUpdate) options === null || options === void 0 ? void 0 : options.onUpdate(`Failed to clone "${repoSSH}" (${branch}) to "${dir}" directory: ${e.message}`); } } // TMP DIRECTORY -> EXISTS try { // try pull if (options === null || options === void 0 ? void 0 : options.isDebugging) console.log("pullOrCloneGitRepo() > directory exists :>> try to PULL..."); git = (0, simple_git_1.simpleGit)(dir, { progress: onProgress }); // ----------------------- // ! DO NOT SET TO "FALSE" // ----------------------- const remotes = ((await git.getRemotes(true)) || []).filter((remote) => remote.name === "origin"); const originRemote = remotes[0]; if (!originRemote) throw new Error(`This directory doesn't have any git remotes.`); if (options === null || options === void 0 ? void 0 : options.isDebugging) console.log("originRemote :>> ", originRemote, `>`, { repoSSH }); if (((_a = originRemote === null || originRemote === void 0 ? void 0 : originRemote.refs) === null || _a === void 0 ? void 0 : _a.fetch) !== repoSSH) await git.addRemote("origin", repoSSH); const curBranch = await (0, git_utils_1.getCurrentGitBranch)(dir); await git.pull("origin", curBranch, ["--no-ff"]); // remove git on finish if (options === null || options === void 0 ? void 0 : options.removeGitOnFinish) await (0, exports.deleteFolderRecursive)(path_1.default.join(dir, ".git")); if (options === null || options === void 0 ? void 0 : options.removeCIOnFinish) await (0, exports.deleteFolderRecursive)(path_1.default.join(dir, ".github")); success = true; } catch (e) { // if PULL failed -> delete dir -> try CLONE if (options === null || options === void 0 ? void 0 : options.isDebugging) console.log("pullOrCloneGitRepo() > Failed to PULL :>> try to CLONE...", e); if (options === null || options === void 0 ? void 0 : options.onUpdate) options === null || options === void 0 ? void 0 : options.onUpdate(`Failed to pull "${repoSSH}" in "${dir}" directory (${e.message}) -> trying to clone new...`); try { // just for sure... await (0, exports.deleteFolderRecursive)(dir); // for CLI create new app from a framework git = (0, simple_git_1.simpleGit)({ progress: onProgress }); await git.clone(repoSSH, dir, [`--branch=${branch}`, "--single-branch", "--depth=1"]); if (options === null || options === void 0 ? void 0 : options.isDebugging) console.log("pullOrCloneGitRepo() > Success to CLONE !"); // remove git on finish if (options === null || options === void 0 ? void 0 : options.removeGitOnFinish) await (0, exports.deleteFolderRecursive)(path_1.default.join(dir, ".git")); if (options === null || options === void 0 ? void 0 : options.removeCIOnFinish) await (0, exports.deleteFolderRecursive)(path_1.default.join(dir, ".github")); success = true; } catch (e2) { if (options === null || options === void 0 ? void 0 : options.isDebugging) console.log("pullOrCloneGitRepo() > Failed to PULL & CLONE :>> ", e2); if (options === null || options === void 0 ? void 0 : options.onUpdate) options === null || options === void 0 ? void 0 : options.onUpdate(`Failed to clone "${repoSSH}" (${branch}) to "${dir}" directory: ${e2.message}`); } } return success; }; exports.pullOrCloneGitRepo = pullOrCloneGitRepo; /** * Get current remote SSH & URL */ const getCurrentGitRepoData = async (dir = process.cwd(), options) => { var _a, _b; try { const git = (0, simple_git_1.simpleGit)(dir, { baseDir: `${dir}`, binary: "git", }); // ----------------------- // ! DO NOT SET TO "FALSE" // ----------------------- const remotes = await git.getRemotes(true); if (options === null || options === void 0 ? void 0 : options.isDebugging) { console.log("[CURRENT DIR] Current git > remotes :>>"); console.dir(remotes, { depth: 10 }); } const repoSshOrUrl = (_b = (_a = remotes[0]) === null || _a === void 0 ? void 0 : _a.refs) === null || _b === void 0 ? void 0 : _b.fetch; if (!repoSshOrUrl) return; if (options === null || options === void 0 ? void 0 : options.isDebugging) console.log("getCurrentGitRepoData() > repoSshOrUrl :>> ", repoSshOrUrl); const branch = await (0, git_utils_1.getCurrentGitBranch)(dir); if (!branch) return; if (options === null || options === void 0 ? void 0 : options.isDebugging) console.log("getCurrentGitRepoData() > branch :>> ", branch); const repoSSH = (0, git_utils_1.isValidRepoURL)(repoSshOrUrl) ? (0, git_utils_1.repoUrlToRepoSSH)(repoSshOrUrl) : repoSshOrUrl; const repoURL = (0, git_utils_1.isValidRepoURL)(repoSshOrUrl) ? repoSshOrUrl : (0, git_utils_1.repoSshToRepoURL)(repoSshOrUrl); if (options === null || options === void 0 ? void 0 : options.isDebugging) { console.log("getCurrentGitRepoData() > repoSSH :>> ", repoSSH); console.log("getCurrentGitRepoData() > repoURL :>> ", repoURL); } const gitData = (0, git_utils_1.parseGitRepoDataFromRepoSSH)(repoSSH); if (options === null || options === void 0 ? void 0 : options.isDebugging) console.log("getCurrentGitRepoData() > gitData :>> ", gitData); const { repoSlug: slug, providerType: provider, namespace, gitDomain, fullSlug } = gitData; return { repoSSH, repoURL, provider, slug, fullSlug, namespace, gitDomain, branch }; } catch (e) { if (options === null || options === void 0 ? void 0 : options.isDebugging) console.warn(`getCurrentGitRepoData() > error :>>`, e.toString()); return; } }; exports.getCurrentGitRepoData = getCurrentGitRepoData; const getGitProviderFromRepoSSH = (repoSSH) => { if (repoSSH.indexOf("bitbucket") > -1) return "bitbucket"; if (repoSSH.indexOf("github") > -1) return "github"; // if (repoSSH.indexOf("gitlab") > -1) return "gitlab"; return; }; exports.getGitProviderFromRepoSSH = getGitProviderFromRepoSSH; const isUsingExpressjsFramework = (options) => { let val = false; const { error, appDirectory } = (0, monorepo_1.checkMonorepo)(options); if (error) return val; // framework name const frameworkConfigPath = path_1.default.resolve(appDirectory || process.cwd(), "package.json"); // TODO: check if using express js return val; }; exports.isUsingExpressjsFramework = isUsingExpressjsFramework; const isUsingNodejsFramework = (options) => { let val = false; const { error, appDirectory } = (0, monorepo_1.checkMonorepo)(options); if (error) return val; // framework name const frameworkConfigPath = path_1.default.resolve(appDirectory || process.cwd(), "package.json"); return val; }; exports.isUsingNodejsFramework = isUsingNodejsFramework; const isUsingDiginextFramework = async (options) => { var _a; let val = false; const { error, appDirectory } = (0, monorepo_1.checkMonorepo)(options); if (error) return val; // framework name const frameworkConfigPath = path_1.default.resolve(appDirectory || process.cwd(), "package.json"); if (fs.existsSync(frameworkConfigPath)) { const frameworkConfig = await (_a = frameworkConfigPath, Promise.resolve().then(() => __importStar(require(_a)))); val = frameworkConfig.dependencies && frameworkConfig.dependencies.hasOwnProperty("next"); } return val; }; exports.isUsingDiginextFramework = isUsingDiginextFramework; const isUsingDiginestAPIFramework = async (options) => { var _a; let val = false; const { error, appDirectory } = (0, monorepo_1.checkMonorepo)(options); if (error) return val; // framework name const frameworkConfigPath = path_1.default.resolve(appDirectory || process.cwd(), "package.json"); if (fs.existsSync(frameworkConfigPath)) { const frameworkConfig = await (_a = frameworkConfigPath, Promise.resolve().then(() => __importStar(require(_a)))); val = frameworkConfig.dependencies && frameworkConfig.dependencies.hasOwnProperty("@nestjs/core"); } return val; }; exports.isUsingDiginestAPIFramework = isUsingDiginestAPIFramework; const isUsingStaticHtmlFramework = async (options) => { var _a; let val = false; const { error, appDirectory } = (0, monorepo_1.checkMonorepo)(options); if (error) return val; const frameworkConfigPath = path_1.default.resolve(appDirectory || process.cwd(), "dx.json"); if (fs.existsSync(frameworkConfigPath)) { const frameworkConfig = await (_a = frameworkConfigPath, Promise.resolve().then(() => __importStar(require(_a)))); val = typeof frameworkConfig.framework != "undefined" && frameworkConfig.framework == "static"; } return val; }; exports.isUsingStaticHtmlFramework = isUsingStaticHtmlFramework; /** * Get current using framework of the project. * @return {("unknown"|"diginest"|"diginext"|"nodejs"|"expressjs"|"static")} */ const getCurrentFramework = (options) => { let val = "unknown"; if ((0, exports.isUsingDiginextFramework)(options)) val = "diginext"; if ((0, exports.isUsingDiginestAPIFramework)(options)) val = "diginest"; if ((0, exports.isUsingNodejsFramework)(options)) val = "nodejs"; if ((0, exports.isUsingExpressjsFramework)(options)) val = "expressjs"; if ((0, exports.isUsingStaticHtmlFramework)(options)) val = "static"; return val; }; exports.getCurrentFramework = getCurrentFramework; const getImageFromYaml = (docs) => { let value = ""; docs.map((doc) => { // log("doc", doc); if (doc && doc.kind == "Deployment") { value = doc.spec.template.spec.containers[0].image; } }); return value; }; exports.getImageFromYaml = getImageFromYaml; const getReplicasFromYaml = (docs) => { let value = 1; docs.map((doc) => { // log("doc", doc); if (doc && doc.kind == "Deployment") { value = doc.spec.replicas; } }); return value; }; exports.getReplicasFromYaml = getReplicasFromYaml; /** * Completely remove the first / of the string * @param {String} input * @returns {String} */ const trimFirstSlash = (input) => { // trim first slash of BASE_PATH: let output = input; for (let i = 0; i < 10; i++) { if (output.length > 0 && output.charAt(0) == "/") output = output.substr(1); } return output; }; exports.trimFirstSlash = trimFirstSlash; /** * Convert {Object} to environment variables of Kuberketes container * @param {Object} object - Input raw object, **not containing any methods** */ const objectToKubeEnvVars = (object) => { return Object.entries(object).map(([name, value]) => { return { name, value }; }); }; exports.objectToKubeEnvVars = objectToKubeEnvVars; /** * Convert {Object} to .env content * @param {Object} object - Input raw object, **not containing any methods** * @returns {String} */ const objectToDotenv = (object) => { let content = ""; for (let key in object) { let val = object[key]; content += key + "=" + `"${val}"` + "\n"; } return content; }; exports.objectToDotenv = objectToDotenv; /** * Load ENV file (.env.*) and parse to array of K8S container environment variables */ const loadEnvFileAsContainerEnvVars = (filePath) => { const envObject = dotenv_1.default.config({ path: filePath }).parsed; if ((0, lodash_1.isEmpty)(envObject)) return []; return (0, exports.objectToKubeEnvVars)(envObject); }; exports.loadEnvFileAsContainerEnvVars = loadEnvFileAsContainerEnvVars; /** * Grab value of Kube ENV variables by name */ const getValueOfKubeEnvVarsByName = (name, envVars) => { var _a; return (_a = envVars.find((envVar) => envVar.name === name)) === null || _a === void 0 ? void 0 : _a.value; }; exports.getValueOfKubeEnvVarsByName = getValueOfKubeEnvVarsByName; /** * Convert K8S container's ENV to .env content * @param {[{name,value}]} inputEnvs - Input raw object, **not containing any methods** * @returns {String} */ const kubeEnvToDotenv = (inputEnvs) => { let content = ""; inputEnvs.map((envVar) => { content += envVar.name + "=" + `"${envVar.value}"` + "\n"; }); return content; }; exports.kubeEnvToDotenv = kubeEnvToDotenv; const objectToDeploymentYaml = (deploymentCfg) => { let deploymentContent = ""; if (!(0, lodash_1.isArray)(deploymentCfg)) deploymentCfg = [deploymentCfg]; deploymentCfg.map((doc) => { if (doc) { deploymentContent += js_yaml_1.default.dump(doc); deploymentContent += "\n---\n"; } }); return deploymentContent; }; exports.objectToDeploymentYaml = objectToDeploymentYaml; const strToArray = (str, splitter = ",") => { let arr = []; if (str.indexOf(splitter) > -1) { arr = [...str.split(splitter)]; } else { arr = [str]; } return arr; }; exports.strToArray = strToArray; const getDiginextEnvVars = (env, projectSlug, domains) => { let environment = "staging"; if (env == "prod") environment = "production"; return { NEXT_PUBLIC_ENV: environment, NEXT_PUBLIC_CDN_BASE_PATH: `${const_1.DIGITOP_CDN_URL}/${projectSlug}/${env}`, NEXT_PUBLIC_BASE_PATH: typeof domains != "undefined" && domains.length ? "" : projectSlug, NEXT_PUBLIC_BASE_URL: typeof domains != "undefined" && domains.length ? `https://${domains[0]}` : ``, IRON_SESSION_SECRET: "NcvPDa2tlje1i6nvzZt6PmCHU5qcTcx4", }; }; exports.getDiginextEnvVars = getDiginextEnvVars; const objToEnv = (obj = {}) => { let content = ""; for (const [key, val] of Object.entries(obj)) { let value = val; if ((0, lodash_1.isString)(val)) value = `"${val}"`; content += `${key}=${value}\n`; } return content; }; exports.objToEnv = objToEnv; const sequentialExec = async (array, func) => { if (typeof func == "undefined") { (0, log_1.logWarn)("Input function not defined."); return; } return array.reduce(async (previous, item) => { await func(item); return item; }, Promise.resolve([])); }; exports.sequentialExec = sequentialExec; /** * Resolve a location path of the file within the application. */ const resolveFilePath = (fileNamePrefix, options) => { const { targetDirectory = process.cwd(), env = "dev", ignoreIfNotExisted = false, msg } = options; let filePath = path_1.default.resolve(targetDirectory, `${fileNamePrefix}.${env}`); if (fs.existsSync(filePath)) return filePath; filePath = path_1.default.resolve(targetDirectory, `deployment/${fileNamePrefix}.${env}`); if (fs.existsSync(filePath)) return filePath; filePath = path_1.default.resolve(targetDirectory, fileNamePrefix); if (fs.existsSync(filePath)) return filePath; filePath = path_1.default.resolve(targetDirectory, `deployment/${fileNamePrefix}`); if (fs.existsSync(filePath)) return filePath; filePath = path_1.default.resolve(targetDirectory, fileNamePrefix); if (fs.existsSync(filePath)) return filePath; if (!ignoreIfNotExisted) { const message = msg !== null && msg !== void 0 ? msg : `Missing "./${fileNamePrefix}" file, are you in the project directory?`; throw new Error(message); } else { if (msg) (0, log_1.logWarn)(msg); } return; }; exports.resolveFilePath = resolveFilePath; /** * Resolve a location path of the "Dockerfile". */ const resolveDockerfilePath = (options) => (0, exports.resolveFilePath)("Dockerfile", options); exports.resolveDockerfilePath = resolveDockerfilePath; /** * Resolve a location path of the DOTENV (`.env.*`) file. */ const resolveEnvFilePath = (options) => (0, exports.resolveFilePath)(".env", options); exports.resolveEnvFilePath = resolveEnvFilePath; /** * Execute an command within a Docker container * @deprecated */ const cliContainerExec = async (command, options) => { let getContainerName, cliContainerName; // restart the CLI container to update the environment: // if (!options.pipelineReady) { // await startPipeline([], options); // await wait(2000); // options.pipelineReady = true; // } if ((0, os_1.isWin)()) { getContainerName = await (0, execa_1.execaCommand)(`docker ps --format '{{.Names}}' | findstr diginext-cli`); } else { getContainerName = await (0, execa_1.execaCommand)(`docker ps --format '{{.Names}}' | grep diginext-cli`); } cliContainerName = getContainerName.stdout; (0, log_1.log)("[cliContainerExec] cliContainerName:", cliContainerName); if (cliContainerName) { if (options.isDebugging) { (0, log_1.log)(chalk_1.default.cyan("---------------- DIGINEXT-CLI DOCKER VERSION ------------------")); await (0, execa_1.execa)("docker", ["exec", "-ti", cliContainerName, "docker", "-v"], { stdio: "inherit" }); (0, log_1.log)(chalk_1.default.cyan("---------------- INSIDE DIGINEXT-CLI CONTAINER ----------------")); await (0, execa_1.execa)("docker", ["exec", "-ti", cliContainerName, "ls"], { stdio: "inherit" }); (0, log_1.log)(chalk_1.default.cyan("---------------------------------------")); } const args = command.split(" "); const { stdout } = await (0, execa_1.execa)("docker", ["exec", "-ti", cliContainerName, ...args], { stdio: "inherit", }); return stdout; } else { return false; } }; exports.cliContainerExec = cliContainerExec; async function logHelp(options) { (0, log_1.log)(`Nothing... bwahahaha...`); } exports.logHelp = logHelp; const getIPFromDomain = async (domain) => { return new Promise((resolve, reject) => { dns_1.default.lookup(domain, (err, address, family) => { if (err) { (0, log_1.logError)(`${domain} chưa được trỏ về IP nào.`); reject(err); } resolve(address); }); }); }; exports.getIPFromDomain = getIPFromDomain; const getClusterIP = async (options) => { let svcName = "nginx-ingress-controller", namespace = "nginx-ingress"; let ingress, stdout; try { stdout = await (0, exports.cliContainerExec)(`kubectl get svc/${svcName} -n ${namespace} -o json`, options); ingress = stdout ? JSON.parse(stdout) : null; } catch (e) { svcName = "ingress-nginx-controller"; namespace = "ingress-nginx"; stdout = await (0, exports.cliContainerExec)(`kubectl get svc/${svcName} -n ${namespace} -o json`, options); ingress = stdout ? JSON.parse(stdout) : null; } return ingress ? ingress.status.loadBalancer.ingress[0].ip : null; }; exports.getClusterIP = getClusterIP; const getIngress = async (ingName, namespace = "default", options = {}) => { let stdout = await (0, exports.cliContainerExec)(`kubectl get ing/${ingName} -n ${namespace} -o json`, options); const ingress = stdout ? JSON.parse(stdout) : null; return ingress; }; exports.getIngress = getIngress; const getIngressEndpoint = async (ingName, namespace = "default", options = {}) => { let ingress = await (0, exports.getIngress)(ingName, namespace, options); return ingress.spec.rules[0].host; }; exports.getIngressEndpoint = getIngressEndpoint; const getIngressIP = async (ingName, namespace = "default", index = 0, options = {}) => { let stdout = await (0, exports.cliContainerExec)(`kubectl get ing/${ingName} -n ${namespace} -o json`, options); const ingress = stdout ? JSON.parse(stdout) : null; return ingress ? ingress.status.loadBalancer.ingress[index].ip : null; }; exports.getIngressIP = getIngressIP; const getCurrentDeployment = async (deployName, namespace = "default", options = {}) => { let stdout = await (0, exports.cliContainerExec)(`kubectl get deploy/${deployName} -n ${namespace} -o json`, options); if (typeof stdout == "string") { try { return JSON.parse(stdout); } catch (e) { return null; } } else { return null; } }; exports.getCurrentDeployment = getCurrentDeployment; const getCurrentImageName = async (deployName, namespace = "default", options = {}) => { const deployObj = await (0, exports.getCurrentDeployment)(deployName, namespace, options); return deployObj.spec.template.spec.containers[0].image || ""; }; exports.getCurrentImageName = getCurrentImageName; const getCurrentContainerEnvs = async (deployName, namespace = "default", options = {}) => { const deployObj = await (0, exports.getCurrentDeployment)(deployName, namespace, options); return deployObj.spec.template.spec.containers[0].env || {}; }; exports.getCurrentContainerEnvs = getCurrentContainerEnvs; const extractWorkspaceSlugFromUrl = (url) => { try { return url.split("//")[1].split(".")[0]; } catch (e) { return; } }; exports.extractWorkspaceSlugFromUrl = extractWorkspaceSlugFromUrl; const extractWorkspaceIdFromUser = (user) => { const workspaceId = user.activeWorkspace._id ? mongodb_1.MongoDB.toString(user.activeWorkspace._id) : mongodb_1.MongoDB.toString(user.activeWorkspace); return workspaceId; }; exports.extractWorkspaceIdFromUser = extractWorkspaceIdFromUser; function getUnexpiredAccessToken(access_token) { let expiredDate = (0, dayjs_1.default)("2999-12-31"); let expiredTimestamp = expiredDate.diff((0, dayjs_1.default)()); // assign "access_token" info to request: const token = { access_token, expiredTimestamp: expiredTimestamp, expiredDate: expiredDate.toDate(), expiredDateGTM7: expiredDate.format("YYYY-MM-DD HH:mm:ss"), }; return token; } exports.getUnexpiredAccessToken = getUnexpiredAccessToken; const generateWorkspaceApiAccessToken = () => { const name = (0, crypto_1.randomUUID)(); return { name, value: `${name}-${(0, crypto_1.randomUUID)()}` }; }; exports.generateWorkspaceApiAccessToken = generateWorkspaceApiAccessToken;