UNPKG

@cto.ai/ops

Version:

šŸ’» CTO.ai Ops - The CLI built for Teams šŸš€

126 lines (125 loc) • 5.21 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const tslib_1 = require("tslib"); const sdk_1 = require("@cto.ai/sdk"); const child_process_1 = require("child_process"); const debug_1 = tslib_1.__importDefault(require("debug")); const uuid_1 = require("uuid"); const path = tslib_1.__importStar(require("path")); const fs = tslib_1.__importStar(require("fs-extra")); const CustomErrors_1 = require("../errors/CustomErrors"); const utils_1 = require("../utils"); const stateAndConfigHelpers_1 = require("../utils/stateAndConfigHelpers"); const debug = debug_1.default('ops:WorkflowService'); const { callOutCyan, whiteBright, bold, redBright } = sdk_1.ux.colors; class WorkflowService { async run(workflow, opParams, config) { try { const { name, steps } = Object.assign(Object.assign({}, workflow), { steps: interpolateRunCmd(workflow, config.team.name) }); workflow = getRunEnv(workflow, config); setRunEnv(workflow, config); const options = { stdio: 'inherit', shell: true, env: process.env, }; const workflowCommands = steps.map(convertCommandToSpawnFunction(options)); const errors = []; const workflowPipeline = utils_1.asyncPipe(...workflowCommands); const finalOutput = await workflowPipeline({ errors, args: opParams, }); const { errors: finalErrors } = finalOutput; if (finalErrors.length) { console.log(`\nā—ļø Workflow ${callOutCyan(name)} failed.`); finalErrors.forEach((error, i) => { console.log(redBright(`šŸ¤” There was a problem with the ${whiteBright(error.runCommand)}.\n`)); }); } !finalErrors.length && _printMessage(`😌 Workflow ${callOutCyan(name)} completed successfully.`); } catch (err) { debug('%O', err); throw err; } } } exports.WorkflowService = WorkflowService; const getRunEnv = (workflow, config) => { const runId = uuid_1.v4(); workflow.runId = runId; const opsHome = `${process.env.HOME || process.env.USERPROFILE}/.config/@cto.ai/ops`; workflow.opsHome = opsHome === undefined ? '' : opsHome; workflow.stateDir = `/${config.team.name}/${workflow.name}/${runId}`; workflow.configDir = `/${config.team.name}/${workflow.name}`; if (!fs.existsSync(workflow.stateDir)) { try { fs.ensureDirSync(path.resolve(workflow.opsHome + workflow.stateDir)); } catch (err) { this.debug('%O', err); throw new CustomErrors_1.CouldNotMakeDir(err, path.resolve(workflow.opsHome + workflow.stateDir)); } } return workflow; }; // TODO this should be refactored so with the opService setEnv to make it dry const setRunEnv = (workflow, config) => { const defaultEnv = { SDK_STATE_DIR: workflow.stateDir, SDK_CONFIG_DIR: workflow.configDir, RUN_ID: workflow.runId, OPS_OP_NAME: workflow.name, OPS_TEAM_NAME: config.team.name, OPS_ACCESS_TOKEN: config.tokens.accessToken, }; const opsYamlEnv = workflow.env ? workflow.env.reduce(convertEnvStringsToObject, {}) : {}; workflow.env = Object.entries(Object.assign(Object.assign({}, defaultEnv), opsYamlEnv)) .map(overrideEnvWithProcessEnv(process.env)) .map(([key, val]) => `${key}=${val}`); workflow.env.forEach(env => { const envParts = env.split('='); process.env[envParts[0]] = envParts[1]; }); }; const convertEnvStringsToObject = (acc, curr) => { const [key, val] = curr.split('='); if (!val) { return Object.assign({}, acc); } return Object.assign(Object.assign({}, acc), { [key]: val }); }; const overrideEnvWithProcessEnv = (processEnv) => ([key, val]) => [key, processEnv[key] || val]; const interpolateRunCmd = ({ steps, runId, name }, teamName) => { if (!steps.length) { throw new CustomErrors_1.NoStepsFound(); } return steps.map(step => { step = stateAndConfigHelpers_1.replaceStateDirEnv(step, teamName, name, runId); return stateAndConfigHelpers_1.replaceConfigDirEnv(step, teamName, name); }); }; const convertCommandToSpawnFunction = (options) => (runCommand) => { return _runWorkflow(options)(runCommand); }; const _runWorkflow = (options) => _runWorkflowHof(options); const _runWorkflowHof = (options) => (runCommand) => async ({ errors, args, }) => { console.log(`\n ${bold(`šŸƒ Running ${runCommand}`)} \n`, ``); const childProcess = child_process_1.spawn(runCommand, [], options); const exitResponse = await utils_1.onExit(childProcess); if (exitResponse) { _printMessage(`šŸƒ Running ${runCommand}`); } const newErrors = exitResponse ? [...errors, { exitResponse, runCommand }] : [...errors]; return { errors: newErrors, args }; }; const _printMessage = (boldText, normalText = '') => { console.log(`\n ${bold(boldText)} ${normalText}\n`); };