@contrail/cli 3.5.4-alpha.2a94b1c → 3.5.4-alpha.640db77

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/README.md CHANGED
@@ -17,7 +17,7 @@ $ npm install -g @contrail/cli
17
17
  $ contrail COMMAND
18
18
  running command...
19
19
  $ contrail (--version)
20
- @contrail/cli/3.5.4-alpha.2a94b1c linux-x64 node-v24.18.0
20
+ @contrail/cli/3.5.4-alpha.640db77 linux-x64 node-v24.18.0
21
21
  $ contrail --help [COMMAND]
22
22
  USAGE
23
23
  $ contrail COMMAND
@@ -97,7 +97,7 @@ To get instructions on how to set up autocomplete for your shell, run `contrail
97
97
  * [`contrail workflow-templates delete`](#contrail-workflow-templates-delete)
98
98
  * [`contrail workflow-templates export`](#contrail-workflow-templates-export)
99
99
  * [`contrail workflow-templates list`](#contrail-workflow-templates-list)
100
- * [`contrail workflow-templates load [FILELOCATION]`](#contrail-workflow-templates-load-filelocation)
100
+ * [`contrail workflow-templates load FILELOCATION`](#contrail-workflow-templates-load-filelocation)
101
101
 
102
102
  ## `contrail app create`
103
103
 
@@ -1611,31 +1611,25 @@ EXAMPLES
1611
1611
 
1612
1612
  ## `contrail workflow-templates export`
1613
1613
 
1614
- Export all workflows in the org. By default exports one file per app to the current directory.
1614
+ Export all workflows in the org.
1615
1615
 
1616
1616
  ```
1617
1617
  USAGE
1618
- $ contrail workflow-templates export [-l error|warn|info|debug] [-e true|false] [-f <value>] [-d <value>]
1619
- [--overwrite]
1618
+ $ contrail workflow-templates export [-l error|warn|info|debug] [-e true|false] [-f <value>] [--overwrite]
1620
1619
 
1621
1620
  FLAGS
1622
- -d, --dir=<value> [default: .] Directory to write per-app workflow files
1623
1621
  -e, --alwaysConfirmEnv=<option> [default: true] The Environment variables
1624
1622
  <options: true|false>
1625
- -f, --outFile=<value> Export all workflows to a single file at this path (overrides per-app export)
1623
+ -f, --outFile=<value> [default: workflows.yml] The location for the file to be saved
1626
1624
  -l, --logLevel=<option> The Log Level
1627
1625
  <options: error|warn|info|debug>
1628
1626
  --overwrite Replaces existing files if they exist
1629
1627
 
1630
1628
  DESCRIPTION
1631
- Export all workflows in the org. By default exports one file per app to the current directory.
1629
+ Export all workflows in the org.
1632
1630
 
1633
1631
  EXAMPLES
1634
1632
  $ contrail workflow-templates export
1635
-
1636
- $ contrail workflow-templates export --dir ./workflows
1637
-
1638
- $ contrail workflow-templates export --outFile workflows.yml
1639
1633
  ```
1640
1634
 
1641
1635
  ## `contrail workflow-templates list`
@@ -1659,32 +1653,27 @@ EXAMPLES
1659
1653
  $ contrail workflow-templates list
1660
1654
  ```
1661
1655
 
1662
- ## `contrail workflow-templates load [FILELOCATION]`
1656
+ ## `contrail workflow-templates load FILELOCATION`
1663
1657
 
1664
- Load workflow templates from a file or scan a directory for per-app workflow files
1658
+ Loads your workflow from a local file
1665
1659
 
1666
1660
  ```
1667
1661
  USAGE
1668
- $ contrail workflow-templates load [FILELOCATION] [-l error|warn|info|debug] [-e true|false] [-d <value>]
1662
+ $ contrail workflow-templates load FILELOCATION [-l error|warn|info|debug] [-e true|false]
1669
1663
 
1670
1664
  ARGUMENTS
1671
- FILELOCATION A specific workflow template file to load
1665
+ FILELOCATION The workflow template file to load
1672
1666
 
1673
1667
  FLAGS
1674
- -d, --dir=<value> [default: .] Directory to scan for workflow files when no file argument is given
1675
1668
  -e, --alwaysConfirmEnv=<option> [default: true] The Environment variables
1676
1669
  <options: true|false>
1677
1670
  -l, --logLevel=<option> The Log Level
1678
1671
  <options: error|warn|info|debug>
1679
1672
 
1680
1673
  DESCRIPTION
1681
- Load workflow templates from a file or scan a directory for per-app workflow files
1674
+ Loads your workflow from a local file
1682
1675
 
1683
1676
  EXAMPLES
1684
1677
  $ contrail workflow-templates load <FILE_LOCATION>
1685
-
1686
- $ contrail workflow-templates load
1687
-
1688
- $ contrail workflow-templates load --dir ./workflows
1689
1678
  ```
