@contrail/cli 3.5.3 → 3.5.4-alpha.2a94b1c

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.3 linux-x64 node-v24.15.0
20
+ @contrail/cli/3.5.4-alpha.2a94b1c 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,25 +1611,31 @@ EXAMPLES
1611
1611
 
1612
1612
  ## `contrail workflow-templates export`
1613
1613
 
1614
- Export all workflows in the org.
1614
+ Export all workflows in the org. By default exports one file per app to the current directory.
1615
1615
 
1616
1616
  ```
1617
1617
  USAGE
1618
- $ contrail workflow-templates export [-l error|warn|info|debug] [-e true|false] [-f <value>] [--overwrite]
1618
+ $ contrail workflow-templates export [-l error|warn|info|debug] [-e true|false] [-f <value>] [-d <value>]
1619
+ [--overwrite]
1619
1620
 
1620
1621
  FLAGS
1622
+ -d, --dir=<value> [default: .] Directory to write per-app workflow files
1621
1623
  -e, --alwaysConfirmEnv=<option> [default: true] The Environment variables
1622
1624
  <options: true|false>
1623
- -f, --outFile=<value> [default: workflows.yml] The location for the file to be saved
1625
+ -f, --outFile=<value> Export all workflows to a single file at this path (overrides per-app export)
1624
1626
  -l, --logLevel=<option> The Log Level
1625
1627
  <options: error|warn|info|debug>
1626
1628
  --overwrite Replaces existing files if they exist
1627
1629
 
1628
1630
  DESCRIPTION
1629
- Export all workflows in the org.
1631
+ Export all workflows in the org. By default exports one file per app to the current directory.
1630
1632
 
1631
1633
  EXAMPLES
1632
1634
  $ contrail workflow-templates export
1635
+
1636
+ $ contrail workflow-templates export --dir ./workflows
1637
+
1638
+ $ contrail workflow-templates export --outFile workflows.yml
1633
1639
  ```
1634
1640
 
1635
1641
  ## `contrail workflow-templates list`
@@ -1653,27 +1659,32 @@ EXAMPLES
1653
1659
  $ contrail workflow-templates list
1654
1660
  ```
1655
1661
 
1656
- ## `contrail workflow-templates load FILELOCATION`
1662
+ ## `contrail workflow-templates load [FILELOCATION]`
1657
1663
 
1658
- Loads your workflow from a local file
1664
+ Load workflow templates from a file or scan a directory for per-app workflow files
1659
1665
 
1660
1666
  ```
1661
1667
  USAGE
1662
- $ contrail workflow-templates load FILELOCATION [-l error|warn|info|debug] [-e true|false]
1668
+ $ contrail workflow-templates load [FILELOCATION] [-l error|warn|info|debug] [-e true|false] [-d <value>]
1663
1669
 
1664
1670
  ARGUMENTS
1665
- FILELOCATION The workflow template file to load
1671
+ FILELOCATION A specific workflow template file to load
1666
1672
 
1667
1673
  FLAGS
1674
+ -d, --dir=<value> [default: .] Directory to scan for workflow files when no file argument is given
1668
1675
  -e, --alwaysConfirmEnv=<option> [default: true] The Environment variables
1669
1676
  <options: true|false>
1670
1677
  -l, --logLevel=<option> The Log Level
1671
1678
  <options: error|warn|info|debug>
1672
1679
 
1673
1680
  DESCRIPTION
1674
- Loads your workflow from a local file
1681
+ Load workflow templates from a file or scan a directory for per-app workflow files
1675
1682
 
1676
1683
  EXAMPLES
1677
1684
  $ contrail workflow-templates load <FILE_LOCATION>
