@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 +11 -22
- package/dist/commands/types/getAll.js +2 -2
- package/dist/commands/types/getOptionSets.js +2 -2
- package/dist/commands/types/parseOptionSetsLocalFiles.js +1 -1
- package/dist/commands/types/parseOptionSetsToFolderStructure.js +1 -1
- package/dist/commands/workflow-templates/export.d.ts +2 -3
- package/dist/commands/workflow-templates/export.js +30 -117
- package/dist/commands/workflow-templates/load.d.ts +0 -2
- package/dist/commands/workflow-templates/load.js +6 -63
- package/dist/common.d.ts +1 -1
- package/dist/common.js +12 -5
- package/dist/common.spec.d.ts +1 -0
- package/dist/common.spec.js +22 -0
- package/dist/helpers/workflow-templates/helper.d.ts +0 -1
- package/dist/helpers/workflow-templates/helper.js +3 -28
- package/dist/interfaces.d.ts +1 -1
- package/oclif.manifest.json +9 -30
- package/package.json +1 -1
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.
|
|
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
|
|
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.
|
|
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>] [
|
|
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>
|
|
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.
|
|
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
|
|
1656
|
+
## `contrail workflow-templates load FILELOCATION`
|
|
1663
1657
|
|
|
1664
|
-
|
|
1658
|
+
Loads your workflow from a local file
|
|
1665
1659
|
|
|
1666
1660
|
```
|
|
1667
1661
|
USAGE
|
|
1668
|
-
$ contrail workflow-templates load
|
|
1662
|
+
$ contrail workflow-templates load FILELOCATION [-l error|warn|info|debug] [-e true|false]
|
|
1669
1663
|
|
|
1670
1664
|
ARGUMENTS
|
|
1671
|
-
FILELOCATION
|
|
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
|
-
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
|
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.
|
|
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.
|
|
18
|
+
static description = 'Export all workflows in the org.';
|
|
20
19
|
static examples = [
|
|
21
|
-
|
|
22
|
-
|
|
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: '
|
|
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
|
-
|
|
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
|
|
65
|
-
const
|
|
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
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
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
|
-
|
|
68
|
+
await saveData(workflowsObj, fileLocation, overwrite);
|
|
159
69
|
}
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
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.
|
|
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 = '
|
|
8
|
+
static description = 'Loads your workflow from a local file';
|
|
15
9
|
static examples = [
|
|
16
|
-
|
|
17
|
-
|
|
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: '
|
|
32
|
-
required:
|
|
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
|
-
|
|
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
|
|
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.
|
|
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
|
-
|
|
15
|
-
|
|
16
|
-
|
|
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.
|
|
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.
|
|
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
|
|
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;
|
package/dist/interfaces.d.ts
CHANGED
|
@@ -98,7 +98,7 @@ export interface WorkflowDefinition {
|
|
|
98
98
|
dynamicMessageGroupId?: string;
|
|
99
99
|
}
|
|
100
100
|
export interface WorkflowTemplateDeclaration {
|
|
101
|
-
appIdentifier
|
|
101
|
+
appIdentifier: string;
|
|
102
102
|
workflows?: WorkflowTemplate[];
|
|
103
103
|
}
|
|
104
104
|
export interface WorkflowTemplate {
|
package/oclif.manifest.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "3.5.4-alpha.
|
|
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.
|
|
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": "
|
|
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": "
|
|
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": "
|
|
3122
|
-
"required":
|
|
3100
|
+
"description": "The workflow template file to load",
|
|
3101
|
+
"required": true
|
|
3123
3102
|
}
|
|
3124
3103
|
}
|
|
3125
3104
|
},
|