1690
1679
  <!-- commandsstop -->
@@ -99,7 +99,7 @@ const saveTypesFunction = async (data, dir, overwrite) => {
99
99
  if (!fileLabel) {
100
100
  logger_1.default.warn(`skipping bad type root: ${root}`);
101
101
  }
102
- const pathToWrite = path.join(subDir, `${(0, common_1.removeSlash)(fileLabel)}.yml`);
102
+ const pathToWrite = path.join(subDir, `${(0, common_1.sanitizeFileName)(fileLabel)}.yml`);
103
103
  if (fs_1.default.existsSync(pathToWrite)) {
104
104
  await (0, file_helpers_1.safeFileOverwrite)(pathToWrite, overwrite);
105
105
  }
@@ -150,7 +150,7 @@ async function saveData(reducedData, dir, overwrite) {
150
150
  logger_1.default.warn(`skipping bad data: ${item}`);
151
151
  continue;
152
152
  }
153
- const pathToWrite = path.join(subDir, `${(0, common_1.removeSlash)(fileLabel)}.yml`);
153
+ const pathToWrite = path.join(subDir, `${(0, common_1.sanitizeFileName)(fileLabel)}.yml`);
154
154
  if (fs_1.default.existsSync(pathToWrite)) {
155
155
  await (0, file_helpers_1.safeFileOverwrite)(pathToWrite, overwrite);
156
156
  }
@@ -136,7 +136,7 @@ async function saveOptionSetsToCSV(optionSets, dir, fileLabel, overwrite, combin
136
136
  }
137
137
  else {
138
138
  dataToAdd = [];
139
- pathToWrite = path.join(dir, `${(0, common_1.removeSlash)(fileLabelValue)}.csv`);
139
+ pathToWrite = path.join(dir, `${(0, common_1.sanitizeFileName)(fileLabelValue)}.csv`);
140
140
  const csvHeaders = 'Option Set Name,Value Key,Label\n'; // CSV headers
141
141
  if (!fs_1.default.existsSync(pathToWrite)) {
142
142
  fs_1.default.writeFileSync(pathToWrite, csvHeaders, 'utf8');
@@ -162,7 +162,7 @@ async function saveOptionSetsToYAML(optionSets, dir, fileLabel, overwrite) {
162
162
  logger_1.default.warn('skipping bad data:', item);
163
163
  continue;
164
164
  }
165
- const pathToWrite = path.join(dir, `${(0, common_1.removeSlash)(fileLabelValue)}.yml`);
165
+ const pathToWrite = path.join(dir, `${(0, common_1.sanitizeFileName)(fileLabelValue)}.yml`);
166
166
  if (fs_1.default.existsSync(pathToWrite)) {
167
167
  await (0, file_helpers_1.safeFileOverwrite)(pathToWrite, overwrite);
168
168
  }
@@ -139,7 +139,7 @@ function saveDataInFolders(data) {
139
139
  if (!fileLabel) {
140
140
  logger_1.default.warn('skipping bad data:', item);
141
141
  }
142
- fs_1.default.writeFileSync(path.join(subDir, `${(0, common_1.removeSlash)(fileLabel)}.yml`), yamlStr, 'utf8');
142
+ fs_1.default.writeFileSync(path.join(subDir, `${(0, common_1.sanitizeFileName)(fileLabel)}.yml`), yamlStr, 'utf8');
143
143
  }
144
144
  }
145
145
  /**
@@ -63,6 +63,6 @@ function saveDataInFolders(data) {
63
63
  if (!fileLabel) {
64
64
  logger_1.default.warn('skipping bad data:', item);
65
65
  }
66
- fs_1.default.writeFileSync(path.join(subDir, `${(0, common_1.removeSlash)(fileLabel)}.yml`), yamlStr, 'utf8');
66
+ fs_1.default.writeFileSync(path.join(subDir, `${(0, common_1.sanitizeFileName)(fileLabel)}.yml`), yamlStr, 'utf8');
67
67
  }
68
68
  }
@@ -1,15 +1,14 @@
1
1
  import { BaseCommand } from '../../basecommand';
2
+ export declare const DEFAULT_FILE_LOCATION = "workflows.yml";
2
3
  export default class ExportWorkflows extends BaseCommand {
3
4
  static description: string;
4
5
  static examples: string[];
5
6
  static flags: {
6
7
  outFile: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
7
- dir: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
8
8
  overwrite: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
9
9
  alwaysConfirmEnv: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
10
10
  logLevel: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
11
11
  };
12
12
  run(): Promise<void>;
13
13
  }
14
- export declare function exportWorkflowsByApp(outputDir: string, overwrite: boolean): Promise<void>;
15
- export declare function exportWorkflowsToFile(fileLocation: string, overwrite: boolean): Promise<void>;
14
+ export declare function exportWorkflows(fileLocation: string, overwrite: boolean): Promise<void>;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.exportWorkflowsToFile = exports.exportWorkflowsByApp = void 0;
3
+ exports.exportWorkflows = exports.DEFAULT_FILE_LOCATION = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const path = tslib_1.__importStar(require("path"));
6
6
  const chalk_1 = tslib_1.__importDefault(require("chalk"));
@@ -11,29 +11,22 @@ const js_yaml_1 = tslib_1.__importDefault(require("js-yaml"));
11
11
  const core_1 = require("@oclif/core");
12
12
  const file_helpers_1 = require("../../helpers/file-helpers");
13
13
  const event_workflow_templates_1 = require("../../api/event-workflow-templates");
14
- const schedules_1 = require("../../api/schedules");
15
- const apps_1 = require("../../api/apps");
16
14
  const helper_1 = require("../../helpers/workflow-templates/helper");
17
15
  const basecommand_1 = require("../../basecommand");
16
+ exports.DEFAULT_FILE_LOCATION = 'workflows.yml';
18
17
  class ExportWorkflows extends basecommand_1.BaseCommand {
19
- static description = 'Export all workflows in the org. By default exports one file per app to the current directory.';
18
+ static description = 'Export all workflows in the org.';
20
19
  static examples = [
21
- '$ contrail workflow-templates export',
22
- '$ contrail workflow-templates export --dir ./workflows',
23
- '$ contrail workflow-templates export --outFile workflows.yml',
20
+ `$ contrail workflow-templates export
21
+ `,
24
22
  ];
25
23
  static flags = {
26
24
  ...basecommand_1.BaseCommand.baseFlags,
27
25
  outFile: core_1.Flags.string({
28
26
  char: 'f',
29
- description: 'Export all workflows to a single file at this path (overrides per-app export)',
27
+ description: 'The location for the file to be saved',
30
28
  required: false,
31
- }),
32
- dir: core_1.Flags.string({
33
- char: 'd',
34
- description: 'Directory to write per-app workflow files',
35
- required: false,
36
- default: '.',
29
+ default: exports.DEFAULT_FILE_LOCATION,
37
30
  }),
38
31
  overwrite: core_1.Flags.boolean({
39
32
  description: 'Replaces existing files if they exist',
@@ -45,12 +38,7 @@ class ExportWorkflows extends basecommand_1.BaseCommand {
45
38
  try {
46
39
  await (0, login_1.authUser)();
47
40
  this.log(`${chalk_1.default.blue.bold('START')} Getting Workflows.`);
48
- if (this.flags.outFile) {
49
- await exportWorkflowsToFile(this.flags.outFile, this.flags.overwrite);
50
- }
51
- else {
52
- await exportWorkflowsByApp(this.flags.dir ?? '.', this.flags.overwrite);
53
- }
41
+ await exportWorkflows(this.flags.outFile ?? exports.DEFAULT_FILE_LOCATION, this.flags.overwrite);
54
42
  this.log(`${chalk_1.default.yellow.bold('WORKFLOWS')} Done`);
55
43
  }
56
44
  catch (e) {
@@ -61,106 +49,31 @@ class ExportWorkflows extends basecommand_1.BaseCommand {
61
49
  }
62
50
  }
63
51
  exports.default = ExportWorkflows;
64
- async function exportWorkflowsByApp(outputDir, overwrite) {
65
- const [allWorkflowsInOrg, allSchedules, installedApps] = await Promise.all([
66
- (0, event_workflow_templates_1.getExistingWorkflowTemplates)(),
67
- (0, schedules_1.getExistingSchedules)(),
68
- (0, apps_1.getInstalledApps)(),
69
- ]);
70
- const appIdToIdentifier = new Map(installedApps
71
- .filter((appOrg) => appOrg.appId && appOrg.app?.identifier)
72
- .map((appOrg) => [appOrg.appId, appOrg.app.identifier]));
73
- const workflowsByApp = new Map();
74
- const unassigned = [];
75
- for (const workflow of allWorkflowsInOrg) {
76
- let appIdentifier = workflow.supportingAppId
77
- ? appIdToIdentifier.get(workflow.supportingAppId)
78
- : undefined;
79
- // If no supportingAppId, try to extract app identifier from workflow identifier
80
- // Format: @{appIdentifier}@{randomId}:{workflowName}
81
- if (!appIdentifier && workflow.identifier) {
82
- const match = workflow.identifier.match(/^@([^@]+)@/);
83
- if (match) {
84
- // Keep the @ prefix in the appIdentifier
85
- appIdentifier = `@${match[1]}`;
86
- }
87
- }
88
- if (appIdentifier) {
89
- if (!workflowsByApp.has(appIdentifier)) {
90
- workflowsByApp.set(appIdentifier, []);
91
- }
92
- const workflows = workflowsByApp.get(appIdentifier);
93
- if (workflows) {
94
- workflows.push(workflow);
95
- }
96
- }
97
- else {
98
- unassigned.push(workflow);
99
- }
100
- }
101
- const resolvedDir = path.resolve(process.cwd(), outputDir);
102
- for (const [appIdentifier, workflows] of workflowsByApp.entries()) {
103
- const exportObj = { appIdentifier, workflows: [] };
104
- for (const workflow of workflows) {
105
- exportObj.workflows.push(await buildExportWorkflow(workflow, allSchedules, appIdentifier));
106
- }
107
- const safeAppIdentifier = appIdentifier.replace(/[\\/]/g, '-');
108
- const filePath = path.join(resolvedDir, `workflows-${safeAppIdentifier}.yml`);
109
- await writeYamlFile(exportObj, filePath, overwrite);
110
- console.log(`${chalk_1.default.green('EXPORTED')} ${filePath}`);
111
- }
112
- if (unassigned.length > 0) {
113
- const unassignedObj = { workflows: [] };
114
- for (const workflow of unassigned) {
115
- unassignedObj.workflows.push(await buildExportWorkflow(workflow, allSchedules));
116
- }
117
- const unassignedFilePath = path.join(resolvedDir, 'workflows-unassigned.yml');
118
- await writeYamlFile(unassignedObj, unassignedFilePath, overwrite);
119
- console.log(`${chalk_1.default.yellow('EXPORTED')} ${unassignedFilePath} (unassigned workflows)`);
120
- }
121
- }
122
- exports.exportWorkflowsByApp = exportWorkflowsByApp;
123
- async function exportWorkflowsToFile(fileLocation, overwrite) {
124
- const [allWorkflowsInOrg, allSchedules] = await Promise.all([
125
- (0, event_workflow_templates_1.getExistingWorkflowTemplates)(),
126
- (0, schedules_1.getExistingSchedules)(),
127
- ]);
52
+ async function exportWorkflows(fileLocation, overwrite) {
53
+ const allWorkflowsInOrg = await (0, event_workflow_templates_1.getExistingWorkflowTemplates)();
128
54
  const workflowsObj = { workflows: [] };
129
55
  for (const workflow of allWorkflowsInOrg) {
130
- workflowsObj.workflows.push(await buildExportWorkflow(workflow, allSchedules));
131
- }
132
- const pathToWrite = path.resolve(process.cwd(), fileLocation);
133
- await writeYamlFile(workflowsObj, pathToWrite, overwrite);
134
- }
135
- exports.exportWorkflowsToFile = exportWorkflowsToFile;
136
- async function buildExportWorkflow(workflow, allSchedules, appIdentifier) {
137
- const exportWorkflow = lodash_1.default.pick(workflow, [
138
- 'identifier',
139
- 'name',
140
- 'triggerKey',
141
- 'isActive',
142
- 'messageGroup',
143
- 'dynamicMessageGroupId',
144
- 'parallelWorkerCount',
145
- 'workflowDefinition',
146
- ]);
147
- const schedules = allSchedules.filter((s) => s.ownerReference === `event-workflow-template:${workflow.id}`);
148
- if (schedules.length > 0) {
149
- exportWorkflow.crons = schedules.map((s) => ({ name: s.name, cron: s.cron }));
150
- }
151
- await (0, helper_1.populateActionIdentifiers)(exportWorkflow);
152
- // Shortened keys can only be resolved back to a full action identifier on
153
- // import if an appIdentifier is known. Without one (e.g. unassigned
154
- // workflows), keep the full identifier so the workflow stays re-importable.
155
- if (appIdentifier) {
156
- (0, helper_1.extractShortActionKeys)(exportWorkflow);
56
+ const exportWorkflow = lodash_1.default.pick(workflow, [
57
+ 'triggerKey',
58
+ 'workflowDefinition',
59
+ 'name',
60
+ 'isActive',
61
+ 'identifier',
62
+ 'messageGroup',
63
+ 'dynamicMessageGroupId',
64
+ ]);
65
+ await (0, helper_1.populateActionIdentifiers)(exportWorkflow);
66
+ workflowsObj.workflows.push(exportWorkflow);
157
67
  }
158
- return exportWorkflow;
68
+ await saveData(workflowsObj, fileLocation, overwrite);
159
69
  }
160
- async function writeYamlFile(data, absolutePath, overwrite) {
161
- if (fs_1.default.existsSync(absolutePath)) {
162
- await (0, file_helpers_1.safeFileOverwrite)(absolutePath, overwrite);
70
+ exports.exportWorkflows = exportWorkflows;
71
+ async function saveData(data, fileLocation, overwrite) {
72
+ const yamlStr = js_yaml_1.default.dump(data);
73
+ const CURRENT_DIR = process.cwd();
74
+ const pathToWrite = path.resolve(path.join(CURRENT_DIR, fileLocation));
75
+ if (fs_1.default.existsSync(pathToWrite)) {
76
+ await (0, file_helpers_1.safeFileOverwrite)(pathToWrite, overwrite);
163
77
  }
164
- fs_1.default.mkdirSync(path.dirname(absolutePath), { recursive: true });
165
- fs_1.default.writeFileSync(absolutePath, js_yaml_1.default.dump(data), 'utf8');
78
+ fs_1.default.writeFileSync(pathToWrite, yamlStr, 'utf8');
166
79
  }
@@ -3,7 +3,6 @@ export default class LoadWorkflowTemplates extends BaseCommand {
3
3
  static description: string;
4
4
  static examples: string[];
5
5
  static flags: {
6
- dir: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
7
6
  alwaysConfirmEnv: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
8
7
  logLevel: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
9
8
  };
@@ -12,4 +11,3 @@ export default class LoadWorkflowTemplates extends BaseCommand {
12
11
  };
13
12
  run(): Promise<void>;
14
13
  }
15
- export declare function importWorkflowsBySelection(dir: string): Promise<void>;
@@ -1,84 +1,27 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.importWorkflowsBySelection = void 0;
4
- const tslib_1 = require("tslib");
5
- const path = tslib_1.__importStar(require("path"));
6
- const fs_1 = tslib_1.__importDefault(require("fs"));
7
- const chalk_1 = tslib_1.__importDefault(require("chalk"));
8
- const inquirer_1 = tslib_1.__importDefault(require("inquirer"));
9
3
  const core_1 = require("@oclif/core");
10
4
  const login_1 = require("../../auth/login");
11
5
  const helper_1 = require("../../helpers/workflow-templates/helper");
12
6
  const basecommand_1 = require("../../basecommand");
13
7
  class LoadWorkflowTemplates extends basecommand_1.BaseCommand {
14
- static description = 'Load workflow templates from a file or scan a directory for per-app workflow files';
8
+ static description = 'Loads your workflow from a local file';
15
9
  static examples = [
16
- '$ contrail workflow-templates load <FILE_LOCATION>',
17
- '$ contrail workflow-templates load',
18
- '$ contrail workflow-templates load --dir ./workflows',
10
+ `$ contrail workflow-templates load <FILE_LOCATION>
11
+ `,
19
12
  ];
20
13
  static flags = {
21
14
  ...basecommand_1.BaseCommand.baseFlags,
22
- dir: core_1.Flags.string({
23
- char: 'd',
24
- description: 'Directory to scan for workflow files when no file argument is given',
25
- required: false,
26
- default: '.',
27
- }),
28
15
  };
29
16
  static args = {
30
17
  fileLocation: core_1.Args.string({
31
- description: 'A specific workflow template file to load',
32
- required: false,
18
+ description: 'The workflow template file to load',
19
+ required: true,
33
20
  }),
34
21
  };
35
22
  async run() {
36
23
  await (0, login_1.authUser)();
37
- if (this.args.fileLocation) {
38
- await (0, helper_1.localDeployWorkflowTemplate)(this.args.fileLocation);
39
- }
40
- else {
41
- await importWorkflowsBySelection(this.flags.dir ?? '.');
42
- }
24
+ await (0, helper_1.localDeployWorkflowTemplate)(this.args.fileLocation);
43
25
  }
44
26
  }
45
27
  exports.default = LoadWorkflowTemplates;
46
- async function importWorkflowsBySelection(dir) {
47
- const resolvedDir = path.resolve(process.cwd(), dir);
48
- const files = fs_1.default
49
- .readdirSync(resolvedDir)
50
- .filter((f) => f.startsWith('workflows-') && f.endsWith('.yml') && f !== 'workflows-unassigned.yml')
51
- .sort();
52
- if (files.length === 0) {
53
- console.log(chalk_1.default.yellow(`No workflow files found in ${resolvedDir}`));
54
- return;
55
- }
56
- const choices = files.map((f) => ({
57
- name: f,
58
- value: f,
59
- checked: true,
60
- }));
61
- const { selectedFiles } = await inquirer_1.default.prompt([
62
- {
63
- type: 'checkbox',
64
- name: 'selectedFiles',
65
- message: 'Select workflow files to import (space to toggle, enter to confirm):',
66
- choices,
67
- },
68
- ]);
69
- if (selectedFiles.length === 0) {
70
- console.log(chalk_1.default.yellow('No files selected — nothing imported.'));
71
- return;
72
- }
73
- //log selected file
74
- console.log(chalk_1.default.blue.bold('SELECTED WORKFLOW FILES:'));
75
- selectedFiles.forEach((file) => {
76
- console.log(` - ${file}`);
77
- });
78
- for (const file of selectedFiles) {
79
- console.log(`\n${chalk_1.default.blue.bold('IMPORTING')} ${file}`);
80
- await (0, helper_1.localDeployWorkflowTemplate)(path.join(dir, file));
81
- console.log(`${chalk_1.default.green.bold('DONE')} ${file}`);
82
- }
83
- }
84
- exports.importWorkflowsBySelection = importWorkflowsBySelection;
package/dist/common.d.ts CHANGED
@@ -1,4 +1,4 @@
1
1
  /// <reference types="node" />
2
2
  export declare function getSeparatorByPlatform(): string;
3
3
  export declare function delay(ms: number): Promise<NodeJS.Timeout>;
4
- export declare function removeSlash(string: any): string;
4
+ export declare function sanitizeFileName(name: string): string;
package/dist/common.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.removeSlash = exports.delay = exports.getSeparatorByPlatform = void 0;
3
+ exports.sanitizeFileName = exports.delay = exports.getSeparatorByPlatform = void 0;
4
4
  function getSeparatorByPlatform() {
5
5
  const isWin = process.platform === 'win32';
6
6
  const separator = isWin ? '\\' : '/';
@@ -11,8 +11,15 @@ function delay(ms) {
11
11
  return new Promise((resolve) => setTimeout(resolve, ms));
12
12
  }
13
13
  exports.delay = delay;
14
- function removeSlash(string) {
15
- const re = /\//gi;
16
- return string.replace(re, '-');
14
+ // Characters that are invalid in Windows filenames (superset of POSIX, which only forbids `/`)
15
+ // eslint-disable-next-line no-control-regex
16
+ const INVALID_FILENAME_CHARS = /[<>:"/\\|?*\x00-\x1f]/g;
17
+ const WINDOWS_RESERVED_NAMES = /^(con|prn|aux|nul|com\d|lpt\d)$/i;
18
+ function sanitizeFileName(name) {
19
+ let sanitized = name.replace(INVALID_FILENAME_CHARS, '-').replace(/[. ]+$/, '');
20
+ if (WINDOWS_RESERVED_NAMES.test(sanitized)) {
21
+ sanitized = `${sanitized}-`;
22
+ }
23
+ return sanitized;
17
24
  }
18
- exports.removeSlash = removeSlash;
25
+ exports.sanitizeFileName = sanitizeFileName;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const common_1 = require("./common");
4
+ describe('sanitizeFileName', () => {
5
+ it('replaces slashes with dashes', () => {
6
+ expect((0, common_1.sanitizeFileName)('a/b/c')).toEqual('a-b-c');
7
+ });
8
+ it('replaces Windows-invalid characters with dashes', () => {
9
+ expect((0, common_1.sanitizeFileName)('isArchived?')).toEqual('isArchived-');
10
+ expect((0, common_1.sanitizeFileName)('a<b>c:d"e\\f|g?h*i')).toEqual('a-b-c-d-e-f-g-h-i');
11
+ });
12
+ it('strips trailing dots and spaces', () => {
13
+ expect((0, common_1.sanitizeFileName)('label. ')).toEqual('label');
14
+ });
15
+ it('escapes Windows reserved device names', () => {
16
+ expect((0, common_1.sanitizeFileName)('CON')).toEqual('CON-');
17
+ expect((0, common_1.sanitizeFileName)('com1')).toEqual('com1-');
18
+ });
19
+ it('leaves safe labels unchanged', () => {
20
+ expect((0, common_1.sanitizeFileName)('My Label - v2')).toEqual('My Label - v2');
21
+ });
22
+ });
@@ -18,4 +18,3 @@ export declare class WorkflowTemplateDeployer {
18
18
  export declare function deleteWorkflowTemplates(): Promise<void>;
19
19
  export declare function localDeployWorkflowTemplate(saveFileLocation: string): Promise<void>;
20
20
  export declare function populateActionIdentifiers(workflowTemplate: WorkflowTemplate): Promise<void>;
21
- export declare function extractShortActionKeys(workflowTemplate: WorkflowTemplate): void;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.extractShortActionKeys = exports.populateActionIdentifiers = exports.localDeployWorkflowTemplate = exports.deleteWorkflowTemplates = exports.WorkflowTemplateDeployer = exports.getActionByIdentifier = exports.getWorkflowTemplateIdentifier = exports.LocalWorkflowTemplateDeployer = void 0;
3
+ exports.populateActionIdentifiers = exports.localDeployWorkflowTemplate = exports.deleteWorkflowTemplates = exports.WorkflowTemplateDeployer = exports.getActionByIdentifier = exports.getWorkflowTemplateIdentifier = exports.LocalWorkflowTemplateDeployer = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const util_1 = require("@contrail/util");
6
6
  const chalk_1 = tslib_1.__importDefault(require("chalk"));
@@ -44,8 +44,6 @@ class LocalWorkflowTemplateDeployer {
44
44
  isActive: workflowTemplate.isActive,
45
45
  supportingAppId: workflowTemplate.supportingAppId,
46
46
  messageGroupId: workflowTemplate.messageGroupId,
47
- messageGroup: workflowTemplate.messageGroup,
48
- dynamicMessageGroupId: workflowTemplate.dynamicMessageGroupId,
49
47
  parallelWorkerCount: workflowTemplate.parallelWorkerCount,
50
48
  };
51
49
  const newWorkflowTemplate = await (0, event_workflow_templates_1.createWorkflowTemplate)(newObject);
@@ -57,11 +55,8 @@ class LocalWorkflowTemplateDeployer {
57
55
  }
58
56
  async populateActionIds(workflowTemplate, workflowKey, appIdentifier) {
59
57
  const installedApps = await (0, apps_1.getInstalledApps)();
60
- const appOrg = installedApps.find((x) => x.app?.identifier === appIdentifier);
58
+ const appOrg = installedApps.find((x) => x.app.identifier === appIdentifier);
61
59
  logger_1.default.info('workflow template:', JSON.stringify(workflowTemplate, null, 2));
62
- if (!appOrg) {
63
- throw new Error(`Could not find installed app with identifier "${appIdentifier}". Make sure the app is installed in this org before importing workflows.`);
64
- }
65
60
  if (!workflowTemplate?.workflowDefinition?.paths) {
66
61
  return;
67
62
  }
@@ -91,7 +86,7 @@ class LocalWorkflowTemplateDeployer {
91
86
  }
92
87
  }
93
88
  async createWorkflowSchedule(workflowTemplate, workflowId) {
94
- if (!workflowTemplate?.crons?.length) {
89
+ if (!workflowTemplate?.crons?.length || !workflowTemplate.id) {
95
90
  return;
96
91
  }
97
92
  const crons = [];
@@ -163,8 +158,6 @@ class LocalWorkflowTemplateDeployer {
163
158
  triggerKey: workflowTemplate.triggerKey,
164
159
  builtIn: workflowTemplate.builtIn,
165
160
  workflowDefinition: workflowTemplate.workflowDefinition,
166
- messageGroupId: workflowTemplate.messageGroupId ?? existingWorkflowTemplate.messageGroupId,
167
- messageGroup: workflowTemplate.messageGroup ?? existingWorkflowTemplate.messageGroup,
168
161
  dynamicMessageGroupId: workflowTemplate.dynamicMessageGroupId ?? existingWorkflowTemplate.dynamicMessageGroupId,
169
162
  parallelWorkerCount: workflowTemplate.parallelWorkerCount ?? existingWorkflowTemplate.parallelWorkerCount,
170
163
  });
@@ -290,21 +283,3 @@ async function populateActionIdentifiers(workflowTemplate) {
290
283
  }
291
284
  }
292
285
  exports.populateActionIdentifiers = populateActionIdentifiers;
293
- function extractShortActionKeys(workflowTemplate) {
294
- if (!workflowTemplate?.workflowDefinition?.paths) {
295
- return;
296
- }
297
- for (const wfPath of workflowTemplate.workflowDefinition.paths) {
298
- if (!wfPath?.actionDefinitionConfigs) {
299
- continue;
300
- }
301
- for (const actionConfig of wfPath.actionDefinitionConfigs) {
302
- if (actionConfig.action?.includes(':')) {
303
- // Full identifier format: "app-id@version:action-name" -> "action-name"
304
- actionConfig.action = actionConfig.action.split(':').pop();
305
- }
306
- delete actionConfig.identifier;
307
- }
308
- }
309
- }
310
- exports.extractShortActionKeys = extractShortActionKeys;
@@ -98,7 +98,7 @@ export interface WorkflowDefinition {
98
98
  dynamicMessageGroupId?: string;
99
99
  }
100
100
  export interface WorkflowTemplateDeclaration {
101
- appIdentifier?: string;
101
+ appIdentifier: string;
102
102
  workflows?: WorkflowTemplate[];
103
103
  }
104
104
  export interface WorkflowTemplate {
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "3.5.4-alpha.2a94b1c",
2
+ "version": "3.5.4-alpha.640db77",
3
3
  "commands": {
4
4
  "app:create": {
5
5
  "id": "app:create",
@@ -2956,16 +2956,14 @@
2956
2956
  },
2957
2957
  "workflow-templates:export": {
2958
2958
  "id": "workflow-templates:export",
2959
- "description": "Export all workflows in the org. By default exports one file per app to the current directory.",
2959
+ "description": "Export all workflows in the org.",
2960
2960
  "strict": true,
2961
2961
  "pluginName": "@contrail/cli",
2962
2962
  "pluginAlias": "@contrail/cli",
2963
2963
  "pluginType": "core",
2964
2964
  "aliases": [],
2965
2965
  "examples": [
2966
- "$ contrail workflow-templates export",
2967
- "$ contrail workflow-templates export --dir ./workflows",
2968
- "$ contrail workflow-templates export --outFile workflows.yml"
2966
+ "$ contrail workflow-templates export\n"
2969
2967
  ],
2970
2968
  "flags": {
2971
2969
  "logLevel": {
@@ -2999,18 +2997,10 @@
2999
2997
  "name": "outFile",
3000
2998
  "type": "option",
3001
2999
  "char": "f",
3002
- "description": "Export all workflows to a single file at this path (overrides per-app export)",
3003
- "required": false,
3004
- "multiple": false
3005
- },
3006
- "dir": {
3007
- "name": "dir",
3008
- "type": "option",
3009
- "char": "d",
3010
- "description": "Directory to write per-app workflow files",
3000
+ "description": "The location for the file to be saved",
3011
3001
  "required": false,
3012
3002
  "multiple": false,
3013
- "default": "."
3003
+ "default": "workflows.yml"
3014
3004
  },
3015
3005
  "overwrite": {
3016
3006
  "name": "overwrite",
@@ -3066,16 +3056,14 @@
3066
3056
  },
3067
3057
  "workflow-templates:load": {
3068
3058
  "id": "workflow-templates:load",
3069
- "description": "Load workflow templates from a file or scan a directory for per-app workflow files",
3059
+ "description": "Loads your workflow from a local file",
3070
3060
  "strict": true,
3071
3061
  "pluginName": "@contrail/cli",
3072
3062
  "pluginAlias": "@contrail/cli",
3073
3063
  "pluginType": "core",
3074
3064
  "aliases": [],
3075
3065
  "examples": [
3076
- "$ contrail workflow-templates load <FILE_LOCATION>",
3077
- "$ contrail workflow-templates load",
3078
- "$ contrail workflow-templates load --dir ./workflows"
3066
+ "$ contrail workflow-templates load <FILE_LOCATION>\n"
3079
3067
  ],
3080
3068
  "flags": {
3081
3069
  "logLevel": {
@@ -3104,22 +3092,13 @@
3104
3092
  "false"
3105
3093
  ],
3106
3094
  "default": "true"
3107
- },
3108
- "dir": {
3109
- "name": "dir",
3110
- "type": "option",
3111
- "char": "d",
3112
- "description": "Directory to scan for workflow files when no file argument is given",
3113
- "required": false,
3114
- "multiple": false,
3115
- "default": "."
3116
3095
  }
3117
3096
  },
3118
3097
  "args": {
3119
3098
  "fileLocation": {
3120
3099
  "name": "fileLocation",
3121
- "description": "A specific workflow template file to load",
3122
- "required": false
3100
+ "description": "The workflow template file to load",
3101
+ "required": true
3123
3102
  }
3124
3103
  }
3125
3104
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contrail/cli",
3
- "version": "3.5.4-alpha.2a94b1c",
3
+ "version": "3.5.4-alpha.640db77",
4
4
  "description": "VibeIQ's Contrail Platform CLI.",
5
5
  "bin": {
6
6
  "contrail-cli": "./bin/run",