@contrail/cli 3.5.4-alpha.103cd15 → 3.5.4-alpha.a78e2b0
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 +12 -7
- package/dist/commands/workflow-templates/export.js +8 -3
- package/dist/commands/workflow-templates/load.d.ts +2 -0
- package/dist/commands/workflow-templates/load.js +67 -6
- package/dist/helpers/workflow-templates/helper.d.ts +1 -1
- package/dist/helpers/workflow-templates/helper.js +9 -4
- package/dist/interfaces.d.ts +1 -1
- package/oclif.manifest.json +16 -5
- 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.a78e2b0 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
|
|
|
@@ -1659,27 +1659,32 @@ EXAMPLES
|
|
|
1659
1659
|
$ contrail workflow-templates list
|
|
1660
1660
|
```
|
|
1661
1661
|
|
|
1662
|
-
## `contrail workflow-templates load FILELOCATION`
|
|
1662
|
+
## `contrail workflow-templates load [FILELOCATION]`
|
|
1663
1663
|
|
|
1664
|
-
|
|
1664
|
+
Load workflow templates from a file or scan a directory for per-app workflow files
|
|
1665
1665
|
|
|
1666
1666
|
```
|
|
1667
1667
|
USAGE
|
|
1668
|
-
$ 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>]
|
|
1669
1669
|
|
|
1670
1670
|
ARGUMENTS
|
|
1671
|
-
FILELOCATION
|
|
1671
|
+
FILELOCATION A specific workflow template file to load
|
|
1672
1672
|
|
|
1673
1673
|
FLAGS
|
|
1674
|
+
-d, --dir=<value> [default: .] Directory to scan for workflow files when no file argument is given
|
|
1674
1675
|
-e, --alwaysConfirmEnv=<option> [default: true] The Environment variables
|
|
1675
1676
|
<options: true|false>
|
|
1676
1677
|
-l, --logLevel=<option> The Log Level
|
|
1677
1678
|
<options: error|warn|info|debug>
|
|
1678
1679
|
|
|
1679
1680
|
DESCRIPTION
|
|
1680
|
-
|
|
1681
|
+
Load workflow templates from a file or scan a directory for per-app workflow files
|
|
1681
1682
|
|
|
1682
1683
|
EXAMPLES
|
|
1683
1684
|
$ contrail workflow-templates load <FILE_LOCATION>
|
|
1685
|
+
|
|
1686
|
+
$ contrail workflow-templates load
|
|
1687
|
+
|
|
1688
|
+
$ contrail workflow-templates load --dir ./workflows
|
|
1684
1689
|
```
|
|
1685
1690
|
<!-- commandsstop -->
|
|
@@ -102,7 +102,7 @@ async function exportWorkflowsByApp(outputDir, overwrite) {
|
|
|
102
102
|
for (const [appIdentifier, workflows] of workflowsByApp.entries()) {
|
|
103
103
|
const exportObj = { appIdentifier, workflows: [] };
|
|
104
104
|
for (const workflow of workflows) {
|
|
105
|
-
exportObj.workflows.push(await buildExportWorkflow(workflow, allSchedules));
|
|
105
|
+
exportObj.workflows.push(await buildExportWorkflow(workflow, allSchedules, appIdentifier));
|
|
106
106
|
}
|
|
107
107
|
const safeAppIdentifier = appIdentifier.replace(/[\\/]/g, '-');
|
|
108
108
|
const filePath = path.join(resolvedDir, `workflows-${safeAppIdentifier}.yml`);
|
|
@@ -133,7 +133,7 @@ async function exportWorkflowsToFile(fileLocation, overwrite) {
|
|
|
133
133
|
await writeYamlFile(workflowsObj, pathToWrite, overwrite);
|
|
134
134
|
}
|
|
135
135
|
exports.exportWorkflowsToFile = exportWorkflowsToFile;
|
|
136
|
-
async function buildExportWorkflow(workflow, allSchedules) {
|
|
136
|
+
async function buildExportWorkflow(workflow, allSchedules, appIdentifier) {
|
|
137
137
|
const exportWorkflow = lodash_1.default.pick(workflow, [
|
|
138
138
|
'identifier',
|
|
139
139
|
'name',
|
|
@@ -149,7 +149,12 @@ async function buildExportWorkflow(workflow, allSchedules) {
|
|
|
149
149
|
exportWorkflow.crons = schedules.map((s) => ({ name: s.name, cron: s.cron }));
|
|
150
150
|
}
|
|
151
151
|
await (0, helper_1.populateActionIdentifiers)(exportWorkflow);
|
|
152
|
-
|
|
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);
|
|
157
|
+
}
|
|
153
158
|
return exportWorkflow;
|
|
154
159
|
}
|
|
155
160
|
async function writeYamlFile(data, absolutePath, overwrite) {
|
|
@@ -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,88 @@
|
|
|
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 = '
|
|
14
|
+
static description = 'Load workflow templates from a file or scan a directory for per-app workflow files';
|
|
9
15
|
static examples = [
|
|
10
|
-
|
|
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: '
|
|
19
|
-
required:
|
|
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
|
-
|
|
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
|
+
if (!fs_1.default.existsSync(resolvedDir) || !fs_1.default.statSync(resolvedDir).isDirectory()) {
|
|
49
|
+
console.log(chalk_1.default.red(`Directory not found: ${resolvedDir}`));
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
const files = fs_1.default
|
|
53
|
+
.readdirSync(resolvedDir)
|
|
54
|
+
.filter((f) => f.startsWith('workflows-') && f.endsWith('.yml'))
|
|
55
|
+
.sort();
|
|
56
|
+
if (files.length === 0) {
|
|
57
|
+
console.log(chalk_1.default.yellow(`No workflow files found in ${resolvedDir}`));
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
const choices = files.map((f) => ({
|
|
61
|
+
name: f,
|
|
62
|
+
value: f,
|
|
63
|
+
checked: true,
|
|
64
|
+
}));
|
|
65
|
+
const { selectedFiles } = await inquirer_1.default.prompt([
|
|
66
|
+
{
|
|
67
|
+
type: 'checkbox',
|
|
68
|
+
name: 'selectedFiles',
|
|
69
|
+
message: 'Select workflow files to import (space to toggle, enter to confirm):',
|
|
70
|
+
choices,
|
|
71
|
+
},
|
|
72
|
+
]);
|
|
73
|
+
if (selectedFiles.length === 0) {
|
|
74
|
+
console.log(chalk_1.default.yellow('No files selected — nothing imported.'));
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
//log selected file
|
|
78
|
+
console.log(chalk_1.default.blue.bold('SELECTED WORKFLOW FILES:'));
|
|
79
|
+
selectedFiles.forEach((file) => {
|
|
80
|
+
console.log(` - ${file}`);
|
|
81
|
+
});
|
|
82
|
+
for (const file of selectedFiles) {
|
|
83
|
+
console.log(`\n${chalk_1.default.blue.bold('IMPORTING')} ${file}`);
|
|
84
|
+
await (0, helper_1.localDeployWorkflowTemplate)(path.join(dir, file));
|
|
85
|
+
console.log(`${chalk_1.default.green.bold('DONE')} ${file}`);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
exports.importWorkflowsBySelection = importWorkflowsBySelection;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { EventWorkflowActionDefinition, WorkflowTemplate, WorkflowTemplateDeclaration } from '../../interfaces';
|
|
2
2
|
export declare class LocalWorkflowTemplateDeployer {
|
|
3
3
|
deployWorkflows(wtDeclaration: WorkflowTemplateDeclaration): Promise<void>;
|
|
4
|
-
deployWorkflowTemplate(workflow: WorkflowTemplate, existingWorkflows: WorkflowTemplate[], appIdentifier: string): Promise<WorkflowTemplate>;
|
|
4
|
+
deployWorkflowTemplate(workflow: WorkflowTemplate, existingWorkflows: WorkflowTemplate[], appIdentifier: string | undefined): Promise<WorkflowTemplate>;
|
|
5
5
|
private createNewWorkflowTemplate;
|
|
6
6
|
private populateActionIds;
|
|
7
7
|
createWorkflowSchedule(workflowTemplate: WorkflowTemplate, workflowId: string): Promise<any>;
|
|
@@ -35,14 +35,14 @@ class LocalWorkflowTemplateDeployer {
|
|
|
35
35
|
return await this.createNewWorkflowTemplate(identifier, workflow, appIdentifier);
|
|
36
36
|
}
|
|
37
37
|
async createNewWorkflowTemplate(workflowKey, workflowTemplate, appIdentifier) {
|
|
38
|
-
await this.populateActionIds(workflowTemplate, workflowKey, appIdentifier);
|
|
38
|
+
const appId = await this.populateActionIds(workflowTemplate, workflowKey, appIdentifier);
|
|
39
39
|
const newObject = {
|
|
40
40
|
identifier: getWorkflowTemplateIdentifier(workflowTemplate),
|
|
41
41
|
name: workflowTemplate.name,
|
|
42
42
|
triggerKey: workflowTemplate.triggerKey,
|
|
43
43
|
workflowDefinition: workflowTemplate.workflowDefinition,
|
|
44
44
|
isActive: workflowTemplate.isActive,
|
|
45
|
-
supportingAppId:
|
|
45
|
+
supportingAppId: appId,
|
|
46
46
|
messageGroupId: workflowTemplate.messageGroupId,
|
|
47
47
|
messageGroup: workflowTemplate.messageGroup,
|
|
48
48
|
dynamicMessageGroupId: workflowTemplate.dynamicMessageGroupId,
|
|
@@ -56,6 +56,10 @@ class LocalWorkflowTemplateDeployer {
|
|
|
56
56
|
return newWorkflowTemplate;
|
|
57
57
|
}
|
|
58
58
|
async populateActionIds(workflowTemplate, workflowKey, appIdentifier) {
|
|
59
|
+
if (!appIdentifier) {
|
|
60
|
+
logger_1.default.info(`WORKFLOW TEMPLATES No appIdentifier for "${workflowKey}" — skipping action ID resolution.`);
|
|
61
|
+
return undefined;
|
|
62
|
+
}
|
|
59
63
|
const installedApps = await (0, apps_1.getInstalledApps)();
|
|
60
64
|
const appOrg = installedApps.find((x) => x.app?.identifier === appIdentifier);
|
|
61
65
|
logger_1.default.info('workflow template:', JSON.stringify(workflowTemplate, null, 2));
|
|
@@ -63,7 +67,7 @@ class LocalWorkflowTemplateDeployer {
|
|
|
63
67
|
throw new Error(`Could not find installed app with identifier "${appIdentifier}". Make sure the app is installed in this org before importing workflows.`);
|
|
64
68
|
}
|
|
65
69
|
if (!workflowTemplate?.workflowDefinition?.paths) {
|
|
66
|
-
return;
|
|
70
|
+
return appOrg.appId;
|
|
67
71
|
}
|
|
68
72
|
for (const path of workflowTemplate.workflowDefinition.paths) {
|
|
69
73
|
if (!path?.actionDefinitionConfigs) {
|
|
@@ -89,6 +93,7 @@ class LocalWorkflowTemplateDeployer {
|
|
|
89
93
|
}
|
|
90
94
|
}
|
|
91
95
|
}
|
|
96
|
+
return appOrg.appId;
|
|
92
97
|
}
|
|
93
98
|
async createWorkflowSchedule(workflowTemplate, workflowId) {
|
|
94
99
|
if (!workflowTemplate?.crons?.length) {
|
|
@@ -301,7 +306,7 @@ function extractShortActionKeys(workflowTemplate) {
|
|
|
301
306
|
for (const actionConfig of wfPath.actionDefinitionConfigs) {
|
|
302
307
|
if (actionConfig.action?.includes(':')) {
|
|
303
308
|
// Full identifier format: "app-id@version:action-name" -> "action-name"
|
|
304
|
-
actionConfig.action = actionConfig.action.split(':').pop();
|
|
309
|
+
actionConfig.action = actionConfig.action.split(':').pop() ?? actionConfig.action;
|
|
305
310
|
}
|
|
306
311
|
delete actionConfig.identifier;
|
|
307
312
|
}
|
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.a78e2b0",
|
|
3
3
|
"commands": {
|
|
4
4
|
"app:create": {
|
|
5
5
|
"id": "app:create",
|
|
@@ -3066,14 +3066,16 @@
|
|
|
3066
3066
|
},
|
|
3067
3067
|
"workflow-templates:load": {
|
|
3068
3068
|
"id": "workflow-templates:load",
|
|
3069
|
-
"description": "
|
|
3069
|
+
"description": "Load workflow templates from a file or scan a directory for per-app workflow files",
|
|
3070
3070
|
"strict": true,
|
|
3071
3071
|
"pluginName": "@contrail/cli",
|
|
3072
3072
|
"pluginAlias": "@contrail/cli",
|
|
3073
3073
|
"pluginType": "core",
|
|
3074
3074
|
"aliases": [],
|
|
3075
3075
|
"examples": [
|
|
3076
|
-
"$ contrail workflow-templates load <FILE_LOCATION
|
|
3076
|
+
"$ contrail workflow-templates load <FILE_LOCATION>",
|
|
3077
|
+
"$ contrail workflow-templates load",
|
|
3078
|
+
"$ contrail workflow-templates load --dir ./workflows"
|
|
3077
3079
|
],
|
|
3078
3080
|
"flags": {
|
|
3079
3081
|
"logLevel": {
|
|
@@ -3102,13 +3104,22 @@
|
|
|
3102
3104
|
"false"
|
|
3103
3105
|
],
|
|
3104
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": "."
|
|
3105
3116
|
}
|
|
3106
3117
|
},
|
|
3107
3118
|
"args": {
|
|
3108
3119
|
"fileLocation": {
|
|
3109
3120
|
"name": "fileLocation",
|
|
3110
|
-
"description": "
|
|
3111
|
-
"required":
|
|
3121
|
+
"description": "A specific workflow template file to load",
|
|
3122
|
+
"required": false
|
|
3112
3123
|
}
|
|
3113
3124
|
}
|
|
3114
3125
|
},
|