@cto.ai/ops-rc
Version:
💻 CTO.ai Ops - The CLI built for Teams 🚀
140 lines (137 loc) • 6.11 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const tslib_1 = require("tslib");
/**
* Author: Brett Campbell (brett@hackcapital.com)
* Date: Saturday, 6th April 2019 10:39:58 pm
* Last Modified By: Brett Campbell (brett@hackcapital.com)
* Last Modified Time: Saturday, 6th April 2019 10:40:00 pm
*
* DESCRIPTION
*
*/
const sdk_1 = require("@cto.ai/sdk");
const fs = tslib_1.__importStar(require("fs-extra"));
const path = tslib_1.__importStar(require("path"));
const base_1 = tslib_1.__importStar(require("./../base"));
const opConfig_1 = require("./../constants/opConfig");
const CustomErrors_1 = require("./../errors/CustomErrors");
const utils_1 = require("./../utils");
const OpsYml_1 = require("./../types/OpsYml");
const templateUtils_1 = require("./../utils/templateUtils");
class Build extends base_1.default {
constructor() {
super(...arguments);
this.resolvePath = (opPath) => {
return opPath ? path.resolve(process.cwd(), opPath) : process.cwd();
};
this.getOpsFromFileSystem = async (opPath) => {
const manifest = await fs
.readFile(path.join(opPath, opConfig_1.OP_FILE), 'utf8')
.catch(err => {
this.debug('%O', err);
throw new CustomErrors_1.FileNotFoundError(err, opPath, opConfig_1.OP_FILE);
});
if (manifest.length == 0) {
throw new CustomErrors_1.NoLocalOpsOrPipelinesFound();
}
const { ops, pipelines, services } = utils_1.parseYaml(manifest);
if (ops.length == 0 && pipelines.length == 0 && services.length == 0) {
throw new CustomErrors_1.NoLocalOpsOrPipelinesFound();
}
return { ops, pipelines, services };
};
this.convertPipelinesToOps = async (pipelines, config) => {
const ops = [];
for (const pipeline of pipelines) {
for (let jobIndex = 0; jobIndex < pipeline.jobs.length; jobIndex++) {
const job = pipeline.jobs[jobIndex];
const { name, description } = job;
const templateDir = path.resolve(__dirname, '../templates/command/Bash');
const destDir = '/tmp/' + name;
//remove temp dir if exists
fs.removeSync(destDir);
await templateUtils_1.copyTemplate(templateDir, destDir);
await templateUtils_1.customizeManifest('command', { name, description, version: pipeline.version }, destDir);
const jobContents = await this.createJobContents(config, pipeline, job, jobIndex);
this.writeJobContents(jobContents, destDir + '/main.sh');
this.addJobPackages(job.packages, destDir + '/Dockerfile');
let jobOp = await this.getOpsFromFileSystem(destDir);
//set op type as 'job'
jobOp.ops[0].type = opConfig_1.JOB_TYPE;
ops.push(jobOp.ops[0]);
}
}
return ops;
};
this.createJobContents = async (config, pipeline, job, jobIndex) => {
const { team: { id: teamId }, } = config;
const { name: pipelineName } = pipeline;
const { name: jobName } = job;
return `#!/bin/bash
set -euo pipefail
IFS=$'\n\t'
${job.steps.join('\n')}
`;
};
this.addJobPackages = (packages, targetFile) => {
if (packages !== undefined && packages.length > 0) {
const installStr = `\nRUN apt-get update && apt-get -y install ${packages.join(' ')} && rm -r /var/cache/apt/archives/`;
fs.appendFileSync(targetFile, installStr);
}
};
this.writeJobContents = (contents, targetFile) => {
fs.removeSync(targetFile);
fs.writeFileSync(targetFile, contents);
};
this.selectOpToBuild = async (ops, pipelines) => {
if (ops.length === 1) {
return ops;
}
// NOTE: this causes unexpected behaviour if there are commands and pipelines
if (pipelines.length > 0) {
return ops;
}
const { opsToBuild } = await sdk_1.ux.prompt({
type: 'checkbox',
name: 'opsToBuild',
message: `\n Which ops would you like to build ${sdk_1.ux.colors.reset.green('→')}`,
choices: ops.map(op => {
return {
value: op,
name: `${op.name} - ${op.description}`,
};
}),
validate: input => input.length > 0,
});
return opsToBuild;
};
this.executeOpService = async (opsToBuild, opPath, config) => {
await this.services.opService.opsBuildLoop(opsToBuild, opPath, config);
};
}
async run() {
const { args: { path }, } = this.parse(Build);
try {
await this.isLoggedIn();
const opPath = this.resolvePath(path);
const inputManifest = await this.getOpsFromFileSystem(opPath);
const pipelineOps = await this.convertPipelinesToOps(inputManifest.pipelines, this.state.config);
const serviceOps = OpsYml_1.convertServicesToOps(inputManifest.services);
const opsToBuild = await this.selectOpToBuild([...inputManifest.ops, ...pipelineOps, ...serviceOps], inputManifest.pipelines);
await this.executeOpService(opsToBuild, opPath, this.state.config);
}
catch (err) {
this.debug('%O', err);
this.config.runHook('error', { err, accessToken: this.accessToken });
}
}
}
exports.default = Build;
Build.description = 'Build your op for sharing.';
Build.flags = {
help: base_1.flags.help({ char: 'h' }),
};
Build.args = [
{ name: 'path', description: 'Path to the op you want to build.' },
];