UNPKG

@cto.ai/ops

Version:

💻 CTO.ai - The CLI built for Teams 🚀

214 lines (213 loc) 9.8 kB
"use strict"; /** * @author: Prachi Singh (prachi@hackcapital.com) * @date: Tuesday, 5th November 2019 1:11:40 pm * @lastModifiedBy: Prachi Singh (prachi@hackcapital.com) * @lastModifiedTime: Monday, 18th November 2019 4:28:12 pm * * DESCRIPTION: ops add * * @copyright (c) 2019 Hack Capital */ Object.defineProperty(exports, "__esModule", { value: true }); const tslib_1 = require("tslib"); const fuzzy_1 = tslib_1.__importDefault(require("fuzzy")); const base_1 = tslib_1.__importStar(require("../base")); const cli_sdk_1 = require("@cto.ai/cli-sdk"); const CustomErrors_1 = require("./../errors/CustomErrors"); const validate_1 = require("./../utils/validate"); const utils_1 = require("./../utils"); const opConfig_1 = require("../constants/opConfig"); const opConfig_2 = require("../constants/opConfig"); class Add extends base_1.default { constructor() { super(...arguments); this.ops = []; this.promptFilter = async (inputs) => { if (inputs.opName) return inputs; const answers = await cli_sdk_1.ux.prompt({ type: 'input', name: 'workflowName', message: `\n Please type in the name of the public workflow you want to add ${cli_sdk_1.ux.colors.reset.green('→')}\n ${cli_sdk_1.ux.colors.reset(cli_sdk_1.ux.colors.secondary(`Leave blank to list all public workflows that you can add`))} \n\n 🗑 ${cli_sdk_1.ux.colors.reset.white('Name')}`, }); const opName = answers.opName; return Object.assign(Object.assign({}, inputs), { opName }); }; this.isOpAlreadyInTeam = (opResults, opName, opTeamName, opVersionName, myTeamName) => { if (opTeamName === myTeamName) return true; const result = opResults.filter(op => op.name == opName && op.teamName == opTeamName && op.version == opVersionName); return Boolean(result.length); }; this.getAllMyOps = async (config) => { try { const { data: opResults, } = await this.services.api.find(`private/teams/${config.team.name}/ops`, { headers: { Authorization: config.tokens.accessToken, }, }); return opResults; } catch (err) { this.debug('%0', err); throw new CustomErrors_1.APIError(err); } }; this.getAllPublicOps = async (inputs) => { if (inputs.opName) return inputs; try { const findResponse = await this.services.api.find(`/private/ops`, { headers: { Authorization: inputs.config.tokens.accessToken, }, }); let { data: apiOps } = findResponse; apiOps = apiOps.filter(op => op.type !== opConfig_2.JOB_TYPE); const myOps = await this.getAllMyOps(inputs.config); apiOps = apiOps.filter(op => { const flag = this.isOpAlreadyInTeam(myOps, op.name, op.teamName, op.version, inputs.config.team.name); return !flag; }); this.ops = apiOps; return Object.assign(Object.assign({}, inputs), { ops: apiOps }); } catch (err) { this.debug('error: %O', err); throw new CustomErrors_1.APIError(err); } }; this._fuzzyFilterParams = () => { const list = this.ops.map(op => { const { name, teamName, version } = op; const opDisplayName = this._formatOpOrWorkflowName(op); const opFullName = `@${teamName}/${name}:${version}`; return { name: `${opDisplayName} - ${op.description || op.publishDescription}`, value: opFullName, }; }); const options = { extract: el => el.name }; return { list, options }; }; this._formatOpOrWorkflowName = (op) => { const { reset, multiOrange, multiBlue } = this.ux.colors; const teamName = op.teamName ? `@${op.teamName}/` : ''; const opVersion = op.version ? `(${op.version})` : ''; const name = `${reset.white(`${teamName}${op.name}`)} ${reset.dim(`${opVersion}`)}`; if (op.type === opConfig_1.WORKFLOW_TYPE) { return `${reset(multiOrange('\u2022'))} ${name}`; } else { return `${reset(multiBlue('\u2022'))} ${name}`; } }; this._autocompleteSearch = async (_, input = '') => { const { list, options } = this._fuzzyFilterParams(); const fuzzyResult = fuzzy_1.default.filter(input, list, options); return fuzzyResult.map(result => result.original); }; this.selectOpPrompt = async (inputs) => { if (inputs.opName) return inputs; const commandText = cli_sdk_1.ux.colors.multiBlue('\u2022Command'); const workflowText = cli_sdk_1.ux.colors.multiOrange('\u2022Workflow'); const result = await this.ux.prompt({ type: 'autocomplete', name: 'selectedOp', pageSize: 5, message: `\nSelect a public ${commandText} or ${workflowText} to add ${this.ux.colors.reset.green('→')}\n${this.ux.colors.reset.dim('🔍 Search:')} `, source: this._autocompleteSearch.bind(this), bottomContent: `\n \n${this.ux.colors.white(`Or, run ${this.ux.colors.callOutCyan('ops help')} for usage information.`)}`, }); const opName = result.selectedOp; return Object.assign(Object.assign({}, inputs), { opName }); }; this.checkValidOpName = async (inputs) => { if (!(0, validate_1.isValidOpFullName)(inputs.opName)) { this.log(`❗Oops, that's an invalid input.\n💡Try adding in this format ${cli_sdk_1.ux.colors.callOutCyan(`@teamname/workflowName:versionname`)}`); process.exit(); } return inputs; }; // @teamname/workflowName:versionname => {teamname, workflowName, versionname} this.splitOpName = (inputs) => { const [field1, field2] = inputs.opName.split('/'); const opTeamName = field1.substring(1); const [opName, opVersionName] = field2.split(':'); const opFilter = { opTeamName, opName, opVersionName, }; return Object.assign(Object.assign({}, inputs), { opFilter }); }; this.addOp = async (inputs) => { const { opTeamName, opName, opVersionName } = inputs.opFilter; if (opTeamName === inputs.config.team.name) { throw new CustomErrors_1.OpAlreadyBelongsToTeam(); } try { const { data: result } = await this.services.api.create(`/private/teams/${inputs.config.team.name}/ops/refs`, { opName, opTeamName, versionName: opVersionName }, { headers: { Authorization: inputs.config.tokens.accessToken, }, }); return Object.assign(Object.assign({}, inputs), { addedOpID: result }); } catch (err) { this.debug('%0', err); // TODO @slajax - this is not great, fix our API if (err.error[0].message === 'op not found') { throw new CustomErrors_1.OpNotFoundOpsAdd(); } else if ( // TODO @slajax - this is not great, fix our API err.error[0].message === 'cannot create duplicate op reference for the same team') { throw new CustomErrors_1.OpAlreadyAdded(); } throw new CustomErrors_1.APIError(err); } }; this.sendAnalytics = async (inputs) => { const { config, opName } = inputs; this.services.analytics.track('Ops CLI Add', { username: config.user.username, addedOp: opName, }, config); return inputs; }; this.getSuccessMessage = (inputs) => { this.log(`\n🎉 Good job! ${cli_sdk_1.ux.colors.callOutCyan(`${inputs.opName}`)} has been successfully added to your team. \n\n Type ${this.ux.colors.italic.dim('ops list')} to find this workflow in your team.\n`); return inputs; }; } async run() { try { await this.isLoggedIn(); const { args: { opName }, } = this.parse(Add); await this.isLoggedIn(); const addPipeline = (0, utils_1.asyncPipe)(this.promptFilter, this.getAllPublicOps, this.selectOpPrompt, this.checkValidOpName, this.splitOpName, this.addOp, this.sendAnalytics, this.getSuccessMessage); await addPipeline({ opName, config: this.state.config }); } catch (err) { this.debug('%0', err); this.config.runHook('error', { err, accessToken: this.accessToken }); } } } exports.default = Add; Add.description = 'Add a workflow to your team.'; Add.flags = { help: base_1.flags.help({ char: 'h' }), }; Add.args = [ { name: 'opName', description: 'Name of the public workflow to be added to your team. It should be of the format - @teamname/workflowName:versionName', }, ];