jiradc-cli 1.0.41 → 1.0.43
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/dist/index.js +107 -47
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2393,33 +2393,45 @@ async function withNames(client, structureId, rows) {
|
|
|
2393
2393
|
itemId: r.itemId
|
|
2394
2394
|
}));
|
|
2395
2395
|
}
|
|
2396
|
+
function resolveEnclosingRow(opts, fallback = 0) {
|
|
2397
|
+
const { parent, under } = opts;
|
|
2398
|
+
if (parent !== void 0 && under !== void 0 && parent !== under) {
|
|
2399
|
+
throw new CliUsageError(
|
|
2400
|
+
`--parent (${parent}) and --under (${under}) are the same option and disagree`,
|
|
2401
|
+
"They are aliases; pass only one."
|
|
2402
|
+
);
|
|
2403
|
+
}
|
|
2404
|
+
return parent ?? under ?? fallback;
|
|
2405
|
+
}
|
|
2396
2406
|
|
|
2397
2407
|
// src/commands/structure/folder/create.ts
|
|
2398
2408
|
function create7(parent) {
|
|
2399
2409
|
const cmd = parent.command("create").description("Create a folder in a structure");
|
|
2400
2410
|
scopeIdOption(cmd, "structure", { mandatory: true });
|
|
2401
2411
|
cmd.requiredOption("--name <text>", "Folder name", text);
|
|
2402
|
-
cmd.option("--under <rowId>", "Parent folder row id (0 = top level)", integer
|
|
2412
|
+
cmd.option("--under <rowId>", "Parent folder row id (0 = top level)", integer);
|
|
2413
|
+
cmd.option("--parent <rowId>", "Alias for --under", integer);
|
|
2403
2414
|
examples(cmd, ["--structure 42 --name Backlog", '--structure 42 --name "Phase Two" --under 1001']);
|
|
2404
2415
|
cmd.action(async (opts) => {
|
|
2416
|
+
const under = resolveEnclosingRow(opts);
|
|
2405
2417
|
const client = getClient();
|
|
2406
2418
|
const structureId = await resolveStructureId(client, opts.structure);
|
|
2407
2419
|
const forest = await client.structure.getForest({ structureId });
|
|
2408
|
-
if (
|
|
2409
|
-
assertRowExists(parseForest(forest),
|
|
2420
|
+
if (under !== 0) {
|
|
2421
|
+
assertRowExists(parseForest(forest), under, structureId, "Target parent row");
|
|
2410
2422
|
}
|
|
2411
2423
|
const result = await client.structure.createFolder({
|
|
2412
2424
|
structureId,
|
|
2413
2425
|
version: forest.version,
|
|
2414
2426
|
name: opts.name,
|
|
2415
|
-
under
|
|
2427
|
+
under
|
|
2416
2428
|
});
|
|
2417
2429
|
output({
|
|
2418
2430
|
structureId,
|
|
2419
2431
|
itemId: result.itemId,
|
|
2420
2432
|
rowId: result.newRowIds?.[0] ?? null,
|
|
2421
2433
|
name: opts.name,
|
|
2422
|
-
under
|
|
2434
|
+
under
|
|
2423
2435
|
});
|
|
2424
2436
|
});
|
|
2425
2437
|
}
|
|
@@ -2460,7 +2472,8 @@ function get7(parent) {
|
|
|
2460
2472
|
function list8(parent) {
|
|
2461
2473
|
const cmd = parent.command("list").description("List folders in a structure");
|
|
2462
2474
|
scopeIdOption(cmd, "structure", { mandatory: true });
|
|
2463
|
-
cmd.option("--parent <rowId>", "Only look under this folder row (default: top level)", integer
|
|
2475
|
+
cmd.option("--parent <rowId>", "Only look under this folder row (default: top level)", integer);
|
|
2476
|
+
cmd.option("--under <rowId>", "Alias for --parent", integer);
|
|
2464
2477
|
cmd.option("--depth <n>", "How many levels below the parent to include", integer, 1);
|
|
2465
2478
|
cmd.option("--query <text>", "Only folders whose name contains this text, at any depth", text);
|
|
2466
2479
|
paginationOptions(cmd, { defaultLimit: 25 });
|
|
@@ -2476,7 +2489,8 @@ function list8(parent) {
|
|
|
2476
2489
|
const structureId = await resolveStructureId(client, opts.structure);
|
|
2477
2490
|
const forest = await client.structure.getForest({ structureId });
|
|
2478
2491
|
const rows = parseForest(forest);
|
|
2479
|
-
const
|
|
2492
|
+
const parent2 = resolveEnclosingRow(opts);
|
|
2493
|
+
const scoped = opts.query ? parent2 === 0 ? rows : descendantsOf(rows, parent2) : withinDepth(rows, parent2, opts.depth);
|
|
2480
2494
|
const folders = scoped.filter((r) => r.isFolder);
|
|
2481
2495
|
let named = await withNames(client, structureId, folders);
|
|
2482
2496
|
if (opts.query) {
|
|
@@ -2515,16 +2529,19 @@ function get8(parent) {
|
|
|
2515
2529
|
function list9(parent) {
|
|
2516
2530
|
const cmd = parent.command("list").description("List every structure visible to you");
|
|
2517
2531
|
cmd.option("--permissions", "Include each structure\u2019s permission rules");
|
|
2532
|
+
cmd.option("--query <text>", "Only structures whose name contains this text", text);
|
|
2518
2533
|
paginationOptions(cmd, { defaultLimit: 25 });
|
|
2519
2534
|
cmd.option("--all", "Collect every match, not just one page");
|
|
2520
|
-
examples(cmd, ["", "--limit 50", "--all --permissions"]);
|
|
2535
|
+
examples(cmd, ["", "--query billing", "--limit 50", "--all --permissions"]);
|
|
2521
2536
|
cmd.action(async (opts) => {
|
|
2522
2537
|
if (opts.all && process.argv.includes("--limit")) {
|
|
2523
2538
|
const { CliUsageError: CliUsageError2 } = await import("./dist-JXPWCMQP.js");
|
|
2524
2539
|
throw new CliUsageError2("--all and --limit ask for opposite things; pass one or the other");
|
|
2525
2540
|
}
|
|
2526
2541
|
const client = getClient();
|
|
2527
|
-
const { structures } = await client.structure.list({ withPermissions: opts.permissions });
|
|
2542
|
+
const { structures: found } = await client.structure.list({ withPermissions: opts.permissions });
|
|
2543
|
+
const needle = opts.query?.toLowerCase();
|
|
2544
|
+
const structures = needle ? found.filter((s) => (s.name ?? "").toLowerCase().includes(needle)) : found;
|
|
2528
2545
|
const start = opts.start ?? 0;
|
|
2529
2546
|
const page = opts.all ? structures.slice(start) : structures.slice(start, start + opts.limit);
|
|
2530
2547
|
output({ total: structures.length, start, count: page.length, structures: page });
|
|
@@ -2536,24 +2553,26 @@ function add(parent) {
|
|
|
2536
2553
|
const cmd = parent.command("add").description("Add an issue to a structure, under a folder");
|
|
2537
2554
|
scopeIdOption(cmd, "structure", { mandatory: true });
|
|
2538
2555
|
cmd.requiredOption("--issue <key>", "Issue key to place, e.g. PROJ-123", text);
|
|
2539
|
-
cmd.option("--under <rowId>", "Parent folder row id (0 = top level)", integer
|
|
2556
|
+
cmd.option("--under <rowId>", "Parent folder row id (0 = top level)", integer);
|
|
2557
|
+
cmd.option("--parent <rowId>", "Alias for --under", integer);
|
|
2540
2558
|
examples(cmd, ["--structure 42 --issue PROJ-123 --under 1001", '--structure "My Structure" --issue PROJ-123']);
|
|
2541
2559
|
cmd.action(async (opts) => {
|
|
2560
|
+
const under = resolveEnclosingRow(opts);
|
|
2542
2561
|
const client = getClient();
|
|
2543
2562
|
const structureId = await resolveStructureId(client, opts.structure);
|
|
2544
2563
|
const issue = await client.issues.get({ issueKeyOrId: opts.issue, fields: ["summary"] });
|
|
2545
2564
|
const issueId = Number(issue.id);
|
|
2546
2565
|
const forest = await client.structure.getForest({ structureId });
|
|
2547
2566
|
const rows = parseForest(forest);
|
|
2548
|
-
if (
|
|
2549
|
-
const already = childrenOf(rows,
|
|
2550
|
-
const elsewhere = rows.filter((r) => r.itemType === "issue" && r.itemNumericId === issueId && r.parentRowId !==
|
|
2567
|
+
if (under !== 0) assertRowExists(rows, under, structureId, "Target parent row");
|
|
2568
|
+
const already = childrenOf(rows, under).find((r) => r.itemType === "issue" && r.itemNumericId === issueId);
|
|
2569
|
+
const elsewhere = rows.filter((r) => r.itemType === "issue" && r.itemNumericId === issueId && r.parentRowId !== under).map((r) => ({ rowId: r.rowId, parentRowId: r.parentRowId }));
|
|
2551
2570
|
if (already) {
|
|
2552
2571
|
output({
|
|
2553
2572
|
structureId,
|
|
2554
2573
|
issue: issue.key,
|
|
2555
2574
|
rowId: already.rowId,
|
|
2556
|
-
under
|
|
2575
|
+
under,
|
|
2557
2576
|
added: false,
|
|
2558
2577
|
reason: "already under this parent",
|
|
2559
2578
|
alsoAppearsAt: elsewhere
|
|
@@ -2563,13 +2582,13 @@ function add(parent) {
|
|
|
2563
2582
|
const result = await client.structure.updateForest({
|
|
2564
2583
|
structureId,
|
|
2565
2584
|
version: forest.version,
|
|
2566
|
-
actions: [{ action: "add", under
|
|
2585
|
+
actions: [{ action: "add", under, after: 0, before: 0, forest: addSpec(issueId) }]
|
|
2567
2586
|
});
|
|
2568
2587
|
output({
|
|
2569
2588
|
structureId,
|
|
2570
2589
|
issue: issue.key,
|
|
2571
2590
|
rowId: result.newRowIds?.[0] ?? null,
|
|
2572
|
-
under
|
|
2591
|
+
under,
|
|
2573
2592
|
added: true,
|
|
2574
2593
|
alsoAppearsAt: elsewhere
|
|
2575
2594
|
});
|
|
@@ -2580,17 +2599,36 @@ function add(parent) {
|
|
|
2580
2599
|
function list10(parent) {
|
|
2581
2600
|
const cmd = parent.command("list").description("List rows (issues and folders) under a parent row");
|
|
2582
2601
|
scopeIdOption(cmd, "structure", { mandatory: true });
|
|
2583
|
-
cmd.option("--parent <rowId>", "Parent row id (0 = top level)", integer
|
|
2602
|
+
cmd.option("--parent <rowId>", "Parent row id (0 = top level)", integer);
|
|
2603
|
+
cmd.option("--under <rowId>", "Alias for --parent", integer);
|
|
2584
2604
|
cmd.option("--depth <n>", "How many levels below the parent to include", integer, 1);
|
|
2605
|
+
cmd.option("--issue <key>", "Only rows for this issue, wherever they are in the structure", text);
|
|
2585
2606
|
paginationOptions(cmd, { defaultLimit: 25 });
|
|
2586
2607
|
cmd.option("--all", "Collect every match, not just one page");
|
|
2587
|
-
examples(cmd, [
|
|
2608
|
+
examples(cmd, [
|
|
2609
|
+
"--structure 42",
|
|
2610
|
+
'--structure "My Structure" --parent 1001 --depth 2',
|
|
2611
|
+
'--structure "My Structure" --issue PROJ-123'
|
|
2612
|
+
]);
|
|
2588
2613
|
cmd.action(
|
|
2589
2614
|
async (opts) => {
|
|
2590
2615
|
const client = getClient();
|
|
2591
2616
|
const structureId = await resolveStructureId(client, opts.structure);
|
|
2592
2617
|
const rows = parseForest(await client.structure.getForest({ structureId }));
|
|
2593
|
-
|
|
2618
|
+
if (opts.issue !== void 0 && (opts.parent !== void 0 || opts.under !== void 0)) {
|
|
2619
|
+
throw new CliUsageError(
|
|
2620
|
+
"--issue and --parent ask different questions; pass one",
|
|
2621
|
+
"--issue finds an issue wherever it sits; --parent lists what is under a row."
|
|
2622
|
+
);
|
|
2623
|
+
}
|
|
2624
|
+
let scoped;
|
|
2625
|
+
if (opts.issue !== void 0) {
|
|
2626
|
+
const issue = await client.issues.get({ issueKeyOrId: opts.issue, fields: ["summary"] });
|
|
2627
|
+
const issueId = Number(issue.id);
|
|
2628
|
+
scoped = rows.filter((r) => r.itemType === "issue" && r.itemNumericId === issueId);
|
|
2629
|
+
} else {
|
|
2630
|
+
scoped = withinDepth(rows, resolveEnclosingRow(opts), opts.depth);
|
|
2631
|
+
}
|
|
2594
2632
|
const start = opts.start ?? 0;
|
|
2595
2633
|
const page = opts.all ? scoped.slice(start) : scoped.slice(start, start + opts.limit);
|
|
2596
2634
|
output({
|
|
@@ -2609,22 +2647,27 @@ function move(parent) {
|
|
|
2609
2647
|
const cmd = parent.command("move").description("Move a row to a different parent");
|
|
2610
2648
|
subjectArg(cmd, "rowId", { description: "Row id to move (not the issue id)", parser: positiveInt });
|
|
2611
2649
|
scopeIdOption(cmd, "structure", { mandatory: true });
|
|
2612
|
-
cmd.
|
|
2650
|
+
cmd.option("--under <rowId>", "New parent row id (0 = top level)", integer);
|
|
2651
|
+
cmd.option("--parent <rowId>", "Alias for --under", integer);
|
|
2613
2652
|
examples(cmd, ["1002 --structure 42 --under 1001", '1002 --structure "My Structure" --under 0']);
|
|
2614
2653
|
cmd.action(async (rowId, opts) => {
|
|
2654
|
+
if (opts.under === void 0 && opts.parent === void 0) {
|
|
2655
|
+
throw new CliUsageError("A destination is required", "Pass --under <rowId> (or its alias --parent).");
|
|
2656
|
+
}
|
|
2657
|
+
const under = resolveEnclosingRow(opts);
|
|
2615
2658
|
const client = getClient();
|
|
2616
2659
|
const structureId = await resolveStructureId(client, opts.structure);
|
|
2617
2660
|
const forest = await client.structure.getForest({ structureId });
|
|
2618
2661
|
const rows = parseForest(forest);
|
|
2619
2662
|
assertRowExists(rows, rowId, structureId);
|
|
2620
|
-
if (
|
|
2663
|
+
if (under !== 0) assertRowExists(rows, under, structureId, "Target parent row");
|
|
2621
2664
|
const row = rows.find((r) => r.rowId === rowId);
|
|
2622
2665
|
const result = await client.structure.updateForest({
|
|
2623
2666
|
structureId,
|
|
2624
2667
|
version: forest.version,
|
|
2625
|
-
actions: [{ action: "move", rowId, under
|
|
2668
|
+
actions: [{ action: "move", rowId, under, after: 0, before: 0 }]
|
|
2626
2669
|
});
|
|
2627
|
-
output({ structureId, rowId, from: row.parentRowId, under
|
|
2670
|
+
output({ structureId, rowId, from: row.parentRowId, under, moved: result.successfulActions > 0 });
|
|
2628
2671
|
});
|
|
2629
2672
|
}
|
|
2630
2673
|
|
|
@@ -2668,39 +2711,56 @@ function search3(parent) {
|
|
|
2668
2711
|
parser: nonEmpty
|
|
2669
2712
|
});
|
|
2670
2713
|
scopeIdOption(cmd, "structure", { mandatory: true });
|
|
2671
|
-
cmd.option("--fields <fields>", "Comma-separated fields to return", text);
|
|
2714
|
+
cmd.option("--fields <fields>", "Comma-separated fields to return, by name or id", text);
|
|
2715
|
+
cmd.option("--all-fields", "Return all fields instead of defaults");
|
|
2672
2716
|
paginationOptions(cmd, { defaultLimit: 25, maxLimit: 50 });
|
|
2673
2717
|
examples(cmd, [
|
|
2674
2718
|
`"child of folder('Billing')" --structure "My Structure"`,
|
|
2675
2719
|
`"descendants of folder('Billing')" --structure 42 --limit 50`
|
|
2676
2720
|
]);
|
|
2677
|
-
cmd.action(
|
|
2678
|
-
|
|
2679
|
-
[
|
|
2680
|
-
|
|
2681
|
-
|
|
2682
|
-
|
|
2721
|
+
cmd.action(
|
|
2722
|
+
async (sjql, opts) => {
|
|
2723
|
+
for (const [name, value] of [
|
|
2724
|
+
["--structure", opts.structure],
|
|
2725
|
+
["<sjql>", sjql]
|
|
2726
|
+
]) {
|
|
2727
|
+
if (value.includes('"')) {
|
|
2728
|
+
throw new CliUsageError(
|
|
2729
|
+
`${name} must not contain a double quote \u2014 S-JQL uses single quotes inside, e.g. "child of folder('Billing')"`
|
|
2730
|
+
);
|
|
2731
|
+
}
|
|
2732
|
+
}
|
|
2733
|
+
const client = getClient();
|
|
2734
|
+
const fields = await selectFields(client, opts, SEARCH_DEFAULT_FIELDS);
|
|
2735
|
+
const jql = `issue in structure("${opts.structure}", "${sjql}")`;
|
|
2736
|
+
let res;
|
|
2737
|
+
try {
|
|
2738
|
+
res = await client.issues.search({
|
|
2739
|
+
jql,
|
|
2740
|
+
startAt: opts.start ?? 0,
|
|
2741
|
+
maxResults: opts.limit,
|
|
2742
|
+
fields
|
|
2743
|
+
});
|
|
2744
|
+
} catch (err) {
|
|
2745
|
+
const detail = err.response?.data;
|
|
2746
|
+
const raw = detail === void 0 ? "" : JSON.stringify(detail);
|
|
2747
|
+
if (!raw.includes("Structure query")) throw err;
|
|
2748
|
+
const suggestion = /did you mean ([^"]+?)\?/.exec(raw)?.[1];
|
|
2683
2749
|
throw new CliUsageError(
|
|
2684
|
-
|
|
2750
|
+
`Structure rejected the query ${JSON.stringify(sjql)}`,
|
|
2751
|
+
suggestion !== void 0 ? `The query is S-JQL, not JQL. Structure suggests: ${suggestion}.` : `The query is S-JQL, not JQL \u2014 use shapes like "child of folder('Name')", "descendants of folder('Name')" or "issue in (PROJ-123)", with single quotes inside.`,
|
|
2752
|
+
detail
|
|
2685
2753
|
);
|
|
2686
2754
|
}
|
|
2755
|
+
output({
|
|
2756
|
+
jql,
|
|
2757
|
+
total: res.total,
|
|
2758
|
+
startAt: res.startAt,
|
|
2759
|
+
count: res.issues?.length ?? 0,
|
|
2760
|
+
issues: (res.issues ?? []).map(transformIssue)
|
|
2761
|
+
});
|
|
2687
2762
|
}
|
|
2688
|
-
|
|
2689
|
-
const jql = `issue in structure("${opts.structure}", "${sjql}")`;
|
|
2690
|
-
const res = await client.issues.search({
|
|
2691
|
-
jql,
|
|
2692
|
-
startAt: opts.start ?? 0,
|
|
2693
|
-
maxResults: opts.limit,
|
|
2694
|
-
fields: opts.fields
|
|
2695
|
-
});
|
|
2696
|
-
output({
|
|
2697
|
-
jql,
|
|
2698
|
-
total: res.total,
|
|
2699
|
-
startAt: res.startAt,
|
|
2700
|
-
count: res.issues?.length ?? 0,
|
|
2701
|
-
issues: (res.issues ?? []).map(transformIssue)
|
|
2702
|
-
});
|
|
2703
|
-
});
|
|
2763
|
+
);
|
|
2704
2764
|
}
|
|
2705
2765
|
|
|
2706
2766
|
// src/commands/structure/index.ts
|