@contrail/cli 3.5.3-alpha.cc8f6c0 → 3.5.3-alpha.d39a3e1

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-alpha.cc8f6c0 linux-x64 node-v24.15.0
20
+ @contrail/cli/3.5.3-alpha.d39a3e1 linux-x64 node-v24.16.0
21
21
  $ contrail --help [COMMAND]
22
22
  USAGE
23
23
  $ contrail COMMAND
@@ -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`
@@ -5,10 +5,12 @@ export default class ExportWorkflows extends BaseCommand {
5
5
  static examples: string[];
6
6
  static flags: {
7
7
  outFile: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
8
+ dir: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
8
9
  overwrite: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
9
10
  alwaysConfirmEnv: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
10
11
  logLevel: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
11
12
  };
12
13
  run(): Promise<void>;
13
14
  }
14
- export declare function exportWorkflows(fileLocation: string, overwrite: boolean): Promise<void>;
15
+ export declare function exportWorkflowsByApp(outputDir: string, overwrite: boolean): Promise<void>;
16
+ 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 = 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,22 +11,30 @@ 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
18
  exports.DEFAULT_FILE_LOCATION = 'workflows.yml';
17
19
  class ExportWorkflows extends basecommand_1.BaseCommand {
18
- static description = 'Export all workflows in the org.';
20
+ static description = 'Export all workflows in the org. By default exports one file per app to the current directory.';
19
21
  static examples = [
20
- `$ contrail workflow-templates export
21
- `,
22
+ '$ contrail workflow-templates export',
23
+ '$ contrail workflow-templates export --dir ./workflows',
24
+ '$ contrail workflow-templates export --outFile workflows.yml',
22
25
  ];
23
26
  static flags = {
24
27
  ...basecommand_1.BaseCommand.baseFlags,
25
28
  outFile: core_1.Flags.string({
26
29
  char: 'f',
27
- description: 'The location for the file to be saved',
30
+ description: 'Export all workflows to a single file at this path (overrides per-app export)',
28
31
  required: false,
29
- default: exports.DEFAULT_FILE_LOCATION,
32
+ }),
33
+ dir: core_1.Flags.string({
34
+ char: 'd',
35
+ description: 'Directory to write per-app workflow files',
36
+ required: false,
37
+ default: '.',
30
38
  }),
31
39
  overwrite: core_1.Flags.boolean({
32
40
  description: 'Replaces existing files if they exist',
@@ -38,7 +46,12 @@ class ExportWorkflows extends basecommand_1.BaseCommand {
38
46
  try {
39
47
  await (0, login_1.authUser)();
40
48
  this.log(`${chalk_1.default.blue.bold('START')} Getting Workflows.`);
41
- await exportWorkflows(this.flags.outFile ?? exports.DEFAULT_FILE_LOCATION, this.flags.overwrite);
49
+ if (this.flags.outFile) {
50
+ await exportWorkflowsToFile(this.flags.outFile, this.flags.overwrite);
51
+ }
52
+ else {
53
+ await exportWorkflowsByApp(this.flags.dir ?? '.', this.flags.overwrite);
54
+ }
42
55
  this.log(`${chalk_1.default.yellow.bold('WORKFLOWS')} Done`);
43
56
  }
44
57
  catch (e) {
@@ -49,31 +62,95 @@ class ExportWorkflows extends basecommand_1.BaseCommand {
49
62
  }
50
63
  }
51
64
  exports.default = ExportWorkflows;
52
- async function exportWorkflows(fileLocation, overwrite) {
65
+ async function exportWorkflowsByApp(outputDir, overwrite) {
53
66
  const allWorkflowsInOrg = await (0, event_workflow_templates_1.getExistingWorkflowTemplates)();
67
+ const allSchedules = await (0, schedules_1.getExistingSchedules)();
68
+ const installedApps = await (0, apps_1.getInstalledApps)();
69
+ const appIdToIdentifier = new Map(installedApps.map((a) => [a.appId, a.app.identifier]));
70
+ const workflowsByApp = new Map();
71
+ const unassigned = [];
72
+ for (const workflow of allWorkflowsInOrg) {
73
+ let appIdentifier = workflow.supportingAppId
74
+ ? appIdToIdentifier.get(workflow.supportingAppId)
75
+ : undefined;
76
+ // If no supportingAppId, try to extract app identifier from workflow identifier
77
+ // Format: @{appIdentifier}@{randomId}:{workflowName}
78
+ if (!appIdentifier && workflow.identifier) {
79
+ const match = workflow.identifier.match(/^@([^@]+)@/);
80
+ if (match) {
81
+ // Keep the @ prefix in the appIdentifier
82
+ appIdentifier = `@${match[1]}`;
83
+ }
84
+ }
85
+ if (appIdentifier) {
86
+ if (!workflowsByApp.has(appIdentifier)) {
87
+ workflowsByApp.set(appIdentifier, []);
88
+ }
89
+ const workflows = workflowsByApp.get(appIdentifier);
90
+ if (workflows) {
91
+ workflows.push(workflow);
92
+ }
93
+ }
94
+ else {
95
+ unassigned.push(workflow);
96
+ }
97
+ }
98
+ const resolvedDir = path.resolve(process.cwd(), outputDir);
99
+ for (const [appIdentifier, workflows] of workflowsByApp.entries()) {
100
+ const exportObj = { appIdentifier, workflows: [] };
101
+ for (const workflow of workflows) {
102
+ exportObj.workflows.push(await buildExportWorkflow(workflow, allSchedules));
103
+ }
104
+ const safeAppIdentifier = appIdentifier.replace(/[\\/]/g, '-');
105
+ const filePath = path.join(resolvedDir, `workflows-${safeAppIdentifier}.yml`);
106
+ await writeYamlFile(exportObj, filePath, overwrite);
107
+ console.log(`${chalk_1.default.green('EXPORTED')} ${filePath}`);
108
+ }
109
+ if (unassigned.length > 0) {
110
+ const unassignedObj = { workflows: [] };
111
+ for (const workflow of unassigned) {
112
+ unassignedObj.workflows.push(await buildExportWorkflow(workflow, allSchedules));
113
+ }
114
+ const unassignedFilePath = path.join(resolvedDir, 'workflows-unassigned.yml');
115
+ await writeYamlFile(unassignedObj, unassignedFilePath, overwrite);
116
+ console.log(`${chalk_1.default.yellow('EXPORTED')} ${unassignedFilePath} (unassigned workflows)`);
117
+ }
118
+ }
119
+ exports.exportWorkflowsByApp = exportWorkflowsByApp;
120
+ async function exportWorkflowsToFile(fileLocation, overwrite) {
121
+ const allWorkflowsInOrg = await (0, event_workflow_templates_1.getExistingWorkflowTemplates)();
122
+ const allSchedules = await (0, schedules_1.getExistingSchedules)();
54
123
  const workflowsObj = { workflows: [] };
55
124
  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);
125
+ workflowsObj.workflows.push(await buildExportWorkflow(workflow, allSchedules));
126
+ }
127
+ const pathToWrite = path.resolve(process.cwd(), fileLocation);
128
+ await writeYamlFile(workflowsObj, pathToWrite, overwrite);
129
+ }
130
+ exports.exportWorkflowsToFile = exportWorkflowsToFile;
131
+ async function buildExportWorkflow(workflow, allSchedules) {
132
+ const exportWorkflow = lodash_1.default.pick(workflow, [
133
+ 'identifier',
134
+ 'name',
135
+ 'triggerKey',
136
+ 'isActive',
137
+ 'messageGroup',
138
+ 'dynamicMessageGroupId',
139
+ 'parallelWorkerCount',
140
+ 'workflowDefinition',
141
+ ]);
142
+ const schedules = allSchedules.filter((s) => s.ownerReference === `event-workflow-template:${workflow.id}`);
143
+ if (schedules.length > 0) {
144
+ exportWorkflow.crons = schedules.map((s) => ({ name: s.name, cron: s.cron }));
67
145
  }
68
- await saveData(workflowsObj, fileLocation, overwrite);
146
+ await (0, helper_1.populateActionIdentifiers)(exportWorkflow);
147
+ (0, helper_1.extractShortActionKeys)(exportWorkflow);
148
+ return exportWorkflow;
69
149
  }
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);
150
+ async function writeYamlFile(data, absolutePath, overwrite) {
151
+ if (fs_1.default.existsSync(absolutePath)) {
152
+ await (0, file_helpers_1.safeFileOverwrite)(absolutePath, overwrite);
77
153
  }
78
- fs_1.default.writeFileSync(pathToWrite, yamlStr, 'utf8');
154
+ fs_1.default.mkdirSync(path.dirname(absolutePath), { recursive: true });
155
+ fs_1.default.writeFileSync(absolutePath, js_yaml_1.default.dump(data), 'utf8');
79
156
  }
@@ -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"));
@@ -20,7 +20,6 @@ class LocalWorkflowTemplateDeployer {
20
20
  const existingWorkflows = await (0, event_workflow_templates_1.getExistingWorkflowTemplates)();
21
21
  // UPSERT / DELETE BASED ON WORKFLOW TEMPLATES IDENTIFIER
22
22
  logger_1.default.info(`${chalk_1.default.yellow.bold('WORKFLOW TEMPLATES')} Deploying workflow templates.`);
23
- logger_1.default.info(wtDeclaration);
24
23
  for (const workflowKey of Object.keys(wtDeclaration.workflows)) {
25
24
  await this.deployWorkflowTemplate(wtDeclaration.workflows[workflowKey], existingWorkflows, wtDeclaration.appIdentifier);
26
25
  }
@@ -44,6 +43,8 @@ class LocalWorkflowTemplateDeployer {
44
43
  isActive: workflowTemplate.isActive,
45
44
  supportingAppId: workflowTemplate.supportingAppId,
46
45
  messageGroupId: workflowTemplate.messageGroupId,
46
+ messageGroup: workflowTemplate.messageGroup,
47
+ dynamicMessageGroupId: workflowTemplate.dynamicMessageGroupId,
47
48
  parallelWorkerCount: workflowTemplate.parallelWorkerCount,
48
49
  };
49
50
  const newWorkflowTemplate = await (0, event_workflow_templates_1.createWorkflowTemplate)(newObject);
@@ -55,8 +56,10 @@ class LocalWorkflowTemplateDeployer {
55
56
  }
56
57
  async populateActionIds(workflowTemplate, workflowKey, appIdentifier) {
57
58
  const installedApps = await (0, apps_1.getInstalledApps)();
58
- const appOrg = installedApps.find((x) => x.app.identifier === appIdentifier);
59
- logger_1.default.info('workflow template:', JSON.stringify(workflowTemplate, null, 2));
59
+ const appOrg = installedApps.find((x) => x.app?.identifier === appIdentifier);
60
+ if (!appOrg) {
61
+ throw new Error(`Could not find installed app with identifier "${appIdentifier}". Make sure the app is installed in this org before importing workflows.`);
62
+ }
60
63
  if (!workflowTemplate?.workflowDefinition?.paths) {
61
64
  return;
62
65
  }
@@ -86,7 +89,7 @@ class LocalWorkflowTemplateDeployer {
86
89
  }
87
90
  }
88
91
  async createWorkflowSchedule(workflowTemplate, workflowId) {
89
- if (!workflowTemplate?.crons?.length || !workflowTemplate.id) {
92
+ if (!workflowTemplate?.crons?.length) {
90
93
  return;
91
94
  }
92
95
  const crons = [];
@@ -283,3 +286,21 @@ async function populateActionIdentifiers(workflowTemplate) {
283
286
  }
284
287
  }
285
288
  exports.populateActionIdentifiers = populateActionIdentifiers;
289
+ function extractShortActionKeys(workflowTemplate) {
290
+ if (!workflowTemplate?.workflowDefinition?.paths) {
291
+ return;
292
+ }
293
+ for (const wfPath of workflowTemplate.workflowDefinition.paths) {
294
+ if (!wfPath?.actionDefinitionConfigs) {
295
+ continue;
296
+ }
297
+ for (const actionConfig of wfPath.actionDefinitionConfigs) {
298
+ if (actionConfig.action?.includes(':')) {
299
+ // Full identifier format: "app-id@version:action-name" -> "action-name"
300
+ actionConfig.action = actionConfig.action.split(':').pop();
301
+ }
302
+ delete actionConfig.identifier;
303
+ }
304
+ }
305
+ }
306
+ exports.extractShortActionKeys = extractShortActionKeys;
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "3.5.3-alpha.cc8f6c0",
2
+ "version": "3.5.3-alpha.d39a3e1",
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",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contrail/cli",
3
- "version": "3.5.3-alpha.cc8f6c0",
3
+ "version": "3.5.3-alpha.d39a3e1",
4
4
  "description": "VibeIQ's Contrail Platform CLI.",
5
5
  "bin": {
6
6
  "contrail-cli": "./bin/run",