@camunda8/cli 2.6.0-alpha.17 → 2.6.0-alpha.19
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 +4 -1
- package/dist/client.d.ts +10 -2
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +7 -17
- package/dist/client.js.map +1 -1
- package/dist/commands/completion.d.ts.map +1 -1
- package/dist/commands/completion.js +41 -41
- package/dist/commands/completion.js.map +1 -1
- package/dist/commands/deployments.d.ts.map +1 -1
- package/dist/commands/deployments.js +158 -131
- package/dist/commands/deployments.js.map +1 -1
- package/dist/commands/forms.d.ts.map +1 -1
- package/dist/commands/forms.js +52 -28
- package/dist/commands/forms.js.map +1 -1
- package/dist/commands/help.d.ts.map +1 -1
- package/dist/commands/help.js +587 -169
- package/dist/commands/help.js.map +1 -1
- package/dist/commands/identity-authorizations.d.ts +1 -1
- package/dist/commands/identity-authorizations.d.ts.map +1 -1
- package/dist/commands/identity-authorizations.js +45 -33
- package/dist/commands/identity-authorizations.js.map +1 -1
- package/dist/commands/identity-groups.d.ts +2 -1
- package/dist/commands/identity-groups.d.ts.map +1 -1
- package/dist/commands/identity-groups.js +24 -21
- package/dist/commands/identity-groups.js.map +1 -1
- package/dist/commands/identity-mapping-rules.d.ts +1 -1
- package/dist/commands/identity-mapping-rules.d.ts.map +1 -1
- package/dist/commands/identity-mapping-rules.js +23 -24
- package/dist/commands/identity-mapping-rules.js.map +1 -1
- package/dist/commands/identity-roles.d.ts +2 -1
- package/dist/commands/identity-roles.d.ts.map +1 -1
- package/dist/commands/identity-roles.js +23 -20
- package/dist/commands/identity-roles.js.map +1 -1
- package/dist/commands/identity-tenants.d.ts +1 -1
- package/dist/commands/identity-tenants.d.ts.map +1 -1
- package/dist/commands/identity-tenants.js +22 -22
- package/dist/commands/identity-tenants.js.map +1 -1
- package/dist/commands/identity-users.d.ts +1 -1
- package/dist/commands/identity-users.d.ts.map +1 -1
- package/dist/commands/identity-users.js +24 -26
- package/dist/commands/identity-users.js.map +1 -1
- package/dist/commands/identity.d.ts +6 -6
- package/dist/commands/identity.d.ts.map +1 -1
- package/dist/commands/identity.js +170 -105
- package/dist/commands/identity.js.map +1 -1
- package/dist/commands/incidents.d.ts +1 -1
- package/dist/commands/incidents.d.ts.map +1 -1
- package/dist/commands/incidents.js +19 -17
- package/dist/commands/incidents.js.map +1 -1
- package/dist/commands/jobs.d.ts +1 -1
- package/dist/commands/jobs.d.ts.map +1 -1
- package/dist/commands/jobs.js +39 -39
- package/dist/commands/jobs.js.map +1 -1
- package/dist/commands/mcp-proxy.d.ts +2 -2
- package/dist/commands/mcp-proxy.d.ts.map +1 -1
- package/dist/commands/mcp-proxy.js +34 -33
- package/dist/commands/mcp-proxy.js.map +1 -1
- package/dist/commands/messages.d.ts.map +1 -1
- package/dist/commands/messages.js +23 -21
- package/dist/commands/messages.js.map +1 -1
- package/dist/commands/open.d.ts +2 -1
- package/dist/commands/open.d.ts.map +1 -1
- package/dist/commands/open.js +29 -20
- package/dist/commands/open.js.map +1 -1
- package/dist/commands/plugins.d.ts.map +1 -1
- package/dist/commands/plugins.js +184 -140
- package/dist/commands/plugins.js.map +1 -1
- package/dist/commands/process-definitions.d.ts +1 -1
- package/dist/commands/process-definitions.d.ts.map +1 -1
- package/dist/commands/process-definitions.js +10 -10
- package/dist/commands/process-definitions.js.map +1 -1
- package/dist/commands/process-instances.d.ts +2 -2
- package/dist/commands/process-instances.d.ts.map +1 -1
- package/dist/commands/process-instances.js +49 -45
- package/dist/commands/process-instances.js.map +1 -1
- package/dist/commands/profiles.d.ts.map +1 -1
- package/dist/commands/profiles.js +27 -27
- package/dist/commands/profiles.js.map +1 -1
- package/dist/commands/run.d.ts.map +1 -1
- package/dist/commands/run.js +21 -17
- package/dist/commands/run.js.map +1 -1
- package/dist/commands/search.d.ts +3 -3
- package/dist/commands/search.d.ts.map +1 -1
- package/dist/commands/search.js +227 -145
- package/dist/commands/search.js.map +1 -1
- package/dist/commands/session.d.ts.map +1 -1
- package/dist/commands/session.js +8 -8
- package/dist/commands/session.js.map +1 -1
- package/dist/commands/topology.d.ts.map +1 -1
- package/dist/commands/topology.js +2 -2
- package/dist/commands/topology.js.map +1 -1
- package/dist/commands/user-tasks.d.ts +1 -1
- package/dist/commands/user-tasks.d.ts.map +1 -1
- package/dist/commands/user-tasks.js +25 -23
- package/dist/commands/user-tasks.js.map +1 -1
- package/dist/commands/watch.d.ts.map +1 -1
- package/dist/commands/watch.js +25 -21
- package/dist/commands/watch.js.map +1 -1
- package/dist/config.d.ts +3 -3
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +95 -89
- package/dist/config.js.map +1 -1
- package/dist/date-filter.d.ts.map +1 -1
- package/dist/date-filter.js +10 -8
- package/dist/date-filter.js.map +1 -1
- package/dist/errors.d.ts +1 -1
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +1 -1
- package/dist/errors.js.map +1 -1
- package/dist/ignore.d.ts +1 -1
- package/dist/ignore.d.ts.map +1 -1
- package/dist/ignore.js +9 -13
- package/dist/ignore.js.map +1 -1
- package/dist/index.d.ts +5 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +591 -475
- package/dist/index.js.map +1 -1
- package/dist/logger.d.ts +7 -7
- package/dist/logger.d.ts.map +1 -1
- package/dist/logger.js +78 -55
- package/dist/logger.js.map +1 -1
- package/dist/plugin-loader.d.ts.map +1 -1
- package/dist/plugin-loader.js +37 -34
- package/dist/plugin-loader.js.map +1 -1
- package/dist/plugin-registry.d.ts.map +1 -1
- package/dist/plugin-registry.js +22 -12
- package/dist/plugin-registry.js.map +1 -1
- package/dist/runtime.d.ts +2 -2
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +10 -9
- package/dist/runtime.js.map +1 -1
- package/package.json +4 -2
|
@@ -1,22 +1,23 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Deployment commands with building-block folder prioritization
|
|
3
3
|
*/
|
|
4
|
-
import {
|
|
4
|
+
import { existsSync, readdirSync, readFileSync, statSync } from "node:fs";
|
|
5
|
+
import { basename, dirname, extname, join, relative, resolve } from "node:path";
|
|
6
|
+
import { TenantId } from "@camunda8/orchestration-cluster-api";
|
|
5
7
|
import { createClient } from "../client.js";
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
+
import { resolveClusterConfig, resolveTenantId } from "../config.js";
|
|
9
|
+
import { isIgnored, loadIgnoreRules } from "../ignore.js";
|
|
10
|
+
import { isRecord } from "../index.js";
|
|
11
|
+
import { getLogger } from "../logger.js";
|
|
8
12
|
import { c8ctl } from "../runtime.js";
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
import { loadIgnoreRules, isIgnored } from "../ignore.js";
|
|
12
|
-
const RESOURCE_EXTENSIONS = ['.bpmn', '.dmn', '.form'];
|
|
13
|
-
const PROCESS_APPLICATION_FILE = '.process-application';
|
|
13
|
+
const RESOURCE_EXTENSIONS = [".bpmn", ".dmn", ".form"];
|
|
14
|
+
const PROCESS_APPLICATION_FILE = ".process-application";
|
|
14
15
|
/**
|
|
15
16
|
* Helper to output messages that respect JSON mode for Unix pipe compatibility
|
|
16
17
|
*/
|
|
17
18
|
function logMessage(message) {
|
|
18
|
-
if (c8ctl.outputMode ===
|
|
19
|
-
console.error(JSON.stringify({ type:
|
|
19
|
+
if (c8ctl.outputMode === "json") {
|
|
20
|
+
console.error(JSON.stringify({ type: "message", message }));
|
|
20
21
|
}
|
|
21
22
|
else {
|
|
22
23
|
console.error(message);
|
|
@@ -26,18 +27,18 @@ function logMessage(message) {
|
|
|
26
27
|
* Extract process/decision IDs from BPMN/DMN files to detect duplicates
|
|
27
28
|
*/
|
|
28
29
|
function extractDefinitionId(content, extension) {
|
|
29
|
-
const text = content.toString(
|
|
30
|
-
if (extension ===
|
|
30
|
+
const text = content.toString("utf-8");
|
|
31
|
+
if (extension === ".bpmn") {
|
|
31
32
|
// Extract bpmn:process id attribute
|
|
32
33
|
const match = text.match(/<bpmn\d?:process[^>]+id="([^"]+)"/);
|
|
33
34
|
return match ? match[1] : null;
|
|
34
35
|
}
|
|
35
|
-
else if (extension ===
|
|
36
|
+
else if (extension === ".dmn") {
|
|
36
37
|
// Extract decision id attribute
|
|
37
38
|
const match = text.match(/<decision[^>]+id="([^"]+)"/);
|
|
38
39
|
return match ? match[1] : null;
|
|
39
40
|
}
|
|
40
|
-
else if (extension ===
|
|
41
|
+
else if (extension === ".form") {
|
|
41
42
|
// Forms are identified by filename, not internal ID
|
|
42
43
|
return null;
|
|
43
44
|
}
|
|
@@ -47,7 +48,7 @@ function extractDefinitionId(content, extension) {
|
|
|
47
48
|
* Check if a path is a building block folder (contains _bb- in name)
|
|
48
49
|
*/
|
|
49
50
|
function isBuildingBlockFolder(path) {
|
|
50
|
-
return basename(path).includes(
|
|
51
|
+
return basename(path).includes("_bb-");
|
|
51
52
|
}
|
|
52
53
|
/**
|
|
53
54
|
* Check if a directory contains a .process-application file
|
|
@@ -66,16 +67,16 @@ function findGroupRoot(filePath, basePath) {
|
|
|
66
67
|
while (true) {
|
|
67
68
|
// Check if we've gone outside the basePath
|
|
68
69
|
const rel = relative(basePath, currentDir);
|
|
69
|
-
if (rel.startsWith(
|
|
70
|
+
if (rel.startsWith("..") || rel === "") {
|
|
70
71
|
break;
|
|
71
72
|
}
|
|
72
73
|
// Check if this directory is a building block
|
|
73
74
|
if (isBuildingBlockFolder(currentDir)) {
|
|
74
|
-
return { type:
|
|
75
|
+
return { type: "bb", root: currentDir };
|
|
75
76
|
}
|
|
76
77
|
// Check if this directory has a .process-application file
|
|
77
78
|
if (hasProcessApplicationFile(currentDir)) {
|
|
78
|
-
return { type:
|
|
79
|
+
return { type: "pa", root: currentDir };
|
|
79
80
|
}
|
|
80
81
|
// Move up one level
|
|
81
82
|
const parentDir = dirname(currentDir);
|
|
@@ -108,8 +109,8 @@ function collectResourceFiles(dirPath, collected = [], basePath, ig, ignoreBaseD
|
|
|
108
109
|
path: dirPath,
|
|
109
110
|
name: basename(dirPath),
|
|
110
111
|
content: readFileSync(dirPath),
|
|
111
|
-
isBuildingBlock: groupInfo.type ===
|
|
112
|
-
isProcessApplication: groupInfo.type ===
|
|
112
|
+
isBuildingBlock: groupInfo.type === "bb",
|
|
113
|
+
isProcessApplication: groupInfo.type === "pa",
|
|
113
114
|
groupPath: groupInfo.root || undefined,
|
|
114
115
|
});
|
|
115
116
|
}
|
|
@@ -117,7 +118,7 @@ function collectResourceFiles(dirPath, collected = [], basePath, ig, ignoreBaseD
|
|
|
117
118
|
}
|
|
118
119
|
if (stat.isDirectory()) {
|
|
119
120
|
// Skip entire directory if it matches an ignore rule
|
|
120
|
-
if (ig && ignoreBaseDir && isIgnored(ig, dirPath
|
|
121
|
+
if (ig && ignoreBaseDir && isIgnored(ig, `${dirPath}/`, ignoreBaseDir)) {
|
|
121
122
|
return collected;
|
|
122
123
|
}
|
|
123
124
|
const entries = readdirSync(dirPath);
|
|
@@ -125,12 +126,14 @@ function collectResourceFiles(dirPath, collected = [], basePath, ig, ignoreBaseD
|
|
|
125
126
|
const bbFolders = [];
|
|
126
127
|
const regularFolders = [];
|
|
127
128
|
const files = [];
|
|
128
|
-
entries.forEach(entry => {
|
|
129
|
+
entries.forEach((entry) => {
|
|
129
130
|
const fullPath = join(dirPath, entry);
|
|
130
131
|
const entryStat = statSync(fullPath);
|
|
131
132
|
if (entryStat.isDirectory()) {
|
|
132
133
|
// Skip ignored directories early to avoid descending into them
|
|
133
|
-
if (ig &&
|
|
134
|
+
if (ig &&
|
|
135
|
+
ignoreBaseDir &&
|
|
136
|
+
isIgnored(ig, `${fullPath}/`, ignoreBaseDir)) {
|
|
134
137
|
return;
|
|
135
138
|
}
|
|
136
139
|
if (isBuildingBlockFolder(entry)) {
|
|
@@ -149,7 +152,7 @@ function collectResourceFiles(dirPath, collected = [], basePath, ig, ignoreBaseD
|
|
|
149
152
|
}
|
|
150
153
|
});
|
|
151
154
|
// Process files in current directory first
|
|
152
|
-
files.forEach(file => {
|
|
155
|
+
files.forEach((file) => {
|
|
153
156
|
const ext = extname(file);
|
|
154
157
|
if (RESOURCE_EXTENSIONS.includes(ext)) {
|
|
155
158
|
const groupInfo = findGroupRoot(file, basePath);
|
|
@@ -157,18 +160,18 @@ function collectResourceFiles(dirPath, collected = [], basePath, ig, ignoreBaseD
|
|
|
157
160
|
path: file,
|
|
158
161
|
name: basename(file),
|
|
159
162
|
content: readFileSync(file),
|
|
160
|
-
isBuildingBlock: groupInfo.type ===
|
|
161
|
-
isProcessApplication: groupInfo.type ===
|
|
163
|
+
isBuildingBlock: groupInfo.type === "bb",
|
|
164
|
+
isProcessApplication: groupInfo.type === "pa",
|
|
162
165
|
groupPath: groupInfo.root || undefined,
|
|
163
166
|
});
|
|
164
167
|
}
|
|
165
168
|
});
|
|
166
169
|
// Process building block folders first (prioritized)
|
|
167
|
-
bbFolders.forEach(bbFolder => {
|
|
170
|
+
bbFolders.forEach((bbFolder) => {
|
|
168
171
|
collectResourceFiles(bbFolder, collected, basePath, ig, ignoreBaseDir);
|
|
169
172
|
});
|
|
170
173
|
// Then process regular folders
|
|
171
|
-
regularFolders.forEach(regularFolder => {
|
|
174
|
+
regularFolders.forEach((regularFolder) => {
|
|
172
175
|
collectResourceFiles(regularFolder, collected, basePath, ig, ignoreBaseDir);
|
|
173
176
|
});
|
|
174
177
|
}
|
|
@@ -180,7 +183,7 @@ function collectResourceFiles(dirPath, collected = [], basePath, ig, ignoreBaseD
|
|
|
180
183
|
function findDuplicateDefinitionIds(resources) {
|
|
181
184
|
const idMap = resources.reduce((map, r) => {
|
|
182
185
|
const ext = extname(r.path);
|
|
183
|
-
if (ext ===
|
|
186
|
+
if (ext === ".bpmn" || ext === ".dmn") {
|
|
184
187
|
const defId = extractDefinitionId(r.content, ext);
|
|
185
188
|
if (defId)
|
|
186
189
|
map.set(defId, [...(map.get(defId) ?? []), r.path]);
|
|
@@ -200,18 +203,18 @@ export async function deploy(paths, options) {
|
|
|
200
203
|
// Store the base paths for relative path calculation
|
|
201
204
|
const basePaths = paths.length === 0 ? [process.cwd()] : paths;
|
|
202
205
|
if (paths.length === 0) {
|
|
203
|
-
logger.error(
|
|
206
|
+
logger.error("No paths provided. Use: c8 deploy <path> or c8 deploy (for current directory)");
|
|
204
207
|
process.exit(1);
|
|
205
208
|
}
|
|
206
209
|
// Load .c8ignore rules from the working directory
|
|
207
210
|
const ignoreBaseDir = resolve(process.cwd());
|
|
208
211
|
const ig = loadIgnoreRules(ignoreBaseDir);
|
|
209
212
|
// Collect all resource files (respecting .c8ignore)
|
|
210
|
-
paths.forEach(path => {
|
|
213
|
+
paths.forEach((path) => {
|
|
211
214
|
collectResourceFiles(path, resources, undefined, ig, ignoreBaseDir);
|
|
212
215
|
});
|
|
213
216
|
if (resources.length === 0) {
|
|
214
|
-
logger.error(
|
|
217
|
+
logger.error("No BPMN/DMN/Form files found in the specified paths");
|
|
215
218
|
process.exit(1);
|
|
216
219
|
}
|
|
217
220
|
// Dry-run: emit the would-be API request without executing
|
|
@@ -219,12 +222,12 @@ export async function deploy(paths, options) {
|
|
|
219
222
|
const config = resolveClusterConfig(options.profile);
|
|
220
223
|
logger.json({
|
|
221
224
|
dryRun: true,
|
|
222
|
-
command:
|
|
223
|
-
method:
|
|
225
|
+
command: "deploy",
|
|
226
|
+
method: "POST",
|
|
224
227
|
url: `${config.baseUrl}/deployments`,
|
|
225
228
|
body: {
|
|
226
229
|
tenantId,
|
|
227
|
-
resources: resources.map(r => ({ name: r.name })),
|
|
230
|
+
resources: resources.map((r) => ({ name: r.name })),
|
|
228
231
|
},
|
|
229
232
|
});
|
|
230
233
|
return;
|
|
@@ -232,7 +235,7 @@ export async function deploy(paths, options) {
|
|
|
232
235
|
const client = createClient(options.profile);
|
|
233
236
|
// Calculate relative paths for display
|
|
234
237
|
const basePath = basePaths.length === 1 ? basePaths[0] : process.cwd();
|
|
235
|
-
resources.forEach(r => {
|
|
238
|
+
resources.forEach((r) => {
|
|
236
239
|
r.relativePath = relative(basePath, r.path) || r.name;
|
|
237
240
|
});
|
|
238
241
|
// Sort: group resources by their group, with building blocks first, then process applications, then standalone
|
|
@@ -271,77 +274,84 @@ export async function deploy(paths, options) {
|
|
|
271
274
|
// Validate for duplicate process/decision IDs
|
|
272
275
|
const duplicates = findDuplicateDefinitionIds(resources);
|
|
273
276
|
if (duplicates.size > 0) {
|
|
274
|
-
logger.error(
|
|
275
|
-
duplicates.forEach((paths, id) =>
|
|
276
|
-
|
|
277
|
-
|
|
277
|
+
logger.error("Cannot deploy: Multiple files with the same process/decision ID in one deployment");
|
|
278
|
+
duplicates.forEach((paths, id) => {
|
|
279
|
+
logMessage(` Process/Decision ID "${id}" found in: ${paths.join(", ")}`);
|
|
280
|
+
});
|
|
281
|
+
logMessage("\nCamunda does not allow deploying multiple resources with the same definition ID in a single deployment.");
|
|
282
|
+
logMessage("Please deploy these files separately or ensure each process/decision has a unique ID.");
|
|
278
283
|
process.exit(1);
|
|
279
284
|
}
|
|
280
285
|
logger.info(`Deploying ${resources.length} resource(s)...`);
|
|
281
286
|
// Create a mapping from definition ID to resource file for later reference
|
|
282
287
|
const definitionIdToResource = new Map();
|
|
283
288
|
const formNameToResource = new Map();
|
|
284
|
-
resources.forEach(r => {
|
|
289
|
+
resources.forEach((r) => {
|
|
285
290
|
const ext = extname(r.path);
|
|
286
|
-
if (ext ===
|
|
291
|
+
if (ext === ".bpmn" || ext === ".dmn") {
|
|
287
292
|
const defId = extractDefinitionId(r.content, ext);
|
|
288
293
|
if (defId) {
|
|
289
294
|
definitionIdToResource.set(defId, r);
|
|
290
295
|
}
|
|
291
296
|
}
|
|
292
|
-
else if (ext ===
|
|
297
|
+
else if (ext === ".form") {
|
|
293
298
|
// Forms are matched by filename (without extension)
|
|
294
|
-
const formId = basename(r.name,
|
|
299
|
+
const formId = basename(r.name, ".form");
|
|
295
300
|
formNameToResource.set(formId, r);
|
|
296
301
|
}
|
|
297
302
|
});
|
|
298
303
|
// Create deployment request - convert buffers to File objects with proper MIME types
|
|
299
304
|
const result = await client.createDeployment({
|
|
300
305
|
tenantId: TenantId.assumeExists(tenantId),
|
|
301
|
-
resources: resources.map(r => {
|
|
306
|
+
resources: resources.map((r) => {
|
|
302
307
|
// Determine MIME type based on extension
|
|
303
|
-
const ext = r.name.split(
|
|
304
|
-
const mimeType = ext ===
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
+
const ext = r.name.split(".").pop()?.toLowerCase();
|
|
309
|
+
const mimeType = ext === "bpmn"
|
|
310
|
+
? "application/xml"
|
|
311
|
+
: ext === "dmn"
|
|
312
|
+
? "application/xml"
|
|
313
|
+
: ext === "form"
|
|
314
|
+
? "application/json"
|
|
315
|
+
: "application/octet-stream";
|
|
308
316
|
// Convert Buffer to Uint8Array for File constructor
|
|
309
|
-
return new File([new Uint8Array(r.content)], r.name, {
|
|
317
|
+
return new File([new Uint8Array(r.content)], r.name, {
|
|
318
|
+
type: mimeType,
|
|
319
|
+
});
|
|
310
320
|
}),
|
|
311
321
|
});
|
|
312
|
-
logger.success(
|
|
322
|
+
logger.success("Deployment successful", result.deploymentKey.toString());
|
|
313
323
|
// Normalize all deployed resources into a common structure
|
|
314
324
|
const allResources = [
|
|
315
|
-
...result.processes.map(proc => ({
|
|
316
|
-
type:
|
|
325
|
+
...result.processes.map((proc) => ({
|
|
326
|
+
type: "Process",
|
|
317
327
|
id: proc.processDefinitionId,
|
|
318
328
|
version: proc.processDefinitionVersion,
|
|
319
329
|
key: proc.processDefinitionKey.toString(),
|
|
320
330
|
resource: definitionIdToResource.get(proc.processDefinitionId),
|
|
321
331
|
})),
|
|
322
|
-
...result.decisions.map(dec => ({
|
|
323
|
-
type:
|
|
324
|
-
id: dec.decisionDefinitionId ||
|
|
325
|
-
version: dec.version ??
|
|
326
|
-
key: dec.decisionDefinitionKey?.toString() ||
|
|
327
|
-
resource: definitionIdToResource.get(dec.decisionDefinitionId ||
|
|
332
|
+
...result.decisions.map((dec) => ({
|
|
333
|
+
type: "Decision",
|
|
334
|
+
id: dec.decisionDefinitionId || "-",
|
|
335
|
+
version: dec.version ?? "-",
|
|
336
|
+
key: dec.decisionDefinitionKey?.toString() || "-",
|
|
337
|
+
resource: definitionIdToResource.get(dec.decisionDefinitionId || ""),
|
|
328
338
|
})),
|
|
329
|
-
...result.forms.map(form => ({
|
|
330
|
-
type:
|
|
331
|
-
id: form.formId ||
|
|
332
|
-
version: form.version ??
|
|
333
|
-
key: form.formKey?.toString() ||
|
|
334
|
-
resource: formNameToResource.get(form.formId ||
|
|
339
|
+
...result.forms.map((form) => ({
|
|
340
|
+
type: "Form",
|
|
341
|
+
id: form.formId || "-",
|
|
342
|
+
version: form.version ?? "-",
|
|
343
|
+
key: form.formKey?.toString() || "-",
|
|
344
|
+
resource: formNameToResource.get(form.formId || ""),
|
|
335
345
|
})),
|
|
336
346
|
];
|
|
337
347
|
const tableData = allResources.map(({ type, id, version, key, resource }) => {
|
|
338
348
|
const fileDisplay = resource
|
|
339
|
-
? `${resource.isBuildingBlock ?
|
|
340
|
-
:
|
|
349
|
+
? `${resource.isBuildingBlock ? "🧱 " : ""}${resource.isProcessApplication ? "📦 " : ""}${resource.relativePath || resource.name}`
|
|
350
|
+
: "-";
|
|
341
351
|
// Extract directory path for grouping (e.g., "bla/_bb-building-block" or "pa")
|
|
342
352
|
const sortKey = resource?.relativePath
|
|
343
|
-
? resource.relativePath.substring(0, resource.relativePath.lastIndexOf(
|
|
344
|
-
:
|
|
353
|
+
? resource.relativePath.substring(0, resource.relativePath.lastIndexOf("/") + 1) || resource.relativePath
|
|
354
|
+
: "zzz"; // Resources without paths go last
|
|
345
355
|
return {
|
|
346
356
|
File: fileDisplay,
|
|
347
357
|
Type: type,
|
|
@@ -359,7 +369,13 @@ export async function deploy(paths, options) {
|
|
|
359
369
|
return a.File.localeCompare(b.File);
|
|
360
370
|
});
|
|
361
371
|
// Remove sortKey before displaying
|
|
362
|
-
const displayData = tableData.map(({ File, Type, ID, Version, Key }) => ({
|
|
372
|
+
const displayData = tableData.map(({ File, Type, ID, Version, Key }) => ({
|
|
373
|
+
File,
|
|
374
|
+
Type,
|
|
375
|
+
ID,
|
|
376
|
+
Version,
|
|
377
|
+
Key,
|
|
378
|
+
}));
|
|
363
379
|
if (displayData.length > 0) {
|
|
364
380
|
logger.table(displayData);
|
|
365
381
|
}
|
|
@@ -373,9 +389,9 @@ export async function deploy(paths, options) {
|
|
|
373
389
|
*/
|
|
374
390
|
function handleDeploymentError(error, resources, logger, continueOnError, continueOnUserError) {
|
|
375
391
|
// Extract problem title early to determine whether this is a user-fixable error
|
|
376
|
-
const raw = (error
|
|
377
|
-
const problemTitle = typeof raw.title ===
|
|
378
|
-
const isUserFixable = problemTitle ===
|
|
392
|
+
const raw = isRecord(error) ? error : {};
|
|
393
|
+
const problemTitle = typeof raw.title === "string" ? raw.title : undefined;
|
|
394
|
+
const isUserFixable = problemTitle === "INVALID_ARGUMENT";
|
|
379
395
|
const shouldContinue = continueOnError || (continueOnUserError && isUserFixable);
|
|
380
396
|
if (c8ctl.verbose) {
|
|
381
397
|
if (shouldContinue) {
|
|
@@ -387,56 +403,56 @@ function handleDeploymentError(error, resources, logger, continueOnError, contin
|
|
|
387
403
|
}
|
|
388
404
|
// Try to interpret common transport/network issues first for actionable guidance
|
|
389
405
|
const deriveNetworkErrorTitle = (err) => {
|
|
390
|
-
const anyErr = err;
|
|
391
|
-
const code = typeof anyErr
|
|
406
|
+
const anyErr = isRecord(err) ? err : {};
|
|
407
|
+
const code = typeof anyErr.code === "string"
|
|
392
408
|
? anyErr.code
|
|
393
|
-
: (typeof anyErr
|
|
409
|
+
: isRecord(anyErr.cause) && typeof anyErr.cause.code === "string"
|
|
394
410
|
? anyErr.cause.code
|
|
395
|
-
: undefined
|
|
396
|
-
if (!code && typeof anyErr?.name ===
|
|
411
|
+
: undefined;
|
|
412
|
+
if (!code && typeof anyErr?.name === "string") {
|
|
397
413
|
// Handle fetch/abort style errors
|
|
398
|
-
if (anyErr.name ===
|
|
399
|
-
return
|
|
414
|
+
if (anyErr.name === "AbortError") {
|
|
415
|
+
return "Request to Camunda cluster timed out or was aborted. Please check your network connection and try again.";
|
|
400
416
|
}
|
|
401
417
|
}
|
|
402
418
|
switch (code) {
|
|
403
|
-
case
|
|
404
|
-
return
|
|
405
|
-
case
|
|
406
|
-
return
|
|
407
|
-
case
|
|
408
|
-
return
|
|
409
|
-
case
|
|
410
|
-
return
|
|
411
|
-
case
|
|
412
|
-
return
|
|
419
|
+
case "ECONNREFUSED":
|
|
420
|
+
return "Cannot connect to Camunda cluster (connection refused). Verify the endpoint URL and that the cluster is reachable.";
|
|
421
|
+
case "ENOTFOUND":
|
|
422
|
+
return "Cannot resolve Camunda cluster host. Check the cluster URL and your DNS/network configuration.";
|
|
423
|
+
case "EHOSTUNREACH":
|
|
424
|
+
return "Camunda cluster host is unreachable. Check VPN/proxy settings and your network connectivity.";
|
|
425
|
+
case "ECONNRESET":
|
|
426
|
+
return "Connection to Camunda cluster was reset. Retry the operation and check for intermittent network issues.";
|
|
427
|
+
case "ETIMEDOUT":
|
|
428
|
+
return "Request to Camunda cluster timed out. Check your network connection and consider retrying.";
|
|
413
429
|
default:
|
|
414
430
|
return undefined;
|
|
415
431
|
}
|
|
416
432
|
};
|
|
417
433
|
// Extract RFC 9457 Problem Detail fields and other useful signals
|
|
418
434
|
const networkTitle = deriveNetworkErrorTitle(error);
|
|
419
|
-
const errorInstanceTitle = error instanceof Error && typeof error.message ===
|
|
435
|
+
const errorInstanceTitle = error instanceof Error && typeof error.message === "string" && error.message
|
|
420
436
|
? error.message
|
|
421
437
|
: undefined;
|
|
422
|
-
const messageFieldTitle = typeof raw.message ===
|
|
438
|
+
const messageFieldTitle = typeof raw.message === "string" ? raw.message : undefined;
|
|
423
439
|
const title = problemTitle ??
|
|
424
440
|
networkTitle ??
|
|
425
441
|
errorInstanceTitle ??
|
|
426
442
|
messageFieldTitle ??
|
|
427
|
-
|
|
428
|
-
const detail = typeof raw.detail ===
|
|
429
|
-
const status = typeof raw.status ===
|
|
443
|
+
"Unknown error (unexpected error format; re-run with increased logging or check network configuration).";
|
|
444
|
+
const detail = typeof raw.detail === "string" ? raw.detail : undefined;
|
|
445
|
+
const status = typeof raw.status === "number" ? raw.status : undefined;
|
|
430
446
|
// Display the main error
|
|
431
|
-
logger.error(
|
|
447
|
+
logger.error("Deployment failed", new Error(title));
|
|
432
448
|
// Display the detailed error message if available
|
|
433
449
|
if (detail) {
|
|
434
|
-
logMessage(
|
|
450
|
+
logMessage(`\n${formatDeploymentErrorDetail(detail)}`);
|
|
435
451
|
}
|
|
436
452
|
// Provide actionable hints based on error type
|
|
437
|
-
logMessage(
|
|
453
|
+
logMessage("");
|
|
438
454
|
printDeploymentHints(title, detail, status, resources);
|
|
439
|
-
logMessage(
|
|
455
|
+
logMessage("For more details on the error, run with the --verbose flag");
|
|
440
456
|
if (shouldContinue) {
|
|
441
457
|
return;
|
|
442
458
|
}
|
|
@@ -447,78 +463,89 @@ function handleDeploymentError(error, resources, logger, continueOnError, contin
|
|
|
447
463
|
*/
|
|
448
464
|
function formatDeploymentErrorDetail(detail) {
|
|
449
465
|
// The detail often contains embedded newlines, format them nicely
|
|
450
|
-
const lines = detail
|
|
466
|
+
const lines = detail
|
|
467
|
+
.split("\n")
|
|
468
|
+
.map((line) => line.trim())
|
|
469
|
+
.filter(Boolean);
|
|
451
470
|
// Find the main message and the file-specific errors
|
|
452
471
|
const result = [];
|
|
453
472
|
let inFileError = false;
|
|
454
473
|
for (const line of lines) {
|
|
455
|
-
if (line.startsWith("'") &&
|
|
474
|
+
if (line.startsWith("'") &&
|
|
475
|
+
(line.includes(".bpmn") ||
|
|
476
|
+
line.includes(".dmn") ||
|
|
477
|
+
line.includes(".form"))) {
|
|
456
478
|
// This is a file-specific error
|
|
457
479
|
inFileError = true;
|
|
458
480
|
result.push(` 📄 ${line}`);
|
|
459
481
|
}
|
|
460
|
-
else if (line.startsWith(
|
|
482
|
+
else if (line.startsWith("- Element:")) {
|
|
461
483
|
result.push(` ${line}`);
|
|
462
484
|
}
|
|
463
|
-
else if (line.startsWith(
|
|
464
|
-
const icon = line.startsWith(
|
|
485
|
+
else if (line.startsWith("- ERROR:") || line.startsWith("- WARNING:")) {
|
|
486
|
+
const icon = line.startsWith("- ERROR:") ? "❌" : "⚠️";
|
|
465
487
|
result.push(` ${icon} ${line.substring(2)}`);
|
|
466
488
|
}
|
|
467
|
-
else if (inFileError && line.startsWith(
|
|
489
|
+
else if (inFileError && line.startsWith("-")) {
|
|
468
490
|
result.push(` ${line}`);
|
|
469
491
|
}
|
|
470
492
|
else {
|
|
471
493
|
result.push(` ${line}`);
|
|
472
494
|
}
|
|
473
495
|
}
|
|
474
|
-
return result.join(
|
|
496
|
+
return result.join("\n");
|
|
475
497
|
}
|
|
476
498
|
/**
|
|
477
499
|
* Print actionable hints based on the error type
|
|
478
500
|
*/
|
|
479
501
|
function printDeploymentHints(title, detail, status, resources) {
|
|
480
502
|
const hints = [];
|
|
481
|
-
if (title ===
|
|
482
|
-
if (detail?.includes(
|
|
483
|
-
hints.push(
|
|
484
|
-
hints.push(
|
|
503
|
+
if (title === "INVALID_ARGUMENT") {
|
|
504
|
+
if (detail?.includes("Must reference a message")) {
|
|
505
|
+
hints.push("💡 A message start event or intermediate catch event is missing a message reference.");
|
|
506
|
+
hints.push(" Open the BPMN file in Camunda Modeler and configure the message name.");
|
|
485
507
|
}
|
|
486
|
-
if (detail?.includes(
|
|
487
|
-
hints.push(
|
|
488
|
-
hints.push(
|
|
508
|
+
if (detail?.includes("duplicate")) {
|
|
509
|
+
hints.push("💡 Resource IDs must be unique within a deployment.");
|
|
510
|
+
hints.push(" Check for duplicate process/decision IDs in your files.");
|
|
489
511
|
}
|
|
490
|
-
if (detail?.includes(
|
|
491
|
-
hints.push(
|
|
492
|
-
hints.push(
|
|
512
|
+
if (detail?.includes("parsing") || detail?.includes("syntax")) {
|
|
513
|
+
hints.push("💡 The resource file contains syntax errors.");
|
|
514
|
+
hints.push(" Validate the file in Camunda Modeler or check the XML/JSON structure.");
|
|
493
515
|
}
|
|
494
516
|
}
|
|
495
|
-
else if (title ===
|
|
496
|
-
hints.push(
|
|
497
|
-
hints.push(
|
|
517
|
+
else if (title === "RESOURCE_EXHAUSTED") {
|
|
518
|
+
hints.push("💡 The server is under heavy load (backpressure).");
|
|
519
|
+
hints.push(" Wait a moment and retry the deployment.");
|
|
498
520
|
}
|
|
499
|
-
else if (title ===
|
|
500
|
-
hints.push(
|
|
501
|
-
hints.push(
|
|
521
|
+
else if (title === "NOT_FOUND" || status === 404) {
|
|
522
|
+
hints.push("💡 The Camunda server could not be reached or the endpoint was not found.");
|
|
523
|
+
hints.push(" Check your connection settings with: c8 list profiles");
|
|
502
524
|
}
|
|
503
|
-
else if (title ===
|
|
504
|
-
|
|
505
|
-
|
|
525
|
+
else if (title === "UNAUTHENTICATED" ||
|
|
526
|
+
title === "PERMISSION_DENIED" ||
|
|
527
|
+
status === 401 ||
|
|
528
|
+
status === 403) {
|
|
529
|
+
hints.push("💡 Authentication or authorization failed.");
|
|
530
|
+
hints.push(" Check your credentials and permissions for the current profile.");
|
|
506
531
|
}
|
|
507
532
|
else {
|
|
508
|
-
hints.push(
|
|
509
|
-
hints.push(
|
|
533
|
+
hints.push("💡 Review the error message above for specific issues.");
|
|
534
|
+
hints.push(" You may need to fix the resource files before deploying.");
|
|
510
535
|
}
|
|
511
536
|
// Show which files were being deployed
|
|
512
537
|
if (resources.length > 0) {
|
|
513
|
-
hints.push(
|
|
538
|
+
hints.push("");
|
|
514
539
|
hints.push(`📁 Resources attempted (${resources.length}):`);
|
|
515
|
-
resources.slice(0, 5).forEach(r => {
|
|
540
|
+
resources.slice(0, 5).forEach((r) => {
|
|
516
541
|
hints.push(` - ${r.relativePath || r.name}`);
|
|
517
542
|
});
|
|
518
543
|
if (resources.length > 5) {
|
|
519
544
|
hints.push(` ... and ${resources.length - 5} more`);
|
|
520
545
|
}
|
|
521
546
|
}
|
|
522
|
-
hints.forEach(h =>
|
|
547
|
+
hints.forEach((h) => {
|
|
548
|
+
logMessage(h);
|
|
549
|
+
});
|
|
523
550
|
}
|
|
524
551
|
//# sourceMappingURL=deployments.js.map
|