1 | "use strict";
|
2 | Object.defineProperty(exports, "__esModule", { value: true });
|
3 | const tslib_1 = require("tslib");
|
4 | const fuzzy_1 = tslib_1.__importDefault(require("fuzzy"));
|
5 | const fs = tslib_1.__importStar(require("fs-extra"));
|
6 | const path = tslib_1.__importStar(require("path"));
|
7 | const base_1 = tslib_1.__importStar(require("../base"));
|
8 | const asyncPipe_1 = require("../utils/asyncPipe");
|
9 | const CustomErrors_1 = require("../errors/CustomErrors");
|
10 | const opConfig_1 = require("../constants/opConfig");
|
11 | const utils_1 = require("../utils");
|
12 | class Search extends base_1.default {
|
13 | constructor() {
|
14 | super(...arguments);
|
15 | this.opsAndWorkflows = [];
|
16 | this.getApiOps = async (inputs) => {
|
17 | try {
|
18 | const findResponse = await this.services.api.find(`/private/ops`, {
|
19 | headers: {
|
20 | Authorization: this.accessToken,
|
21 | },
|
22 | });
|
23 | let { data: apiOps } = findResponse;
|
24 | apiOps = apiOps.filter(op => op.type !== opConfig_1.GLUECODE_TYPE);
|
25 | return Object.assign(Object.assign({}, inputs), { apiOps });
|
26 | }
|
27 | catch (err) {
|
28 | this.debug('error: %O', err);
|
29 | throw new CustomErrors_1.APIError(err);
|
30 | }
|
31 | };
|
32 | this.getLocalWorkflows = async (inputs) => {
|
33 | const localWorkflows = [];
|
34 | try {
|
35 | const manifest = await fs.readFile(path.join(process.cwd(), opConfig_1.OP_FILE), 'utf8');
|
36 | if (!manifest)
|
37 | return inputs;
|
38 | const { workflows = [] } = utils_1.parseYaml(manifest);
|
39 | workflows.forEach(workflow => (workflow.local = true));
|
40 | return Object.assign(Object.assign({}, inputs), { localWorkflows: workflows });
|
41 | }
|
42 | catch (_a) {
|
43 | return Object.assign(Object.assign({}, inputs), { localWorkflows });
|
44 | }
|
45 | };
|
46 | this._removeIfNameOrDescriptionDontContainQuery = (filter) => (workflow) => {
|
47 | return (workflow.name.includes(filter) || workflow.description.includes(filter));
|
48 | };
|
49 | this.filterLocalWorkflows = (inputs) => {
|
50 | let { localWorkflows, filter } = inputs;
|
51 | if (!localWorkflows.length)
|
52 | return inputs;
|
53 | localWorkflows = localWorkflows.filter(this._removeIfNameOrDescriptionDontContainQuery(filter));
|
54 | return Object.assign(Object.assign({}, inputs), { localWorkflows });
|
55 | };
|
56 | this._removeIfLocalExists = (workflows) => (apiOp) => {
|
57 | const match = workflows.find(workflow => workflow.name === apiOp.name);
|
58 | return !match;
|
59 | };
|
60 | this.resolveLocalAndApi = (inputs) => {
|
61 | const { apiOps, localWorkflows } = inputs;
|
62 | const ops = apiOps.filter(this._removeIfLocalExists(localWorkflows));
|
63 | this.opsAndWorkflows = [...ops, ...localWorkflows].sort((a, b) => {
|
64 | if (a.name < b.name)
|
65 | return -1;
|
66 | if (b.name < a.name)
|
67 | return 1;
|
68 | return 0;
|
69 | });
|
70 | return inputs;
|
71 | };
|
72 | this.checkData = async (inputs) => {
|
73 | if (!this.opsAndWorkflows.length) {
|
74 | 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`);
|
75 | }
|
76 | return inputs;
|
77 | };
|
78 | this.selectOpOrWorkflowPrompt = async (inputs) => {
|
79 | const commandText = this.ux.colors.multiBlue('\u2022Command');
|
80 | const workflowText = this.ux.colors.multiOrange('\u2022Workflow');
|
81 | const { selectedOpOrWorkflow } = await this.ux.prompt({
|
82 | type: 'autocomplete',
|
83 | name: 'selectedOpOrWorkflow',
|
84 | pageSize: 5,
|
85 | message: `\nSelect a public ${commandText} or ${workflowText} to continue ${this.ux.colors.reset.green('ā')}\n${this.ux.colors.reset.dim('š Search:')} `,
|
86 | source: this._autocompleteSearch.bind(this),
|
87 | bottomContent: `\n \n${this.ux.colors.white(`Or, run ${this.ux.colors.callOutCyan('ops help')} for usage information.`)}`,
|
88 | });
|
89 | return Object.assign(Object.assign({}, inputs), { selectedOpOrWorkflow });
|
90 | };
|
91 | this.showRunMessage = (inputs) => {
|
92 | const { selectedOpOrWorkflow: { name, teamName }, } = inputs;
|
93 | this.log(`\nš» Run ${this.ux.colors.green('$')} ${this.ux.colors.italic.dim('ops run @' + teamName + '/' + name)} to test your op. \n`);
|
94 | return inputs;
|
95 | };
|
96 | this.sendAnalytics = (filter) => async (inputs) => {
|
97 | const { selectedOpOrWorkflow, selectedOpOrWorkflow: { id: opId, teamID }, } = inputs;
|
98 | const teamOp = teamID === this.team.id;
|
99 | const remote = 'remote' in selectedOpOrWorkflow ? selectedOpOrWorkflow.remote : false;
|
100 | try {
|
101 | this.services.analytics.track({
|
102 | userId: this.user.email,
|
103 | teamId: this.team.id,
|
104 | cliEvent: 'Ops CLI Search',
|
105 | event: 'Ops CLI Search',
|
106 | properties: {
|
107 | email: this.user.email,
|
108 | username: this.user.username,
|
109 | selectedOp: opId,
|
110 | teamOp,
|
111 | remote,
|
112 | results: this.opsAndWorkflows.length,
|
113 | filter,
|
114 | },
|
115 | }, this.accessToken);
|
116 | }
|
117 | catch (err) {
|
118 | this.debug('%O', err);
|
119 | throw new CustomErrors_1.AnalyticsError(err);
|
120 | }
|
121 | };
|
122 | this._autocompleteSearch = async (_, input = '') => {
|
123 | const { list, options } = this.fuzzyFilterParams();
|
124 | const fuzzyResult = fuzzy_1.default.filter(input, list, options);
|
125 | return fuzzyResult.map(result => result.original);
|
126 | };
|
127 | this.fuzzyFilterParams = () => {
|
128 | const list = this.opsAndWorkflows.map(opOrWorkflow => {
|
129 | const name = this._formatOpOrWorkflowName(opOrWorkflow);
|
130 | return {
|
131 | name: `${name} - ${opOrWorkflow.description}`,
|
132 | value: opOrWorkflow,
|
133 | };
|
134 | });
|
135 | const options = { extract: el => el.name };
|
136 | return { list, options };
|
137 | };
|
138 | this._formatOpOrWorkflowName = (opOrWorkflow) => {
|
139 | const teamName = opOrWorkflow.teamName ? `@${opOrWorkflow.teamName}/` : '';
|
140 | const name = `${this.ux.colors.reset.white(`${teamName}${opOrWorkflow.name}`)} ${this.ux.colors.reset.dim(`(${opOrWorkflow.version})`)}`;
|
141 | if (opOrWorkflow.type === opConfig_1.WORKFLOW_TYPE) {
|
142 | return `${this.ux.colors.reset(this.ux.colors.multiOrange('\u2022'))} ${name}`;
|
143 | }
|
144 | else {
|
145 | return `${this.ux.colors.reset(this.ux.colors.multiBlue('\u2022'))} ${name}`;
|
146 | }
|
147 | };
|
148 | this.startSpinner = async (inputs) => {
|
149 | 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)}`)}`);
|
150 | return inputs;
|
151 | };
|
152 | this.stopSpinner = async (inputs) => {
|
153 | await this.ux.spinner.stop(`${this.ux.colors.successGreen('Done')}`);
|
154 | return inputs;
|
155 | };
|
156 | }
|
157 | async run() {
|
158 | const { args: { filter = '' }, } = this.parse(Search);
|
159 | try {
|
160 | await this.isLoggedIn();
|
161 | 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));
|
162 | await searchPipeline(filter);
|
163 | }
|
164 | catch (err) {
|
165 | await this.ux.spinner.stop(`${this.ux.colors.errorRed('Failed')}`);
|
166 | this.debug('%O', err);
|
167 | this.config.runHook('error', { err, accessToken: this.accessToken });
|
168 | }
|
169 | }
|
170 | }
|
171 | exports.default = Search;
|
172 | Search.description = 'Search for ops in your workspaces.';
|
173 | Search.args = [
|
174 | {
|
175 | name: 'filter',
|
176 | description: 'Filters Op results which include filter text in Op name or description.',
|
177 | },
|
178 | ];
|
179 | Search.flags = {
|
180 | help: base_1.flags.help({ char: 'h' }),
|
181 | };
|