@cto.ai/ops
Version:
💻 CTO.ai - The CLI built for Teams 🚀
214 lines (213 loc) • 9.8 kB
JavaScript
;
/**
* @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',
},
];