@contrail/cli 1.0.66 → 1.0.68

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.
@@ -17,7 +17,7 @@ function parseArgumentsIntoOptions(rawArgs) {
17
17
  };
18
18
  }
19
19
  async function promptForMissingOptions(options) {
20
- const defaultTemplate = 'JavaScript';
20
+ const defaultTemplate = 'TypeScript';
21
21
  const questions = [];
22
22
  if (!options.appName) {
23
23
  questions.push({
@@ -32,7 +32,7 @@ async function promptForMissingOptions(options) {
32
32
  type: 'list',
33
33
  name: 'template',
34
34
  message: 'Which project template would you like to use?',
35
- choices: ['JavaScript', 'TypeScript'],
35
+ choices: ['TypeScript', 'JavaScript'],
36
36
  default: defaultTemplate,
37
37
  });
38
38
  }
package/lib/cli.js CHANGED
@@ -3,7 +3,7 @@ import { deployApp, removeApp } from './apps/deploy-app/deploy';
3
3
  import { getAll } from './types/types-extractor';
4
4
  import { uploadTypes } from './types/types-uploader';
5
5
  import { UploadOptionSets } from './types/option-set-uploader';
6
- import { ParseOptionSetsLocalFiles } from './types/option-set-parser';
6
+ import { ParseOptionSetsLocalFiles, ParseOptionSetsToFolderStructure } from './types/option-set-parser';
7
7
  import { ParseOptionSetsHierarchyLocalFile, UploadOptionSetsHierarchyLocalFile } from './types/option-set-hierarchy-parser';
8
8
  import { ExportOptionSetsHierarchies } from './types/option-set-hierarchy-exporter';
9
9
  import { MergeOptionSets } from './types/option-set-merger';
@@ -23,6 +23,8 @@ import { uploadRuleSets } from './types/rule-set-uploader';
23
23
  import { UploadOptionSetHierarchies } from './types/option-set-hierarchy-uploader';
24
24
  import { uploadTypePropertyPolicies } from './types/type-property-policy-uploader';
25
25
  import { uploadAll } from './types/allUploader';
26
+ import { ExportUsers } from './users/user-exporter';
27
+ import { UploadUsers } from './users/user-uploader';
26
28
  const cliUsage = require('command-line-usage');
27
29
  /**
28
30
  * Built using documentation here:
@@ -103,6 +105,10 @@ export async function cli(args) {
103
105
  ParseOptionSetsLocalFiles(args);
104
106
  break;
105
107
  }
108
+ case 'parseOptionSetsToFolderStructure': {
109
+ ParseOptionSetsToFolderStructure(args);
110
+ break;
111
+ }
106
112
  case 'parseOptionSetsHierarchyLocalFile': {
107
113
  ParseOptionSetsHierarchyLocalFile(args);
108
114
  break;
@@ -213,6 +219,22 @@ export async function cli(args) {
213
219
  }
214
220
  break;
215
221
  }
222
+ case 'users': {
223
+ switch (command) {
224
+ case 'export': {
225
+ await ExportUsers();
226
+ break;
227
+ }
228
+ case 'import': {
229
+ await UploadUsers();
230
+ break;
231
+ }
232
+ default: {
233
+ printIllegalCommand();
234
+ }
235
+ }
236
+ break;
237
+ }
216
238
  case 'workflow-templates': {
217
239
  switch (command) {
218
240
  case 'load': {
@@ -372,6 +394,19 @@ const helpSections = [
372
394
  }
373
395
  ],
374
396
  },
397
+ {
398
+ header: 'Users Commands - Domain: users',
399
+ content: [
400
+ {
401
+ name: 'export',
402
+ summary: 'Export all users in the org.'
403
+ },
404
+ {
405
+ name: 'import',
406
+ summary: 'Import all users in the users.yml file.'
407
+ }
408
+ ],
409
+ },
375
410
  {
376
411
  header: 'Workflow Template Commands - Domain: workflow-templates',
377
412
  content: [
@@ -414,11 +449,15 @@ const helpSections = [
414
449
  },
415
450
  {
416
451
  name: 'uploadOptionSets',
417
- summary: 'Upload OptionSets for your Org. OptionSets are loaded from option_sets.yml\n'
452
+ summary: 'Upload OptionSets for your Org. OptionSets are loaded from .yml files in the option-sets directory.\n'
453
+ },
454
+ {
455
+ name: 'parseOptionSetsLocalFiles <File Paths> <style>',
456
+ summary: 'Parse CSV files into OptionSets. Style denotes the format the csv is in. If the csv file has a column for name and label, use "NameAndLabel". If the file has one column for each option set with the rows being the label value use "LabelsInColumn"\n'
418
457
  },
419
458
  {
420
- name: 'parseOptionSetsLocalFiles <File Paths>',
421
- summary: 'Parse CSV files into OptionSets.\n'
459
+ name: 'parseOptionSetsToFolderStructure <File Path>',
460
+ summary: 'Parse single yml file into a folder with separate files per option set.\n'
422
461
  },
423
462
  {
424
463
  name: 'parseOptionSetsHierarchyLocalFile <File Path>',
@@ -476,6 +515,10 @@ const helpSections = [
476
515
  name: 'mergeTypeProperties <File Path> <TypePaths>',
477
516
  summary: 'Merge the TypeProperties from an existing org and the TypeProperties passed in. Add to Types via TypePath File must be .yml\n'
478
517
  },
518
+ {
519
+ name: 'mergeOptionSets <File Path>',
520
+ summary: 'Merge the OptionSets from an existing org and the OptionSets passed in. OptionSets File must be .yml.',
521
+ },
479
522
  ],
480
523
  },
481
524
  ];
@@ -28,7 +28,7 @@ function loadOptionSets(fileLocation) {
28
28
  const fullPath = TARGET_DIR + separator + fileLocation;
29
29
  console.log('Getting file from path: ', fullPath);
30
30
  const doc = yaml.load(fs.readFileSync(TARGET_DIR + separator + fileLocation, 'utf8'));
31
- return doc.optionSets;
31
+ return doc;
32
32
  }
33
33
  catch (e) {
34
34
  throw new Error(`ERROR PARSING YAML: ${e}`);
@@ -76,20 +76,23 @@ async function mergeOptionSets(fileLocation) {
76
76
  mergedOptionSets.push(currentOptionSet);
77
77
  }
78
78
  }
79
- saveData({ optionSets: mergedOptionSets });
79
+ saveData(mergedOptionSets);
80
80
  }
81
81
  function mergeOptionSet(existingOptionSet, uploadedOptionSet) {
82
+ var _a;
82
83
  const merged = {
83
84
  name: uploadedOptionSet.name,
84
85
  optionSet: uploadedOptionSet.optionSet,
85
86
  isArchived: uploadedOptionSet.isArchived,
86
87
  };
87
- for (const keyVal of existingOptionSet.optionSet) {
88
- const value = keyVal.value;
89
- const display = keyVal.display;
90
- const found = merged.optionSet.find(keyVal => keyVal.value === value);
91
- if (!found) {
92
- merged.optionSet.push({ value, display });
88
+ if (((_a = existingOptionSet === null || existingOptionSet === void 0 ? void 0 : existingOptionSet.optionSet) === null || _a === void 0 ? void 0 : _a.length) > 0) {
89
+ for (const keyVal of existingOptionSet.optionSet) {
90
+ const value = keyVal.value;
91
+ const display = keyVal.display;
92
+ const found = merged.optionSet.find(keyVal => keyVal.value === value);
93
+ if (!found) {
94
+ merged.optionSet.push({ value, display });
95
+ }
93
96
  }
94
97
  }
95
98
  return merged;
@@ -1 +1,3 @@
1
1
  export declare function ParseOptionSetsLocalFiles(args: any): Promise<void>;
2
+ export declare function ParseOptionSetsToFolderStructure(args: any): Promise<void>;
3
+ export declare function parseLabelsInColumn(uploadedOptionData: any): any[];
@@ -1,9 +1,11 @@
1
1
  import fs from 'fs';
2
2
  import { getSeparatorByPlatform } from '../common';
3
3
  import { parseOptionSets } from '@contrail/types';
4
+ import { StringUtil } from '@contrail/util';
4
5
  import chalk from 'chalk';
5
6
  const csv = require('csvtojson');
6
7
  const yaml = require('js-yaml');
8
+ import * as path from 'path';
7
9
  export async function ParseOptionSetsLocalFiles(args) {
8
10
  try {
9
11
  if ((args === null || args === void 0 ? void 0 : args.length) < 4) {
@@ -11,8 +13,26 @@ export async function ParseOptionSetsLocalFiles(args) {
11
13
  }
12
14
  console.log('%s Importing local file', chalk.yellow.bold('OPTION SET PARSE'));
13
15
  const fileLocation = args[3];
16
+ const csvStyle = args[4];
14
17
  console.log('Using File: ', fileLocation);
15
- await parseOptionSetsLocalFiles(fileLocation);
18
+ await parseOptionSetsLocalFiles(fileLocation, csvStyle);
19
+ console.log('%s Parsed', chalk.yellow.bold('OPTION SET PARSE'));
20
+ }
21
+ catch (e) {
22
+ console.log(`%s PARSE Failed. ${e}`, chalk.red.bold('FAIL'));
23
+ return;
24
+ }
25
+ console.log('%s PARSE Complete.', chalk.green.bold('COMPLETE'));
26
+ }
27
+ export async function ParseOptionSetsToFolderStructure(args) {
28
+ try {
29
+ if ((args === null || args === void 0 ? void 0 : args.length) < 4) {
30
+ throw new Error('File name must be included.');
31
+ }
32
+ console.log('%s Importing local file', chalk.yellow.bold('OPTION SET PARSE'));
33
+ const fileLocation = args[3];
34
+ console.log('Using File: ', fileLocation);
35
+ await parseOptionSetsToFolderStructure(fileLocation);
16
36
  console.log('%s Parsed', chalk.yellow.bold('OPTION SET PARSE'));
17
37
  }
18
38
  catch (e) {
@@ -33,14 +53,33 @@ async function loadOptionSetCSV(fileLocation) {
33
53
  throw new Error(`ERROR PARSING CSV: ${e}`);
34
54
  }
35
55
  }
36
- async function parseOptionSetsLocalFiles(fileLocation) {
56
+ function loadOptionSets(fileLocation) {
57
+ const TARGET_DIR = process.cwd();
58
+ try {
59
+ const separator = getSeparatorByPlatform();
60
+ const fullPath = TARGET_DIR + separator + fileLocation;
61
+ console.log('Getting file from path: ', fullPath);
62
+ const doc = yaml.load(fs.readFileSync(TARGET_DIR + separator + fileLocation, 'utf8'));
63
+ return doc;
64
+ }
65
+ catch (e) {
66
+ throw new Error(`ERROR PARSING YAML: ${e}`);
67
+ }
68
+ }
69
+ async function parseOptionSetsLocalFiles(fileLocation, csvStyle) {
37
70
  const uploadedOptionData = await loadOptionSetCSV(fileLocation);
38
- // const newData = [];
39
- // for (const row of uploadedOptionData) {
40
- // newData.push({[row.optionSetName]: row.displayName});
41
- // }
42
- const parsedOptionSets = parseOptionSets(uploadedOptionData);
43
- saveData({ optionSets: parsedOptionSets });
71
+ if (csvStyle === 'NameAndLabel') {
72
+ const parsedOptionSets = parseOptionSets(uploadedOptionData);
73
+ saveData(parsedOptionSets);
74
+ }
75
+ if (csvStyle === 'LabelsInColumn') {
76
+ const parsedOptionSets = parseLabelsInColumn(uploadedOptionData);
77
+ saveData(parsedOptionSets);
78
+ }
79
+ }
80
+ async function parseOptionSetsToFolderStructure(fileLocation) {
81
+ const uploadedOptionData = await loadOptionSets(fileLocation);
82
+ saveDataInFolders(uploadedOptionData);
44
83
  }
45
84
  function saveData(data) {
46
85
  const yamlStr = yaml.dump(data);
@@ -48,3 +87,54 @@ function saveData(data) {
48
87
  const separator = getSeparatorByPlatform();
49
88
  fs.writeFileSync(CURRENT_DIR + separator + 'parsed_local_optionSets.yml', yamlStr, 'utf8');
50
89
  }
90
+ function saveDataInFolders(data) {
91
+ const folder = { filename: 'option-sets', split: true, fileLabel: 'name' };
92
+ const dir = 'merged_option_sets';
93
+ const CURRENT_DIR = process.cwd();
94
+ const subDir = path.join(CURRENT_DIR, dir, folder.filename);
95
+ if (!fs.existsSync(subDir)) {
96
+ fs.mkdirSync(subDir, { recursive: true });
97
+ }
98
+ for (const item of data) {
99
+ const yamlStr = yaml.dump(item);
100
+ const fileLabel = item[folder.fileLabel];
101
+ if (!fileLabel) {
102
+ console.warn('skipping bad data:', item);
103
+ }
104
+ fs.writeFileSync(path.join(subDir, `${removeSlash(fileLabel)}.yml`), yamlStr, 'utf8');
105
+ }
106
+ }
107
+ function removeSlash(string) {
108
+ const re = /\//gi;
109
+ return string.replace(re, '-');
110
+ }
111
+ export function parseLabelsInColumn(uploadedOptionData) {
112
+ const optionSets = [];
113
+ const optionSetNames = Object.keys(uploadedOptionData[0]);
114
+ for (const optionSetName of optionSetNames) {
115
+ const uniqueOptionSetValues = new Set();
116
+ for (const data of uploadedOptionData) {
117
+ const label = data[optionSetName];
118
+ uniqueOptionSetValues.add(label);
119
+ }
120
+ const optionSet = [];
121
+ if (uniqueOptionSetValues) {
122
+ for (const entry of uniqueOptionSetValues.values()) {
123
+ if (entry === '') {
124
+ continue;
125
+ }
126
+ optionSet.push({
127
+ value: StringUtil.convertToCamelCase(entry),
128
+ display: entry,
129
+ });
130
+ }
131
+ }
132
+ const reducedOptionSet = {
133
+ name: optionSetName,
134
+ isArchived: false,
135
+ optionSet,
136
+ };
137
+ optionSets.push(reducedOptionSet);
138
+ }
139
+ return optionSets;
140
+ }
@@ -110,7 +110,7 @@ async function parseTypesFromLocalFiles(fileLocations) {
110
110
  }
111
111
  console.log(`CSV imports were successful. ${csvJSONData === null || csvJSONData === void 0 ? void 0 : csvJSONData.length} total rows found.`);
112
112
  const suggestions = GetSuggestedTypes(csvJSONData);
113
- saveData({ optionSets: suggestions.OptionSets }, 'parsed_optionSets.yml');
113
+ saveData(suggestions.OptionSets, 'parsed_optionSets.yml');
114
114
  saveData({ typeProperties: suggestions.TypeProperties }, 'parsed_typeProperties.yml');
115
115
  }
116
116
  async function parseTypesFromTemplateFromLocalFiles(templateFileLocation, dataFileLocation) {
@@ -129,7 +129,7 @@ async function parseTypesFromTemplateFromLocalFiles(templateFileLocation, dataFi
129
129
  throw e;
130
130
  }
131
131
  const types = GetTypesFromTemplate(templateCSVData, dataCSVData);
132
- saveData({ optionSets: types.OptionSets }, 'parsed_optionSets.yml');
132
+ saveData(types.OptionSets, 'parsed_optionSets.yml');
133
133
  saveData({ TypePropertiesByEntity: types.TypePropertiesByEntity }, 'parsed_TypePropertiesByEntity.yml');
134
134
  }
135
135
  async function parseTypesFromTemplateAndDataFromLocalFiles(templateFileLocation, dataFileLocations) {
@@ -157,7 +157,7 @@ async function parseTypesFromTemplateAndDataFromLocalFiles(templateFileLocation,
157
157
  }
158
158
  }
159
159
  const types = GetTypesFromTemplateWithOptionSetsFromData(templateCSVData, dataCSVData);
160
- saveData({ optionSets: types.OptionSets }, 'parsed_optionSets.yml');
160
+ saveData(types.OptionSets, 'parsed_optionSets.yml');
161
161
  saveData({ TypePropertiesByEntity: types.TypePropertiesByEntity }, 'parsed_TypePropertiesByEntity.yml');
162
162
  }
163
163
  async function parseTypesFromFiles(fileIds) {
@@ -178,7 +178,7 @@ async function parseTypesFromFiles(fileIds) {
178
178
  }
179
179
  console.log(`CSV downloads were successful. ${csvJSONData === null || csvJSONData === void 0 ? void 0 : csvJSONData.length} total rows found.`);
180
180
  const suggestions = GetSuggestedTypes(csvJSONData);
181
- saveData({ optionSets: suggestions.OptionSets }, 'parsed_optionSets.yml');
181
+ saveData(suggestions.OptionSets, 'parsed_optionSets.yml');
182
182
  saveData({ typeProperties: suggestions.TypeProperties }, 'parsed_typeProperties.yml');
183
183
  }
184
184
  function saveData(data, name) {
@@ -0,0 +1 @@
1
+ export declare function ExportUsers(): Promise<void>;
@@ -0,0 +1,41 @@
1
+ import { Entities } from '@contrail/sdk';
2
+ import chalk from 'chalk';
3
+ import fs from 'fs';
4
+ import { authUser } from '../auth/login';
5
+ import { getSeparatorByPlatform } from '../common';
6
+ import yaml from 'js-yaml';
7
+ export async function ExportUsers() {
8
+ try {
9
+ await authUser();
10
+ console.log('%s Getting Users.', chalk.blue.bold('START'));
11
+ await exportUsers();
12
+ console.log('%s Done', chalk.yellow.bold('USERS'));
13
+ }
14
+ catch (e) {
15
+ console.log(`%s Users download Failed. ${e}`, chalk.red.bold('FAIL'));
16
+ return;
17
+ }
18
+ console.log('%s Users download Complete.', chalk.green.bold('COMPLETE'));
19
+ }
20
+ async function exportUsers() {
21
+ const allUsersInOrg = await new Entities().get({
22
+ entityName: 'user-org',
23
+ });
24
+ const users = [];
25
+ for (const userInOrg of allUsersInOrg) {
26
+ delete userInOrg.user.id;
27
+ delete userInOrg.user.updatedBy;
28
+ delete userInOrg.user.createdBy;
29
+ if (userInOrg.user.email.includes('@vibeappuser.com')) {
30
+ continue;
31
+ }
32
+ users.push(Object.assign({ role: userInOrg.role }, userInOrg.user));
33
+ }
34
+ saveData({ users: users }, 'users');
35
+ }
36
+ function saveData(data, name) {
37
+ const yamlStr = yaml.dump(data);
38
+ const CURRENT_DIR = process.cwd();
39
+ const separator = getSeparatorByPlatform();
40
+ fs.writeFileSync(CURRENT_DIR + separator + name + '-export.yml', yamlStr, 'utf8');
41
+ }
@@ -0,0 +1 @@
1
+ export declare function UploadUsers(): Promise<void>;
@@ -0,0 +1,45 @@
1
+ import { Entities } from '@contrail/sdk';
2
+ import chalk from 'chalk';
3
+ import fs from 'fs';
4
+ import { authUser } from '../auth/login';
5
+ import * as path from 'path';
6
+ import yaml from 'js-yaml';
7
+ export async function UploadUsers() {
8
+ try {
9
+ await authUser();
10
+ console.log('%s Uploading Users.', chalk.blue.bold('START'));
11
+ console.log('%s Uploading', chalk.yellow.bold('USER'));
12
+ await uploadUsers();
13
+ console.log('%s Uploaded', chalk.yellow.bold('USER'));
14
+ }
15
+ catch (e) {
16
+ console.log(`%s User Upload Failed. ${e}`, chalk.red.bold('FAIL'));
17
+ return;
18
+ }
19
+ console.log('%s User Upload Complete.', chalk.green.bold('COMPLETE'));
20
+ }
21
+ function getUsersFile() {
22
+ const CURRENT_DIR = process.cwd();
23
+ try {
24
+ const fullPath = path.join(CURRENT_DIR, 'users.yml');
25
+ console.log('Getting file from path: ', fullPath);
26
+ const doc = yaml.load(fs.readFileSync(fullPath, 'utf8'));
27
+ return doc.users;
28
+ }
29
+ catch (e) {
30
+ throw new Error(`ERROR PARSING YAML: ${e}`);
31
+ }
32
+ }
33
+ async function uploadUsers() {
34
+ const users = getUsersFile();
35
+ for (const user of users) {
36
+ const role = user.role;
37
+ const email = user.email;
38
+ delete user.role;
39
+ delete user.email;
40
+ await new Entities().create({
41
+ entityName: 'user-org',
42
+ object: Object.assign({ role: role, userEmail: email }, user)
43
+ });
44
+ }
45
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contrail/cli",
3
- "version": "1.0.66",
3
+ "version": "1.0.68",
4
4
  "description": "VibeIQ's Contrail Platform CLI.",
5
5
  "main": "lib/index.js",
6
6
  "bin": {
@@ -21,7 +21,7 @@ function parseArgumentsIntoOptions(rawArgs) {
21
21
  };
22
22
  }
23
23
  async function promptForMissingOptions(options) {
24
- const defaultTemplate = 'JavaScript';
24
+ const defaultTemplate = 'TypeScript';
25
25
 
26
26
  const questions = [];
27
27
  if (!options.appName) {
@@ -38,7 +38,7 @@ async function promptForMissingOptions(options) {
38
38
  type: 'list',
39
39
  name: 'template',
40
40
  message: 'Which project template would you like to use?',
41
- choices: ['JavaScript', 'TypeScript'],
41
+ choices: ['TypeScript', 'JavaScript'],
42
42
  default: defaultTemplate,
43
43
  });
44
44
  }
package/src/cli.ts CHANGED
@@ -4,7 +4,7 @@ import { deployApp, removeApp } from './apps/deploy-app/deploy';
4
4
  import { getAll } from './types/types-extractor';
5
5
  import { uploadTypes } from './types/types-uploader';
6
6
  import { UploadOptionSets } from './types/option-set-uploader';
7
- import { ParseOptionSetsLocalFiles } from './types/option-set-parser';
7
+ import { ParseOptionSetsLocalFiles, ParseOptionSetsToFolderStructure } from './types/option-set-parser';
8
8
  import { ParseOptionSetsHierarchyLocalFile, UploadOptionSetsHierarchyLocalFile } from './types/option-set-hierarchy-parser';
9
9
  import { ExportOptionSetsHierarchies } from './types/option-set-hierarchy-exporter';
10
10
  import { MergeOptionSets } from './types/option-set-merger';
@@ -24,6 +24,8 @@ import { uploadRuleSets } from './types/rule-set-uploader';
24
24
  import { UploadOptionSetHierarchies } from './types/option-set-hierarchy-uploader';
25
25
  import { uploadTypePropertyPolicies } from './types/type-property-policy-uploader';
26
26
  import { uploadAll } from './types/allUploader';
27
+ import { ExportUsers } from './users/user-exporter';
28
+ import { UploadUsers } from './users/user-uploader';
27
29
 
28
30
  const cliUsage = require('command-line-usage');
29
31
 
@@ -113,6 +115,10 @@ export async function cli(args) {
113
115
  ParseOptionSetsLocalFiles(args);
114
116
  break;
115
117
  }
118
+ case 'parseOptionSetsToFolderStructure': {
119
+ ParseOptionSetsToFolderStructure(args);
120
+ break;
121
+ }
116
122
  case 'parseOptionSetsHierarchyLocalFile': {
117
123
  ParseOptionSetsHierarchyLocalFile(args);
118
124
  break;
@@ -223,6 +229,23 @@ export async function cli(args) {
223
229
  }
224
230
  break;
225
231
  }
232
+ case 'users': {
233
+ switch (command) {
234
+ case 'export': {
235
+ await ExportUsers();
236
+ break;
237
+ }
238
+ case 'import': {
239
+ await UploadUsers();
240
+ break;
241
+ }
242
+ default: {
243
+ printIllegalCommand();
244
+ }
245
+ }
246
+ break;
247
+ }
248
+
226
249
  case 'workflow-templates': {
227
250
  switch (command) {
228
251
  case 'load': {
@@ -387,6 +410,19 @@ const helpSections = [
387
410
  }
388
411
  ],
389
412
  },
413
+ {
414
+ header: 'Users Commands - Domain: users',
415
+ content: [
416
+ {
417
+ name: 'export',
418
+ summary: 'Export all users in the org.'
419
+ },
420
+ {
421
+ name: 'import',
422
+ summary: 'Import all users in the users.yml file.'
423
+ }
424
+ ],
425
+ },
390
426
  {
391
427
  header: 'Workflow Template Commands - Domain: workflow-templates',
392
428
  content: [
@@ -429,11 +465,15 @@ const helpSections = [
429
465
  },
430
466
  {
431
467
  name: 'uploadOptionSets',
432
- summary: 'Upload OptionSets for your Org. OptionSets are loaded from option_sets.yml\n'
468
+ summary: 'Upload OptionSets for your Org. OptionSets are loaded from .yml files in the option-sets directory.\n'
469
+ },
470
+ {
471
+ name: 'parseOptionSetsLocalFiles <File Paths> <style>',
472
+ summary: 'Parse CSV files into OptionSets. Style denotes the format the csv is in. If the csv file has a column for name and label, use "NameAndLabel". If the file has one column for each option set with the rows being the label value use "LabelsInColumn"\n'
433
473
  },
434
474
  {
435
- name: 'parseOptionSetsLocalFiles <File Paths>',
436
- summary: 'Parse CSV files into OptionSets.\n'
475
+ name: 'parseOptionSetsToFolderStructure <File Path>',
476
+ summary: 'Parse single yml file into a folder with separate files per option set.\n'
437
477
  },
438
478
  {
439
479
  name: 'parseOptionSetsHierarchyLocalFile <File Path>',
@@ -491,6 +531,10 @@ const helpSections = [
491
531
  name: 'mergeTypeProperties <File Path> <TypePaths>',
492
532
  summary: 'Merge the TypeProperties from an existing org and the TypeProperties passed in. Add to Types via TypePath File must be .yml\n'
493
533
  },
534
+ {
535
+ name: 'mergeOptionSets <File Path>',
536
+ summary: 'Merge the OptionSets from an existing org and the OptionSets passed in. OptionSets File must be .yml.',
537
+ },
494
538
  ],
495
539
  },
496
540
  ];
@@ -35,7 +35,7 @@ function loadOptionSets(fileLocation) {
35
35
  console.log('Getting file from path: ', fullPath);
36
36
 
37
37
  const doc = yaml.load(fs.readFileSync(TARGET_DIR + separator + fileLocation, 'utf8'));
38
- return doc.optionSets;
38
+ return doc;
39
39
  } catch (e) {
40
40
  throw new Error(`ERROR PARSING YAML: ${e}`);
41
41
  }
@@ -91,7 +91,7 @@ async function mergeOptionSets(fileLocation) {
91
91
  }
92
92
  }
93
93
 
94
- saveData({optionSets: mergedOptionSets});
94
+ saveData(mergedOptionSets);
95
95
  }
96
96
 
97
97
  function mergeOptionSet(existingOptionSet: ReducedOptionSet, uploadedOptionSet: ReducedOptionSet) {
@@ -101,15 +101,16 @@ function mergeOptionSet(existingOptionSet: ReducedOptionSet, uploadedOptionSet:
101
101
  isArchived: uploadedOptionSet.isArchived,
102
102
  };
103
103
 
104
- for (const keyVal of existingOptionSet.optionSet) {
105
- const value = keyVal.value;
106
- const display = keyVal.display;
104
+ if (existingOptionSet?.optionSet?.length > 0) {
105
+ for (const keyVal of existingOptionSet.optionSet) {
106
+ const value = keyVal.value;
107
+ const display = keyVal.display;
107
108
 
108
- const found = merged.optionSet.find(keyVal => keyVal.value === value);
109
- if (!found) {
110
- merged.optionSet.push({value, display});
109
+ const found = merged.optionSet.find(keyVal => keyVal.value === value);
110
+ if (!found) {
111
+ merged.optionSet.push({value, display});
112
+ }
111
113
  }
112
-
113
114
  }
114
115
 
115
116
  return merged;
@@ -1,9 +1,11 @@
1
1
  import fs from 'fs';
2
2
  import { getSeparatorByPlatform } from '../common';
3
3
  import { parseOptionSets } from '@contrail/types';
4
+ import { StringUtil } from '@contrail/util';
4
5
  import chalk from 'chalk';
5
6
  const csv = require('csvtojson');
6
7
  const yaml = require('js-yaml');
8
+ import * as path from 'path';
7
9
 
8
10
  export async function ParseOptionSetsLocalFiles(args) {
9
11
  try {
@@ -12,9 +14,31 @@ export async function ParseOptionSetsLocalFiles(args) {
12
14
  }
13
15
  console.log('%s Importing local file', chalk.yellow.bold('OPTION SET PARSE'));
14
16
  const fileLocation = args[3];
17
+ const csvStyle = args[4];
15
18
  console.log('Using File: ', fileLocation);
16
19
 
17
- await parseOptionSetsLocalFiles(fileLocation);
20
+ await parseOptionSetsLocalFiles(fileLocation, csvStyle);
21
+ console.log('%s Parsed', chalk.yellow.bold('OPTION SET PARSE'));
22
+
23
+ }
24
+ catch (e) {
25
+ console.log(`%s PARSE Failed. ${e}`, chalk.red.bold('FAIL'));
26
+ return;
27
+ }
28
+
29
+ console.log('%s PARSE Complete.', chalk.green.bold('COMPLETE'));
30
+ }
31
+
32
+ export async function ParseOptionSetsToFolderStructure(args) {
33
+ try {
34
+ if (args?.length < 4) {
35
+ throw new Error('File name must be included.');
36
+ }
37
+ console.log('%s Importing local file', chalk.yellow.bold('OPTION SET PARSE'));
38
+ const fileLocation = args[3];
39
+ console.log('Using File: ', fileLocation);
40
+
41
+ await parseOptionSetsToFolderStructure(fileLocation);
18
42
  console.log('%s Parsed', chalk.yellow.bold('OPTION SET PARSE'));
19
43
 
20
44
  }
@@ -40,16 +64,38 @@ async function loadOptionSetCSV(fileLocation) {
40
64
  }
41
65
  }
42
66
 
43
- async function parseOptionSetsLocalFiles(fileLocation) {
67
+ function loadOptionSets(fileLocation) {
68
+ const TARGET_DIR = process.cwd();
69
+ try {
70
+ const separator = getSeparatorByPlatform();
71
+
72
+ const fullPath = TARGET_DIR + separator + fileLocation;
73
+ console.log('Getting file from path: ', fullPath);
74
+
75
+ const doc = yaml.load(fs.readFileSync(TARGET_DIR + separator + fileLocation, 'utf8'));
76
+ return doc;
77
+ } catch (e) {
78
+ throw new Error(`ERROR PARSING YAML: ${e}`);
79
+ }
80
+ }
81
+
82
+ async function parseOptionSetsLocalFiles(fileLocation, csvStyle) {
44
83
  const uploadedOptionData = await loadOptionSetCSV(fileLocation);
45
84
 
46
- // const newData = [];
47
- // for (const row of uploadedOptionData) {
48
- // newData.push({[row.optionSetName]: row.displayName});
49
- // }
85
+ if (csvStyle === 'NameAndLabel') {
86
+ const parsedOptionSets = parseOptionSets(uploadedOptionData);
87
+ saveData(parsedOptionSets);
88
+ }
89
+
90
+ if (csvStyle === 'LabelsInColumn') {
91
+ const parsedOptionSets = parseLabelsInColumn(uploadedOptionData);
92
+ saveData(parsedOptionSets);
93
+ }
94
+ }
50
95
 
51
- const parsedOptionSets = parseOptionSets(uploadedOptionData);
52
- saveData({optionSets: parsedOptionSets});
96
+ async function parseOptionSetsToFolderStructure(fileLocation) {
97
+ const uploadedOptionData = await loadOptionSets(fileLocation);
98
+ saveDataInFolders(uploadedOptionData);
53
99
  }
54
100
 
55
101
  function saveData(data) {
@@ -57,4 +103,64 @@ function saveData(data) {
57
103
  const CURRENT_DIR = process.cwd();
58
104
  const separator = getSeparatorByPlatform();
59
105
  fs.writeFileSync(CURRENT_DIR + separator + 'parsed_local_optionSets.yml', yamlStr, 'utf8');
106
+ }
107
+
108
+ function saveDataInFolders(data) {
109
+ const folder = { filename: 'option-sets', split: true, fileLabel: 'name' };
110
+ const dir = 'merged_option_sets';
111
+
112
+ const CURRENT_DIR = process.cwd();
113
+
114
+ const subDir = path.join(CURRENT_DIR, dir, folder.filename);
115
+ if(!fs.existsSync(subDir)) {
116
+ fs.mkdirSync(subDir, { recursive: true });
117
+ }
118
+ for(const item of data) {
119
+ const yamlStr = yaml.dump(item);
120
+ const fileLabel = item[folder.fileLabel];
121
+ if(!fileLabel) {
122
+ console.warn('skipping bad data:', item);
123
+ }
124
+ fs.writeFileSync(path.join(subDir, `${removeSlash(fileLabel)}.yml`), yamlStr, 'utf8');
125
+ }
126
+ }
127
+
128
+ function removeSlash(string) {
129
+ const re = /\//gi;
130
+ return string.replace(re, '-');
131
+ }
132
+
133
+ export function parseLabelsInColumn(uploadedOptionData) {
134
+ const optionSets = [];
135
+ const optionSetNames = Object.keys(uploadedOptionData[0]);
136
+ for (const optionSetName of optionSetNames) {
137
+ const uniqueOptionSetValues = new Set<string>();
138
+ for (const data of uploadedOptionData) {
139
+ const label = data[optionSetName];
140
+ uniqueOptionSetValues.add(label);
141
+ }
142
+
143
+ const optionSet: any[] = [];
144
+ if (uniqueOptionSetValues) {
145
+ for (const entry of uniqueOptionSetValues.values()) {
146
+ if (entry === '') {
147
+ continue;
148
+ }
149
+ optionSet.push({
150
+ value: StringUtil.convertToCamelCase(entry),
151
+ display: entry,
152
+ });
153
+ }
154
+ }
155
+
156
+ const reducedOptionSet = {
157
+ name: optionSetName,
158
+ isArchived: false,
159
+ optionSet,
160
+ };
161
+
162
+ optionSets.push(reducedOptionSet);
163
+ }
164
+
165
+ return optionSets;
60
166
  }
@@ -134,7 +134,7 @@ async function parseTypesFromLocalFiles(fileLocations: string[]) {
134
134
 
135
135
  console.log(`CSV imports were successful. ${csvJSONData?.length} total rows found.`);
136
136
  const suggestions = GetSuggestedTypes(csvJSONData);
137
- saveData({ optionSets: suggestions.OptionSets }, 'parsed_optionSets.yml');
137
+ saveData(suggestions.OptionSets, 'parsed_optionSets.yml');
138
138
  saveData({ typeProperties: suggestions.TypeProperties }, 'parsed_typeProperties.yml');
139
139
  }
140
140
 
@@ -157,7 +157,7 @@ async function parseTypesFromTemplateFromLocalFiles(templateFileLocation: string
157
157
  }
158
158
 
159
159
  const types = GetTypesFromTemplate(templateCSVData, dataCSVData);
160
- saveData({ optionSets: types.OptionSets }, 'parsed_optionSets.yml');
160
+ saveData(types.OptionSets, 'parsed_optionSets.yml');
161
161
  saveData({ TypePropertiesByEntity: types.TypePropertiesByEntity }, 'parsed_TypePropertiesByEntity.yml');
162
162
  }
163
163
 
@@ -190,7 +190,7 @@ async function parseTypesFromTemplateAndDataFromLocalFiles(templateFileLocation:
190
190
  }
191
191
 
192
192
  const types = GetTypesFromTemplateWithOptionSetsFromData(templateCSVData, dataCSVData);
193
- saveData({ optionSets: types.OptionSets }, 'parsed_optionSets.yml');
193
+ saveData(types.OptionSets, 'parsed_optionSets.yml');
194
194
  saveData({ TypePropertiesByEntity: types.TypePropertiesByEntity }, 'parsed_TypePropertiesByEntity.yml');
195
195
  }
196
196
 
@@ -215,7 +215,7 @@ async function parseTypesFromFiles(fileIds: string[]) {
215
215
  console.log(`CSV downloads were successful. ${csvJSONData?.length} total rows found.`);
216
216
  const suggestions = GetSuggestedTypes(csvJSONData);
217
217
 
218
- saveData({ optionSets: suggestions.OptionSets }, 'parsed_optionSets.yml');
218
+ saveData(suggestions.OptionSets, 'parsed_optionSets.yml');
219
219
  saveData({ typeProperties: suggestions.TypeProperties }, 'parsed_typeProperties.yml');
220
220
  }
221
221
 
@@ -0,0 +1,52 @@
1
+ import { Entities } from '@contrail/sdk';
2
+ import chalk from 'chalk';
3
+ import fs from 'fs';
4
+ import { authUser } from '../auth/login';
5
+ import { getSeparatorByPlatform } from '../common';
6
+ import yaml from 'js-yaml';
7
+
8
+ export async function ExportUsers() {
9
+ try {
10
+ await authUser();
11
+ console.log('%s Getting Users.', chalk.blue.bold('START'));
12
+
13
+ await exportUsers();
14
+ console.log('%s Done', chalk.yellow.bold('USERS'));
15
+
16
+ }
17
+ catch (e) {
18
+ console.log(`%s Users download Failed. ${e}`, chalk.red.bold('FAIL'));
19
+ return;
20
+ }
21
+
22
+ console.log('%s Users download Complete.', chalk.green.bold('COMPLETE'));
23
+ }
24
+
25
+ async function exportUsers() {
26
+ const allUsersInOrg = await new Entities().get({
27
+ entityName: 'user-org',
28
+ });
29
+
30
+ const users = [];
31
+ for (const userInOrg of allUsersInOrg) {
32
+ delete userInOrg.user.id;
33
+ delete userInOrg.user.updatedBy;
34
+ delete userInOrg.user.createdBy;
35
+ if (userInOrg.user.email.includes('@vibeappuser.com')) {
36
+ continue;
37
+ }
38
+ users.push({
39
+ role: userInOrg.role,
40
+ ...userInOrg.user
41
+ });
42
+ }
43
+
44
+ saveData({users: users}, 'users');
45
+ }
46
+
47
+ function saveData(data, name) {
48
+ const yamlStr = yaml.dump(data);
49
+ const CURRENT_DIR = process.cwd();
50
+ const separator = getSeparatorByPlatform();
51
+ fs.writeFileSync(CURRENT_DIR + separator + name + '-export.yml', yamlStr, 'utf8');
52
+ }
@@ -0,0 +1,58 @@
1
+ import { Entities } from '@contrail/sdk';
2
+ import chalk from 'chalk';
3
+ import fs from 'fs';
4
+ import { authUser } from '../auth/login';
5
+ import * as path from 'path';
6
+
7
+ import yaml from 'js-yaml';
8
+
9
+ export async function UploadUsers() {
10
+ try {
11
+ await authUser();
12
+ console.log('%s Uploading Users.', chalk.blue.bold('START'));
13
+
14
+ console.log('%s Uploading', chalk.yellow.bold('USER'));
15
+ await uploadUsers();
16
+ console.log('%s Uploaded', chalk.yellow.bold('USER'));
17
+
18
+ }
19
+ catch (e) {
20
+ console.log(`%s User Upload Failed. ${e}`, chalk.red.bold('FAIL'));
21
+ return;
22
+ }
23
+
24
+ console.log('%s User Upload Complete.', chalk.green.bold('COMPLETE'));
25
+ }
26
+
27
+ function getUsersFile(){
28
+ const CURRENT_DIR = process.cwd();
29
+ try {
30
+ const fullPath = path.join(CURRENT_DIR, 'users.yml');
31
+ console.log('Getting file from path: ', fullPath);
32
+
33
+ const doc = yaml.load(fs.readFileSync(fullPath, 'utf8'));
34
+ return doc.users;
35
+ } catch (e) {
36
+ throw new Error(`ERROR PARSING YAML: ${e}`);
37
+ }
38
+ }
39
+
40
+ async function uploadUsers() {
41
+ const users = getUsersFile();
42
+
43
+ for (const user of users) {
44
+ const role = user.role;
45
+ const email = user.email;
46
+ delete user.role;
47
+ delete user.email;
48
+
49
+ await new Entities().create({
50
+ entityName: 'user-org',
51
+ object: {
52
+ role: role,
53
+ userEmail: email,
54
+ ...user
55
+ }
56
+ });
57
+ }
58
+ }
@@ -22,7 +22,7 @@ export async function execute(data) {
22
22
  }
23
23
 
24
24
  try {
25
- login({ apiKey: data.apiKey, orgSlug: data.orgSlug });
25
+ await login({ apiKey: data.apiKey, orgSlug: data.orgSlug });
26
26
  const results = {};
27
27
 
28
28
  logger.log('Sending message: ', event);
@@ -0,0 +1,24 @@
1
+ import { execute } from './handler';
2
+ const express = require('express');
3
+ const bodyParser = require('body-parser');
4
+ const app = express();
5
+ const port = 5050;
6
+
7
+ // parse application/x-www-form-urlencoded
8
+ app.use(bodyParser.urlencoded({ extended: false }));
9
+ // parse application/json
10
+ app.use(bodyParser.json());
11
+
12
+ app.get('/health_check', (req, res) => {
13
+ res.send('Hello World!');
14
+ });
15
+
16
+ // DO NOT CHANGE THIS IMPLEMENTATION
17
+ app.post('/', async (req, res) => {
18
+ const result = await execute(req.body);
19
+ res.send(result);
20
+ });
21
+
22
+ app.listen(port, () => {
23
+ console.log(`Mock server listening on port ${port}`);
24
+ });
@@ -1,15 +1,15 @@
1
1
  export class Logger {
2
2
  allEntries = [];
3
3
  public log(...args){
4
- console.log(args);
4
+ console.log(...args);
5
5
  this.allEntries.push(args);
6
6
  }
7
7
 
8
8
  public getEntries(){
9
- return this.allEntries;
9
+ return this.allEntries.join('\n');
10
10
  }
11
11
 
12
12
  public clearEntries(){
13
13
  this.allEntries = [];
14
14
  }
15
- }
15
+ }
@@ -15,6 +15,8 @@
15
15
  },
16
16
  "scripts": {
17
17
  "build": "tsc",
18
+ "start": "nodemon --watch 'actions/**/*.ts' --exec ts-node actions/mock-server.ts",
19
+ "debug": "nodemon -r ts-node/register --inspect=127.0.0.1:60002 --watch 'actions/**/*.ts' --exec node actions/mock-server.ts",
18
20
  "lint": "eslint . --fix",
19
21
  "test": "jest",
20
22
  "test-watch": "jest --watch",
@@ -39,8 +41,12 @@
39
41
  "chalk": "^4.0.0"
40
42
  },
41
43
  "devDependencies": {
44
+ "body-parser": "^1.20.2",
45
+ "express": "^4.18.2",
46
+ "nodemon": "^1.19.4",
42
47
  "jest": "^29.2.2",
43
48
  "ts-jest": "^29.0.3",
49
+ "ts-node": "^7.0.1",
44
50
  "typescript": "^4.7.4"
45
51
  }
46
52
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "compilerOptions": {
3
- "target": "es2017",
3
+ "target": "ES2020",
4
4
  "module": "commonjs",
5
5
  "declaration": true,
6
6
  "esModuleInterop": true,
@@ -17,15 +17,11 @@
17
17
  "ES2015",
18
18
  "ES2016",
19
19
  "ES2017",
20
+ "ES2020",
20
21
  "dom",
21
22
  "esnext.asynciterable"
22
- ],
23
+ ]
23
24
  },
24
- "include": [
25
- "actions"
26
- ],
27
- "exclude": [
28
- "node_modules",
29
- "**/__tests__/*"
30
- ]
31
- }
25
+ "include": ["actions"],
26
+ "exclude": ["node_modules", "**/__tests__/*"]
27
+ }