UNPKG

5.16 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3const tslib_1 = require("tslib");
4const sdk_1 = require("@cto.ai/sdk");
5const child_process_1 = require("child_process");
6const debug_1 = tslib_1.__importDefault(require("debug"));
7const uuid_1 = require("uuid");
8const path = tslib_1.__importStar(require("path"));
9const fs = tslib_1.__importStar(require("fs-extra"));
10const CustomErrors_1 = require("../errors/CustomErrors");
11const utils_1 = require("../utils");
12const stateAndConfigHelpers_1 = require("../utils/stateAndConfigHelpers");
13const debug = debug_1.default('ops:WorkflowService');
14const { callOutCyan, whiteBright, bold, redBright } = sdk_1.ux.colors;
15class WorkflowService {
16 async run(workflow, opParams, config) {
17 try {
18 const { name, steps } = Object.assign({}, workflow, { steps: interpolateRunCmd(workflow, config.team.name) });
19 workflow = getRunEnv(workflow, config);
20 setRunEnv(workflow, config);
21 const options = {
22 stdio: 'inherit',
23 shell: true,
24 env: process.env,
25 };
26 const workflowCommands = steps.map(convertCommandToSpawnFunction(options));
27 const errors = [];
28 const workflowPipeline = utils_1.asyncPipe(...workflowCommands);
29 const finalOutput = await workflowPipeline({
30 errors,
31 args: opParams,
32 });
33 const { errors: finalErrors } = finalOutput;
34 if (finalErrors.length) {
35 console.log(`\nā—ļø Workflow ${callOutCyan(name)} failed.`);
36 finalErrors.forEach((error, i) => {
37 console.log(redBright(`šŸ¤” There was a problem with the ${whiteBright(error.runCommand)}.\n`));
38 });
39 }
40 !finalErrors.length &&
41 _printMessage(`šŸ˜Œ Workflow ${callOutCyan(name)} completed successfully.`);
42 }
43 catch (err) {
44 debug('%O', err);
45 throw err;
46 }
47 }
48}
49exports.WorkflowService = WorkflowService;
50const getRunEnv = (workflow, config) => {
51 const runId = uuid_1.v4();
52 workflow.runId = runId;
53 const opsHome = `${process.env.HOME ||
54 process.env.USERPROFILE}/.config/@cto.ai/ops`;
55 workflow.opsHome = opsHome === undefined ? '' : opsHome;
56 workflow.stateDir = `/${config.team.name}/${workflow.name}/${runId}`;
57 workflow.configDir = `/${config.team.name}/${workflow.name}`;
58 if (!fs.existsSync(workflow.stateDir)) {
59 try {
60 fs.ensureDirSync(path.resolve(workflow.opsHome + workflow.stateDir));
61 }
62 catch (err) {
63 this.debug('%O', err);
64 throw new CustomErrors_1.CouldNotMakeDir(err, path.resolve(workflow.opsHome + workflow.stateDir));
65 }
66 }
67 return workflow;
68};
69// TODO this should be refactored so with the opService setEnv to make it dry
70const setRunEnv = (workflow, config) => {
71 const defaultEnv = {
72 STATE_DIR: workflow.stateDir,
73 CONFIG_DIR: workflow.configDir,
74 RUN_ID: workflow.runId,
75 OPS_OP_NAME: workflow.name,
76 OPS_TEAM_NAME: config.team.name,
77 OPS_ACCESS_TOKEN: config.tokens.accessToken,
78 };
79 const opsYamlEnv = workflow.env
80 ? workflow.env.reduce(convertEnvStringsToObject, {})
81 : [];
82 workflow.env = Object.entries(Object.assign({}, defaultEnv, opsYamlEnv))
83 .map(overrideEnvWithProcessEnv(process.env))
84 .map(([key, val]) => `${key}=${val}`);
85 workflow.env.forEach(env => {
86 const envParts = env.split('=');
87 process.env[envParts[0]] = envParts[1];
88 });
89};
90const convertEnvStringsToObject = (acc, curr) => {
91 const [key, val] = curr.split('=');
92 if (!val) {
93 return Object.assign({}, acc);
94 }
95 return Object.assign({}, acc, { [key]: val });
96};
97const overrideEnvWithProcessEnv = (processEnv) => ([key, val]) => [key, processEnv[key] || val];
98const interpolateRunCmd = ({ steps, runId, name }, teamName) => {
99 if (!steps.length) {
100 throw new CustomErrors_1.NoStepsFound();
101 }
102 return steps.map(step => {
103 step = stateAndConfigHelpers_1.replaceStateDirEnv(step, teamName, name, runId);
104 return stateAndConfigHelpers_1.replaceConfigDirEnv(step, teamName, name);
105 });
106};
107const convertCommandToSpawnFunction = (options) => (runCommand) => {
108 return _runWorkflow(options)(runCommand);
109};
110const _runWorkflow = (options) => _runWorkflowHof(options);
111const _runWorkflowHof = (options) => (runCommand) => async ({ errors, args, }) => {
112 console.log(`\n ${bold(`šŸƒ Running ${runCommand}`)} \n`, ``);
113 const childProcess = child_process_1.spawn(runCommand, [], options);
114 const exitResponse = await utils_1.onExit(childProcess);
115 if (exitResponse) {
116 _printMessage(`šŸƒ Running ${runCommand}`);
117 }
118 const newErrors = exitResponse
119 ? [...errors, { exitResponse, runCommand }]
120 : [...errors];
121 return { errors: newErrors, args };
122};
123const _printMessage = (boldText, normalText = '') => {
124 console.log(`\n ${bold(boldText)} ${normalText}\n`);
125};