jiradc-cli 1.0.30 → 1.0.32
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 +24 -24
- package/dist/index.js +301 -149
- package/package.json +4 -2
package/README.md
CHANGED
|
@@ -119,52 +119,52 @@ Search and list commands accept `--limit` to control page size (Jira DC caps at
|
|
|
119
119
|
|
|
120
120
|
```bash
|
|
121
121
|
# Get an issue with default fields
|
|
122
|
-
jiradc issue get
|
|
122
|
+
jiradc issue get PROJ-123
|
|
123
123
|
|
|
124
124
|
# Get an issue with specific fields
|
|
125
|
-
jiradc issue get
|
|
125
|
+
jiradc issue get PROJ-123 --fields summary,status,assignee,customfield_10100
|
|
126
126
|
|
|
127
127
|
# Search with JQL
|
|
128
128
|
jiradc issue search 'project = AI AND status = "In Development" ORDER BY updated DESC'
|
|
129
129
|
|
|
130
130
|
# Create an issue
|
|
131
|
-
jiradc issue create --project
|
|
131
|
+
jiradc issue create --project PROJ --type Task --summary "Implement feature X" --description "Details here"
|
|
132
132
|
|
|
133
133
|
# Create with custom fields
|
|
134
|
-
jiradc issue create --project
|
|
134
|
+
jiradc issue create --project PROJ --type Story --summary "User login" --custom-fields '{"customfield_10100": "value"}'
|
|
135
135
|
|
|
136
136
|
# Transition by ID or by status name
|
|
137
|
-
jiradc issue transitions
|
|
138
|
-
jiradc issue transition
|
|
139
|
-
jiradc issue transition
|
|
137
|
+
jiradc issue transitions PROJ-123
|
|
138
|
+
jiradc issue transition PROJ-123 --to 31
|
|
139
|
+
jiradc issue transition PROJ-123 --to "In Review" --comment "Ready for review"
|
|
140
140
|
|
|
141
141
|
# Assign
|
|
142
|
-
jiradc issue assign
|
|
143
|
-
jiradc issue assign
|
|
144
|
-
jiradc issue assign
|
|
142
|
+
jiradc issue assign PROJ-123 me
|
|
143
|
+
jiradc issue assign PROJ-123 jsmith
|
|
144
|
+
jiradc issue assign PROJ-123 none
|
|
145
145
|
|
|
146
146
|
# Update with shortcuts (instead of --fields JSON)
|
|
147
|
-
jiradc issue update
|
|
148
|
-
jiradc issue update
|
|
149
|
-
jiradc issue update
|
|
150
|
-
jiradc issue update
|
|
151
|
-
jiradc issue update
|
|
152
|
-
jiradc issue update
|
|
147
|
+
jiradc issue update PROJ-123 --summary "New title" --priority High
|
|
148
|
+
jiradc issue update PROJ-123 --assignee me
|
|
149
|
+
jiradc issue update PROJ-123 --labels backend,urgent # set mode
|
|
150
|
+
jiradc issue update PROJ-123 --labels +urgent,-backend # mutate mode
|
|
151
|
+
jiradc issue update PROJ-123 --components +Frontend
|
|
152
|
+
jiradc issue update PROJ-123 --fix-versions 1.0,2.0
|
|
153
153
|
|
|
154
154
|
# Link multiple issues to an epic in one call
|
|
155
|
-
jiradc issue link-epic
|
|
155
|
+
jiradc issue link-epic PROJ-456 PROJ-457 PROJ-458 --epic PROJ-100
|
|
156
156
|
|
|
157
157
|
# Add a comment
|
|
158
|
-
jiradc issue comment add
|
|
158
|
+
jiradc issue comment add PROJ-123 --body "Fixed in commit abc123"
|
|
159
159
|
|
|
160
160
|
# Delete a comment
|
|
161
|
-
jiradc issue comment delete
|
|
161
|
+
jiradc issue comment delete PROJ-123 --id 12345
|
|
162
162
|
|
|
163
163
|
# Link two issues
|
|
164
|
-
jiradc issue link
|
|
164
|
+
jiradc issue link PROJ-123 PROJ-456 --type "blocks"
|
|
165
165
|
|
|
166
166
|
# Log work
|
|
167
|
-
jiradc issue worklog add
|
|
167
|
+
jiradc issue worklog add PROJ-123 --time "2h 30m" --comment "Code review"
|
|
168
168
|
|
|
169
169
|
# List active sprints
|
|
170
170
|
jiradc sprint list 42 --state active
|
|
@@ -176,11 +176,11 @@ jiradc sprint issues 42 100
|
|
|
176
176
|
jiradc field search --query "story points"
|
|
177
177
|
|
|
178
178
|
# Clone an issue with subtasks
|
|
179
|
-
jiradc issue clone
|
|
179
|
+
jiradc issue clone PROJ-123
|
|
180
180
|
|
|
181
181
|
# Get dev status (linked branches, PRs)
|
|
182
|
-
jiradc issue dev-status
|
|
182
|
+
jiradc issue dev-status PROJ-123
|
|
183
183
|
|
|
184
184
|
# List components for a project
|
|
185
|
-
jiradc component list --project
|
|
185
|
+
jiradc component list --project PROJ
|
|
186
186
|
```
|
package/dist/index.js
CHANGED
|
@@ -237,6 +237,24 @@ var CliAuthError = class extends Error {
|
|
|
237
237
|
this.name = "CliAuthError";
|
|
238
238
|
}
|
|
239
239
|
};
|
|
240
|
+
var NOT_FOUND_RECOVERY = "Verify the id/key, then check your access.";
|
|
241
|
+
var NOT_FOUND_MESSAGE = "Not found: it may not exist, or you may not have permission to see it";
|
|
242
|
+
var CliNotFoundError = class extends Error {
|
|
243
|
+
recovery;
|
|
244
|
+
constructor(message, recovery = NOT_FOUND_RECOVERY) {
|
|
245
|
+
super(message);
|
|
246
|
+
this.name = "CliNotFoundError";
|
|
247
|
+
this.recovery = recovery;
|
|
248
|
+
}
|
|
249
|
+
};
|
|
250
|
+
var SubcommandRequiredError = class extends Error {
|
|
251
|
+
subcommands;
|
|
252
|
+
constructor(commandPath3, subcommands) {
|
|
253
|
+
super(`'${commandPath3}' requires a subcommand`);
|
|
254
|
+
this.name = "SubcommandRequiredError";
|
|
255
|
+
this.subcommands = subcommands;
|
|
256
|
+
}
|
|
257
|
+
};
|
|
240
258
|
var TYPE_EXIT = {
|
|
241
259
|
usage: EXIT.USAGE,
|
|
242
260
|
not_found: EXIT.NOT_FOUND,
|
|
@@ -245,10 +263,55 @@ var TYPE_EXIT = {
|
|
|
245
263
|
auth: EXIT.AUTH,
|
|
246
264
|
rate_limited: EXIT.GENERIC,
|
|
247
265
|
server: EXIT.GENERIC,
|
|
266
|
+
timeout: EXIT.GENERIC,
|
|
248
267
|
network: EXIT.GENERIC,
|
|
249
268
|
unknown: EXIT.GENERIC
|
|
250
269
|
};
|
|
251
|
-
var
|
|
270
|
+
var TRANSPORT_CODES = {
|
|
271
|
+
/** Our own timeout fired: connected (or tried to), no response in time. */
|
|
272
|
+
readTimeout: ["ECONNABORTED"],
|
|
273
|
+
/** The OS gave up establishing the connection. */
|
|
274
|
+
connectTimeout: ["ETIMEDOUT"],
|
|
275
|
+
/** No such host, or DNS itself is unavailable. */
|
|
276
|
+
unresolved: ["ENOTFOUND", "EAI_AGAIN"],
|
|
277
|
+
/** Host is there, nothing is listening on that port. */
|
|
278
|
+
refused: ["ECONNREFUSED"],
|
|
279
|
+
/** Established, then died mid-flight. */
|
|
280
|
+
dropped: ["ECONNRESET", "EPIPE"]
|
|
281
|
+
};
|
|
282
|
+
function humanMs(ms) {
|
|
283
|
+
return ms % 1e3 === 0 ? `${ms / 1e3}s` : `${ms}ms`;
|
|
284
|
+
}
|
|
285
|
+
function targetHost(err) {
|
|
286
|
+
const config = err?.config;
|
|
287
|
+
const raw = config?.baseURL ?? config?.url;
|
|
288
|
+
if (raw === void 0 || raw === "")
|
|
289
|
+
return void 0;
|
|
290
|
+
try {
|
|
291
|
+
return new URL(raw).host;
|
|
292
|
+
} catch {
|
|
293
|
+
return void 0;
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
function configuredTimeoutMs(err) {
|
|
297
|
+
const t = err?.config?.timeout;
|
|
298
|
+
return typeof t === "number" && t > 0 ? t : void 0;
|
|
299
|
+
}
|
|
300
|
+
function retryAfterSeconds(err) {
|
|
301
|
+
const headers = err?.response?.headers;
|
|
302
|
+
const raw = headers?.["retry-after"];
|
|
303
|
+
if (raw === void 0 || raw === "")
|
|
304
|
+
return void 0;
|
|
305
|
+
const seconds = Number(raw);
|
|
306
|
+
if (Number.isFinite(seconds))
|
|
307
|
+
return Math.max(0, Math.round(seconds));
|
|
308
|
+
if (typeof raw !== "string")
|
|
309
|
+
return void 0;
|
|
310
|
+
const at = Date.parse(raw);
|
|
311
|
+
if (Number.isNaN(at))
|
|
312
|
+
return void 0;
|
|
313
|
+
return Math.max(0, Math.round((at - Date.now()) / 1e3));
|
|
314
|
+
}
|
|
252
315
|
function httpStatus(err) {
|
|
253
316
|
const e = err;
|
|
254
317
|
return e?.response?.status ?? e?.statusCode;
|
|
@@ -285,9 +348,21 @@ function normalize(err, opts) {
|
|
|
285
348
|
retryable: false
|
|
286
349
|
};
|
|
287
350
|
}
|
|
351
|
+
if (err instanceof SubcommandRequiredError) {
|
|
352
|
+
return {
|
|
353
|
+
type: "usage",
|
|
354
|
+
message,
|
|
355
|
+
recovery: `Re-run with one of these subcommands: ${err.subcommands.join(", ")}.`,
|
|
356
|
+
retryable: false,
|
|
357
|
+
detail: { subcommands: err.subcommands }
|
|
358
|
+
};
|
|
359
|
+
}
|
|
288
360
|
if (err instanceof CliAuthError) {
|
|
289
361
|
return { type: "auth", message: message || "Missing credentials", recovery: opts.authRecovery, retryable: false };
|
|
290
362
|
}
|
|
363
|
+
if (err instanceof CliNotFoundError) {
|
|
364
|
+
return { type: "not_found", message, recovery: err.recovery, retryable: false };
|
|
365
|
+
}
|
|
291
366
|
const status = httpStatus(err);
|
|
292
367
|
const detail = responseDetail(err);
|
|
293
368
|
if (status !== void 0) {
|
|
@@ -296,7 +371,7 @@ function normalize(err, opts) {
|
|
|
296
371
|
return {
|
|
297
372
|
type: "usage",
|
|
298
373
|
status,
|
|
299
|
-
message: "Bad request
|
|
374
|
+
message: "Bad request",
|
|
300
375
|
recovery: "Check parameter values (ids, keys, query syntax) against the API.",
|
|
301
376
|
retryable: false,
|
|
302
377
|
detail
|
|
@@ -305,7 +380,7 @@ function normalize(err, opts) {
|
|
|
305
380
|
return {
|
|
306
381
|
type: "auth",
|
|
307
382
|
status,
|
|
308
|
-
message: "Authentication failed
|
|
383
|
+
message: "Authentication failed",
|
|
309
384
|
recovery: opts.authRecovery,
|
|
310
385
|
retryable: false
|
|
311
386
|
};
|
|
@@ -313,7 +388,7 @@ function normalize(err, opts) {
|
|
|
313
388
|
return {
|
|
314
389
|
type: "forbidden",
|
|
315
390
|
status,
|
|
316
|
-
message: "Forbidden
|
|
391
|
+
message: "Forbidden",
|
|
317
392
|
recovery: `Your ${opts.service} account lacks permission for this operation; check token scope and resource permissions.`,
|
|
318
393
|
retryable: false,
|
|
319
394
|
detail
|
|
@@ -322,8 +397,8 @@ function normalize(err, opts) {
|
|
|
322
397
|
return {
|
|
323
398
|
type: "not_found",
|
|
324
399
|
status,
|
|
325
|
-
message:
|
|
326
|
-
recovery:
|
|
400
|
+
message: NOT_FOUND_MESSAGE,
|
|
401
|
+
recovery: NOT_FOUND_RECOVERY,
|
|
327
402
|
retryable: false,
|
|
328
403
|
detail
|
|
329
404
|
};
|
|
@@ -331,26 +406,29 @@ function normalize(err, opts) {
|
|
|
331
406
|
return {
|
|
332
407
|
type: "conflict",
|
|
333
408
|
status,
|
|
334
|
-
message: "Conflict
|
|
409
|
+
message: "Conflict",
|
|
335
410
|
recovery: "The resource changed or already exists; re-fetch current state and retry.",
|
|
336
411
|
retryable: false,
|
|
337
412
|
detail
|
|
338
413
|
};
|
|
339
|
-
case 429:
|
|
414
|
+
case 429: {
|
|
415
|
+
const wait = retryAfterSeconds(err);
|
|
340
416
|
return {
|
|
341
417
|
type: "rate_limited",
|
|
342
418
|
status,
|
|
343
|
-
message:
|
|
344
|
-
recovery:
|
|
345
|
-
retryable: true
|
|
419
|
+
message: `${opts.service} is rate limiting these requests`,
|
|
420
|
+
recovery: wait === void 0 ? `${opts.service} did not say how long to wait. Pause a few seconds before retrying, and make fewer requests at once.` : `${opts.service} asked for a ${wait}s pause before the next request. Wait at least that long, then retry.`,
|
|
421
|
+
retryable: true,
|
|
422
|
+
...wait === void 0 ? {} : { detail: { retryAfterSeconds: wait } }
|
|
346
423
|
};
|
|
424
|
+
}
|
|
347
425
|
}
|
|
348
426
|
if (status >= 500) {
|
|
349
427
|
return {
|
|
350
428
|
type: "server",
|
|
351
429
|
status,
|
|
352
|
-
message:
|
|
353
|
-
recovery: `${opts.service}
|
|
430
|
+
message: status === 503 ? `${opts.service} returned 503 (service unavailable)` : `${opts.service} returned ${status}`,
|
|
431
|
+
recovery: status === 503 ? `${opts.service} is temporarily refusing work. Retry shortly.` : `${opts.service} failed to complete the request. Usually temporary, so retry. If it persists, the request itself may be at fault.`,
|
|
354
432
|
retryable: true,
|
|
355
433
|
detail
|
|
356
434
|
};
|
|
@@ -365,15 +443,59 @@ function normalize(err, opts) {
|
|
|
365
443
|
};
|
|
366
444
|
}
|
|
367
445
|
const code = errorCode(err);
|
|
368
|
-
|
|
446
|
+
const transport = classifyTransport(err, code, message, opts);
|
|
447
|
+
if (transport)
|
|
448
|
+
return transport;
|
|
449
|
+
return { type: "unknown", message, recovery: "Unexpected error; inspect the message.", retryable: false };
|
|
450
|
+
}
|
|
451
|
+
function classifyTransport(err, code, message, opts) {
|
|
452
|
+
const matches = (codes) => code !== void 0 && codes.includes(code) || codes.some((c) => message.includes(c));
|
|
453
|
+
const host = targetHost(err);
|
|
454
|
+
const where = host ?? opts.service;
|
|
455
|
+
const urlVar = opts.urlEnvVar ?? "the base-URL environment variable";
|
|
456
|
+
if (matches(TRANSPORT_CODES.readTimeout)) {
|
|
457
|
+
const limit = configuredTimeoutMs(err);
|
|
458
|
+
return {
|
|
459
|
+
type: "timeout",
|
|
460
|
+
message: `${opts.service} did not respond${limit === void 0 ? " in time" : ` within ${humanMs(limit)}`}`,
|
|
461
|
+
recovery: `The request reached ${opts.service} but no response came back in time. Usually the server is busy or the query is too large. Retry, or ask for less: fewer results per page, fewer fields, a narrower query.`,
|
|
462
|
+
retryable: true
|
|
463
|
+
};
|
|
464
|
+
}
|
|
465
|
+
if (matches(TRANSPORT_CODES.connectTimeout)) {
|
|
466
|
+
const limit = configuredTimeoutMs(err);
|
|
467
|
+
return {
|
|
468
|
+
type: "timeout",
|
|
469
|
+
message: `Could not open a connection to ${where}${limit === void 0 ? "" : ` within ${humanMs(limit)}`}`,
|
|
470
|
+
recovery: `The host did not accept a connection in time. If it is reachable at all it is likely overloaded, so retry. If this repeats, confirm ${urlVar} points at a host this machine can reach.`,
|
|
471
|
+
retryable: true
|
|
472
|
+
};
|
|
473
|
+
}
|
|
474
|
+
if (matches(TRANSPORT_CODES.unresolved)) {
|
|
475
|
+
return {
|
|
476
|
+
type: "network",
|
|
477
|
+
message: `The host ${where} does not resolve`,
|
|
478
|
+
recovery: `${urlVar} points at a hostname that cannot be looked up from this machine. Check it for a typo. Retrying will not help until it changes.`,
|
|
479
|
+
retryable: false
|
|
480
|
+
};
|
|
481
|
+
}
|
|
482
|
+
if (matches(TRANSPORT_CODES.refused)) {
|
|
483
|
+
return {
|
|
484
|
+
type: "network",
|
|
485
|
+
message: `Nothing accepted a connection at ${where}`,
|
|
486
|
+
recovery: `The host resolved but refused the connection, usually a wrong port or a service that is not running. Retrying will not help until that changes.`,
|
|
487
|
+
retryable: false
|
|
488
|
+
};
|
|
489
|
+
}
|
|
490
|
+
if (matches(TRANSPORT_CODES.dropped)) {
|
|
369
491
|
return {
|
|
370
492
|
type: "network",
|
|
371
|
-
message: `
|
|
372
|
-
recovery:
|
|
493
|
+
message: `The connection to ${opts.service} closed before a response arrived`,
|
|
494
|
+
recovery: `The connection dropped mid-request. This is usually a blip, so retry.`,
|
|
373
495
|
retryable: true
|
|
374
496
|
};
|
|
375
497
|
}
|
|
376
|
-
return
|
|
498
|
+
return void 0;
|
|
377
499
|
}
|
|
378
500
|
function classifyError(err, opts) {
|
|
379
501
|
const base = normalize(err, opts);
|
|
@@ -410,8 +532,30 @@ function routeErrors(cmd) {
|
|
|
410
532
|
cmd.configureOutput({ writeErr: () => void 0 });
|
|
411
533
|
cmd.commands.forEach(routeErrors);
|
|
412
534
|
}
|
|
535
|
+
function commandPath2(cmd) {
|
|
536
|
+
const parts = [];
|
|
537
|
+
let cur = cmd;
|
|
538
|
+
while (cur) {
|
|
539
|
+
parts.unshift(cur.name());
|
|
540
|
+
cur = cur.parent;
|
|
541
|
+
}
|
|
542
|
+
return parts.join(" ");
|
|
543
|
+
}
|
|
544
|
+
function attachSubcommandGuards(cmd) {
|
|
545
|
+
cmd.commands.forEach(attachSubcommandGuards);
|
|
546
|
+
if (cmd.commands.length === 0)
|
|
547
|
+
return;
|
|
548
|
+
const hasAction = Boolean(cmd._actionHandler);
|
|
549
|
+
if (hasAction)
|
|
550
|
+
return;
|
|
551
|
+
cmd.action(() => {
|
|
552
|
+
const names = cmd.commands.map((c) => c.name()).filter((name) => name !== "help");
|
|
553
|
+
throw new SubcommandRequiredError(commandPath2(cmd), names);
|
|
554
|
+
});
|
|
555
|
+
}
|
|
413
556
|
async function runCli(program, opts) {
|
|
414
557
|
routeErrors(program);
|
|
558
|
+
attachSubcommandGuards(program);
|
|
415
559
|
try {
|
|
416
560
|
await program.parseAsync();
|
|
417
561
|
} catch (err) {
|
|
@@ -962,9 +1106,9 @@ function create(parent) {
|
|
|
962
1106
|
const cmd = parent.command("create").description("Create a new component in a project").requiredOption("--project <key>", "Project key (e.g., AI)", text).requiredOption("--name <name>", "Component name", text).option("--lead <username>", "Username of the component lead", text).addOption(new Option3("--assignee-type <type>", "Assignee strategy").choices(ASSIGNEE_TYPES));
|
|
963
1107
|
textOrFileOption(cmd, "description", { description: "Component description" });
|
|
964
1108
|
examples(cmd, [
|
|
965
|
-
"--project
|
|
966
|
-
'--project
|
|
967
|
-
"--project
|
|
1109
|
+
"--project PROJ --name Backend",
|
|
1110
|
+
'--project PROJ --name Frontend --description "UI work" --lead jsmith',
|
|
1111
|
+
"--project PROJ --name Infra --assignee-type COMPONENT_LEAD --lead jsmith"
|
|
968
1112
|
]);
|
|
969
1113
|
cmd.action(
|
|
970
1114
|
async (opts) => {
|
|
@@ -1018,7 +1162,7 @@ function issueCount(parent) {
|
|
|
1018
1162
|
// src/commands/component/list.ts
|
|
1019
1163
|
function list2(parent) {
|
|
1020
1164
|
const cmd = parent.command("list").description("List all components for a project").requiredOption("--project <key>", "Project key (e.g., AI)", text);
|
|
1021
|
-
examples(cmd, ["--project
|
|
1165
|
+
examples(cmd, ["--project PROJ"]);
|
|
1022
1166
|
cmd.action(async (opts) => {
|
|
1023
1167
|
const client = getClient();
|
|
1024
1168
|
const result = await client.components.list({ projectKeyOrId: opts.project });
|
|
@@ -1065,9 +1209,9 @@ function update(parent) {
|
|
|
1065
1209
|
function registerComponentCommands(program) {
|
|
1066
1210
|
const component = program.command("component").description("Project component operations");
|
|
1067
1211
|
examples(component, [
|
|
1068
|
-
"list --project
|
|
1212
|
+
"list --project PROJ",
|
|
1069
1213
|
"get 11289",
|
|
1070
|
-
"create --project
|
|
1214
|
+
"create --project PROJ --name Backend",
|
|
1071
1215
|
"update 11289 --name Backend",
|
|
1072
1216
|
"delete 11289 --move-issues-to 11290",
|
|
1073
1217
|
"issue-count 11289"
|
|
@@ -1737,7 +1881,7 @@ function link(parent) {
|
|
|
1737
1881
|
const cmd = parent.command("link").description("Link two issues together").requiredOption("--type <name>", "Link type name (e.g., 'Blocks', 'Duplicate', 'Relates')", text).requiredOption("--from <key>", 'Source issue key (e.g., the issue that "blocks")', issueKey).requiredOption("--to <key>", 'Target issue key (e.g., the issue that "is blocked by")', issueKey);
|
|
1738
1882
|
commentOption(cmd, { description: "Optional comment" });
|
|
1739
1883
|
examples(cmd, [
|
|
1740
|
-
"--type Relates --from
|
|
1884
|
+
"--type Relates --from PROJ-154 --to PROJ-149",
|
|
1741
1885
|
["--type Blocks --from PROJ-456 --to PROJ-123", "PROJ-456 blocks PROJ-123"]
|
|
1742
1886
|
]);
|
|
1743
1887
|
cmd.action(async (opts) => {
|
|
@@ -2411,16 +2555,16 @@ function assertAtLeastOne(opts, keys) {
|
|
|
2411
2555
|
|
|
2412
2556
|
// src/commands/xray/execution/add.ts
|
|
2413
2557
|
function add(parent) {
|
|
2414
|
-
const cmd = parent.command("add").description("Add tests to a Test Execution, directly (--test) and/or by expanding Test Sets (--set)").argument("<execKey>", "Test Execution issue key (e.g.
|
|
2558
|
+
const cmd = parent.command("add").description("Add tests to a Test Execution, directly (--test) and/or by expanding Test Sets (--set)").argument("<execKey>", "Test Execution issue key (e.g. PROJ-200)", issueKey).option("--test <keys>", "Comma-separated test issue keys to add (e.g. PROJ-1,PROJ-2)", keyList).option(
|
|
2415
2559
|
"--set <keys>",
|
|
2416
|
-
"Comma-separated Test Set keys; each set's current tests are added to the execution (e.g.
|
|
2560
|
+
"Comma-separated Test Set keys; each set's current tests are added to the execution (e.g. PROJ-300)",
|
|
2417
2561
|
keyList
|
|
2418
2562
|
);
|
|
2419
2563
|
examples(cmd, [
|
|
2420
|
-
"
|
|
2421
|
-
"
|
|
2422
|
-
"
|
|
2423
|
-
"
|
|
2564
|
+
"PROJ-200 --test PROJ-1",
|
|
2565
|
+
"PROJ-200 --test PROJ-1,PROJ-2",
|
|
2566
|
+
"PROJ-200 --set PROJ-300",
|
|
2567
|
+
"PROJ-200 --test PROJ-1 --set PROJ-300"
|
|
2424
2568
|
]);
|
|
2425
2569
|
cmd.action(async (execKey, opts) => {
|
|
2426
2570
|
assertAtLeastOne(opts, ["test", "set"]);
|
|
@@ -2477,8 +2621,8 @@ function create7(parent) {
|
|
|
2477
2621
|
const cmd = parent.command("create").description("Create a new Xray Test Execution issue").requiredOption("--project <key>", "Project key (e.g. AI)", text).requiredOption("--summary <text>", "Test Execution summary (title)", text);
|
|
2478
2622
|
textOrFileOption(cmd, "description", { description: "Test Execution description" });
|
|
2479
2623
|
examples(cmd, [
|
|
2480
|
-
'--project
|
|
2481
|
-
'--project
|
|
2624
|
+
'--project PROJ --summary "Sprint 42 regression run"',
|
|
2625
|
+
'--project PROJ --summary "Smoke run" --description "Post-deploy smoke"'
|
|
2482
2626
|
]);
|
|
2483
2627
|
cmd.action(async (opts) => {
|
|
2484
2628
|
const description = resolveTextOrFile(opts, "description", { required: false });
|
|
@@ -2495,8 +2639,8 @@ function create7(parent) {
|
|
|
2495
2639
|
|
|
2496
2640
|
// src/commands/xray/execution/delete.ts
|
|
2497
2641
|
function deleteExecution(parent) {
|
|
2498
|
-
const cmd = parent.command("delete").description("Delete an Xray Test Execution issue").argument("<execKey>", "Test Execution issue key (e.g.
|
|
2499
|
-
examples(cmd, ["
|
|
2642
|
+
const cmd = parent.command("delete").description("Delete an Xray Test Execution issue").argument("<execKey>", "Test Execution issue key (e.g. PROJ-200)", issueKey);
|
|
2643
|
+
examples(cmd, ["PROJ-200"]);
|
|
2500
2644
|
cmd.action(async (execKey) => {
|
|
2501
2645
|
const client = getClient();
|
|
2502
2646
|
await deleteXrayIssue(client, execKey);
|
|
@@ -2508,8 +2652,8 @@ function deleteExecution(parent) {
|
|
|
2508
2652
|
function list8(parent) {
|
|
2509
2653
|
const cmd = parent.command("list").description(
|
|
2510
2654
|
"List Test Executions that contain a given test (inverse view). For the tests inside an execution, use: xray test list --execution <key>."
|
|
2511
|
-
).requiredOption("--test <key>", "Test issue key whose executions to list (e.g.
|
|
2512
|
-
examples(cmd, ["--test
|
|
2655
|
+
).requiredOption("--test <key>", "Test issue key whose executions to list (e.g. PROJ-584)", issueKey);
|
|
2656
|
+
examples(cmd, ["--test PROJ-584"]);
|
|
2513
2657
|
cmd.action(async (opts) => {
|
|
2514
2658
|
const client = getClient();
|
|
2515
2659
|
const executions = await client.xrayTests.getTestExecutions({ testKey: opts.test });
|
|
@@ -2519,8 +2663,8 @@ function list8(parent) {
|
|
|
2519
2663
|
|
|
2520
2664
|
// src/commands/xray/execution/remove.ts
|
|
2521
2665
|
function remove(parent) {
|
|
2522
|
-
const cmd = parent.command("remove").description("Remove tests from a Test Execution").argument("<execKey>", "Test Execution issue key (e.g.
|
|
2523
|
-
examples(cmd, ["
|
|
2666
|
+
const cmd = parent.command("remove").description("Remove tests from a Test Execution").argument("<execKey>", "Test Execution issue key (e.g. PROJ-200)", issueKey).requiredOption("--test <keys>", "Comma-separated test issue keys to remove (e.g. PROJ-1,PROJ-2)", keyList);
|
|
2667
|
+
examples(cmd, ["PROJ-200 --test PROJ-1", "PROJ-200 --test PROJ-1,PROJ-2"]);
|
|
2524
2668
|
cmd.action(async (execKey, opts) => {
|
|
2525
2669
|
const client = getClient();
|
|
2526
2670
|
const result = await client.testExecutions.removeTests({ execKey, keys: opts.test });
|
|
@@ -2530,9 +2674,9 @@ function remove(parent) {
|
|
|
2530
2674
|
|
|
2531
2675
|
// src/commands/xray/execution/update.ts
|
|
2532
2676
|
function update6(parent) {
|
|
2533
|
-
const cmd = parent.command("update").description("Update an Xray Test Execution issue").argument("<execKey>", "Test Execution issue key (e.g.
|
|
2677
|
+
const cmd = parent.command("update").description("Update an Xray Test Execution issue").argument("<execKey>", "Test Execution issue key (e.g. PROJ-200)", issueKey).option("--summary <text>", "New summary (title)", text);
|
|
2534
2678
|
textOrFileOption(cmd, "description", { description: "New Test Execution description" });
|
|
2535
|
-
examples(cmd, ['
|
|
2679
|
+
examples(cmd, ['PROJ-200 --summary "Updated execution title"', 'PROJ-200 --description "Post-hotfix run"']);
|
|
2536
2680
|
cmd.action(async (execKey, opts) => {
|
|
2537
2681
|
const description = resolveTextOrFile(opts, "description", { required: false });
|
|
2538
2682
|
const client = getClient();
|
|
@@ -2547,9 +2691,9 @@ function registerExecutionCommands(xray) {
|
|
|
2547
2691
|
"Xray Test Execution issue management (CRUD, membership). To list tests inside an execution, use: xray test list --execution <key>."
|
|
2548
2692
|
);
|
|
2549
2693
|
examples(execution2, [
|
|
2550
|
-
'create --project
|
|
2551
|
-
"add
|
|
2552
|
-
"list --test
|
|
2694
|
+
'create --project PROJ --summary "Sprint 42 regression run"',
|
|
2695
|
+
"add PROJ-200 --test PROJ-1,PROJ-2",
|
|
2696
|
+
"list --test PROJ-584"
|
|
2553
2697
|
]);
|
|
2554
2698
|
create7(execution2);
|
|
2555
2699
|
update6(execution2);
|
|
@@ -2564,7 +2708,7 @@ import { writeFileSync as writeFileSync2 } from "fs";
|
|
|
2564
2708
|
import { basename, join as join5 } from "path";
|
|
2565
2709
|
function feature(parent) {
|
|
2566
2710
|
const cmd = parent.command("feature").description("Export Gherkin .feature files for the given test keys").requiredOption("--test <keys>", "Comma-separated Test, Set, Plan, or Execution issue keys", keyList).option("--output <path>", "Write the exported file to this path (default: ./<filename> from response)", text).option("--zip", "Request a zip archive instead of a single .feature file");
|
|
2567
|
-
examples(cmd, ["--test
|
|
2711
|
+
examples(cmd, ["--test PROJ-584 --output ai-584.feature"]);
|
|
2568
2712
|
cmd.action(async (opts) => {
|
|
2569
2713
|
const client = getClient();
|
|
2570
2714
|
const { data, filename } = await client.xrayExport.exportFeature({
|
|
@@ -2602,8 +2746,8 @@ function registerFieldCommands2(xray) {
|
|
|
2602
2746
|
|
|
2603
2747
|
// src/commands/xray/folder/add.ts
|
|
2604
2748
|
function add2(parent) {
|
|
2605
|
-
const cmd = parent.command("add").description("Add tests to a folder in the test repository").argument("<folderId>", "Folder id (from folder list)", positiveInt).requiredOption("--project <key>", "Project key (e.g. QA)", text).requiredOption("--test <keys>", "Comma-separated test issue keys to add (e.g.
|
|
2606
|
-
examples(cmd, ["818 --project
|
|
2749
|
+
const cmd = parent.command("add").description("Add tests to a folder in the test repository").argument("<folderId>", "Folder id (from folder list)", positiveInt).requiredOption("--project <key>", "Project key (e.g. QA)", text).requiredOption("--test <keys>", "Comma-separated test issue keys to add (e.g. PROJ-1,PROJ-2)", keyList);
|
|
2750
|
+
examples(cmd, ["818 --project PROJ --test PROJ-1", "818 --project PROJ --test PROJ-1,PROJ-2,PROJ-3"]);
|
|
2607
2751
|
cmd.action(async (folderId, opts) => {
|
|
2608
2752
|
const client = getClient();
|
|
2609
2753
|
const result = await client.testRepository.updateFolderTests({
|
|
@@ -2619,9 +2763,9 @@ function add2(parent) {
|
|
|
2619
2763
|
function create8(parent) {
|
|
2620
2764
|
const cmd = parent.command("create").description("Create a new folder in the test repository").requiredOption("--project <key>", "Project key (e.g. QA)", text).option("--parent-id <id>", "Parent folder id (-1 = root)", integer, -1).requiredOption("--name <text>", "Folder name", text);
|
|
2621
2765
|
examples(cmd, [
|
|
2622
|
-
"--project
|
|
2623
|
-
'--project
|
|
2624
|
-
'--project
|
|
2766
|
+
"--project PROJ --name Smoke",
|
|
2767
|
+
'--project PROJ --parent-id -1 --name "Regression Suite"',
|
|
2768
|
+
'--project PROJ --parent-id 818 --name "Sub-folder"'
|
|
2625
2769
|
]);
|
|
2626
2770
|
cmd.action(async (opts) => {
|
|
2627
2771
|
const client = getClient();
|
|
@@ -2637,7 +2781,7 @@ function create8(parent) {
|
|
|
2637
2781
|
// src/commands/xray/folder/delete.ts
|
|
2638
2782
|
function deleteFolder(parent) {
|
|
2639
2783
|
const cmd = parent.command("delete").description("Delete a folder from the test repository").argument("<folderId>", "Folder id to delete (from folder list)", positiveInt).requiredOption("--project <key>", "Project key (e.g. QA)", text);
|
|
2640
|
-
examples(cmd, ["818 --project
|
|
2784
|
+
examples(cmd, ["818 --project PROJ", "42 --project PROJ"]);
|
|
2641
2785
|
cmd.action(async (folderId, opts) => {
|
|
2642
2786
|
const client = getClient();
|
|
2643
2787
|
await client.testRepository.deleteFolder({ projectKey: opts.project, folderId });
|
|
@@ -2648,7 +2792,7 @@ function deleteFolder(parent) {
|
|
|
2648
2792
|
// src/commands/xray/folder/list.ts
|
|
2649
2793
|
function list10(parent) {
|
|
2650
2794
|
const cmd = parent.command("list").description("List the test repository folder tree for a project").requiredOption("--project <key>", "Project key (e.g. QA)", text);
|
|
2651
|
-
examples(cmd, ["--project
|
|
2795
|
+
examples(cmd, ["--project PROJ", "--project PROJ"]);
|
|
2652
2796
|
cmd.action(async (opts) => {
|
|
2653
2797
|
const client = getClient();
|
|
2654
2798
|
const tree = await client.testRepository.getFolders({ projectKey: opts.project });
|
|
@@ -2658,8 +2802,8 @@ function list10(parent) {
|
|
|
2658
2802
|
|
|
2659
2803
|
// src/commands/xray/folder/remove.ts
|
|
2660
2804
|
function remove2(parent) {
|
|
2661
|
-
const cmd = parent.command("remove").description("Remove tests from a folder in the test repository").argument("<folderId>", "Folder id (from folder list)", positiveInt).requiredOption("--project <key>", "Project key (e.g. QA)", text).requiredOption("--test <keys>", "Comma-separated test issue keys to remove (e.g.
|
|
2662
|
-
examples(cmd, ["818 --project
|
|
2805
|
+
const cmd = parent.command("remove").description("Remove tests from a folder in the test repository").argument("<folderId>", "Folder id (from folder list)", positiveInt).requiredOption("--project <key>", "Project key (e.g. QA)", text).requiredOption("--test <keys>", "Comma-separated test issue keys to remove (e.g. PROJ-1,PROJ-2)", keyList);
|
|
2806
|
+
examples(cmd, ["818 --project PROJ --test PROJ-1", "818 --project PROJ --test PROJ-1,PROJ-2"]);
|
|
2663
2807
|
cmd.action(async (folderId, opts) => {
|
|
2664
2808
|
const client = getClient();
|
|
2665
2809
|
const result = await client.testRepository.updateFolderTests({
|
|
@@ -2675,9 +2819,9 @@ function remove2(parent) {
|
|
|
2675
2819
|
function update7(parent) {
|
|
2676
2820
|
const cmd = parent.command("update").description("Rename or reorder a folder in the test repository").argument("<folderId>", "Folder id (from folder list)", positiveInt).requiredOption("--project <key>", "Project key (e.g. QA)", text).option("--name <text>", "New folder name", text).option("--rank <id>", "New folder rank/position", positiveInt);
|
|
2677
2821
|
examples(cmd, [
|
|
2678
|
-
'818 --project
|
|
2679
|
-
"818 --project
|
|
2680
|
-
"818 --project
|
|
2822
|
+
'818 --project PROJ --name "New Name"',
|
|
2823
|
+
"818 --project PROJ --rank 2",
|
|
2824
|
+
"818 --project PROJ --name Smoke --rank 1"
|
|
2681
2825
|
]);
|
|
2682
2826
|
cmd.action(async (folderId, opts) => {
|
|
2683
2827
|
if (opts.name === void 0 && opts.rank === void 0) {
|
|
@@ -2699,7 +2843,7 @@ function registerFolderCommands(xray) {
|
|
|
2699
2843
|
const folder = xray.command("folder").description(
|
|
2700
2844
|
"Xray Test Repository folder management (rename/reorder within parent only \u2014 cross-parent moves are UI-only, not supported by the API). To list tests in a folder use: xray test list --folder <id> --project <key>"
|
|
2701
2845
|
);
|
|
2702
|
-
examples(folder, ["list --project
|
|
2846
|
+
examples(folder, ["list --project PROJ", "create --project PROJ --parent-id -1 --name Smoke"]);
|
|
2703
2847
|
list10(folder);
|
|
2704
2848
|
create8(folder);
|
|
2705
2849
|
update7(folder);
|
|
@@ -2730,8 +2874,8 @@ function execution(parent) {
|
|
|
2730
2874
|
issueKey
|
|
2731
2875
|
).option("--plan <key>", "Associate with a Test Plan issue key", issueKey).option("--fix-version <text>", "Fix version to set on the Test Execution", text).option("--revision <text>", "Source control revision", text).option("--environments <text>", "Comma-separated test environment names", text);
|
|
2732
2876
|
examples(cmd, [
|
|
2733
|
-
"--file results.xml --format junit --project
|
|
2734
|
-
"--file results.xml --format junit --execution
|
|
2877
|
+
"--file results.xml --format junit --project PROJ",
|
|
2878
|
+
"--file results.xml --format junit --execution PROJ-100",
|
|
2735
2879
|
"--file results.json --format xray"
|
|
2736
2880
|
]);
|
|
2737
2881
|
cmd.action(
|
|
@@ -2766,7 +2910,7 @@ import { readFileSync as readFileSync5 } from "fs";
|
|
|
2766
2910
|
import { basename as basename3 } from "path";
|
|
2767
2911
|
function feature2(parent) {
|
|
2768
2912
|
const cmd = parent.command("feature").description("Import a Gherkin .feature file into the Xray test repository (multipart)").requiredOption("--file <path>", "Path to the .feature file", filePath).requiredOption("--project <text>", "Project key to import the feature into", text);
|
|
2769
|
-
examples(cmd, ["--file login.feature --project
|
|
2913
|
+
examples(cmd, ["--file login.feature --project PROJ"]);
|
|
2770
2914
|
cmd.action(async (opts) => {
|
|
2771
2915
|
const fileBuffer = readFileSync5(opts.file);
|
|
2772
2916
|
const filename = basename3(opts.file);
|
|
@@ -2789,8 +2933,12 @@ function registerImportCommands(xray) {
|
|
|
2789
2933
|
|
|
2790
2934
|
// src/commands/xray/plan/add.ts
|
|
2791
2935
|
function add3(parent) {
|
|
2792
|
-
const cmd = parent.command("add").description("Add tests and/or executions to a Test Plan").argument("<planKey>", "Test Plan issue key (e.g.
|
|
2793
|
-
examples(cmd, [
|
|
2936
|
+
const cmd = parent.command("add").description("Add tests and/or executions to a Test Plan").argument("<planKey>", "Test Plan issue key (e.g. PROJ-573)", issueKey).option("--test <keys>", "Comma-separated test issue keys to add (e.g. PROJ-1,PROJ-2)", keyList).option("--execution <keys>", "Comma-separated test execution keys to add (e.g. PROJ-200,PROJ-201)", keyList);
|
|
2937
|
+
examples(cmd, [
|
|
2938
|
+
"PROJ-573 --test PROJ-1,PROJ-2",
|
|
2939
|
+
"PROJ-573 --execution PROJ-200",
|
|
2940
|
+
"PROJ-573 --test PROJ-1 --execution PROJ-200"
|
|
2941
|
+
]);
|
|
2794
2942
|
cmd.action(async (planKey, opts) => {
|
|
2795
2943
|
assertAtLeastOne(opts, ["test", "execution"]);
|
|
2796
2944
|
const client = getClient();
|
|
@@ -2807,8 +2955,8 @@ function create9(parent) {
|
|
|
2807
2955
|
const cmd = parent.command("create").description("Create a new Xray Test Plan issue").requiredOption("--project <key>", "Project key (e.g. QA)", text).requiredOption("--summary <text>", "Test Plan summary (title)", text);
|
|
2808
2956
|
textOrFileOption(cmd, "description", { description: "Test Plan description" });
|
|
2809
2957
|
examples(cmd, [
|
|
2810
|
-
'--project
|
|
2811
|
-
'--project
|
|
2958
|
+
'--project PROJ --summary "Q3 regression plan"',
|
|
2959
|
+
'--project PROJ --summary "Sprint 42 plan" --description "Covers all sprint stories"'
|
|
2812
2960
|
]);
|
|
2813
2961
|
cmd.action(async (opts) => {
|
|
2814
2962
|
const description = resolveTextOrFile(opts, "description", { required: false });
|
|
@@ -2825,8 +2973,8 @@ function create9(parent) {
|
|
|
2825
2973
|
|
|
2826
2974
|
// src/commands/xray/plan/delete.ts
|
|
2827
2975
|
function deletePlan(parent) {
|
|
2828
|
-
const cmd = parent.command("delete").description("Delete an Xray Test Plan issue").argument("<planKey>", "Test Plan issue key (e.g.
|
|
2829
|
-
examples(cmd, ["
|
|
2976
|
+
const cmd = parent.command("delete").description("Delete an Xray Test Plan issue").argument("<planKey>", "Test Plan issue key (e.g. PROJ-573)", issueKey);
|
|
2977
|
+
examples(cmd, ["PROJ-573"]);
|
|
2830
2978
|
cmd.action(async (planKey) => {
|
|
2831
2979
|
const client = getClient();
|
|
2832
2980
|
await deleteXrayIssue(client, planKey);
|
|
@@ -2838,8 +2986,8 @@ function deletePlan(parent) {
|
|
|
2838
2986
|
function list11(parent) {
|
|
2839
2987
|
const cmd = parent.command("list").description(
|
|
2840
2988
|
"List Test Plans that contain a given test (inverse view). For the tests inside a plan, use: xray test list --plan <key>. For executions in a plan, use: xray execution list --plan <key>."
|
|
2841
|
-
).requiredOption("--test <key>", "Test issue key whose plans to list (e.g.
|
|
2842
|
-
examples(cmd, ["--test
|
|
2989
|
+
).requiredOption("--test <key>", "Test issue key whose plans to list (e.g. PROJ-574)", issueKey);
|
|
2990
|
+
examples(cmd, ["--test PROJ-574"]);
|
|
2843
2991
|
cmd.action(async (opts) => {
|
|
2844
2992
|
const client = getClient();
|
|
2845
2993
|
const plans = await client.xrayTests.getTestPlans({ testKey: opts.test });
|
|
@@ -2849,8 +2997,12 @@ function list11(parent) {
|
|
|
2849
2997
|
|
|
2850
2998
|
// src/commands/xray/plan/remove.ts
|
|
2851
2999
|
function remove3(parent) {
|
|
2852
|
-
const cmd = parent.command("remove").description("Remove tests and/or executions from a Test Plan").argument("<planKey>", "Test Plan issue key (e.g.
|
|
2853
|
-
examples(cmd, [
|
|
3000
|
+
const cmd = parent.command("remove").description("Remove tests and/or executions from a Test Plan").argument("<planKey>", "Test Plan issue key (e.g. PROJ-573)", issueKey).option("--test <keys>", "Comma-separated test issue keys to remove (e.g. PROJ-1,PROJ-2)", keyList).option("--execution <keys>", "Comma-separated test execution keys to remove (e.g. PROJ-200)", keyList);
|
|
3001
|
+
examples(cmd, [
|
|
3002
|
+
"PROJ-573 --test PROJ-1",
|
|
3003
|
+
"PROJ-573 --execution PROJ-200",
|
|
3004
|
+
"PROJ-573 --test PROJ-1 --execution PROJ-200"
|
|
3005
|
+
]);
|
|
2854
3006
|
cmd.action(async (planKey, opts) => {
|
|
2855
3007
|
assertAtLeastOne(opts, ["test", "execution"]);
|
|
2856
3008
|
const client = getClient();
|
|
@@ -2864,9 +3016,9 @@ function remove3(parent) {
|
|
|
2864
3016
|
|
|
2865
3017
|
// src/commands/xray/plan/update.ts
|
|
2866
3018
|
function update8(parent) {
|
|
2867
|
-
const cmd = parent.command("update").description("Update an Xray Test Plan issue").argument("<planKey>", "Test Plan issue key (e.g.
|
|
3019
|
+
const cmd = parent.command("update").description("Update an Xray Test Plan issue").argument("<planKey>", "Test Plan issue key (e.g. PROJ-573)", issueKey).option("--summary <text>", "New summary (title)", text);
|
|
2868
3020
|
textOrFileOption(cmd, "description", { description: "New Test Plan description" });
|
|
2869
|
-
examples(cmd, ['
|
|
3021
|
+
examples(cmd, ['PROJ-573 --summary "Updated plan title"', 'PROJ-573 --description "Revised scope"']);
|
|
2870
3022
|
cmd.action(async (planKey, opts) => {
|
|
2871
3023
|
const description = resolveTextOrFile(opts, "description", { required: false });
|
|
2872
3024
|
const client = getClient();
|
|
@@ -2881,10 +3033,10 @@ function registerPlanCommands(xray) {
|
|
|
2881
3033
|
"Xray Test Plan issue management (CRUD, membership). To list tests inside a plan, use: xray test list --plan <key>."
|
|
2882
3034
|
);
|
|
2883
3035
|
examples(plan, [
|
|
2884
|
-
'create --project
|
|
2885
|
-
"add
|
|
2886
|
-
"add
|
|
2887
|
-
"list --test
|
|
3036
|
+
'create --project PROJ --summary "Q3 regression plan"',
|
|
3037
|
+
"add PROJ-573 --test PROJ-1,PROJ-2",
|
|
3038
|
+
"add PROJ-573 --test PROJ-1 --execution PROJ-200",
|
|
3039
|
+
"list --test PROJ-574"
|
|
2888
3040
|
]);
|
|
2889
3041
|
create9(plan);
|
|
2890
3042
|
update8(plan);
|
|
@@ -2896,8 +3048,8 @@ function registerPlanCommands(xray) {
|
|
|
2896
3048
|
|
|
2897
3049
|
// src/commands/xray/precondition/add.ts
|
|
2898
3050
|
function add4(parent) {
|
|
2899
|
-
const cmd = parent.command("add").description("Add tests to a Pre-Condition").argument("<preKey>", "Pre-Condition issue key (e.g.
|
|
2900
|
-
examples(cmd, ["
|
|
3051
|
+
const cmd = parent.command("add").description("Add tests to a Pre-Condition").argument("<preKey>", "Pre-Condition issue key (e.g. PROJ-50)", issueKey).requiredOption("--test <keys>", "Comma-separated test issue keys to add (e.g. PROJ-1,PROJ-2)", keyList);
|
|
3052
|
+
examples(cmd, ["PROJ-50 --test PROJ-1", "PROJ-50 --test PROJ-1,PROJ-2,PROJ-3"]);
|
|
2901
3053
|
cmd.action(async (preKey, opts) => {
|
|
2902
3054
|
const client = getClient();
|
|
2903
3055
|
const result = await client.preconditions.addTests({ preKey, keys: opts.test });
|
|
@@ -3005,7 +3157,7 @@ function buildPreconditionCustomFields(map, opts) {
|
|
|
3005
3157
|
// src/commands/xray/precondition/create.ts
|
|
3006
3158
|
function create10(parent) {
|
|
3007
3159
|
const cmd = parent.command("create").description(
|
|
3008
|
-
"Create a new Xray Pre-Condition issue. Note: the Pre-Condition issue type is only available in projects that have it configured (e.g. BD); it is not on
|
|
3160
|
+
"Create a new Xray Pre-Condition issue. Note: the Pre-Condition issue type is only available in projects that have it configured (e.g. BD); it is not on your project scheme."
|
|
3009
3161
|
).requiredOption("--project <key>", "Project key (e.g. BD)", text).requiredOption("--summary <text>", "Pre-Condition summary (title)", text).addOption(
|
|
3010
3162
|
new Option10("--type <type>", "Pre-Condition type").choices(["manual", "generic", "cucumber"]).default("manual")
|
|
3011
3163
|
);
|
|
@@ -3044,8 +3196,8 @@ function create10(parent) {
|
|
|
3044
3196
|
|
|
3045
3197
|
// src/commands/xray/precondition/delete.ts
|
|
3046
3198
|
function deletePrecondition(parent) {
|
|
3047
|
-
const cmd = parent.command("delete").description("Delete an Xray Pre-Condition issue").argument("<preKey>", "Pre-Condition issue key (e.g.
|
|
3048
|
-
examples(cmd, ["
|
|
3199
|
+
const cmd = parent.command("delete").description("Delete an Xray Pre-Condition issue").argument("<preKey>", "Pre-Condition issue key (e.g. PROJ-50)", issueKey);
|
|
3200
|
+
examples(cmd, ["PROJ-50"]);
|
|
3049
3201
|
cmd.action(async (preKey) => {
|
|
3050
3202
|
const client = getClient();
|
|
3051
3203
|
await deleteXrayIssue(client, preKey);
|
|
@@ -3057,8 +3209,8 @@ function deletePrecondition(parent) {
|
|
|
3057
3209
|
function list12(parent) {
|
|
3058
3210
|
const cmd = parent.command("list").description(
|
|
3059
3211
|
"List Pre-Conditions that apply to a given test (inverse view). For the forward view (tests covered by a precondition), use: xray precondition add/remove."
|
|
3060
|
-
).requiredOption("--test <key>", "Test issue key whose pre-conditions to list (e.g.
|
|
3061
|
-
examples(cmd, ["--test
|
|
3212
|
+
).requiredOption("--test <key>", "Test issue key whose pre-conditions to list (e.g. PROJ-584)", issueKey);
|
|
3213
|
+
examples(cmd, ["--test PROJ-584"]);
|
|
3062
3214
|
cmd.action(async (opts) => {
|
|
3063
3215
|
const client = getClient();
|
|
3064
3216
|
const preconditions = await client.xrayTests.getPreconditions({ testKey: opts.test });
|
|
@@ -3068,8 +3220,8 @@ function list12(parent) {
|
|
|
3068
3220
|
|
|
3069
3221
|
// src/commands/xray/precondition/remove.ts
|
|
3070
3222
|
function remove4(parent) {
|
|
3071
|
-
const cmd = parent.command("remove").description("Remove tests from a Pre-Condition").argument("<preKey>", "Pre-Condition issue key (e.g.
|
|
3072
|
-
examples(cmd, ["
|
|
3223
|
+
const cmd = parent.command("remove").description("Remove tests from a Pre-Condition").argument("<preKey>", "Pre-Condition issue key (e.g. PROJ-50)", issueKey).requiredOption("--test <keys>", "Comma-separated test issue keys to remove (e.g. PROJ-1,PROJ-2)", keyList);
|
|
3224
|
+
examples(cmd, ["PROJ-50 --test PROJ-1", "PROJ-50 --test PROJ-1,PROJ-2"]);
|
|
3073
3225
|
cmd.action(async (preKey, opts) => {
|
|
3074
3226
|
const client = getClient();
|
|
3075
3227
|
const result = await client.preconditions.removeTests({ preKey, keys: opts.test });
|
|
@@ -3080,10 +3232,10 @@ function remove4(parent) {
|
|
|
3080
3232
|
// src/commands/xray/precondition/update.ts
|
|
3081
3233
|
import { Option as Option11 } from "commander";
|
|
3082
3234
|
function update9(parent) {
|
|
3083
|
-
const cmd = parent.command("update").description("Update an Xray Pre-Condition issue").argument("<preKey>", "Pre-Condition issue key (e.g.
|
|
3235
|
+
const cmd = parent.command("update").description("Update an Xray Pre-Condition issue").argument("<preKey>", "Pre-Condition issue key (e.g. PROJ-50)", issueKey).option("--summary <text>", "New summary (title)", text).addOption(new Option11("--type <type>", "New Pre-Condition type").choices(["manual", "generic", "cucumber"]));
|
|
3084
3236
|
textOrFileOption(cmd, "condition", { description: "New pre-condition body / definition text" });
|
|
3085
3237
|
textOrFileOption(cmd, "description", { description: "New Pre-Condition issue description" });
|
|
3086
|
-
examples(cmd, ['
|
|
3238
|
+
examples(cmd, ['PROJ-50 --summary "Updated precondition"', 'PROJ-50 --type generic --condition "apiKey != null"']);
|
|
3087
3239
|
cmd.action(
|
|
3088
3240
|
async (preKey, opts) => {
|
|
3089
3241
|
const condition = resolveTextOrFile(opts, "condition", { required: false });
|
|
@@ -3121,12 +3273,12 @@ function update9(parent) {
|
|
|
3121
3273
|
// src/commands/xray/precondition/index.ts
|
|
3122
3274
|
function registerPreconditionCommands(xray) {
|
|
3123
3275
|
const precondition = xray.command("precondition").description(
|
|
3124
|
-
"Xray Pre-Condition issue management (CRUD, membership). Note: Pre-Condition issue type is only available in projects where it is configured (not
|
|
3276
|
+
"Xray Pre-Condition issue management (CRUD, membership). Note: Pre-Condition issue type is only available in projects where it is configured (not your project). To list tests covered by a precondition, use: xray test list --precondition <key>."
|
|
3125
3277
|
);
|
|
3126
3278
|
examples(precondition, [
|
|
3127
3279
|
'create --project BD --summary "User is logged in"',
|
|
3128
|
-
"add
|
|
3129
|
-
"list --test
|
|
3280
|
+
"add PROJ-50 --test PROJ-1,PROJ-2",
|
|
3281
|
+
"list --test PROJ-584"
|
|
3130
3282
|
]);
|
|
3131
3283
|
create10(precondition);
|
|
3132
3284
|
update9(precondition);
|
|
@@ -3148,7 +3300,7 @@ async function resolveRunId(client, o) {
|
|
|
3148
3300
|
// src/commands/xray/run/defect/add.ts
|
|
3149
3301
|
function add5(parent) {
|
|
3150
3302
|
const cmd = parent.command("add").description("Link defect issues to a test run").argument("[runId]", "Test run id (from run list)", positiveInt).requiredOption("--defect <keys>", "Comma-separated defect issue keys to link", keyList).option("--execution <key>", "Test execution issue key (used with --test to resolve run id)", issueKey).option("--test <key>", "Test issue key (used with --execution to resolve run id)", issueKey);
|
|
3151
|
-
examples(cmd, ["42 --defect BUG-1", "--execution
|
|
3303
|
+
examples(cmd, ["42 --defect BUG-1", "--execution PROJ-1 --test PROJ-2 --defect BUG-1,BUG-2"]);
|
|
3152
3304
|
cmd.action(async (runId, opts) => {
|
|
3153
3305
|
const client = getClient();
|
|
3154
3306
|
const id = await resolveRunId(client, { runId, execution: opts.execution, test: opts.test });
|
|
@@ -3160,7 +3312,7 @@ function add5(parent) {
|
|
|
3160
3312
|
// src/commands/xray/run/defect/remove.ts
|
|
3161
3313
|
function remove5(parent) {
|
|
3162
3314
|
const cmd = parent.command("remove").description("Unlink defect issues from a test run (per-key, reports failures without aborting)").argument("[runId]", "Test run id (from run list)", positiveInt).requiredOption("--defect <keys>", "Comma-separated defect issue keys to unlink", keyList).option("--execution <key>", "Test execution issue key (used with --test to resolve run id)", issueKey).option("--test <key>", "Test issue key (used with --execution to resolve run id)", issueKey);
|
|
3163
|
-
examples(cmd, ["42 --defect BUG-1", "--execution
|
|
3315
|
+
examples(cmd, ["42 --defect BUG-1", "--execution PROJ-1 --test PROJ-2 --defect BUG-1,BUG-2"]);
|
|
3164
3316
|
cmd.action(async (runId, opts) => {
|
|
3165
3317
|
const client = getClient();
|
|
3166
3318
|
const id = await resolveRunId(client, { runId, execution: opts.execution, test: opts.test });
|
|
@@ -3194,7 +3346,7 @@ function registerDefectCommands(run) {
|
|
|
3194
3346
|
const defect = run.command("defect").description(
|
|
3195
3347
|
"Manage defects linked to a test run. See also: run update --defect for the one-command fail+link loop."
|
|
3196
3348
|
);
|
|
3197
|
-
examples(defect, ["add --execution
|
|
3349
|
+
examples(defect, ["add --execution PROJ-1 --test PROJ-2 --defect BUG-1", "remove 42 --defect BUG-1"]);
|
|
3198
3350
|
add5(defect);
|
|
3199
3351
|
remove5(defect);
|
|
3200
3352
|
}
|
|
@@ -3220,7 +3372,7 @@ function inferContentType(fp) {
|
|
|
3220
3372
|
}
|
|
3221
3373
|
function add6(parent) {
|
|
3222
3374
|
const cmd = parent.command("add").description("Attach a file as evidence to a test run").argument("[runId]", "Test run id (from run list)", positiveInt).requiredOption("--file <path>", "Path to the file to attach", filePath).option("--execution <key>", "Test execution issue key (used with --test to resolve run id)", issueKey).option("--test <key>", "Test issue key (used with --execution to resolve run id)", issueKey);
|
|
3223
|
-
examples(cmd, ["42 --file screenshot.png", "--execution
|
|
3375
|
+
examples(cmd, ["42 --file screenshot.png", "--execution PROJ-1 --test PROJ-2 --file report.pdf"]);
|
|
3224
3376
|
cmd.action(async (runId, opts) => {
|
|
3225
3377
|
const client = getClient();
|
|
3226
3378
|
const id = await resolveRunId(client, { runId, execution: opts.execution, test: opts.test });
|
|
@@ -3236,7 +3388,7 @@ function add6(parent) {
|
|
|
3236
3388
|
// src/commands/xray/run/evidence/delete.ts
|
|
3237
3389
|
function deleteEvidence(parent) {
|
|
3238
3390
|
const cmd = parent.command("delete").description("Delete an evidence attachment from a test run").argument("[runId]", "Test run id (from run list)", positiveInt).requiredOption("--evidence-id <id>", "Id of the evidence attachment (from evidence list)", positiveInt).option("--execution <key>", "Test execution issue key (used with --test to resolve run id)", issueKey).option("--test <key>", "Test issue key (used with --execution to resolve run id)", issueKey);
|
|
3239
|
-
examples(cmd, ["42 --evidence-id 7", "--execution
|
|
3391
|
+
examples(cmd, ["42 --evidence-id 7", "--execution PROJ-1 --test PROJ-2 --evidence-id 7"]);
|
|
3240
3392
|
cmd.action(async (runId, opts) => {
|
|
3241
3393
|
const client = getClient();
|
|
3242
3394
|
const id = await resolveRunId(client, { runId, execution: opts.execution, test: opts.test });
|
|
@@ -3248,7 +3400,7 @@ function deleteEvidence(parent) {
|
|
|
3248
3400
|
// src/commands/xray/run/evidence/list.ts
|
|
3249
3401
|
function list13(parent) {
|
|
3250
3402
|
const cmd = parent.command("list").description("List evidence (attachments) on a test run").argument("[runId]", "Test run id (from run list)", positiveInt).option("--execution <key>", "Test execution issue key (used with --test to resolve run id)", issueKey).option("--test <key>", "Test issue key (used with --execution to resolve run id)", issueKey);
|
|
3251
|
-
examples(cmd, ["42", "--execution
|
|
3403
|
+
examples(cmd, ["42", "--execution PROJ-1 --test PROJ-2"]);
|
|
3252
3404
|
cmd.action(async (runId, opts) => {
|
|
3253
3405
|
const client = getClient();
|
|
3254
3406
|
const id = await resolveRunId(client, { runId, execution: opts.execution, test: opts.test });
|
|
@@ -3261,7 +3413,7 @@ function list13(parent) {
|
|
|
3261
3413
|
function registerEvidenceCommands(run) {
|
|
3262
3414
|
const evidence = run.command("evidence").description("Manage evidence (file attachments) on a test run");
|
|
3263
3415
|
examples(evidence, [
|
|
3264
|
-
"add --execution
|
|
3416
|
+
"add --execution PROJ-1 --test PROJ-2 --file screenshot.png",
|
|
3265
3417
|
"list 42",
|
|
3266
3418
|
"delete 42 --evidence-id 7"
|
|
3267
3419
|
]);
|
|
@@ -3273,7 +3425,7 @@ function registerEvidenceCommands(run) {
|
|
|
3273
3425
|
// src/commands/xray/run/field/get.ts
|
|
3274
3426
|
function get4(parent) {
|
|
3275
3427
|
const cmd = parent.command("get").description("Get a custom field value on a test run").argument("[runId]", "Test run id (from run list)", positiveInt).requiredOption("--field-id <id>", "Custom field id (from xray field list)", text).option("--execution <key>", "Test execution issue key (used with --test to resolve run id)", issueKey).option("--test <key>", "Test issue key (used with --execution to resolve run id)", issueKey);
|
|
3276
|
-
examples(cmd, ["42 --field-id customfield_10100", "--execution
|
|
3428
|
+
examples(cmd, ["42 --field-id customfield_10100", "--execution PROJ-1 --test PROJ-2 --field-id customfield_10100"]);
|
|
3277
3429
|
cmd.action(async (runId, opts) => {
|
|
3278
3430
|
const client = getClient();
|
|
3279
3431
|
const id = await resolveRunId(client, { runId, execution: opts.execution, test: opts.test });
|
|
@@ -3287,7 +3439,7 @@ function set(parent) {
|
|
|
3287
3439
|
const cmd = parent.command("set").description("Set a custom field value on a test run").argument("[runId]", "Test run id (from run list)", positiveInt).requiredOption("--field-id <id>", "Custom field id (from xray field list)", text).requiredOption("--value <text>", "Value to set for the field", text).option("--execution <key>", "Test execution issue key (used with --test to resolve run id)", issueKey).option("--test <key>", "Test issue key (used with --execution to resolve run id)", issueKey);
|
|
3288
3440
|
examples(cmd, [
|
|
3289
3441
|
'42 --field-id customfield_10100 --value "approved"',
|
|
3290
|
-
'--execution
|
|
3442
|
+
'--execution PROJ-1 --test PROJ-2 --field-id customfield_10100 --value "reviewed"'
|
|
3291
3443
|
]);
|
|
3292
3444
|
cmd.action(
|
|
3293
3445
|
async (runId, opts) => {
|
|
@@ -3310,7 +3462,7 @@ function registerRunFieldCommands(run) {
|
|
|
3310
3462
|
// src/commands/xray/run/get.ts
|
|
3311
3463
|
function get5(parent) {
|
|
3312
3464
|
const cmd = parent.command("get").description("Get a test run by id or by execution + test key").argument("[runId]", "Test run id (from run list)", positiveInt).option("--execution <key>", "Test execution issue key (used with --test to resolve run id)", issueKey).option("--test <key>", "Test issue key (used with --execution to resolve run id)", issueKey);
|
|
3313
|
-
examples(cmd, ["42", "--execution
|
|
3465
|
+
examples(cmd, ["42", "--execution PROJ-1 --test PROJ-2"]);
|
|
3314
3466
|
cmd.action(async (runId, opts) => {
|
|
3315
3467
|
const client = getClient();
|
|
3316
3468
|
const id = await resolveRunId(client, { runId, ...opts });
|
|
@@ -3322,7 +3474,7 @@ function get5(parent) {
|
|
|
3322
3474
|
// src/commands/xray/run/list.ts
|
|
3323
3475
|
function list14(parent) {
|
|
3324
3476
|
const cmd = parent.command("list").description("List test runs for a test execution (CLI-side slice with --limit/--start)").requiredOption("--execution <key>", "Test execution issue key", issueKey).option("--limit <number>", "Max results to return (1-200)", intInRange(1, 200), 50).option("--start <number>", "Starting index for pagination", nonNegativeInt);
|
|
3325
|
-
examples(cmd, ["--execution
|
|
3477
|
+
examples(cmd, ["--execution PROJ-1", "--execution PROJ-1 --limit 10", "--execution PROJ-1 --limit 10 --start 10"]);
|
|
3326
3478
|
cmd.action(async (opts) => {
|
|
3327
3479
|
const client = getClient();
|
|
3328
3480
|
const runs = await client.testRuns.listByExecution({ execKey: opts.execution });
|
|
@@ -3335,7 +3487,7 @@ function list14(parent) {
|
|
|
3335
3487
|
// src/commands/xray/run/step/list.ts
|
|
3336
3488
|
function list15(parent) {
|
|
3337
3489
|
const cmd = parent.command("list").description("List step results for a test run").argument("[runId]", "Test run id (from run list)", positiveInt).option("--execution <key>", "Test execution issue key (used with --test to resolve run id)", issueKey).option("--test <key>", "Test issue key (used with --execution to resolve run id)", issueKey);
|
|
3338
|
-
examples(cmd, ["42", "--execution
|
|
3490
|
+
examples(cmd, ["42", "--execution PROJ-1 --test PROJ-2"]);
|
|
3339
3491
|
cmd.action(async (runId, opts) => {
|
|
3340
3492
|
const client = getClient();
|
|
3341
3493
|
const id = await resolveRunId(client, { runId, execution: opts.execution, test: opts.test });
|
|
@@ -3355,7 +3507,7 @@ function update10(parent) {
|
|
|
3355
3507
|
textOrFileOption(cmd, "actual-result", { description: "Actual result text for this step" });
|
|
3356
3508
|
examples(cmd, [
|
|
3357
3509
|
"42 --step-id 1 --status PASS",
|
|
3358
|
-
'--execution
|
|
3510
|
+
'--execution PROJ-1 --test PROJ-2 --step-id 2 --status FAIL --comment "button missing"',
|
|
3359
3511
|
'42 --step-id 1 --status PASS --actual-result "Form submitted successfully"'
|
|
3360
3512
|
]);
|
|
3361
3513
|
cmd.action(
|
|
@@ -3379,7 +3531,7 @@ function update10(parent) {
|
|
|
3379
3531
|
// src/commands/xray/run/step/index.ts
|
|
3380
3532
|
function registerRunStepCommands(run) {
|
|
3381
3533
|
const step = run.command("step").description("Manage step results within a test run. See also: xray step for test step definitions.");
|
|
3382
|
-
examples(step, ["list --execution
|
|
3534
|
+
examples(step, ["list --execution PROJ-1 --test PROJ-2", "update 42 --step-id 1 --status PASS"]);
|
|
3383
3535
|
list15(step);
|
|
3384
3536
|
update10(step);
|
|
3385
3537
|
}
|
|
@@ -3390,8 +3542,8 @@ function update11(parent) {
|
|
|
3390
3542
|
textOrFileOption(cmd, "comment", { description: "Comment text for this run" });
|
|
3391
3543
|
examples(cmd, [
|
|
3392
3544
|
"42 --status PASS",
|
|
3393
|
-
'--execution
|
|
3394
|
-
'--execution
|
|
3545
|
+
'--execution PROJ-1 --test PROJ-2 --status FAIL --comment "broken"',
|
|
3546
|
+
'--execution PROJ-1 --test PROJ-2 --status FAIL --comment "broken" --defect BUG-1'
|
|
3395
3547
|
]);
|
|
3396
3548
|
cmd.action(
|
|
3397
3549
|
async (runId, opts) => {
|
|
@@ -3418,12 +3570,12 @@ function registerRunCommands(xray) {
|
|
|
3418
3570
|
"Manage test run results (status, comments, defects, evidence, steps). Every command accepts [runId] or --execution + --test."
|
|
3419
3571
|
);
|
|
3420
3572
|
examples(run, [
|
|
3421
|
-
"get --execution
|
|
3422
|
-
"list --execution
|
|
3423
|
-
'update --execution
|
|
3573
|
+
"get --execution PROJ-1 --test PROJ-2",
|
|
3574
|
+
"list --execution PROJ-1",
|
|
3575
|
+
'update --execution PROJ-1 --test PROJ-2 --status FAIL --comment "broken" --defect BUG-1',
|
|
3424
3576
|
"defect add 42 --defect BUG-1,BUG-2",
|
|
3425
|
-
"evidence add --execution
|
|
3426
|
-
"step list --execution
|
|
3577
|
+
"evidence add --execution PROJ-1 --test PROJ-2 --file screenshot.png",
|
|
3578
|
+
"step list --execution PROJ-1 --test PROJ-2",
|
|
3427
3579
|
"field get 42 --field-id customfield_10100"
|
|
3428
3580
|
]);
|
|
3429
3581
|
get5(run);
|
|
@@ -3455,13 +3607,13 @@ function registerStatusCommands(xray) {
|
|
|
3455
3607
|
|
|
3456
3608
|
// src/commands/xray/step/add.ts
|
|
3457
3609
|
function add7(parent) {
|
|
3458
|
-
const cmd = parent.command("add").description("Add a manual test step to a Test issue").requiredOption("--test <key>", "Test issue key (e.g.
|
|
3610
|
+
const cmd = parent.command("add").description("Add a manual test step to a Test issue").requiredOption("--test <key>", "Test issue key (e.g. PROJ-584)", issueKey);
|
|
3459
3611
|
textOrFileOption(cmd, "action", { description: "Step action text (required: provide --action or --action-file)" });
|
|
3460
3612
|
textOrFileOption(cmd, "data", { description: "Step test data text" });
|
|
3461
3613
|
textOrFileOption(cmd, "result", { description: "Expected result text" });
|
|
3462
3614
|
examples(cmd, [
|
|
3463
|
-
'--test
|
|
3464
|
-
'--test
|
|
3615
|
+
'--test PROJ-584 --action "Open login page" --result "Login form is shown"',
|
|
3616
|
+
'--test PROJ-584 --action "Submit form" --data "user=admin" --result "Dashboard loads"'
|
|
3465
3617
|
]);
|
|
3466
3618
|
cmd.action(
|
|
3467
3619
|
async (opts) => {
|
|
@@ -3477,8 +3629,8 @@ function add7(parent) {
|
|
|
3477
3629
|
|
|
3478
3630
|
// src/commands/xray/step/delete.ts
|
|
3479
3631
|
function deleteStep(parent) {
|
|
3480
|
-
const cmd = parent.command("delete").description("Delete a manual test step by ID").argument("<stepId>", "Step ID to delete (from step list)", positiveInt).requiredOption("--test <key>", "Test issue key (e.g.
|
|
3481
|
-
examples(cmd, ["3 --test
|
|
3632
|
+
const cmd = parent.command("delete").description("Delete a manual test step by ID").argument("<stepId>", "Step ID to delete (from step list)", positiveInt).requiredOption("--test <key>", "Test issue key (e.g. PROJ-584)", issueKey);
|
|
3633
|
+
examples(cmd, ["3 --test PROJ-584"]);
|
|
3482
3634
|
cmd.action(async (stepId, opts) => {
|
|
3483
3635
|
const client = getClient();
|
|
3484
3636
|
await client.testSteps.delete({ testKey: opts.test, stepId });
|
|
@@ -3488,8 +3640,8 @@ function deleteStep(parent) {
|
|
|
3488
3640
|
|
|
3489
3641
|
// src/commands/xray/step/list.ts
|
|
3490
3642
|
function list17(parent) {
|
|
3491
|
-
const cmd = parent.command("list").description("List manual test steps for a Test issue").requiredOption("--test <key>", "Test issue key (e.g.
|
|
3492
|
-
examples(cmd, ["--test
|
|
3643
|
+
const cmd = parent.command("list").description("List manual test steps for a Test issue").requiredOption("--test <key>", "Test issue key (e.g. PROJ-584)", issueKey);
|
|
3644
|
+
examples(cmd, ["--test PROJ-584"]);
|
|
3493
3645
|
cmd.action(async (opts) => {
|
|
3494
3646
|
const client = getClient();
|
|
3495
3647
|
const steps = await client.testSteps.list({ testKey: opts.test });
|
|
@@ -3499,13 +3651,13 @@ function list17(parent) {
|
|
|
3499
3651
|
|
|
3500
3652
|
// src/commands/xray/step/update.ts
|
|
3501
3653
|
function update12(parent) {
|
|
3502
|
-
const cmd = parent.command("update").description("Update a manual test step by ID").argument("<stepId>", "Step ID to update (from step list)", positiveInt).requiredOption("--test <key>", "Test issue key (e.g.
|
|
3654
|
+
const cmd = parent.command("update").description("Update a manual test step by ID").argument("<stepId>", "Step ID to update (from step list)", positiveInt).requiredOption("--test <key>", "Test issue key (e.g. PROJ-584)", issueKey);
|
|
3503
3655
|
textOrFileOption(cmd, "action", { description: "New step action text" });
|
|
3504
3656
|
textOrFileOption(cmd, "data", { description: "New step test data text" });
|
|
3505
3657
|
textOrFileOption(cmd, "result", { description: "New expected result text" });
|
|
3506
3658
|
examples(cmd, [
|
|
3507
|
-
'3 --test
|
|
3508
|
-
'3 --test
|
|
3659
|
+
'3 --test PROJ-584 --action "Click submit button"',
|
|
3660
|
+
'3 --test PROJ-584 --result "Confirmation email sent"'
|
|
3509
3661
|
]);
|
|
3510
3662
|
cmd.action(
|
|
3511
3663
|
async (stepId, opts) => {
|
|
@@ -3529,7 +3681,7 @@ function registerStepCommands(xray) {
|
|
|
3529
3681
|
const step = xray.command("step").description(
|
|
3530
3682
|
"Manage manual test steps for a Test issue (scope: --test). Steps are ordered by insertion; use step list to see current ids."
|
|
3531
3683
|
);
|
|
3532
|
-
examples(step, ['add --test
|
|
3684
|
+
examples(step, ['add --test PROJ-584 --action "Open login" --result "Form shows"', "list --test PROJ-584"]);
|
|
3533
3685
|
list17(step);
|
|
3534
3686
|
add7(step);
|
|
3535
3687
|
update12(step);
|
|
@@ -3556,15 +3708,15 @@ function create11(parent) {
|
|
|
3556
3708
|
textOrFileOption(cmd, "description", { description: "Test description" });
|
|
3557
3709
|
examples(cmd, [
|
|
3558
3710
|
[
|
|
3559
|
-
`--project
|
|
3711
|
+
`--project PROJ --summary "Login test" --type manual --steps '[{"action":"Open browser","result":"Browser opens"}]'`,
|
|
3560
3712
|
"Create manual test with step seed"
|
|
3561
3713
|
],
|
|
3562
3714
|
[
|
|
3563
|
-
'--project
|
|
3715
|
+
'--project PROJ --summary "Login scenario" --type cucumber --cucumber-type scenario --gherkin "Given I am on login page\\nWhen I enter credentials\\nThen I am logged in"',
|
|
3564
3716
|
"Create cucumber test"
|
|
3565
3717
|
],
|
|
3566
3718
|
[
|
|
3567
|
-
'--project
|
|
3719
|
+
'--project PROJ --summary "Perf baseline" --type generic --definition "Run k6 script and assert p95 < 500ms"',
|
|
3568
3720
|
"Create generic test"
|
|
3569
3721
|
]
|
|
3570
3722
|
]);
|
|
@@ -3621,8 +3773,8 @@ function create11(parent) {
|
|
|
3621
3773
|
|
|
3622
3774
|
// src/commands/xray/test/delete.ts
|
|
3623
3775
|
function deleteTest(parent) {
|
|
3624
|
-
const cmd = parent.command("delete").description("Delete an Xray Test issue").argument("<testKey>", "Test issue key (e.g.
|
|
3625
|
-
examples(cmd, ["
|
|
3776
|
+
const cmd = parent.command("delete").description("Delete an Xray Test issue").argument("<testKey>", "Test issue key (e.g. PROJ-584)", issueKey);
|
|
3777
|
+
examples(cmd, ["PROJ-584"]);
|
|
3626
3778
|
cmd.action(async (testKey) => {
|
|
3627
3779
|
const client = getClient();
|
|
3628
3780
|
await client.issues.delete({ issueKeyOrId: testKey });
|
|
@@ -3632,8 +3784,8 @@ function deleteTest(parent) {
|
|
|
3632
3784
|
|
|
3633
3785
|
// src/commands/xray/test/get.ts
|
|
3634
3786
|
function get6(parent) {
|
|
3635
|
-
const cmd = parent.command("get").description("Get one or more Xray test issues by key").argument("<testKey...>", "One or more test issue keys (e.g.
|
|
3636
|
-
examples(cmd, ["
|
|
3787
|
+
const cmd = parent.command("get").description("Get one or more Xray test issues by key").argument("<testKey...>", "One or more test issue keys (e.g. PROJ-584)", listOf(issueKey));
|
|
3788
|
+
examples(cmd, ["PROJ-584", "PROJ-584 PROJ-585"]);
|
|
3637
3789
|
cmd.action(async (testKeys) => {
|
|
3638
3790
|
const client = getClient();
|
|
3639
3791
|
const tests = await client.xrayTests.getTests({ keys: testKeys });
|
|
@@ -3646,7 +3798,7 @@ function list18(parent) {
|
|
|
3646
3798
|
const cmd = parent.command("list").description(
|
|
3647
3799
|
"List Xray Test issues by scope: all tests in a project, or tests belonging to a set, plan, execution, precondition, or folder. Note: use `jiradc issue search` for richer JQL when scoping by project."
|
|
3648
3800
|
).option("--project <text>", "Project key \u2014 list all tests in the project (or companion to --folder)", text).option("--set <key>", "Test Set issue key \u2014 list tests in this set", issueKey).option("--plan <key>", "Test Plan issue key \u2014 list tests in this plan", issueKey).option("--execution <key>", "Test Execution issue key \u2014 list tests in this execution", issueKey).option("--precondition <key>", "Precondition issue key \u2014 list tests with this precondition", issueKey).option("--folder <id>", "Folder id \u2014 list tests in this folder (requires --project)", positiveInt).option("--limit <number>", "Max results (1-50, applies to --project scope)", intInRange(1, 50), 25).option("--start <number>", "Starting index for pagination (applies to --project scope)", nonNegativeInt);
|
|
3649
|
-
examples(cmd, ["--project
|
|
3801
|
+
examples(cmd, ["--project PROJ", "--set PROJ-100", "--folder 818 --project PROJ"]);
|
|
3650
3802
|
cmd.action(
|
|
3651
3803
|
async (opts) => {
|
|
3652
3804
|
const client = getClient();
|
|
@@ -3718,7 +3870,7 @@ function list18(parent) {
|
|
|
3718
3870
|
// src/commands/xray/test/update.ts
|
|
3719
3871
|
import { Option as Option13 } from "commander";
|
|
3720
3872
|
function update13(parent) {
|
|
3721
|
-
const cmd = parent.command("update").description("Update an Xray Test issue").argument("<testKey>", "Test issue key (e.g.
|
|
3873
|
+
const cmd = parent.command("update").description("Update an Xray Test issue").argument("<testKey>", "Test issue key (e.g. PROJ-584)", issueKey).option("--summary <text>", "New summary (title)", text).addOption(new Option13("--type <type>", "Test type").choices(["manual", "cucumber", "generic"])).addOption(
|
|
3722
3874
|
new Option13("--cucumber-type <cucumberType>", "Cucumber scenario type (required when --type cucumber)").choices([
|
|
3723
3875
|
"scenario",
|
|
3724
3876
|
"scenario-outline"
|
|
@@ -3728,8 +3880,8 @@ function update13(parent) {
|
|
|
3728
3880
|
textOrFileOption(cmd, "definition", { description: "Generic test definition (required when --type generic)" });
|
|
3729
3881
|
textOrFileOption(cmd, "description", { description: "Test description" });
|
|
3730
3882
|
examples(cmd, [
|
|
3731
|
-
'
|
|
3732
|
-
'
|
|
3883
|
+
'PROJ-584 --summary "Updated title"',
|
|
3884
|
+
'PROJ-584 --type cucumber --cucumber-type scenario --gherkin "Given I open the app"'
|
|
3733
3885
|
]);
|
|
3734
3886
|
cmd.action(
|
|
3735
3887
|
async (testKey, opts) => {
|
|
@@ -3783,7 +3935,7 @@ function update13(parent) {
|
|
|
3783
3935
|
// src/commands/xray/test/index.ts
|
|
3784
3936
|
function registerTestCommands(xray) {
|
|
3785
3937
|
const test = xray.command("test").description("Xray Test issue management (CRUD)");
|
|
3786
|
-
examples(test, ["get
|
|
3938
|
+
examples(test, ["get PROJ-584", 'create --project PROJ --summary "Login" --type manual']);
|
|
3787
3939
|
get6(test);
|
|
3788
3940
|
create11(test);
|
|
3789
3941
|
update13(test);
|
|
@@ -3793,8 +3945,8 @@ function registerTestCommands(xray) {
|
|
|
3793
3945
|
|
|
3794
3946
|
// src/commands/xray/testset/add.ts
|
|
3795
3947
|
function add8(parent) {
|
|
3796
|
-
const cmd = parent.command("add").description("Add tests to a Test Set").argument("<setKey>", "Test Set issue key (e.g.
|
|
3797
|
-
examples(cmd, ["
|
|
3948
|
+
const cmd = parent.command("add").description("Add tests to a Test Set").argument("<setKey>", "Test Set issue key (e.g. PROJ-100)", issueKey).requiredOption("--test <keys>", "Comma-separated test issue keys to add (e.g. PROJ-1,PROJ-2)", keyList);
|
|
3949
|
+
examples(cmd, ["PROJ-100 --test PROJ-1", "PROJ-100 --test PROJ-1,PROJ-2,PROJ-3"]);
|
|
3798
3950
|
cmd.action(async (setKey, opts) => {
|
|
3799
3951
|
const client = getClient();
|
|
3800
3952
|
const result = await client.testSets.addTests({ setKey, keys: opts.test });
|
|
@@ -3807,8 +3959,8 @@ function create12(parent) {
|
|
|
3807
3959
|
const cmd = parent.command("create").description("Create a new Xray Test Set issue").requiredOption("--project <key>", "Project key (e.g. AI)", text).requiredOption("--summary <text>", "Test Set summary (title)", text);
|
|
3808
3960
|
textOrFileOption(cmd, "description", { description: "Test Set description" });
|
|
3809
3961
|
examples(cmd, [
|
|
3810
|
-
'--project
|
|
3811
|
-
'--project
|
|
3962
|
+
'--project PROJ --summary "Smoke Test Set"',
|
|
3963
|
+
'--project PROJ --summary "Regression Set" --description "All regression tests"'
|
|
3812
3964
|
]);
|
|
3813
3965
|
cmd.action(async (opts) => {
|
|
3814
3966
|
const description = resolveTextOrFile(opts, "description", { required: false });
|
|
@@ -3825,8 +3977,8 @@ function create12(parent) {
|
|
|
3825
3977
|
|
|
3826
3978
|
// src/commands/xray/testset/delete.ts
|
|
3827
3979
|
function deleteTestset(parent) {
|
|
3828
|
-
const cmd = parent.command("delete").description("Delete an Xray Test Set issue").argument("<setKey>", "Test Set issue key (e.g.
|
|
3829
|
-
examples(cmd, ["
|
|
3980
|
+
const cmd = parent.command("delete").description("Delete an Xray Test Set issue").argument("<setKey>", "Test Set issue key (e.g. PROJ-100)", issueKey);
|
|
3981
|
+
examples(cmd, ["PROJ-100"]);
|
|
3830
3982
|
cmd.action(async (setKey) => {
|
|
3831
3983
|
const client = getClient();
|
|
3832
3984
|
await deleteXrayIssue(client, setKey);
|
|
@@ -3838,8 +3990,8 @@ function deleteTestset(parent) {
|
|
|
3838
3990
|
function list19(parent) {
|
|
3839
3991
|
const cmd = parent.command("list").description(
|
|
3840
3992
|
"List Test Sets that contain a given test (inverse view). For the forward view (tests inside a set), use: xray test list --set <key>"
|
|
3841
|
-
).requiredOption("--test <key>", "Test issue key whose sets to list (e.g.
|
|
3842
|
-
examples(cmd, ["--test
|
|
3993
|
+
).requiredOption("--test <key>", "Test issue key whose sets to list (e.g. PROJ-584)", issueKey);
|
|
3994
|
+
examples(cmd, ["--test PROJ-584"]);
|
|
3843
3995
|
cmd.action(async (opts) => {
|
|
3844
3996
|
const client = getClient();
|
|
3845
3997
|
const sets = await client.xrayTests.getTestSets({ testKey: opts.test });
|
|
@@ -3849,8 +4001,8 @@ function list19(parent) {
|
|
|
3849
4001
|
|
|
3850
4002
|
// src/commands/xray/testset/remove.ts
|
|
3851
4003
|
function remove6(parent) {
|
|
3852
|
-
const cmd = parent.command("remove").description("Remove tests from a Test Set").argument("<setKey>", "Test Set issue key (e.g.
|
|
3853
|
-
examples(cmd, ["
|
|
4004
|
+
const cmd = parent.command("remove").description("Remove tests from a Test Set").argument("<setKey>", "Test Set issue key (e.g. PROJ-100)", issueKey).requiredOption("--test <keys>", "Comma-separated test issue keys to remove (e.g. PROJ-1,PROJ-2)", keyList);
|
|
4005
|
+
examples(cmd, ["PROJ-100 --test PROJ-1", "PROJ-100 --test PROJ-1,PROJ-2"]);
|
|
3854
4006
|
cmd.action(async (setKey, opts) => {
|
|
3855
4007
|
const client = getClient();
|
|
3856
4008
|
const result = await client.testSets.removeTests({ setKey, keys: opts.test });
|
|
@@ -3860,9 +4012,9 @@ function remove6(parent) {
|
|
|
3860
4012
|
|
|
3861
4013
|
// src/commands/xray/testset/update.ts
|
|
3862
4014
|
function update14(parent) {
|
|
3863
|
-
const cmd = parent.command("update").description("Update an Xray Test Set issue").argument("<setKey>", "Test Set issue key (e.g.
|
|
4015
|
+
const cmd = parent.command("update").description("Update an Xray Test Set issue").argument("<setKey>", "Test Set issue key (e.g. PROJ-100)", issueKey).option("--summary <text>", "New summary (title)", text);
|
|
3864
4016
|
textOrFileOption(cmd, "description", { description: "New Test Set description" });
|
|
3865
|
-
examples(cmd, ['
|
|
4017
|
+
examples(cmd, ['PROJ-100 --summary "Updated smoke set"', 'PROJ-100 --description "New description"']);
|
|
3866
4018
|
cmd.action(async (setKey, opts) => {
|
|
3867
4019
|
const description = resolveTextOrFile(opts, "description", { required: false });
|
|
3868
4020
|
const client = getClient();
|
|
@@ -3876,7 +4028,7 @@ function registerTestsetCommands(xray) {
|
|
|
3876
4028
|
const testset = xray.command("testset").description(
|
|
3877
4029
|
"Xray Test Set issue management (CRUD, membership). To list tests inside a set, use: xray test list --set <key>"
|
|
3878
4030
|
);
|
|
3879
|
-
examples(testset, ['create --project
|
|
4031
|
+
examples(testset, ['create --project PROJ --summary "Smoke tests"', "add PROJ-100 --test PROJ-1,PROJ-2"]);
|
|
3880
4032
|
create12(testset);
|
|
3881
4033
|
update14(testset);
|
|
3882
4034
|
deleteTestset(testset);
|
|
@@ -3888,7 +4040,7 @@ function registerTestsetCommands(xray) {
|
|
|
3888
4040
|
// src/commands/xray/index.ts
|
|
3889
4041
|
function registerXrayCommands(program) {
|
|
3890
4042
|
const xray = program.command("xray").description("Xray test management (tests, runs, repository, import/export)");
|
|
3891
|
-
examples(xray, ["test get
|
|
4043
|
+
examples(xray, ["test get PROJ-584"]);
|
|
3892
4044
|
registerStatusCommands(xray);
|
|
3893
4045
|
registerFieldCommands2(xray);
|
|
3894
4046
|
registerTestCommands(xray);
|
|
@@ -3973,5 +4125,5 @@ await runCli(buildProgram(), {
|
|
|
3973
4125
|
credentialInfo: getCredentialInfo,
|
|
3974
4126
|
service: "Jira",
|
|
3975
4127
|
authRecovery: "Set the JIRA_URL and JIRA_TOKEN environment variables.",
|
|
3976
|
-
|
|
4128
|
+
urlEnvVar: "JIRA_URL"
|
|
3977
4129
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "jiradc-cli",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.32",
|
|
4
4
|
"publish": true,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"dependencies": {
|
|
14
14
|
"commander": "^13.1.0",
|
|
15
15
|
"zod": "^3.25.67",
|
|
16
|
-
"jira-data-center-client": "1.0.
|
|
16
|
+
"jira-data-center-client": "1.0.42"
|
|
17
17
|
},
|
|
18
18
|
"devDependencies": {
|
|
19
19
|
"@types/node": "24.10.4",
|
|
@@ -32,6 +32,8 @@
|
|
|
32
32
|
},
|
|
33
33
|
"scripts": {
|
|
34
34
|
"build": "tsup",
|
|
35
|
+
"check-types": "tsc --noEmit -p tsconfig.json",
|
|
36
|
+
"clean": "rm -rf dist",
|
|
35
37
|
"dev": "tsx src/index.ts",
|
|
36
38
|
"lint": "eslint src tests",
|
|
37
39
|
"lint:fix": "eslint src tests --fix",
|