@hahnpro/flow-cli 2.9.0 → 2.12.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/cli.js DELETED
@@ -1,954 +0,0 @@
1
- #!/usr/bin/env node
2
- require('reflect-metadata');
3
-
4
- const archiver = require('archiver');
5
- let axios = require('axios').default;
6
- const chalk = require('chalk');
7
- const { Command } = require('commander');
8
- const execa = require('execa');
9
- const FormData = require('form-data');
10
- const fs = require('fs');
11
- const glob = require('glob');
12
- const HttpsProxyAgent = require('https-proxy-agent');
13
- const ora = require('ora');
14
- const path = require('path');
15
- const queryString = require('querystring');
16
- const readPkg = require('read-pkg');
17
- const writePkg = require('write-pkg');
18
-
19
- require('dotenv').config();
20
-
21
- const log = console.log;
22
- const ok = chalk.bold.green;
23
- const error = chalk.bold.red;
24
-
25
- const apiUser = process.env.API_USER;
26
- const apiKey = process.env.API_KEY;
27
- const baseUrl = process.env.PLATFORM_URL;
28
- const buildDir = process.env.BUILD_DIR || 'dist';
29
- const realm = process.env.REALM;
30
- const authUrl = process.env.AUTH_URL || `${baseUrl}/auth/realms/${realm}/protocol/openid-connect/token`;
31
-
32
- if (process.env.https_proxy || process.env.http_proxy) {
33
- const httpsAgent = new HttpsProxyAgent(process.env.https_proxy || process.env.http_proxy);
34
- axios = axios.create({ httpsAgent, proxy: false });
35
- }
36
-
37
- let apiToken;
38
- let projectsRoot = 'modules';
39
-
40
- const CMD = {
41
- AUDIT: 'audit',
42
- BUILD: 'build',
43
- COPY: 'copy',
44
- FORMAT: 'format',
45
- INSTALL: 'install',
46
- LINT: 'lint',
47
- PUBLISH: 'publish',
48
- RUN: 'run',
49
- TEST: 'test',
50
- WATCH: 'watch',
51
- };
52
-
53
- const program = new Command();
54
-
55
- program
56
- .version('2.7.7', '-v, --version')
57
- .usage('[command] [options]')
58
- .description('Flow Module Management Tool.')
59
- .on('--help', () => {});
60
-
61
- program
62
- .command('build [projectName]')
63
- .description('Builds specified Project.')
64
- .action(async (projectName) => {
65
- try {
66
- if (checkIfAll(projectName)) process.exit(1);
67
- const project = await findProject(projectName);
68
- await exec(CMD.INSTALL, project);
69
- await exec(CMD.AUDIT, project);
70
- await exec(CMD.BUILD, project);
71
- await exec(CMD.LINT, project);
72
- await exec(CMD.COPY, project);
73
- } catch (err) {
74
- if (err) log(err);
75
- process.exit(1);
76
- }
77
- });
78
-
79
- program
80
- .command('install [projectName]')
81
- .description('Installs the dependencies of the specified Project.')
82
- .action(async (projectName) => {
83
- try {
84
- if (projectName === 'all') {
85
- const projects = await findProjects();
86
- for (const project of projects) {
87
- await exec(CMD.INSTALL, project);
88
- }
89
- } else {
90
- const project = await findProject(projectName);
91
- await exec(CMD.INSTALL, project);
92
- }
93
- } catch (err) {
94
- if (err) log(err);
95
- process.exit(1);
96
- }
97
- });
98
-
99
- program
100
- .command('audit [projectName]')
101
- .description('Audit dependencies')
102
- .action(async (projectName) => {
103
- try {
104
- if (projectName === 'all') {
105
- const projects = await findProjects();
106
- for (const project of projects) {
107
- await exec(CMD.AUDIT, project);
108
- }
109
- } else {
110
- const project = await findProject(projectName);
111
- await exec(CMD.AUDIT, project);
112
- }
113
- } catch (err) {
114
- if (err) log(err);
115
- process.exit(1);
116
- }
117
- });
118
-
119
- program
120
- .command('format')
121
- .description('Formats all typescript files according to prettier configuration.')
122
- .action(async () => {
123
- try {
124
- await exec(CMD.FORMAT, { name: 'all' });
125
- } catch (err) {
126
- if (err) log(err);
127
- process.exit(1);
128
- }
129
- });
130
-
131
- program
132
- .command('package [projectName]')
133
- .description('Builds specified Module and packages it as .zip File for manual upload to the platform.')
134
- .action(async (projectName) => {
135
- try {
136
- if (checkIfAll(projectName)) process.exit(1);
137
- const project = await findProject(projectName);
138
- await clean(buildDir);
139
- await exec(CMD.INSTALL, project);
140
- await exec(CMD.AUDIT, project);
141
- await exec(CMD.BUILD, project);
142
- await exec(CMD.LINT, project);
143
- await exec(CMD.COPY, project);
144
- await validateModule(project);
145
- await packageModule(project);
146
- } catch (err) {
147
- if (err) log(err);
148
- process.exit(1);
149
- }
150
- });
151
-
152
- program
153
- .command('publish-module [projectName]')
154
- .option('-f, --functions', 'publish flow functions')
155
- .option('-u, --update', 'update existing flow functions')
156
- .option('-s, --skip', 'skip modules that already exists with the current version')
157
- .description('Publishes specified Module to Cloud Platform.')
158
- .action(async (projectName, options) => {
159
- try {
160
- if (checkEnvModules()) process.exit(1);
161
- const projects = [];
162
- if (projectName === 'all') {
163
- for (const project of await findProjects()) {
164
- projects.push(project);
165
- }
166
- } else {
167
- projects.push(await findProject(projectName));
168
- }
169
-
170
- await getAccessToken();
171
- for (const project of projects) {
172
- await clean(buildDir);
173
- await exec(CMD.INSTALL, project);
174
- await exec(CMD.AUDIT, project);
175
- await exec(CMD.BUILD, project);
176
- await exec(CMD.LINT, project);
177
- await exec(CMD.COPY, project);
178
- await validateModule(project);
179
- try {
180
- await publishModule(project);
181
- } catch (e) {
182
- if (
183
- options.skip &&
184
- e &&
185
- e.response &&
186
- e.response.data &&
187
- e.response.data.message === 'New module version must greater than latest version'
188
- ) {
189
- log(ok(`Module "${project.name}" is up to date. Skipping.`));
190
- } else {
191
- log(error(`Publishing Module "${project.name}" failed.`));
192
- handleApiError(e);
193
- process.exit(1);
194
- }
195
- }
196
- if (options.functions) {
197
- await publishFunctions(project, options.update);
198
- }
199
- }
200
- } catch (err) {
201
- if (err) log(err);
202
- process.exit(1);
203
- }
204
- });
205
-
206
- program
207
- .command('publish-functions [projectName]')
208
- .option('-u, --update', 'update existing flow functions')
209
- .description('Publishes all Flow Functions inside specified Module to Cloud Platform.')
210
- .action(async (projectName, options) => {
211
- try {
212
- if (checkEnvModules()) process.exit(1);
213
- const projects = [];
214
- if (projectName === 'all') {
215
- for (const project of await findProjects()) {
216
- projects.push(project);
217
- }
218
- } else {
219
- projects.push(await findProject(projectName));
220
- }
221
-
222
- await getAccessToken();
223
- for (const project of projects) {
224
- await publishFunctions(project, options.update);
225
- }
226
- } catch (err) {
227
- if (err) log(err);
228
- process.exit(1);
229
- }
230
- });
231
-
232
- program
233
- .command('serve [projectName]')
234
- .description('Builds and serves your Project. Rebuilding on file changes.')
235
- .action(async (projectName) => {
236
- try {
237
- if (checkIfAll(projectName)) process.exit(1);
238
- const project = await findProject(projectName);
239
- await exec(CMD.INSTALL, project);
240
- await exec(CMD.AUDIT, project);
241
- await exec(CMD.BUILD, project);
242
- await exec(CMD.COPY, project);
243
- await exec(CMD.WATCH, project);
244
- } catch (err) {
245
- if (err) log(err);
246
- process.exit(1);
247
- }
248
- });
249
-
250
- program
251
- .command('start [projectName]')
252
- .description('Runs your project.')
253
- .action(async (projectName) => {
254
- try {
255
- if (checkIfAll(projectName)) process.exit(1);
256
- const project = await findProject(projectName);
257
- await exec(CMD.RUN, project);
258
- } catch (err) {
259
- if (err) log(err);
260
- process.exit(1);
261
- }
262
- });
263
-
264
- program
265
- .command('test [projectName]')
266
- .description('Runs tests for your Project.')
267
- .action(async (projectName) => {
268
- try {
269
- // check if it is running in Gitlab CI
270
- if (process.env.CI && projectName === 'all') {
271
- const projects = await findProjects();
272
- for (const project1 of projects.filter((project) => !project['excludeTestsInCI'])) {
273
- // only run tests that can be run in CI
274
- await exec(CMD.TEST, project1);
275
- }
276
- } else {
277
- const project = await findProject(projectName);
278
- await exec(CMD.TEST, project);
279
- }
280
- } catch (err) {
281
- if (err) log(err);
282
- process.exit(1);
283
- }
284
- });
285
-
286
- program
287
- .command('generate-schemas [projectName]')
288
- .description('Generates Input, Output and Properties-Schemas for the project.')
289
- .option('-h, --hide', 'hide warnings')
290
- .option('-v, --verbose', 'get more output info')
291
- .action(async (projectName) => {
292
- try {
293
- const project = await findProject(projectName);
294
- const globOptions = {
295
- cwd: project.location,
296
- ignore: ['node_modules/**/*', '**/package*.json', '**/tsconfig*.json'],
297
- };
298
- glob('**/*.*', globOptions, async (err, files) => {
299
- const filtered = files.filter((file) => !file.endsWith('.spec.ts'));
300
- const tsJsonMap = filtered.reduce((acc, cur, i, arr) => {
301
- if (cur.endsWith('.ts')) {
302
- // get json file for current function
303
- const json = arr.find((v) => v === `${cur.split('.')[0]}.json`);
304
- if (json) {
305
- acc.push({
306
- ts: path.join(globOptions.cwd, cur),
307
- json: path.join(globOptions.cwd, json),
308
- });
309
- }
310
- }
311
- return acc;
312
- }, []);
313
- tsJsonMap.forEach((entry) => {
314
- generateSchemasForFile(entry.ts, entry.json);
315
- });
316
- });
317
- } catch (err) {
318
- if (err) log(err);
319
- process.exit(1);
320
- }
321
- });
322
-
323
- if (process.env.NODE_ENV !== 'test') {
324
- program.parse(process.argv);
325
- }
326
-
327
- function generateSchemasForFile(tsPath, jsonPath) {
328
- // get schema
329
- let json = require(path.join(process.cwd(), jsonPath));
330
-
331
- const filePath = path.join(process.cwd(), tsPath);
332
- const tsFile = String(fs.readFileSync(filePath));
333
- const dir = path.dirname(filePath);
334
-
335
- execa('ts-node', ['-T', '--dir', dir], { input: prepareTsFile(tsFile), preferLocal: true }).then((result) => {
336
- json = handleConvertedOutput(result.stdout, jsonPath, json);
337
-
338
- fs.writeFileSync(path.join(process.cwd(), jsonPath), JSON.stringify(json, null, 2) + '\n');
339
- });
340
- }
341
-
342
- function handleConvertedOutput(result, jsonPath, json) {
343
- let schema;
344
- try {
345
- schema = JSON.parse(result);
346
- } catch (e) {
347
- console.log('ERROR', result);
348
- return json;
349
- }
350
- [
351
- ['propertiesSchema', 'Properties'],
352
- ['inputStreams', 'InputProperties'],
353
- ['outputStreams', 'OutputProperties'],
354
- ].forEach((value) => {
355
- const propsSchema = schema[value[1]] || {};
356
- (propsSchema.required || []).forEach((reqProp) => {
357
- propsSchema.properties[reqProp] = { ...propsSchema.properties[reqProp], required: true };
358
- });
359
- // remove required field
360
- delete propsSchema.required;
361
-
362
- checkTypes(getTypes(jsonPath), propsSchema, jsonPath);
363
-
364
- const completeSchema = {
365
- schema: {
366
- type: 'object',
367
- properties: {
368
- ...propsSchema.properties,
369
- },
370
- },
371
- };
372
-
373
- if (value[0] === 'propertiesSchema') {
374
- if (!json['propertiesSchema']) {
375
- json['propertiesSchema'] = completeSchema;
376
- }
377
- } else {
378
- // check if config for default input/output stream exists
379
- if (!json[value[0]].find((v) => v.name === 'default')) {
380
- if (propsSchema) {
381
- json[value[0]].push({
382
- name: 'default',
383
- ...completeSchema,
384
- });
385
- }
386
- }
387
- }
388
- });
389
-
390
- // add definitions
391
- if (Object.keys(schema).some((key) => !['Properties', 'InputProperties', 'OutputProperties'].includes(key))) {
392
- const typeDefinitions = Object.keys(schema).filter((key) => !['Properties', 'InputProperties', 'OutputProperties'].includes(key));
393
- json.definitions = typeDefinitions.reduce((previousValue, currentValue) => {
394
- const additionalSchema = schema[currentValue];
395
- (additionalSchema.required || []).forEach((reqProp) => {
396
- additionalSchema.properties[reqProp] = { ...additionalSchema.properties[reqProp], required: true };
397
- });
398
- delete additionalSchema.required;
399
- previousValue[currentValue] = additionalSchema;
400
- return previousValue;
401
- }, {});
402
- }
403
- return json;
404
- }
405
-
406
- function checkTypes(definedTypes, propsSchema, jsonPath) {
407
- const knownTypes = [
408
- ...definedTypes,
409
- 'string',
410
- 'undefined',
411
- 'number',
412
- 'boolean',
413
- 'any',
414
- 'object',
415
- 'array',
416
- 'integer',
417
- 'Asset',
418
- 'AssetType',
419
- 'Flow',
420
- 'Secret',
421
- 'TimeSeries',
422
- ];
423
-
424
- // check if all types are known
425
- const props = propsSchema.properties || {};
426
- for (const prop of Object.keys(props)) {
427
- if (props[prop].type && !knownTypes.includes(props[prop].type)) {
428
- log(
429
- error(`ERROR: unknown type ${props[prop].type}.
430
- Please add a schema for this type in ${jsonPath}
431
- for more info check the documentation`),
432
- );
433
- return false;
434
- }
435
- }
436
- return true;
437
- }
438
-
439
- function prepareTsFile(file) {
440
- // if a class extends another and does not have its own fields no metadata is generated and so no schema can be generated
441
- // in this case replace empty block with the block it inherits from
442
- let codeBlocks = getCodeBlocks(file);
443
- const emptyExtendsBlock = codeBlocks.find((block) => classNameIncludes(block, 'extends') && isBlockEmpty(block));
444
- if (emptyExtendsBlock) {
445
- // replace block and remove extends
446
- let replBlock = `${emptyExtendsBlock}`;
447
- if (replBlock.replace(/\s\s+/g, ' ').trim().startsWith('class OutputProperties')) {
448
- // remove extends
449
- replBlock = replBlock.replace('extends InputProperties', '');
450
- // replace block with InputProperties block
451
- const inputPropsBlock = codeBlocks.find((v) => classNameIncludes(v, 'InputProperties') && !classNameIncludes(v, 'OutputProperties'));
452
- replBlock = replBlock.replace(getBlockContent(replBlock), getBlockContent(inputPropsBlock));
453
-
454
- file = file.replace(emptyExtendsBlock, replBlock);
455
- }
456
- }
457
- return (
458
- `import { validationMetadatasToSchemas as v } from 'class-validator-jsonschema';\n` +
459
- `import { defaultMetadataStorage } from 'class-transformer/storage'\n` +
460
- `${file}\n` +
461
- `const s = v({\n
462
- additionalConverters: {\n
463
- UnitArgsValidator: (meta) => {\n
464
- return {\n
465
- measure: meta.constraints[0],\n
466
- unit: meta.constraints[1],\n
467
- type: 'number',\n
468
- };\n
469
- },\n
470
- },\n
471
- classTransformerMetadataStorage: defaultMetadataStorage\n
472
- });\n` +
473
- `console.log(JSON.stringify(s));`
474
- );
475
- }
476
-
477
- function getCodeBlocks(str) {
478
- const blocks = [];
479
- let counter = 0;
480
- let start = 0;
481
- let lastNewline = 0;
482
- [...str].forEach((char, index) => {
483
- if (char === '\n') {
484
- lastNewline = index;
485
- }
486
- if (char === '{') {
487
- if (counter === 0) {
488
- // first bracket of block
489
- start = lastNewline;
490
- }
491
- counter++;
492
- } else if (char === '}') {
493
- counter--;
494
- if (counter === 0) {
495
- // last bracket of block
496
- blocks.push(str.substring(start, index + 1));
497
- }
498
- }
499
- });
500
- return blocks;
501
- }
502
-
503
- function classNameIncludes(str, className) {
504
- return str.trim().split('\n', 1)[0].includes(className);
505
- }
506
-
507
- function getBlockContent(block) {
508
- return block.substring(block.indexOf('{'), block.lastIndexOf('}') + 1);
509
- }
510
-
511
- function isBlockEmpty(block) {
512
- const blockContent = block.substring(block.indexOf('{') + 1, block.lastIndexOf('}'));
513
- return !blockContent.trim();
514
- }
515
-
516
- function getTypes(filePath) {
517
- try {
518
- const json = require(path.join(process.cwd(), filePath));
519
- return json.definitions ? Object.keys(json.definitions) : [];
520
- } catch (e) {
521
- return [];
522
- }
523
- }
524
-
525
- async function clean(buildFolder) {
526
- return new Promise((resolve, reject) => {
527
- const spinner = getSpinner('Cleaning').start();
528
- fs.rmdir(buildFolder, { recursive: true }, (err) => {
529
- if (err) {
530
- spinner.stop();
531
- log(error('Cleaning failed'));
532
- log(error(err));
533
- return reject(err);
534
- } else {
535
- spinner.stop();
536
- log(ok('Cleaning successful'));
537
- return resolve();
538
- }
539
- });
540
- });
541
- }
542
-
543
- function exec(cmd, project) {
544
- return new Promise((resolve, reject) => {
545
- if (!project) {
546
- log(`${chalk.red('Wrong command options.')} Type "hpc ${cmd} --help" to see how to use this command.`);
547
- return reject();
548
- }
549
- if (cmd === CMD.RUN || cmd === CMD.WATCH) {
550
- log(ok(`\n${getLabel(cmd)} ${project.name}:\n`));
551
- execa(getProcess(cmd), getProcessArguments(cmd, project), getProcessOptions(cmd, project)).stdout.pipe(process.stdout);
552
- } else {
553
- const spinner = getSpinner(`${getLabel(cmd)} ${project.name}`);
554
- spinner.start();
555
- execa(getProcess(cmd), getProcessArguments(cmd, project), getProcessOptions(cmd, project))
556
- .then((result) => {
557
- spinner.stop();
558
- log(result.stdout);
559
- log(ok(`${getLabel(cmd)} Succeeded`));
560
- return resolve();
561
- })
562
- .catch((err) => {
563
- spinner.stop();
564
- if (err.stderr) log(error(err.stderr));
565
- else log(error(err));
566
- if (err.stdout) log(err.stdout);
567
- log(error(`${getLabel(cmd)} Failed`));
568
- return reject();
569
- });
570
- }
571
- });
572
- }
573
-
574
- function isDir(p) {
575
- return new Promise((res, rej) => {
576
- fs.lstat(p, (err, stats) => {
577
- if (!err && stats) {
578
- res(stats.isDirectory());
579
- } else {
580
- res(false);
581
- }
582
- });
583
- });
584
- }
585
-
586
- async function findProjects() {
587
- const readDir = (dir) =>
588
- new Promise((res, rej) => {
589
- fs.readdir(dir, (err, files) => {
590
- if (!err && files) {
591
- res(files);
592
- } else {
593
- res([]);
594
- }
595
- });
596
- });
597
- const isProject = (dir) =>
598
- new Promise((res, rej) => {
599
- fs.access(path.join(dir, 'package.json'), (err) => {
600
- if (!err) {
601
- res(true);
602
- } else {
603
- res(false);
604
- }
605
- });
606
- });
607
-
608
- const rootPkg = await readPkg({ normalize: false });
609
-
610
- const projects = [];
611
- const files = await readDir(projectsRoot);
612
- if (files) {
613
- for (const file of files) {
614
- if (file && (await isDir(path.join(projectsRoot, file)))) {
615
- const projectPath = path.join(projectsRoot, file, 'package.json');
616
- if (await isProject(path.join(projectsRoot, file))) {
617
- try {
618
- const pkg = await readPkg({ cwd: path.dirname(projectPath), normalize: false });
619
- pkg.location = path.posix.join(projectsRoot, file);
620
- pkg.dist = path.posix.join(process.cwd(), buildDir, file);
621
- if (rootPkg) {
622
- pkg.dependencies = { ...pkg.dependencies, ...rootPkg.dependencies };
623
- pkg.repository = rootPkg.repository;
624
- }
625
- projects.push(pkg);
626
- } catch (err) {
627
- if (err) log(err);
628
- }
629
- }
630
- }
631
- }
632
- }
633
-
634
- return projects;
635
- }
636
-
637
- function findProject(projectName) {
638
- return new Promise(async (resolve, reject) => {
639
- if (!projectName) {
640
- log(error('No Project specified.'));
641
- return reject();
642
- }
643
- if (projectName === 'all') {
644
- const project = {
645
- name: 'all',
646
- version: '0.0.0',
647
- location: '.',
648
- };
649
- return resolve(project);
650
- }
651
-
652
- const projects = await findProjects();
653
- for (const project of projects) {
654
- const location = path.parse(project.location);
655
- const dirName = location.name + location.ext;
656
- if (project.name === projectName || dirName === projectName) {
657
- return resolve(project);
658
- }
659
- }
660
-
661
- log(error(`Cloud not find ${projectName} Module.`));
662
- reject();
663
- });
664
- }
665
-
666
- async function getAccessToken() {
667
- return new Promise(async (resolve, reject) => {
668
- try {
669
- const body = queryString.stringify({
670
- client_id: apiUser,
671
- client_secret: apiKey,
672
- grant_type: 'client_credentials',
673
- });
674
- const headers = { 'Content-Type': 'application/x-www-form-urlencoded' };
675
- const response = (await axios.post(authUrl, body, { headers })).data;
676
-
677
- if (!response || !response.access_token) {
678
- throw new Error();
679
- }
680
- apiToken = response.access_token;
681
- log(ok('AccessToken acquired'));
682
- return resolve();
683
- } catch (err) {
684
- log(error('Could not get AccessToken'));
685
- handleApiError(err);
686
- return reject();
687
- }
688
- });
689
- }
690
-
691
- async function packageModule(project) {
692
- const { location, dist, ...package } = project;
693
- const file = path.posix.join(dist, '..', `${project.name}.zip`);
694
- await writePkg(dist, package);
695
- await zipDirectory(dist, file);
696
- return file;
697
- }
698
-
699
- async function publishModule(project) {
700
- return new Promise(async (resolve, reject) => {
701
- const file = await packageModule(project);
702
-
703
- const form = new FormData();
704
- form.append('file', fs.createReadStream(file));
705
- form.append('name', project.name);
706
- form.append('description', project.description || '');
707
- form.append('version', project.version || '');
708
-
709
- try {
710
- await axios.post(`${baseUrl}/api/flow/modules`, form, {
711
- headers: {
712
- ...form.getHeaders(),
713
- Authorization: `Bearer ${apiToken}`,
714
- },
715
- });
716
-
717
- log(ok(`Module "${project.name}" published!`));
718
- return resolve();
719
- } catch (err) {
720
- return reject(err);
721
- } finally {
722
- deleteFile(file);
723
- }
724
- });
725
- }
726
-
727
- async function validateModule(project) {
728
- const module = require(project.dist);
729
- const moduleName = Reflect.getMetadata('module:name', module.default);
730
- const moduleDeclarations = Reflect.getMetadata('module:declarations', module.default);
731
-
732
- const funcFqns = [];
733
- for (const declaration of moduleDeclarations) {
734
- const fqn = Reflect.getMetadata('element:functionFqn', declaration);
735
- if (!fqn) {
736
- throw new Error(`FlowFunction (${declaration.name}) metadata is missing or invalid.`);
737
- }
738
- funcFqns.push(fqn);
739
- }
740
-
741
- if (moduleName) {
742
- project.name = moduleName;
743
- project.functions = funcFqns;
744
- } else {
745
- throw new Error('Could not validate module name');
746
- }
747
- }
748
-
749
- async function publishFunctions(project, update) {
750
- return new Promise(async (resolve, reject) => {
751
- const globOptions = {
752
- cwd: project.location,
753
- ignore: ['node_modules/**/*', '**/package*.json', '**/tsconfig*.json'],
754
- };
755
- glob('**/*.json', globOptions, async (err, files) => {
756
- if (err) {
757
- return reject(err);
758
- }
759
- const headers = { Authorization: `Bearer ${apiToken}` };
760
-
761
- for (const file of files) {
762
- try {
763
- const data = await fs.promises.readFile(path.join(globOptions.cwd, file));
764
- const json = JSON.parse(data);
765
- if (json.fqn && json.category) {
766
- if (update) {
767
- try {
768
- await axios.put(`${baseUrl}/api/flow/functions/${json.fqn}`, json, { headers });
769
- log(ok(`Flow Function "${json.fqn}" has been updated`));
770
- } catch (err) {
771
- log(error(`Flow Function "${json.fqn}" could not be updated`));
772
- handleApiError(err);
773
- }
774
- } else {
775
- try {
776
- await axios.post(`${baseUrl}/api/flow/functions`, json, { headers });
777
- log(ok(`Flow Function "${json.fqn}" has been created`));
778
- } catch (err) {
779
- log(error(`Flow Function "${json.fqn}" could not be created`));
780
- handleApiError(err);
781
- }
782
- }
783
- }
784
- } catch (err) {
785
- log(error(err));
786
- }
787
- }
788
- return resolve();
789
- });
790
- });
791
- }
792
-
793
- function handleApiError(err) {
794
- if (err.isAxiosError && err.response) {
795
- log(error(`${err.response.status} ${err.response.statusText}`));
796
- if (err.response.data) {
797
- log(error(JSON.stringify(err.response.data)));
798
- }
799
- } else {
800
- log(error(err));
801
- }
802
- }
803
-
804
- function zipDirectory(source, out) {
805
- const archive = archiver('zip', { zlib: { level: 8 } });
806
- const stream = fs.createWriteStream(out);
807
-
808
- return new Promise((resolve, reject) => {
809
- archive
810
- .directory(source, false)
811
- .on('error', (err) => reject(err))
812
- .pipe(stream);
813
-
814
- stream.on('close', () => resolve());
815
- archive.finalize();
816
- });
817
- }
818
-
819
- function deleteFile(path) {
820
- return new Promise((resolve, reject) => {
821
- fs.unlink(path, (err) => {
822
- if (err) return reject(err);
823
- return resolve();
824
- });
825
- });
826
- }
827
-
828
- function getProcess(cmd) {
829
- switch (cmd) {
830
- case CMD.BUILD:
831
- return './node_modules/.bin/tsc';
832
- case CMD.COPY:
833
- return './node_modules/.bin/copyfiles';
834
- case CMD.FORMAT:
835
- return './node_modules/.bin/prettier';
836
- case CMD.INSTALL:
837
- case CMD.AUDIT:
838
- return 'npm';
839
- case CMD.LINT:
840
- return './node_modules/.bin/tslint';
841
- case CMD.RUN:
842
- return 'node';
843
- case CMD.TEST:
844
- return './node_modules/.bin/jest';
845
- case CMD.WATCH:
846
- return './node_modules/.bin/nodemon';
847
- default:
848
- return '';
849
- }
850
- }
851
-
852
- function getProcessArguments(cmd, project) {
853
- switch (cmd) {
854
- case CMD.AUDIT:
855
- return ['audit', '--audit-level=moderate'];
856
- case CMD.BUILD: {
857
- const filename = path.join(project.location, 'tsconfig.module.json');
858
- const configFile = fs.existsSync(filename) ? filename : project.location;
859
- return ['-p', configFile];
860
- }
861
- case CMD.COPY:
862
- return [
863
- '-u',
864
- '1',
865
- '-e',
866
- `${project.location}/*.json`,
867
- '-e',
868
- `${project.location}/**/*.ts`,
869
- '-e',
870
- `${project.location}/**/test/**`,
871
- `${project.location}/**`,
872
- `${buildDir}/`,
873
- ];
874
- case CMD.FORMAT:
875
- return ['--write', '**/*.ts'];
876
- case CMD.INSTALL:
877
- return ['install', '--no-package-lock'];
878
- case CMD.LINT:
879
- return ['-p', project.location, 'stylish'];
880
- case CMD.RUN:
881
- return [project.location];
882
- case CMD.TEST:
883
- return project.name === 'all'
884
- ? ['--runInBand', '--coverage', '--forceExit', '--verbose', '--passWithNoTests']
885
- : ['roots', project.location, '--forceExit', '--verbose', '--passWithNoTests'];
886
- case CMD.WATCH:
887
- return ['--inspect', project.location];
888
- default:
889
- return [];
890
- }
891
- }
892
-
893
- function getProcessOptions(cmd, project) {
894
- switch (cmd) {
895
- case CMD.INSTALL:
896
- return { cwd: project.location };
897
- }
898
- }
899
-
900
- function getLabel(cmd) {
901
- switch (cmd) {
902
- case CMD.RUN:
903
- return 'Running';
904
- default:
905
- return `${cmd.charAt(0).toUpperCase()}${cmd.slice(1)}ing`;
906
- }
907
- }
908
-
909
- function getSpinner(message) {
910
- return ora({
911
- color: 'magenta',
912
- spinner: 'dots',
913
- text: message,
914
- });
915
- }
916
-
917
- function checkIfAll(projectName) {
918
- if (projectName === 'all') {
919
- log(error(`Please specify a Project. Command can't be run for all.`));
920
- return true;
921
- }
922
- return false;
923
- }
924
-
925
- function checkEnvModules() {
926
- let missing = false;
927
- if (!apiUser) {
928
- log(error('"API_USER" env var is not set.'));
929
- missing = true;
930
- }
931
- if (!apiKey) {
932
- log(error('"API_KEY" env var is not set.'));
933
- missing = true;
934
- }
935
- if (!baseUrl) {
936
- log(error('"PLATFORM_URL" env var is not set.'));
937
- missing = true;
938
- }
939
- if (!realm) {
940
- log(error('"REALM" env var is not set.'));
941
- missing = true;
942
- }
943
- if (!buildDir) {
944
- log(error('"BUILD_DIR" env var is not set.'));
945
- missing = true;
946
- }
947
- return missing;
948
- }
949
-
950
- exports.prepareTsFile = prepareTsFile;
951
- exports.getCodeBlocks = getCodeBlocks;
952
- exports.checkTypes = checkTypes;
953
- exports.getTypes = getTypes;
954
- exports.handleConvertedOutput = handleConvertedOutput;