1685
+
1686
+ $ contrail workflow-templates load
1687
+
1688
+ $ contrail workflow-templates load --dir ./workflows
1678
1689
  ```
1679
1690
  <!-- commandsstop -->
@@ -1,14 +1,15 @@
1
1
  import { BaseCommand } from '../../basecommand';
2
- export declare const DEFAULT_FILE_LOCATION = "workflows.yml";
3
2
  export default class ExportWorkflows extends BaseCommand {
4
3
  static description: string;
5
4
  static examples: string[];
6
5
  static flags: {
7
6
  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 exportWorkflows(fileLocation: string, overwrite: boolean): Promise<void>;
14
+ export declare function exportWorkflowsByApp(outputDir: string, overwrite: boolean): Promise<void>;
15
+ export declare function exportWorkflowsToFile(fileLocation: string, overwrite: boolean): Promise<void>;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.exportWorkflows = exports.DEFAULT_FILE_LOCATION = void 0;
3
+ exports.exportWorkflowsToFile = exports.exportWorkflowsByApp = 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,22 +11,29 @@ 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");
14
16
  const helper_1 = require("../../helpers/workflow-templates/helper");
15
17
  const basecommand_1 = require("../../basecommand");
16
- exports.DEFAULT_FILE_LOCATION = 'workflows.yml';
17
18
  class ExportWorkflows extends basecommand_1.BaseCommand {
18
- static description = 'Export all workflows in the org.';
19
+ static description = 'Export all workflows in the org. By default exports one file per app to the current directory.';
19
20
  static examples = [
20
- `$ contrail workflow-templates export
21
- `,
21
+ '$ contrail workflow-templates export',
22
+ '$ contrail workflow-templates export --dir ./workflows',
23
+ '$ contrail workflow-templates export --outFile workflows.yml',
22
24
  ];
23
25
  static flags = {
24
26
  ...basecommand_1.BaseCommand.baseFlags,
25
27
  outFile: core_1.Flags.string({
26
28
  char: 'f',
27
- description: 'The location for the file to be saved',
29
+ description: 'Export all workflows to a single file at this path (overrides per-app export)',
28
30
  required: false,
29
- default: exports.DEFAULT_FILE_LOCATION,
31
+ }),
32
+ dir: core_1.Flags.string({
33
+ char: 'd',
34
+ description: 'Directory to write per-app workflow files',
35
+ required: false,
36
+ default: '.',
30
37
  }),
31
38
  overwrite: core_1.Flags.boolean({
32
39
  description: 'Replaces existing files if they exist',
@@ -38,7 +45,12 @@ class ExportWorkflows extends basecommand_1.BaseCommand {
38
45
  try {
39
46
  await (0, login_1.authUser)();
40
47
  this.log(`${chalk_1.default.blue.bold('START')} Getting Workflows.`);
41
- await exportWorkflows(this.flags.outFile ?? exports.DEFAULT_FILE_LOCATION, this.flags.overwrite);
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
+ }
42
54
  this.log(`${chalk_1.default.yellow.bold('WORKFLOWS')} Done`);
43
55
  }
44
56
  catch (e) {
@@ -49,31 +61,106 @@ class ExportWorkflows extends basecommand_1.BaseCommand {
49
61
  }
50
62
  }
51
63
  exports.default = ExportWorkflows;
52
- async function exportWorkflows(fileLocation, overwrite) {
53
- const allWorkflowsInOrg = await (0, event_workflow_templates_1.getExistingWorkflowTemplates)();
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
+ ]);
54
128
  const workflowsObj = { workflows: [] };
55
129
  for (const workflow of allWorkflowsInOrg) {
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);
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);
67
157
  }
68
- await saveData(workflowsObj, fileLocation, overwrite);
158
+ return exportWorkflow;
69
159
  }
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);
160
+ async function writeYamlFile(data, absolutePath, overwrite) {
161
+ if (fs_1.default.existsSync(absolutePath)) {
162
+ await (0, file_helpers_1.safeFileOverwrite)(absolutePath, overwrite);
77
163
  }
78
- fs_1.default.writeFileSync(pathToWrite, yamlStr, 'utf8');
164
+ fs_1.default.mkdirSync(path.dirname(absolutePath), { recursive: true });
165
+ fs_1.default.writeFileSync(absolutePath, js_yaml_1.default.dump(data), 'utf8');
79
166
  }
@@ -3,6 +3,7 @@ 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>;
6
7
  alwaysConfirmEnv: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
7
8
  logLevel: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
8
9
  };
@@ -11,3 +12,4 @@ export default class LoadWorkflowTemplates extends BaseCommand {
11
12
  };
12
13
  run(): Promise<void>;
13
14
  }
15
+ export declare function importWorkflowsBySelection(dir: string): Promise<void>;
@@ -1,27 +1,84 @@
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"));
3
9
  const core_1 = require("@oclif/core");
4
10
  const login_1 = require("../../auth/login");
5
11
  const helper_1 = require("../../helpers/workflow-templates/helper");
6
12
  const basecommand_1 = require("../../basecommand");
7
13
  class LoadWorkflowTemplates extends basecommand_1.BaseCommand {
8
- static description = 'Loads your workflow from a local file';
14
+ static description = 'Load workflow templates from a file or scan a directory for per-app workflow files';
9
15
  static examples = [
10
- `$ contrail workflow-templates load <FILE_LOCATION>
11
- `,
16
+ '$ contrail workflow-templates load <FILE_LOCATION>',
17
+ '$ contrail workflow-templates load',
18
+ '$ contrail workflow-templates load --dir ./workflows',
12
19
  ];
13
20
  static flags = {
14
21
  ...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
+ }),
15
28
  };
16
29
  static args = {
17
30
  fileLocation: core_1.Args.string({
18
- description: 'The workflow template file to load',
19
- required: true,
31
+ description: 'A specific workflow template file to load',
32
+ required: false,
20
33
  }),
21
34
  };
22
35
  async run() {
23
36
  await (0, login_1.authUser)();
24
- await (0, helper_1.localDeployWorkflowTemplate)(this.args.fileLocation);
37
+ if (this.args.fileLocation) {
38
+ await (0, helper_1.localDeployWorkflowTemplate)(this.args.fileLocation);
39
+ }
40
+ else {
41
+ await importWorkflowsBySelection(this.flags.dir ?? '.');
42
+ }
25
43
  }
26
44
  }
27
45
  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;
@@ -18,3 +18,4 @@ 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.populateActionIdentifiers = exports.localDeployWorkflowTemplate = exports.deleteWorkflowTemplates = exports.WorkflowTemplateDeployer = exports.getActionByIdentifier = exports.getWorkflowTemplateIdentifier = exports.LocalWorkflowTemplateDeployer = void 0;
3
+ exports.extractShortActionKeys = 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,6 +44,8 @@ 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,
47
49
  parallelWorkerCount: workflowTemplate.parallelWorkerCount,
48
50
  };
49
51
  const newWorkflowTemplate = await (0, event_workflow_templates_1.createWorkflowTemplate)(newObject);
@@ -55,8 +57,11 @@ class LocalWorkflowTemplateDeployer {
55
57
  }
56
58
  async populateActionIds(workflowTemplate, workflowKey, appIdentifier) {
57
59
  const installedApps = await (0, apps_1.getInstalledApps)();
58
- const appOrg = installedApps.find((x) => x.app.identifier === appIdentifier);
60
+ const appOrg = installedApps.find((x) => x.app?.identifier === appIdentifier);
59
61
  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
+ }
60
65
  if (!workflowTemplate?.workflowDefinition?.paths) {
61
66
  return;
62
67
  }
@@ -86,7 +91,7 @@ class LocalWorkflowTemplateDeployer {
86
91
  }
87
92
  }
88
93
  async createWorkflowSchedule(workflowTemplate, workflowId) {
89
- if (!workflowTemplate?.crons?.length || !workflowTemplate.id) {
94
+ if (!workflowTemplate?.crons?.length) {
90
95
  return;
91
96
  }
92
97
  const crons = [];
@@ -158,6 +163,8 @@ class LocalWorkflowTemplateDeployer {
158
163
  triggerKey: workflowTemplate.triggerKey,
159
164
  builtIn: workflowTemplate.builtIn,
160
165
  workflowDefinition: workflowTemplate.workflowDefinition,
166
+ messageGroupId: workflowTemplate.messageGroupId ?? existingWorkflowTemplate.messageGroupId,
167
+ messageGroup: workflowTemplate.messageGroup ?? existingWorkflowTemplate.messageGroup,
161
168
  dynamicMessageGroupId: workflowTemplate.dynamicMessageGroupId ?? existingWorkflowTemplate.dynamicMessageGroupId,
162
169
  parallelWorkerCount: workflowTemplate.parallelWorkerCount ?? existingWorkflowTemplate.parallelWorkerCount,
163
170
  });
@@ -283,3 +290,21 @@ async function populateActionIdentifiers(workflowTemplate) {
283
290
  }
284
291
  }
285
292
  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.3",
2
+ "version": "3.5.4-alpha.2a94b1c",
3
3
  "commands": {
4
4
  "app:create": {
5
5
  "id": "app:create",
@@ -2956,14 +2956,16 @@
2956
2956
  },
2957
2957
  "workflow-templates:export": {
2958
2958
  "id": "workflow-templates:export",
2959
- "description": "Export all workflows in the org.",
2959
+ "description": "Export all workflows in the org. By default exports one file per app to the current directory.",
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\n"
2966
+ "$ contrail workflow-templates export",
2967
+ "$ contrail workflow-templates export --dir ./workflows",
2968
+ "$ contrail workflow-templates export --outFile workflows.yml"
2967
2969
  ],
2968
2970
  "flags": {
2969
2971
  "logLevel": {
@@ -2997,10 +2999,18 @@
2997
2999
  "name": "outFile",
2998
3000
  "type": "option",
2999
3001
  "char": "f",
3000
- "description": "The location for the file to be saved",
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",
3001
3011
  "required": false,
3002
3012
  "multiple": false,
3003
- "default": "workflows.yml"
3013
+ "default": "."
3004
3014
  },
3005
3015
  "overwrite": {
3006
3016
  "name": "overwrite",
@@ -3056,14 +3066,16 @@
3056
3066
  },
3057
3067
  "workflow-templates:load": {
3058
3068
  "id": "workflow-templates:load",
3059
- "description": "Loads your workflow from a local file",
3069
+ "description": "Load workflow templates from a file or scan a directory for per-app workflow files",
3060
3070
  "strict": true,
3061
3071
  "pluginName": "@contrail/cli",
3062
3072
  "pluginAlias": "@contrail/cli",
3063
3073
  "pluginType": "core",
3064
3074
  "aliases": [],
3065
3075
  "examples": [
3066
- "$ contrail workflow-templates load <FILE_LOCATION>\n"
3076
+ "$ contrail workflow-templates load <FILE_LOCATION>",
3077
+ "$ contrail workflow-templates load",
3078
+ "$ contrail workflow-templates load --dir ./workflows"
3067
3079
  ],
3068
3080
  "flags": {
3069
3081
  "logLevel": {
@@ -3092,13 +3104,22 @@
3092
3104
  "false"
3093
3105
  ],
3094
3106
  "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": "."
3095
3116
  }
3096
3117
  },
3097
3118
  "args": {
3098
3119
  "fileLocation": {
3099
3120
  "name": "fileLocation",
3100
- "description": "The workflow template file to load",
3101
- "required": true
3121
+ "description": "A specific workflow template file to load",
3122
+ "required": false
3102
3123
  }
3103
3124
  }
3104
3125
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contrail/cli",
3
- "version": "3.5.3",
3
+ "version": "3.5.4-alpha.2a94b1c",
4
4
  "description": "VibeIQ's Contrail Platform CLI.",
5
5
  "bin": {
6
6
  "contrail-cli": "./bin/run",