@cto.ai/ops
Version:
š» CTO.ai Ops - The CLI built for Teams š
182 lines (181 loc) ⢠8.66 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const tslib_1 = require("tslib");
const fuzzy_1 = tslib_1.__importDefault(require("fuzzy"));
const fs = tslib_1.__importStar(require("fs-extra"));
const path = tslib_1.__importStar(require("path"));
const base_1 = tslib_1.__importStar(require("../base"));
const asyncPipe_1 = require("../utils/asyncPipe");
const CustomErrors_1 = require("../errors/CustomErrors");
const opConfig_1 = require("../constants/opConfig");
const utils_1 = require("../utils");
class Search extends base_1.default {
constructor() {
super(...arguments);
this.opsAndWorkflows = [];
this.getApiOps = async (inputs) => {
try {
const findResponse = await this.services.api.find(`/private/ops`, {
headers: {
Authorization: this.accessToken,
},
});
let { data: apiOps } = findResponse;
apiOps = apiOps.filter(op => op.type !== opConfig_1.GLUECODE_TYPE);
return Object.assign(Object.assign({}, inputs), { apiOps });
}
catch (err) {
this.debug('error: %O', err);
throw new CustomErrors_1.APIError(err);
}
};
this.getLocalWorkflows = async (inputs) => {
const localWorkflows = [];
try {
const manifest = await fs.readFile(path.join(process.cwd(), opConfig_1.OP_FILE), 'utf8');
if (!manifest)
return inputs;
const { workflows = [] } = utils_1.parseYaml(manifest);
workflows.forEach(workflow => (workflow.local = true));
return Object.assign(Object.assign({}, inputs), { localWorkflows: workflows });
}
catch (_a) {
return Object.assign(Object.assign({}, inputs), { localWorkflows });
}
};
this._removeIfNameOrDescriptionDontContainQuery = (filter) => (workflow) => {
return (workflow.name.includes(filter) || workflow.description.includes(filter));
};
this.filterLocalWorkflows = (inputs) => {
let { localWorkflows, filter } = inputs;
if (!localWorkflows.length)
return inputs;
localWorkflows = localWorkflows.filter(this._removeIfNameOrDescriptionDontContainQuery(filter));
return Object.assign(Object.assign({}, inputs), { localWorkflows });
};
this._removeIfLocalExists = (workflows) => (apiOp) => {
const match = workflows.find(workflow => workflow.name === apiOp.name);
return !match;
};
this.resolveLocalAndApi = (inputs) => {
const { apiOps, localWorkflows } = inputs;
const ops = apiOps.filter(this._removeIfLocalExists(localWorkflows));
this.opsAndWorkflows = [...ops, ...localWorkflows].sort((a, b) => {
if (a.name < b.name)
return -1;
if (b.name < a.name)
return 1;
return 0;
});
return inputs;
};
this.checkData = async (inputs) => {
if (!this.opsAndWorkflows.length) {
this.log(`\n š No ops found in your team, public or local workspaces. Try again or run ${this.ux.colors.callOutCyan('ops publish')} to create an op. \n`);
}
return inputs;
};
this.selectOpOrWorkflowPrompt = async (inputs) => {
const commandText = this.ux.colors.multiBlue('\u2022Command');
const workflowText = this.ux.colors.multiOrange('\u2022Workflow');
const { selectedOpOrWorkflow } = await this.ux.prompt({
type: 'autocomplete',
name: 'selectedOpOrWorkflow',
pageSize: 5,
message: `\nSelect a public ${commandText} or ${workflowText} to continue ${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.`)}`,
});
return Object.assign(Object.assign({}, inputs), { selectedOpOrWorkflow });
};
this.showRunMessage = (inputs) => {
const { selectedOpOrWorkflow: { name, teamName }, } = inputs;
this.log(`\nš» Run ${this.ux.colors.green('$')} ${this.ux.colors.italic.dim('ops run @' + teamName + '/' + name)} to test your op. \n`);
return inputs;
};
this.sendAnalytics = (filter) => async (inputs) => {
const { selectedOpOrWorkflow, selectedOpOrWorkflow: { id: opId, teamID }, } = inputs;
const teamOp = teamID === this.team.id;
const remote = 'remote' in selectedOpOrWorkflow ? selectedOpOrWorkflow.remote : false;
try {
this.services.analytics.track({
userId: this.user.email,
teamId: this.team.id,
cliEvent: 'Ops CLI Search',
event: 'Ops CLI Search',
properties: {
email: this.user.email,
username: this.user.username,
selectedOp: opId,
teamOp,
remote,
results: this.opsAndWorkflows.length,
filter,
},
}, this.accessToken);
}
catch (err) {
this.debug('%O', err);
throw new CustomErrors_1.AnalyticsError(err);
}
};
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.fuzzyFilterParams = () => {
const list = this.opsAndWorkflows.map(opOrWorkflow => {
const name = this._formatOpOrWorkflowName(opOrWorkflow);
return {
name: `${name} - ${opOrWorkflow.description}`,
value: opOrWorkflow,
};
});
const options = { extract: el => el.name };
return { list, options };
};
this._formatOpOrWorkflowName = (opOrWorkflow) => {
const teamName = opOrWorkflow.teamName ? `@${opOrWorkflow.teamName}/` : '';
const name = `${this.ux.colors.reset.white(`${teamName}${opOrWorkflow.name}`)} ${this.ux.colors.reset.dim(`(${opOrWorkflow.version})`)}`;
if (opOrWorkflow.type === opConfig_1.WORKFLOW_TYPE) {
return `${this.ux.colors.reset(this.ux.colors.multiOrange('\u2022'))} ${name}`;
}
else {
return `${this.ux.colors.reset(this.ux.colors.multiBlue('\u2022'))} ${name}`;
}
};
this.startSpinner = async (inputs) => {
await this.ux.spinner.start(`š ${this.ux.colors.white('Searching')} ${this.ux.colors.callOutCyan(`all ${utils_1.pluralize(opConfig_1.COMMAND)} and ${utils_1.pluralize(opConfig_1.WORKFLOW)}`)}`);
return inputs;
};
this.stopSpinner = async (inputs) => {
await this.ux.spinner.stop(`${this.ux.colors.successGreen('Done')}`);
return inputs;
};
}
async run() {
const { args: { filter = '' }, } = this.parse(Search);
try {
await this.isLoggedIn();
const searchPipeline = asyncPipe_1.asyncPipe(this.startSpinner, this.getApiOps, this.getLocalWorkflows, this.filterLocalWorkflows, this.resolveLocalAndApi, this.checkData, this.stopSpinner, this.selectOpOrWorkflowPrompt, this.showRunMessage, this.sendAnalytics(filter));
await searchPipeline(filter);
}
catch (err) {
await this.ux.spinner.stop(`${this.ux.colors.errorRed('Failed')}`);
this.debug('%O', err);
this.config.runHook('error', { err, accessToken: this.accessToken });
}
}
}
exports.default = Search;
Search.description = 'Search for ops in your workspaces.';
Search.args = [
{
name: 'filter',
description: 'Filters Op results which include filter text in Op name or description.',
},
];
Search.flags = {
help: base_1.flags.help({ char: 'h' }),
};