@levr-one/cli 0.3.1 → 0.4.0
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 +66 -1
- package/dist/cli.js +121 -8
- package/dist/importHandler-ChywPYeL.js +285 -0
- package/dist/{listHandler-7DZhE8jn.js → listHandler-fK9Mapr3.js} +2 -2
- package/dist/{loginHandler-Dfg89AD2.js → loginHandler-D9k-tQLX.js} +2 -2
- package/dist/{pushHandler-CC709aNJ.js → pushHandler-COg5WbGS.js} +3 -3
- package/dist/{resolve-workspace-vJZku4FK.js → resolve-workspace-CO8d3IBz.js} +1 -1
- package/dist/{sdk-client-BWrIbeUg.js → sdk-client-DyRTezC5.js} +339 -34
- package/dist/{selectHandler-nOUsPW9p.js → selectHandler-BzQRF8E7.js} +2 -2
- package/dist/{statusHandler-DljfUcC2.js → statusHandler-DuVZJMtw.js} +1 -1
- package/package.json +1 -1
- /package/dist/{addHandler-boWTd9yY.js → addHandler-DFtvzTci.js} +0 -0
- /package/dist/{currentHandler-Bm7GFMkj.js → currentHandler-BD-h0j-S.js} +0 -0
- /package/dist/{resolve-token-BRPrqdG-.js → resolve-token-Dq8cAuiu.js} +0 -0
package/README.md
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
# @levr-one/cli
|
|
2
2
|
|
|
3
3
|
The command-line interface for [Levr](https://www.levr.one). The binary is
|
|
4
|
-
`levr`, and it does
|
|
4
|
+
`levr`, and it does three jobs:
|
|
5
5
|
|
|
6
6
|
- **Connect your AI tools** — `levr mcp add` wires the Levr MCP server into
|
|
7
7
|
the AI clients on your machine (Claude Desktop, Claude Code, Cursor,
|
|
8
8
|
Windsurf, Zed) with one command.
|
|
9
9
|
- **Push test results** — `levr push` uploads results from any terminal or CI
|
|
10
10
|
pipeline.
|
|
11
|
+
- **Import test cases** — `levr import` brings existing cases in from CSV,
|
|
12
|
+
Excel, JSON, or Google Sheets.
|
|
11
13
|
|
|
12
14
|
## Install
|
|
13
15
|
|
|
@@ -129,6 +131,69 @@ the source to the workspace's default team, or pass `--team-id` to link it to a
|
|
|
129
131
|
specific team. Subsequent pushes with the same `--source` route to that team
|
|
130
132
|
automatically. Source names are normalized (lowercased, trimmed).
|
|
131
133
|
|
|
134
|
+
## Import test cases
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
levr import <file> --team-id <uuid> [options]
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
Brings existing test cases into Levr from CSV, Excel (`.xlsx`), JSON, or a
|
|
141
|
+
public Google Sheet. It runs in two phases: **preview** proposes a mapping from
|
|
142
|
+
your columns onto the Levr test-case schema (exact and fuzzy matching, with an
|
|
143
|
+
LLM assist for whatever is left over), you review and adjust it, then **commit**
|
|
144
|
+
writes the folders, tests, steps, and preconditions.
|
|
145
|
+
|
|
146
|
+
In a terminal, unmapped and low-confidence columns are walked with a picker. For
|
|
147
|
+
scripts and CI, pass `--yes` — and `--map` or `--mapping-file` to pin the
|
|
148
|
+
mapping so a replay can't drift.
|
|
149
|
+
|
|
150
|
+
**One column must map to `test_name`.** Interactive runs ask for it;
|
|
151
|
+
non-interactive runs exit 1 rather than import unnamed cases.
|
|
152
|
+
|
|
153
|
+
**Examples:**
|
|
154
|
+
|
|
155
|
+
```bash
|
|
156
|
+
# Interactive import from a CSV export
|
|
157
|
+
levr import ./testrail-export.csv --team-id <uuid>
|
|
158
|
+
|
|
159
|
+
# Excel, with one column pinned up front
|
|
160
|
+
levr import ./cases.xlsx --team-id <uuid> --map "Title=test_name"
|
|
161
|
+
|
|
162
|
+
# A public Google Sheet, no prompts
|
|
163
|
+
levr import --sheets-url "https://docs.google.com/spreadsheets/d/..." --team-id <uuid> --yes
|
|
164
|
+
|
|
165
|
+
# Save the confirmed mapping once, then replay it in CI
|
|
166
|
+
levr import ./cases.csv --team-id <uuid> --save-mapping mapping.json
|
|
167
|
+
levr import ./cases.csv --team-id <uuid> --mapping-file mapping.json --yes
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
**Flags:**
|
|
171
|
+
|
|
172
|
+
| Flag | Alias | Description |
|
|
173
|
+
| ----------------------- | ----- | --------------------------------------------------------------------------------- |
|
|
174
|
+
| `--team-id <uuid>` | `-t` | Team the imported test cases belong to (required) |
|
|
175
|
+
| `--workspace-id <uuid>` | `-w` | Workspace ID (required for multi-workspace JWT auth) |
|
|
176
|
+
| `--sheets-url <url>` | | Public Google Sheets URL, used instead of a file argument |
|
|
177
|
+
| `--format <type>` | `-f` | Source format: `csv`, `xlsx`, `json` (auto-detected from the filename if omitted) |
|
|
178
|
+
| `--map <pair>` | `-m` | Column override, repeatable — three forms, below |
|
|
179
|
+
| `--mapping-file <path>` | | JSON file holding a saved confirmed mapping (from `--save-mapping`) |
|
|
180
|
+
| `--save-mapping <path>` | | Write the confirmed mapping to this JSON file for CI replay |
|
|
181
|
+
| `--yes` | `-y` | Accept the mapping without prompts (required for non-TTY runs) |
|
|
182
|
+
| `--verbose` | `-v` | Show detailed output |
|
|
183
|
+
|
|
184
|
+
`--map` accepts three forms:
|
|
185
|
+
|
|
186
|
+
| Form | Effect |
|
|
187
|
+
| ------------------------------- | ------------------------------------------------------------------------------ |
|
|
188
|
+
| `"Source Column=target_field"` | Map the column onto that Levr field |
|
|
189
|
+
| `"Source Column="` | Drop the column (empty target) |
|
|
190
|
+
| `"Source Column=labels:prefix"` | Import each value as the label `prefix:value`, keeping the column's provenance |
|
|
191
|
+
|
|
192
|
+
```bash
|
|
193
|
+
# Keep a TestRail "State" column as state:Draft / state:Approved labels
|
|
194
|
+
levr import ./cases.csv --team-id <uuid> --map "State=labels:state"
|
|
195
|
+
```
|
|
196
|
+
|
|
132
197
|
## CI/CD integration
|
|
133
198
|
|
|
134
199
|
### GitHub Actions
|
package/dist/cli.js
CHANGED
|
@@ -109,7 +109,7 @@ Examples:
|
|
|
109
109
|
aliases: { y: "yes" }
|
|
110
110
|
},
|
|
111
111
|
loader: async () => {
|
|
112
|
-
const { mcpAddHandler } = await import("./addHandler-
|
|
112
|
+
const { mcpAddHandler } = await import("./addHandler-DFtvzTci.js");
|
|
113
113
|
return mcpAddHandler;
|
|
114
114
|
}
|
|
115
115
|
});
|
|
@@ -147,7 +147,7 @@ Examples:
|
|
|
147
147
|
aliases: { d: "device-code" }
|
|
148
148
|
},
|
|
149
149
|
loader: async () => {
|
|
150
|
-
const { loginHandler } = await import("./loginHandler-
|
|
150
|
+
const { loginHandler } = await import("./loginHandler-D9k-tQLX.js");
|
|
151
151
|
return loginHandler;
|
|
152
152
|
}
|
|
153
153
|
});
|
|
@@ -186,7 +186,7 @@ Examples:
|
|
|
186
186
|
},
|
|
187
187
|
parameters: {},
|
|
188
188
|
loader: async () => {
|
|
189
|
-
const { statusHandler } = await import("./statusHandler-
|
|
189
|
+
const { statusHandler } = await import("./statusHandler-DuVZJMtw.js");
|
|
190
190
|
return statusHandler;
|
|
191
191
|
}
|
|
192
192
|
});
|
|
@@ -297,11 +297,123 @@ Examples:
|
|
|
297
297
|
}
|
|
298
298
|
},
|
|
299
299
|
loader: async () => {
|
|
300
|
-
const { pushHandler } = await import("./pushHandler-
|
|
300
|
+
const { pushHandler } = await import("./pushHandler-COg5WbGS.js");
|
|
301
301
|
return pushHandler;
|
|
302
302
|
}
|
|
303
303
|
});
|
|
304
304
|
|
|
305
|
+
//#endregion
|
|
306
|
+
//#region src/commands/import.ts
|
|
307
|
+
const importCommand = buildCommand({
|
|
308
|
+
docs: {
|
|
309
|
+
brief: "Import test cases from CSV, Excel, JSON, or Google Sheets",
|
|
310
|
+
fullDescription: `Two-phase test-case import: preview proposes a column mapping to the
|
|
311
|
+
Levr test-case schema (exact/fuzzy matching with an LLM assist), you review
|
|
312
|
+
and adjust it, then commit writes folders, tests, steps, and preconditions.
|
|
313
|
+
|
|
314
|
+
Interactive mode (default in a terminal) walks unmapped and low-confidence
|
|
315
|
+
columns with a picker. For scripts/CI use --yes and/or --map.
|
|
316
|
+
|
|
317
|
+
Required-field rule: a column must map to test_name or the commit is
|
|
318
|
+
rejected — interactive mode will ask; non-interactive runs exit 1.
|
|
319
|
+
|
|
320
|
+
Examples:
|
|
321
|
+
levr import ./testrail-export.csv --team-id <uuid>
|
|
322
|
+
levr import ./cases.xlsx --team-id <uuid> --map "Title=test_name"
|
|
323
|
+
levr import --sheets-url "https://docs.google.com/spreadsheets/d/..." --team-id <uuid> --yes
|
|
324
|
+
levr import ./cases.csv --team-id <uuid> --save-mapping mapping.json
|
|
325
|
+
levr import ./cases.csv --team-id <uuid> --mapping-file mapping.json --yes # CI replay`
|
|
326
|
+
},
|
|
327
|
+
parameters: {
|
|
328
|
+
positional: {
|
|
329
|
+
kind: "tuple",
|
|
330
|
+
parameters: [{
|
|
331
|
+
parse: String,
|
|
332
|
+
brief: "Path to the source file (.csv, .xlsx, .json)",
|
|
333
|
+
placeholder: "file",
|
|
334
|
+
optional: true
|
|
335
|
+
}]
|
|
336
|
+
},
|
|
337
|
+
flags: {
|
|
338
|
+
"workspace-id": {
|
|
339
|
+
kind: "parsed",
|
|
340
|
+
parse: String,
|
|
341
|
+
brief: "Workspace ID (required for multi-workspace JWT auth)",
|
|
342
|
+
placeholder: "uuid",
|
|
343
|
+
optional: true
|
|
344
|
+
},
|
|
345
|
+
"team-id": {
|
|
346
|
+
kind: "parsed",
|
|
347
|
+
parse: String,
|
|
348
|
+
brief: "Team the imported test cases will belong to",
|
|
349
|
+
placeholder: "uuid",
|
|
350
|
+
optional: false
|
|
351
|
+
},
|
|
352
|
+
"sheets-url": {
|
|
353
|
+
kind: "parsed",
|
|
354
|
+
parse: String,
|
|
355
|
+
brief: "Public Google Sheets URL (instead of a file)",
|
|
356
|
+
placeholder: "url",
|
|
357
|
+
optional: true
|
|
358
|
+
},
|
|
359
|
+
format: {
|
|
360
|
+
kind: "enum",
|
|
361
|
+
values: [
|
|
362
|
+
"csv",
|
|
363
|
+
"xlsx",
|
|
364
|
+
"json"
|
|
365
|
+
],
|
|
366
|
+
brief: "Source format (auto-detected from the filename if omitted)",
|
|
367
|
+
optional: true
|
|
368
|
+
},
|
|
369
|
+
map: {
|
|
370
|
+
kind: "parsed",
|
|
371
|
+
parse: String,
|
|
372
|
+
brief: "Column override (repeatable): \"Column=target_field\", \"Column=\" to drop, or \"Column=labels:prefix\"",
|
|
373
|
+
placeholder: "pair",
|
|
374
|
+
variadic: true,
|
|
375
|
+
optional: true
|
|
376
|
+
},
|
|
377
|
+
"mapping-file": {
|
|
378
|
+
kind: "parsed",
|
|
379
|
+
parse: String,
|
|
380
|
+
brief: "JSON file with a saved confirmed mapping (from --save-mapping)",
|
|
381
|
+
placeholder: "path",
|
|
382
|
+
optional: true
|
|
383
|
+
},
|
|
384
|
+
"save-mapping": {
|
|
385
|
+
kind: "parsed",
|
|
386
|
+
parse: String,
|
|
387
|
+
brief: "Write the confirmed mapping to this JSON file for CI replay",
|
|
388
|
+
placeholder: "path",
|
|
389
|
+
optional: true
|
|
390
|
+
},
|
|
391
|
+
yes: {
|
|
392
|
+
kind: "boolean",
|
|
393
|
+
default: false,
|
|
394
|
+
brief: "Accept the mapping without prompts (required for non-TTY runs)"
|
|
395
|
+
},
|
|
396
|
+
verbose: {
|
|
397
|
+
kind: "boolean",
|
|
398
|
+
default: false,
|
|
399
|
+
brief: "Show detailed output"
|
|
400
|
+
}
|
|
401
|
+
},
|
|
402
|
+
aliases: {
|
|
403
|
+
w: "workspace-id",
|
|
404
|
+
t: "team-id",
|
|
405
|
+
f: "format",
|
|
406
|
+
m: "map",
|
|
407
|
+
y: "yes",
|
|
408
|
+
v: "verbose"
|
|
409
|
+
}
|
|
410
|
+
},
|
|
411
|
+
loader: async () => {
|
|
412
|
+
const { importHandler } = await import("./importHandler-ChywPYeL.js");
|
|
413
|
+
return importHandler;
|
|
414
|
+
}
|
|
415
|
+
});
|
|
416
|
+
|
|
305
417
|
//#endregion
|
|
306
418
|
//#region src/commands/workspace/list.ts
|
|
307
419
|
const listCommand = buildCommand({
|
|
@@ -318,7 +430,7 @@ Examples:
|
|
|
318
430
|
},
|
|
319
431
|
parameters: {},
|
|
320
432
|
loader: async () => {
|
|
321
|
-
const { listHandler } = await import("./listHandler-
|
|
433
|
+
const { listHandler } = await import("./listHandler-fK9Mapr3.js");
|
|
322
434
|
return listHandler;
|
|
323
435
|
}
|
|
324
436
|
});
|
|
@@ -351,7 +463,7 @@ Examples:
|
|
|
351
463
|
flags: {}
|
|
352
464
|
},
|
|
353
465
|
loader: async () => {
|
|
354
|
-
const { selectHandler } = await import("./selectHandler-
|
|
466
|
+
const { selectHandler } = await import("./selectHandler-BzQRF8E7.js");
|
|
355
467
|
return selectHandler;
|
|
356
468
|
}
|
|
357
469
|
});
|
|
@@ -368,14 +480,14 @@ Examples:
|
|
|
368
480
|
},
|
|
369
481
|
parameters: {},
|
|
370
482
|
loader: async () => {
|
|
371
|
-
const { currentHandler } = await import("./currentHandler-
|
|
483
|
+
const { currentHandler } = await import("./currentHandler-BD-h0j-S.js");
|
|
372
484
|
return currentHandler;
|
|
373
485
|
}
|
|
374
486
|
});
|
|
375
487
|
|
|
376
488
|
//#endregion
|
|
377
489
|
//#region package.json
|
|
378
|
-
var version = "0.
|
|
490
|
+
var version = "0.4.0";
|
|
379
491
|
|
|
380
492
|
//#endregion
|
|
381
493
|
//#region src/app.ts
|
|
@@ -404,6 +516,7 @@ const routes = buildRouteMap({
|
|
|
404
516
|
auth: authRoutes,
|
|
405
517
|
workspace: workspaceRoutes,
|
|
406
518
|
push: pushCommand,
|
|
519
|
+
import: importCommand,
|
|
407
520
|
install: buildInstallCommand("levr", { bash: "levr __complete" }),
|
|
408
521
|
uninstall: buildUninstallCommand("levr", { bash: true })
|
|
409
522
|
},
|
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
import { getApiUrl } from "./env-NxtzJJPk.js";
|
|
2
|
+
import { configureClient, testCaseImportCommitV1, testCaseImportPreviewV1 } from "./sdk-client-DyRTezC5.js";
|
|
3
|
+
import "./workspace-store-4hfvsEHS.js";
|
|
4
|
+
import { resolveWorkspace } from "./resolve-workspace-CO8d3IBz.js";
|
|
5
|
+
import "./token-refresh-Cz-FqDtC.js";
|
|
6
|
+
import { resolveToken } from "./resolve-token-Dq8cAuiu.js";
|
|
7
|
+
import { createReadStream } from "node:fs";
|
|
8
|
+
import { basename } from "node:path";
|
|
9
|
+
import chalk from "chalk";
|
|
10
|
+
import { readFile, writeFile } from "node:fs/promises";
|
|
11
|
+
import { createInterface } from "node:readline/promises";
|
|
12
|
+
import ora from "ora";
|
|
13
|
+
|
|
14
|
+
//#region src/utils/import-mapping.ts
|
|
15
|
+
const IMPORT_TARGETS = [
|
|
16
|
+
"row_type",
|
|
17
|
+
"test_id",
|
|
18
|
+
"test_key",
|
|
19
|
+
"folder_id",
|
|
20
|
+
"folder_path",
|
|
21
|
+
"folder_name",
|
|
22
|
+
"test_name",
|
|
23
|
+
"test_description",
|
|
24
|
+
"test_type",
|
|
25
|
+
"case_type_id",
|
|
26
|
+
"case_type_name",
|
|
27
|
+
"test_priority",
|
|
28
|
+
"estimate",
|
|
29
|
+
"is_automated",
|
|
30
|
+
"assignee_email",
|
|
31
|
+
"labels",
|
|
32
|
+
"attachment_filenames",
|
|
33
|
+
"data_set_names",
|
|
34
|
+
"sequence",
|
|
35
|
+
"item_id",
|
|
36
|
+
"method",
|
|
37
|
+
"expected_result",
|
|
38
|
+
"keyword",
|
|
39
|
+
"shared_step_id",
|
|
40
|
+
"shared_precondition_id",
|
|
41
|
+
"data_table",
|
|
42
|
+
"steps",
|
|
43
|
+
"preconditions"
|
|
44
|
+
];
|
|
45
|
+
const REQUIRED_TARGETS = ["test_name"];
|
|
46
|
+
/**
|
|
47
|
+
* Parse a --map value: "Source Column=target", "Source Column=" (drop),
|
|
48
|
+
* or "Source Column=labels:prefix" (import-as-labels: each value becomes
|
|
49
|
+
* the label "prefix:value", preserving the column's provenance).
|
|
50
|
+
*/
|
|
51
|
+
function parseMapFlag(pair) {
|
|
52
|
+
const separator = pair.indexOf("=");
|
|
53
|
+
if (separator <= 0) throw new Error(`Invalid --map "${pair}" — expected "Source Column=target_field" (or "Source Column=" to drop, or "Source Column=labels:prefix" to import values as prefixed labels).`);
|
|
54
|
+
const column = pair.slice(0, separator).trim();
|
|
55
|
+
const raw = pair.slice(separator + 1).trim();
|
|
56
|
+
if (raw === "") return {
|
|
57
|
+
column,
|
|
58
|
+
target: null
|
|
59
|
+
};
|
|
60
|
+
if (raw.startsWith("labels:")) {
|
|
61
|
+
const labelPrefix = raw.slice(7).trim();
|
|
62
|
+
if (!labelPrefix) throw new Error(`Invalid --map "${pair}" — "labels:" needs a prefix (e.g. "State=labels:state").`);
|
|
63
|
+
return {
|
|
64
|
+
column,
|
|
65
|
+
target: "labels",
|
|
66
|
+
labelPrefix
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
const target = IMPORT_TARGETS.find((t) => t === raw);
|
|
70
|
+
if (!target) throw new Error(`Invalid --map target "${raw}". Valid targets: ${IMPORT_TARGETS.join(", ")} (labels also accepts "labels:prefix")`);
|
|
71
|
+
return {
|
|
72
|
+
column,
|
|
73
|
+
target
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
/** Apply overrides (from --map / --mapping-file) onto the proposed mapping. */
|
|
77
|
+
function applyOverrides(mapping, overrides) {
|
|
78
|
+
const result = mapping.map((entry) => ({ ...entry }));
|
|
79
|
+
for (const override of overrides) {
|
|
80
|
+
const entry = result.find((m) => m.originalName === override.column);
|
|
81
|
+
if (!entry) throw new Error(`--map column "${override.column}" not found in the file. Columns: ${result.map((m) => m.originalName).join(", ")}`);
|
|
82
|
+
entry.targetProperty = override.target;
|
|
83
|
+
entry.matchType = override.target ? "manual" : "unmapped";
|
|
84
|
+
entry.confidence = override.target ? 1 : 0;
|
|
85
|
+
entry.labelPrefix = override.labelPrefix;
|
|
86
|
+
}
|
|
87
|
+
return result;
|
|
88
|
+
}
|
|
89
|
+
/** Required targets not covered by any mapped column. */
|
|
90
|
+
function missingRequired(mapping) {
|
|
91
|
+
const covered = new Set(mapping.map((m) => m.targetProperty).filter(Boolean));
|
|
92
|
+
return REQUIRED_TARGETS.filter((t) => !covered.has(t));
|
|
93
|
+
}
|
|
94
|
+
/** Columns worth walking interactively: unmapped, or LLM guesses < 0.7. */
|
|
95
|
+
function columnsNeedingReview(mapping) {
|
|
96
|
+
return mapping.filter((m) => m.targetProperty === null || m.matchType === "llm" && m.confidence < .7);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
//#endregion
|
|
100
|
+
//#region src/commands/importHandler.ts
|
|
101
|
+
const MATCH_COLORS = {
|
|
102
|
+
exact: chalk.green,
|
|
103
|
+
prefix: chalk.green,
|
|
104
|
+
preset: chalk.green,
|
|
105
|
+
fuzzy: chalk.yellow,
|
|
106
|
+
llm: chalk.magenta,
|
|
107
|
+
unmapped: chalk.red,
|
|
108
|
+
manual: chalk.green
|
|
109
|
+
};
|
|
110
|
+
/** Stream the file into a Blob — no readFileSync, no sync stall. */
|
|
111
|
+
async function fileToBlob(path$1) {
|
|
112
|
+
const chunks = [];
|
|
113
|
+
for await (const chunk of createReadStream(path$1)) chunks.push(chunk);
|
|
114
|
+
return new Blob(chunks);
|
|
115
|
+
}
|
|
116
|
+
function printMapping(logger, mapping) {
|
|
117
|
+
const width = Math.max(...mapping.map((m) => m.originalName.length), 13);
|
|
118
|
+
logger.info("");
|
|
119
|
+
logger.info(chalk.bold(` ${"SOURCE COLUMN".padEnd(width)} → ${"TARGET".padEnd(24)} MATCH`));
|
|
120
|
+
for (const m of mapping) {
|
|
121
|
+
const color = MATCH_COLORS[m.matchType] ?? chalk.white;
|
|
122
|
+
const target = m.targetProperty ?? "— unmapped —";
|
|
123
|
+
const badge = m.matchType === "unmapped" ? "unmapped" : `${m.matchType} ${Math.round(m.confidence * 100)}%`;
|
|
124
|
+
logger.info(` ${m.originalName.padEnd(width)} → ${target.padEnd(24)} ${color(badge)}`);
|
|
125
|
+
}
|
|
126
|
+
logger.info("");
|
|
127
|
+
}
|
|
128
|
+
async function pickTarget(rl, logger, column) {
|
|
129
|
+
logger.info(chalk.bold(`"${column.originalName}" is ${column.targetProperty ? `mapped to ${column.targetProperty} (low confidence)` : "unmapped"}.`));
|
|
130
|
+
const columns = 3;
|
|
131
|
+
const cellWidth = 26;
|
|
132
|
+
for (let i = 0; i < IMPORT_TARGETS.length; i += columns) logger.info(" " + IMPORT_TARGETS.slice(i, i + columns).map((t, j) => `${String(i + j + 1).padStart(2)}) ${t}`.padEnd(cellWidth)).join(""));
|
|
133
|
+
for (;;) {
|
|
134
|
+
const answer = (await rl.question("Target number or name (blank = skip/drop this column): ")).trim();
|
|
135
|
+
if (answer === "") return null;
|
|
136
|
+
const byNumber = IMPORT_TARGETS[Number(answer) - 1];
|
|
137
|
+
if (byNumber && String(Number(answer)) === answer) return byNumber;
|
|
138
|
+
const byName = IMPORT_TARGETS.find((t) => t === answer.toLowerCase());
|
|
139
|
+
if (byName) return byName;
|
|
140
|
+
logger.info(chalk.red(` "${answer}" is not a valid target — try again.`));
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
async function importHandler(flags, file) {
|
|
144
|
+
if (flags.verbose) this.logger.setVerbose(true);
|
|
145
|
+
if (!file && !flags["sheets-url"]) {
|
|
146
|
+
this.logger.error("Provide a file path or --sheets-url.");
|
|
147
|
+
this.process.exitCode = 1;
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
if (file && flags["sheets-url"]) {
|
|
151
|
+
this.logger.error("Provide a file OR --sheets-url, not both.");
|
|
152
|
+
this.process.exitCode = 1;
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
let auth;
|
|
156
|
+
try {
|
|
157
|
+
auth = await resolveToken();
|
|
158
|
+
} catch (err) {
|
|
159
|
+
this.logger.error(err instanceof Error ? err.message : "Authentication failed.");
|
|
160
|
+
this.process.exitCode = 1;
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
configureClient(auth);
|
|
164
|
+
if (flags.verbose) {
|
|
165
|
+
this.logger.debug(`Auth: ${auth.type.toUpperCase()}`);
|
|
166
|
+
this.logger.debug(`API: ${getApiUrl()}`);
|
|
167
|
+
}
|
|
168
|
+
if (auth.type === "jwt") {
|
|
169
|
+
if (!await resolveWorkspace.call(this, flags["workspace-id"])) {
|
|
170
|
+
this.process.exitCode = 1;
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
const spinner = ora("Uploading and analyzing the file…").start();
|
|
175
|
+
let preview;
|
|
176
|
+
try {
|
|
177
|
+
const body = {
|
|
178
|
+
team_id: flags["team-id"],
|
|
179
|
+
format: flags.format,
|
|
180
|
+
sheets_url: flags["sheets-url"]
|
|
181
|
+
};
|
|
182
|
+
if (file) {
|
|
183
|
+
const blob = await fileToBlob(file);
|
|
184
|
+
body["file"] = new File([blob], basename(file));
|
|
185
|
+
}
|
|
186
|
+
const result = await testCaseImportPreviewV1({
|
|
187
|
+
body,
|
|
188
|
+
requestValidator: void 0
|
|
189
|
+
});
|
|
190
|
+
if (result.error || !result.data) throw new Error(result.error?.message ?? `Preview failed (HTTP ${result.response?.status ?? "?"}).`);
|
|
191
|
+
preview = result.data;
|
|
192
|
+
spinner.succeed(`${preview.filename} (${preview.format}) — ${preview.row_count} data rows detected`);
|
|
193
|
+
} catch (err) {
|
|
194
|
+
spinner.fail(err instanceof Error ? err.message : "Preview failed.");
|
|
195
|
+
this.process.exitCode = 1;
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
let mapping;
|
|
199
|
+
try {
|
|
200
|
+
const overrides = (flags.map ?? []).map(parseMapFlag);
|
|
201
|
+
if (flags["mapping-file"]) {
|
|
202
|
+
const saved = JSON.parse(await readFile(flags["mapping-file"], "utf8"));
|
|
203
|
+
overrides.push(...saved);
|
|
204
|
+
}
|
|
205
|
+
mapping = applyOverrides(preview.proposed_mapping, overrides);
|
|
206
|
+
} catch (err) {
|
|
207
|
+
this.logger.error(err instanceof Error ? err.message : String(err));
|
|
208
|
+
this.process.exitCode = 1;
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
printMapping(this.logger, mapping);
|
|
212
|
+
if (!flags.yes && process.stdin.isTTY === true) {
|
|
213
|
+
const rl = createInterface({
|
|
214
|
+
input: process.stdin,
|
|
215
|
+
output: process.stdout
|
|
216
|
+
});
|
|
217
|
+
try {
|
|
218
|
+
for (const column of columnsNeedingReview(mapping)) {
|
|
219
|
+
const target = await pickTarget(rl, this.logger, column);
|
|
220
|
+
mapping = applyOverrides(mapping, [{
|
|
221
|
+
column: column.originalName,
|
|
222
|
+
target
|
|
223
|
+
}]);
|
|
224
|
+
}
|
|
225
|
+
while (missingRequired(mapping).length > 0) {
|
|
226
|
+
this.logger.info(chalk.red(`Required field(s) uncovered: ${missingRequired(mapping).join(", ")}. Every test case needs a name.`));
|
|
227
|
+
const source = (await rl.question(`Which source column holds the test name? (${mapping.map((m) => m.originalName).join(", ")}): `)).trim();
|
|
228
|
+
const entry = mapping.find((m) => m.originalName === source);
|
|
229
|
+
if (!entry) {
|
|
230
|
+
this.logger.info(chalk.red(` "${source}" is not a column — try again.`));
|
|
231
|
+
continue;
|
|
232
|
+
}
|
|
233
|
+
mapping = applyOverrides(mapping, [{
|
|
234
|
+
column: entry.originalName,
|
|
235
|
+
target: "test_name"
|
|
236
|
+
}]);
|
|
237
|
+
}
|
|
238
|
+
printMapping(this.logger, mapping);
|
|
239
|
+
const confirm = (await rl.question("Commit this import? [y/N]: ")).trim().toLowerCase();
|
|
240
|
+
if (confirm !== "y" && confirm !== "yes") {
|
|
241
|
+
this.logger.info("Aborted — nothing was written.");
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
} finally {
|
|
245
|
+
rl.close();
|
|
246
|
+
}
|
|
247
|
+
} else if (missingRequired(mapping).length > 0) {
|
|
248
|
+
this.logger.error(`Required field(s) uncovered: ${missingRequired(mapping).join(", ")}. Map them with --map "Source Column=test_name" (non-interactive runs cannot prompt).`);
|
|
249
|
+
this.process.exitCode = 1;
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
if (flags["save-mapping"]) {
|
|
253
|
+
await writeFile(flags["save-mapping"], JSON.stringify(mapping.map((m) => ({
|
|
254
|
+
column: m.originalName,
|
|
255
|
+
target: m.targetProperty
|
|
256
|
+
})), null, 2) + "\n");
|
|
257
|
+
this.logger.info(`Confirmed mapping saved to ${flags["save-mapping"]}`);
|
|
258
|
+
}
|
|
259
|
+
const commitSpinner = ora("Committing import…").start();
|
|
260
|
+
let outcome;
|
|
261
|
+
try {
|
|
262
|
+
const result = await testCaseImportCommitV1({
|
|
263
|
+
body: {
|
|
264
|
+
token: preview.token,
|
|
265
|
+
confirmed_mapping: mapping
|
|
266
|
+
},
|
|
267
|
+
requestValidator: void 0
|
|
268
|
+
});
|
|
269
|
+
if (result.error || !result.data) throw new Error(result.error?.message ?? `Commit failed (HTTP ${result.response?.status ?? "?"}).`);
|
|
270
|
+
outcome = result.data;
|
|
271
|
+
} catch (err) {
|
|
272
|
+
commitSpinner.fail(err instanceof Error ? err.message : "Commit failed.");
|
|
273
|
+
this.process.exitCode = 1;
|
|
274
|
+
return;
|
|
275
|
+
}
|
|
276
|
+
const { stats } = outcome;
|
|
277
|
+
if (outcome.status === "failed") commitSpinner.fail(`Import failed — 0 of ${stats.rows_processed} rows imported.`);
|
|
278
|
+
else commitSpinner.succeed(`Import ${outcome.status.replace(/_/g, " ")}: ${stats.tests_created} tests, ${stats.folders_created} folders, ${stats.steps_created} steps, ${stats.preconditions_created} preconditions (${stats.rows_failed} rows failed)`);
|
|
279
|
+
for (const warning of outcome.warnings) this.logger.info(chalk.yellow(` warning: ${warning.message}`));
|
|
280
|
+
for (const error of outcome.errors) this.logger.info(chalk.red(` error: ${error.message}`));
|
|
281
|
+
if (outcome.status === "failed") this.process.exitCode = 1;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
//#endregion
|
|
285
|
+
export { importHandler };
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import "./env-NxtzJJPk.js";
|
|
2
|
-
import { authGetSitesV1, configureClient } from "./sdk-client-
|
|
2
|
+
import { authGetSitesV1, configureClient } from "./sdk-client-DyRTezC5.js";
|
|
3
3
|
import { loadWorkspace } from "./workspace-store-4hfvsEHS.js";
|
|
4
4
|
import "./token-refresh-Cz-FqDtC.js";
|
|
5
|
-
import { resolveToken } from "./resolve-token-
|
|
5
|
+
import { resolveToken } from "./resolve-token-Dq8cAuiu.js";
|
|
6
6
|
|
|
7
7
|
//#region src/commands/workspace/listHandler.ts
|
|
8
8
|
async function listHandler() {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { CLI_CLIENT_ID, getApiUrl, getAuthUrl, setSessionApiUrl, writeCredentials } from "./env-NxtzJJPk.js";
|
|
2
|
-
import { configureClient } from "./sdk-client-
|
|
2
|
+
import { configureClient } from "./sdk-client-DyRTezC5.js";
|
|
3
3
|
import "./workspace-store-4hfvsEHS.js";
|
|
4
|
-
import { autoSelectWorkspace } from "./resolve-workspace-
|
|
4
|
+
import { autoSelectWorkspace } from "./resolve-workspace-CO8d3IBz.js";
|
|
5
5
|
import chalk from "chalk";
|
|
6
6
|
import { createHash, randomBytes } from "node:crypto";
|
|
7
7
|
import { createServer } from "node:http";
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { getApiUrl, getAutomationSourceIdOverride, getSourceOverride, getTeamId } from "./env-NxtzJJPk.js";
|
|
2
|
-
import { client, configureClient, uploadAutomationIngest, uploadImport } from "./sdk-client-
|
|
2
|
+
import { client, configureClient, uploadAutomationIngest, uploadImport } from "./sdk-client-DyRTezC5.js";
|
|
3
3
|
import "./workspace-store-4hfvsEHS.js";
|
|
4
|
-
import { resolveWorkspace } from "./resolve-workspace-
|
|
4
|
+
import { resolveWorkspace } from "./resolve-workspace-CO8d3IBz.js";
|
|
5
5
|
import "./token-refresh-Cz-FqDtC.js";
|
|
6
|
-
import { resolveToken } from "./resolve-token-
|
|
6
|
+
import { resolveToken } from "./resolve-token-Dq8cAuiu.js";
|
|
7
7
|
import { readFileSync, statSync } from "node:fs";
|
|
8
8
|
import { basename } from "node:path";
|
|
9
9
|
import ora from "ora";
|
|
@@ -11504,7 +11504,6 @@ const zExplorationFindAllV1Data = z.object({
|
|
|
11504
11504
|
"filter.name": z.array(z.string()).optional(),
|
|
11505
11505
|
"filter.key": z.array(z.string()).optional(),
|
|
11506
11506
|
"filter.is_complete": z.array(z.string()).optional(),
|
|
11507
|
-
"filter.milestone_id": z.array(z.string()).optional(),
|
|
11508
11507
|
"filter.status_id": z.array(z.string()).optional(),
|
|
11509
11508
|
"filter.project_id": z.array(z.string()).optional(),
|
|
11510
11509
|
"filter.team_id": z.array(z.string()).optional(),
|
|
@@ -12757,7 +12756,7 @@ const zFolderWithChildrenDto = z.object({
|
|
|
12757
12756
|
epoch: z.number(),
|
|
12758
12757
|
virtual: z.unknown().optional(),
|
|
12759
12758
|
is_root: z.boolean().optional(),
|
|
12760
|
-
|
|
12759
|
+
assignee_id: z.string().optional(),
|
|
12761
12760
|
folder_path: z.string().optional(),
|
|
12762
12761
|
children: z.array(z.union([
|
|
12763
12762
|
z.object({
|
|
@@ -12774,7 +12773,7 @@ const zFolderWithChildrenDto = z.object({
|
|
|
12774
12773
|
epoch: z.number(),
|
|
12775
12774
|
virtual: z.unknown().optional(),
|
|
12776
12775
|
is_root: z.boolean().optional(),
|
|
12777
|
-
|
|
12776
|
+
assignee_id: z.string().optional(),
|
|
12778
12777
|
folder_path: z.string().optional()
|
|
12779
12778
|
}),
|
|
12780
12779
|
z.object({
|
|
@@ -12793,7 +12792,7 @@ const zFolderWithChildrenDto = z.object({
|
|
|
12793
12792
|
updated_by: z.string(),
|
|
12794
12793
|
epoch: z.number(),
|
|
12795
12794
|
key: z.number(),
|
|
12796
|
-
|
|
12795
|
+
assignee_id: z.string().optional(),
|
|
12797
12796
|
estimate: z.number().optional(),
|
|
12798
12797
|
test_type: z.enum([
|
|
12799
12798
|
"manual",
|
|
@@ -12853,7 +12852,7 @@ const zFolderNodeDto = z.object({
|
|
|
12853
12852
|
epoch: z.number(),
|
|
12854
12853
|
virtual: z.unknown(),
|
|
12855
12854
|
is_root: z.boolean().nullable(),
|
|
12856
|
-
|
|
12855
|
+
assignee_id: z.string().nullable(),
|
|
12857
12856
|
folder_path: z.string().optional()
|
|
12858
12857
|
});
|
|
12859
12858
|
const zFolderChildrenResponseDto = z.object({
|
|
@@ -12872,7 +12871,7 @@ const zFolderChildrenResponseDto = z.object({
|
|
|
12872
12871
|
epoch: z.number(),
|
|
12873
12872
|
virtual: z.unknown(),
|
|
12874
12873
|
is_root: z.boolean().nullable(),
|
|
12875
|
-
|
|
12874
|
+
assignee_id: z.string().nullable(),
|
|
12876
12875
|
folder_path: z.string().optional()
|
|
12877
12876
|
}),
|
|
12878
12877
|
z.object({
|
|
@@ -12891,7 +12890,7 @@ const zFolderChildrenResponseDto = z.object({
|
|
|
12891
12890
|
updated_by: z.string(),
|
|
12892
12891
|
epoch: z.number(),
|
|
12893
12892
|
key: z.number(),
|
|
12894
|
-
|
|
12893
|
+
assignee_id: z.string().optional(),
|
|
12895
12894
|
estimate: z.number().optional(),
|
|
12896
12895
|
test_type: z.enum([
|
|
12897
12896
|
"manual",
|
|
@@ -12959,7 +12958,7 @@ const zBulkFolderOperationDto = z.object({
|
|
|
12959
12958
|
name: z.string(),
|
|
12960
12959
|
description: z.string().optional(),
|
|
12961
12960
|
virtual: z.unknown().optional(),
|
|
12962
|
-
|
|
12961
|
+
assignee_id: z.string().optional(),
|
|
12963
12962
|
parent_id: z.string().optional(),
|
|
12964
12963
|
sequence: z.string().optional(),
|
|
12965
12964
|
labels: z.array(z.string()).optional(),
|
|
@@ -12969,7 +12968,7 @@ const zBulkFolderOperationDto = z.object({
|
|
|
12969
12968
|
name: z.string().optional(),
|
|
12970
12969
|
description: z.string().optional(),
|
|
12971
12970
|
virtual: z.unknown().optional(),
|
|
12972
|
-
|
|
12971
|
+
assignee_id: z.string().optional(),
|
|
12973
12972
|
parent_id: z.string().optional(),
|
|
12974
12973
|
sequence: z.string().optional(),
|
|
12975
12974
|
add_labels: z.array(z.string()).optional(),
|
|
@@ -12995,7 +12994,7 @@ const zBulkFolderResponseDto = z.object({
|
|
|
12995
12994
|
epoch: z.number(),
|
|
12996
12995
|
virtual: z.unknown(),
|
|
12997
12996
|
is_root: z.boolean().nullable(),
|
|
12998
|
-
|
|
12997
|
+
assignee_id: z.string().nullable(),
|
|
12999
12998
|
folder_path: z.string().optional()
|
|
13000
12999
|
}).optional(),
|
|
13001
13000
|
error: z.string().optional(),
|
|
@@ -13012,7 +13011,7 @@ const zCreateFolderDto = z.object({
|
|
|
13012
13011
|
name: z.string(),
|
|
13013
13012
|
description: z.string().optional(),
|
|
13014
13013
|
virtual: z.unknown().optional(),
|
|
13015
|
-
|
|
13014
|
+
assignee_id: z.string().optional(),
|
|
13016
13015
|
parent_id: z.string().optional(),
|
|
13017
13016
|
sequence: z.string().optional(),
|
|
13018
13017
|
labels: z.array(z.string()).optional(),
|
|
@@ -13023,7 +13022,7 @@ const zUpdateFolderDto = z.object({
|
|
|
13023
13022
|
name: z.string().optional(),
|
|
13024
13023
|
description: z.string().optional(),
|
|
13025
13024
|
virtual: z.unknown().optional(),
|
|
13026
|
-
|
|
13025
|
+
assignee_id: z.string().optional(),
|
|
13027
13026
|
parent_id: z.string().optional(),
|
|
13028
13027
|
sequence: z.string().optional(),
|
|
13029
13028
|
add_labels: z.array(z.string()).optional(),
|
|
@@ -13042,7 +13041,7 @@ const zFolderFindAllV1Data = z.object({
|
|
|
13042
13041
|
"filter.updated_at": z.array(z.string()).optional(),
|
|
13043
13042
|
"filter.updated_by": z.array(z.string()).optional(),
|
|
13044
13043
|
"filter.is_root": z.array(z.string()).optional(),
|
|
13045
|
-
"filter.
|
|
13044
|
+
"filter.assignee_id": z.array(z.string()).optional(),
|
|
13046
13045
|
"filter.folder_path": z.array(z.string()).optional(),
|
|
13047
13046
|
"sortBy": z.array(z.enum([
|
|
13048
13047
|
"id:ASC",
|
|
@@ -13918,6 +13917,7 @@ const zGitHubAppClientCreateTeamAndMapV1Data = z.object({
|
|
|
13918
13917
|
|
|
13919
13918
|
//#endregion
|
|
13920
13919
|
//#region ../sdk/dist/gen/git-hub-sync-bridge/zod.js
|
|
13920
|
+
const zGitHubSyncBridgeOutboundAckV1Data = z.object({ url: z.literal("/v1/internal/github/outbound-ack") });
|
|
13921
13921
|
const zGitHubSyncBridgeTransitionIssueV1Data = z.object({ url: z.literal("/v1/internal/github/issue/transition") });
|
|
13922
13922
|
const zGitHubSyncBridgeSyncIssueV1Data = z.object({ url: z.literal("/v1/internal/github/issue/sync") });
|
|
13923
13923
|
const zGitHubSyncBridgeSyncIssueCommentV1Data = z.object({ url: z.literal("/v1/internal/github/issue-comment/sync") });
|
|
@@ -14060,11 +14060,6 @@ const zCreateGithubIssueLinkDto = z.object({
|
|
|
14060
14060
|
sync_direction: z.string().optional().describe(""),
|
|
14061
14061
|
origin: z.string().optional().describe(""),
|
|
14062
14062
|
role: z.string().optional().describe(""),
|
|
14063
|
-
last_synced_fingerprint: z.string().nullable().optional().describe(""),
|
|
14064
|
-
last_synced_origin: z.string().nullable().optional().describe(""),
|
|
14065
|
-
last_synced_snapshot: z.unknown().optional().describe(""),
|
|
14066
|
-
sync_status: z.string().optional().describe(""),
|
|
14067
|
-
conflict_id: z.string().nullable().optional().describe(""),
|
|
14068
14063
|
tq_issue_id: z.string(),
|
|
14069
14064
|
github_repository_id: z.string(),
|
|
14070
14065
|
team_id: z.string()
|
|
@@ -14100,11 +14095,6 @@ const zUpdateGithubIssueLinkDto = z.object({
|
|
|
14100
14095
|
sync_direction: z.string().optional().describe(""),
|
|
14101
14096
|
origin: z.string().optional().describe(""),
|
|
14102
14097
|
role: z.string().optional().describe(""),
|
|
14103
|
-
last_synced_fingerprint: z.string().nullable().optional().describe(""),
|
|
14104
|
-
last_synced_origin: z.string().nullable().optional().describe(""),
|
|
14105
|
-
last_synced_snapshot: z.unknown().optional().describe(""),
|
|
14106
|
-
sync_status: z.string().optional().describe(""),
|
|
14107
|
-
conflict_id: z.string().nullable().optional().describe(""),
|
|
14108
14098
|
tq_issue_id: z.string().optional(),
|
|
14109
14099
|
github_repository_id: z.string().optional(),
|
|
14110
14100
|
team_id: z.string().optional()
|
|
@@ -14155,6 +14145,7 @@ const zGithubIssueLinkFindAllV1Data = z.object({
|
|
|
14155
14145
|
"filter.sync_direction": z.array(z.string()).optional(),
|
|
14156
14146
|
"filter.origin": z.array(z.string()).optional(),
|
|
14157
14147
|
"filter.role": z.array(z.string()).optional(),
|
|
14148
|
+
"filter.sync_status": z.array(z.string()).optional(),
|
|
14158
14149
|
"filter.tq_issue_id": z.array(z.string()).optional(),
|
|
14159
14150
|
"filter.github_repository_id": z.array(z.string()).optional(),
|
|
14160
14151
|
"filter.team_id": z.array(z.string()).optional(),
|
|
@@ -14174,6 +14165,8 @@ const zGithubIssueLinkFindAllV1Data = z.object({
|
|
|
14174
14165
|
"origin:DESC",
|
|
14175
14166
|
"role:ASC",
|
|
14176
14167
|
"role:DESC",
|
|
14168
|
+
"sync_status:ASC",
|
|
14169
|
+
"sync_status:DESC",
|
|
14177
14170
|
"created_at:ASC",
|
|
14178
14171
|
"created_at:DESC",
|
|
14179
14172
|
"updated_at:ASC",
|
|
@@ -17189,6 +17182,7 @@ const zIssueViewRestoreV1Data = z.object({
|
|
|
17189
17182
|
|
|
17190
17183
|
//#endregion
|
|
17191
17184
|
//#region ../sdk/dist/gen/jira/zod.js
|
|
17185
|
+
const zJiraStatusV1Data = z.object({ url: z.literal("/v1/jira/status") });
|
|
17192
17186
|
const zJiraLinkV1Data = z.object({ url: z.literal("/v1/jira/link") });
|
|
17193
17187
|
const zJiraInstallationsV1Data = z.object({
|
|
17194
17188
|
query: z.object({ "panelNonce": z.string().optional() }).optional(),
|
|
@@ -23859,6 +23853,7 @@ const zRunNodeDto = z.object({
|
|
|
23859
23853
|
test_scope_id: z.string().nullable(),
|
|
23860
23854
|
cycle_id: z.string().nullable(),
|
|
23861
23855
|
parent_run_id: z.string().nullable(),
|
|
23856
|
+
original_parent_run_id: z.string().nullable(),
|
|
23862
23857
|
name: z.string(),
|
|
23863
23858
|
key: z.number().optional(),
|
|
23864
23859
|
run_type: z.enum([
|
|
@@ -23968,6 +23963,7 @@ const zRunWithContentDto = z.object({
|
|
|
23968
23963
|
test_scope_id: z.string().nullable(),
|
|
23969
23964
|
cycle_id: z.string().nullable(),
|
|
23970
23965
|
parent_run_id: z.string().nullable(),
|
|
23966
|
+
original_parent_run_id: z.string().nullable(),
|
|
23971
23967
|
name: z.string(),
|
|
23972
23968
|
key: z.number().optional(),
|
|
23973
23969
|
run_type: z.enum([
|
|
@@ -27618,7 +27614,7 @@ const zTestResponseDto = z.object({
|
|
|
27618
27614
|
priority: z.number().optional(),
|
|
27619
27615
|
estimate: z.number().nullable().optional().describe(""),
|
|
27620
27616
|
data: z.unknown().optional().describe(""),
|
|
27621
|
-
|
|
27617
|
+
assignee_id: z.string().nullable().optional().describe(""),
|
|
27622
27618
|
is_automated: z.boolean().optional().describe(""),
|
|
27623
27619
|
key: z.number().optional().describe(""),
|
|
27624
27620
|
identifier: z.string().optional().describe(""),
|
|
@@ -27687,7 +27683,7 @@ const zCreateTestDto = z.object({
|
|
|
27687
27683
|
priority: z.number().optional().describe(""),
|
|
27688
27684
|
estimate: z.number().nullable().optional().describe(""),
|
|
27689
27685
|
data: z.unknown().optional().describe(""),
|
|
27690
|
-
|
|
27686
|
+
assignee_id: z.string().nullable().optional().describe(""),
|
|
27691
27687
|
is_automated: z.boolean().optional().describe(""),
|
|
27692
27688
|
key: z.number().optional().describe(""),
|
|
27693
27689
|
identifier: z.string().optional().describe(""),
|
|
@@ -27724,7 +27720,7 @@ const zUpdateTestDto = z.object({
|
|
|
27724
27720
|
is_automated: z.boolean().optional(),
|
|
27725
27721
|
to_automate: z.boolean().optional(),
|
|
27726
27722
|
state_mask: z.number().optional(),
|
|
27727
|
-
|
|
27723
|
+
assignee_id: z.string().optional(),
|
|
27728
27724
|
data: z.object({
|
|
27729
27725
|
description: z.string().optional(),
|
|
27730
27726
|
shared_precondition_id: z.string().nullable().optional(),
|
|
@@ -27784,7 +27780,6 @@ const zUpdateTestDto = z.object({
|
|
|
27784
27780
|
add_labels: z.array(z.string()).optional(),
|
|
27785
27781
|
remove_labels: z.array(z.string()).optional()
|
|
27786
27782
|
});
|
|
27787
|
-
const zExportTestsDto = z.object({ ids: z.array(z.string()).describe("") });
|
|
27788
27783
|
const zTestBulkOperationDto = z.object({
|
|
27789
27784
|
op: z.enum([
|
|
27790
27785
|
"create",
|
|
@@ -27815,6 +27810,7 @@ const zBulkTestResponseDto = z.object({
|
|
|
27815
27810
|
savepoints_used: z.number().describe("")
|
|
27816
27811
|
}).describe("")
|
|
27817
27812
|
});
|
|
27813
|
+
const zExportTestsDto = z.object({ ids: z.array(z.string()).describe("") });
|
|
27818
27814
|
const zTestFindAllV1Data = z.object({
|
|
27819
27815
|
query: z.object({
|
|
27820
27816
|
"page": z.number().optional(),
|
|
@@ -27824,10 +27820,11 @@ const zTestFindAllV1Data = z.object({
|
|
|
27824
27820
|
"filter.name": z.array(z.string()).optional(),
|
|
27825
27821
|
"filter.priority": z.array(z.string()).optional(),
|
|
27826
27822
|
"filter.test_type": z.array(z.string()).optional(),
|
|
27823
|
+
"filter.case_type_id": z.array(z.string()).optional(),
|
|
27827
27824
|
"filter.is_automated": z.array(z.string()).optional(),
|
|
27828
27825
|
"filter.to_automate": z.array(z.string()).optional(),
|
|
27829
27826
|
"filter.state_mask": z.array(z.string()).optional(),
|
|
27830
|
-
"filter.
|
|
27827
|
+
"filter.assignee_id": z.array(z.string()).optional(),
|
|
27831
27828
|
"filter.estimate": z.array(z.string()).optional(),
|
|
27832
27829
|
"filter.created_at": z.array(z.string()).optional(),
|
|
27833
27830
|
"filter.created_by": z.array(z.string()).optional(),
|
|
@@ -27884,14 +27881,14 @@ const zTestRemoveV1Data = z.object({
|
|
|
27884
27881
|
path: z.object({ "testId": z.string() }),
|
|
27885
27882
|
url: z.literal("/v1/test/{testId}")
|
|
27886
27883
|
});
|
|
27887
|
-
const zTestExportTestsV1Data = z.object({
|
|
27888
|
-
body: zExportTestsDto,
|
|
27889
|
-
url: z.literal("/v1/test/export")
|
|
27890
|
-
});
|
|
27891
27884
|
const zTestBulkOperationV1Data = z.object({
|
|
27892
27885
|
body: zBulkTestRequestDto,
|
|
27893
27886
|
url: z.literal("/v1/test/bulk")
|
|
27894
27887
|
});
|
|
27888
|
+
const zTestExportTestsV1Data = z.object({
|
|
27889
|
+
body: zExportTestsDto,
|
|
27890
|
+
url: z.literal("/v1/test/export")
|
|
27891
|
+
});
|
|
27895
27892
|
|
|
27896
27893
|
//#endregion
|
|
27897
27894
|
//#region ../sdk/dist/gen/test-attachment/zod.js
|
|
@@ -28000,6 +27997,311 @@ const zTestAttachmentRemoveV1Data = z.object({
|
|
|
28000
27997
|
url: z.literal("/v1/test/{testId}/attachment/{attachmentId}")
|
|
28001
27998
|
});
|
|
28002
27999
|
|
|
28000
|
+
//#endregion
|
|
28001
|
+
//#region ../sdk/dist/gen/test-case-import/functions.js
|
|
28002
|
+
/**
|
|
28003
|
+
* Uploads (or references) a CSV/Excel/JSON file or a public Google Sheets URL, proposes a column mapping to the test-case schema with per-column confidence, and stages the source for a later commit. Writes NO tests/folders — the returned token is presented to POST /v1/test-case-import/commit after the user reviews and confirms the mapping. Sample rows are capped at 20; row_count reports the full source total. Staged previews expire after 1 hour.
|
|
28004
|
+
*/
|
|
28005
|
+
const testCaseImportPreviewV1 = (options) => {
|
|
28006
|
+
return (options?.client ?? client).post({
|
|
28007
|
+
security: [{
|
|
28008
|
+
scheme: "bearer",
|
|
28009
|
+
type: "http"
|
|
28010
|
+
}],
|
|
28011
|
+
url: "/v1/test-case-import/preview",
|
|
28012
|
+
bodySerializer: (body) => {
|
|
28013
|
+
const fd = new FormData();
|
|
28014
|
+
if (body && typeof body === "object") for (const [k, v] of Object.entries(body)) {
|
|
28015
|
+
if (v == null) continue;
|
|
28016
|
+
fd.append(k, v instanceof Blob ? v : String(v));
|
|
28017
|
+
}
|
|
28018
|
+
return fd;
|
|
28019
|
+
},
|
|
28020
|
+
...options
|
|
28021
|
+
});
|
|
28022
|
+
};
|
|
28023
|
+
/**
|
|
28024
|
+
* Re-parses the staged source through the user-confirmed column mapping and writes folders (auto-created as needed), tests, steps, and preconditions in bulk chunks. Malformed rows are reported as warnings/errors — the batch never aborts. Rejects: 403 cross-workspace token, 409 concurrent or repeated commit / expired preview, 422 when a required target field is unmapped.
|
|
28025
|
+
*/
|
|
28026
|
+
const testCaseImportCommitV1 = (options) => {
|
|
28027
|
+
return (options?.client ?? client).post({
|
|
28028
|
+
security: [{
|
|
28029
|
+
scheme: "bearer",
|
|
28030
|
+
type: "http"
|
|
28031
|
+
}],
|
|
28032
|
+
url: "/v1/test-case-import/commit",
|
|
28033
|
+
...options
|
|
28034
|
+
});
|
|
28035
|
+
};
|
|
28036
|
+
|
|
28037
|
+
//#endregion
|
|
28038
|
+
//#region ../sdk/dist/gen/test-case-import/zod.js
|
|
28039
|
+
const zPreviewImportDto = z.object({
|
|
28040
|
+
team_id: z.string().describe(""),
|
|
28041
|
+
format: z.enum([
|
|
28042
|
+
"csv",
|
|
28043
|
+
"xlsx",
|
|
28044
|
+
"sheets",
|
|
28045
|
+
"json"
|
|
28046
|
+
]).optional().describe(""),
|
|
28047
|
+
file_id: z.string().optional().describe(""),
|
|
28048
|
+
sheets_url: z.string().optional().describe("")
|
|
28049
|
+
});
|
|
28050
|
+
const zPreviewImportResponseDto = z.object({
|
|
28051
|
+
token: z.string(),
|
|
28052
|
+
filename: z.string(),
|
|
28053
|
+
format: z.enum([
|
|
28054
|
+
"csv",
|
|
28055
|
+
"xlsx",
|
|
28056
|
+
"sheets",
|
|
28057
|
+
"json"
|
|
28058
|
+
]),
|
|
28059
|
+
proposed_mapping: z.array(z.object({
|
|
28060
|
+
originalName: z.string(),
|
|
28061
|
+
targetProperty: z.enum([
|
|
28062
|
+
"row_type",
|
|
28063
|
+
"test_id",
|
|
28064
|
+
"test_key",
|
|
28065
|
+
"folder_id",
|
|
28066
|
+
"folder_path",
|
|
28067
|
+
"folder_name",
|
|
28068
|
+
"test_name",
|
|
28069
|
+
"test_description",
|
|
28070
|
+
"test_type",
|
|
28071
|
+
"case_type_id",
|
|
28072
|
+
"case_type_name",
|
|
28073
|
+
"test_priority",
|
|
28074
|
+
"estimate",
|
|
28075
|
+
"is_automated",
|
|
28076
|
+
"assignee_email",
|
|
28077
|
+
"labels",
|
|
28078
|
+
"attachment_filenames",
|
|
28079
|
+
"data_set_names",
|
|
28080
|
+
"sequence",
|
|
28081
|
+
"item_id",
|
|
28082
|
+
"method",
|
|
28083
|
+
"expected_result",
|
|
28084
|
+
"keyword",
|
|
28085
|
+
"shared_step_id",
|
|
28086
|
+
"shared_precondition_id",
|
|
28087
|
+
"data_table",
|
|
28088
|
+
"steps",
|
|
28089
|
+
"preconditions"
|
|
28090
|
+
]).nullable(),
|
|
28091
|
+
matchType: z.enum([
|
|
28092
|
+
"exact",
|
|
28093
|
+
"prefix",
|
|
28094
|
+
"fuzzy",
|
|
28095
|
+
"llm",
|
|
28096
|
+
"unmapped",
|
|
28097
|
+
"manual",
|
|
28098
|
+
"preset"
|
|
28099
|
+
]),
|
|
28100
|
+
confidence: z.number(),
|
|
28101
|
+
fieldType: z.enum([
|
|
28102
|
+
"string",
|
|
28103
|
+
"number",
|
|
28104
|
+
"boolean",
|
|
28105
|
+
"unknown"
|
|
28106
|
+
]).optional(),
|
|
28107
|
+
labelPrefix: z.string().optional().describe(""),
|
|
28108
|
+
descriptionHeading: z.string().optional().describe("")
|
|
28109
|
+
})),
|
|
28110
|
+
missing_required: z.array(z.string()),
|
|
28111
|
+
sample_rows: z.array(z.record(z.string(), z.unknown())),
|
|
28112
|
+
row_count: z.number(),
|
|
28113
|
+
expires_at: z.unknown(),
|
|
28114
|
+
advisories: z.array(z.object({
|
|
28115
|
+
column: z.string(),
|
|
28116
|
+
target: z.enum([
|
|
28117
|
+
"row_type",
|
|
28118
|
+
"test_id",
|
|
28119
|
+
"test_key",
|
|
28120
|
+
"folder_id",
|
|
28121
|
+
"folder_path",
|
|
28122
|
+
"folder_name",
|
|
28123
|
+
"test_name",
|
|
28124
|
+
"test_description",
|
|
28125
|
+
"test_type",
|
|
28126
|
+
"case_type_id",
|
|
28127
|
+
"case_type_name",
|
|
28128
|
+
"test_priority",
|
|
28129
|
+
"estimate",
|
|
28130
|
+
"is_automated",
|
|
28131
|
+
"assignee_email",
|
|
28132
|
+
"labels",
|
|
28133
|
+
"attachment_filenames",
|
|
28134
|
+
"data_set_names",
|
|
28135
|
+
"sequence",
|
|
28136
|
+
"item_id",
|
|
28137
|
+
"method",
|
|
28138
|
+
"expected_result",
|
|
28139
|
+
"keyword",
|
|
28140
|
+
"shared_step_id",
|
|
28141
|
+
"shared_precondition_id",
|
|
28142
|
+
"data_table",
|
|
28143
|
+
"steps",
|
|
28144
|
+
"preconditions"
|
|
28145
|
+
]),
|
|
28146
|
+
message: z.string(),
|
|
28147
|
+
count: z.number(),
|
|
28148
|
+
values: z.array(z.object({
|
|
28149
|
+
value: z.string(),
|
|
28150
|
+
count: z.number()
|
|
28151
|
+
}))
|
|
28152
|
+
})),
|
|
28153
|
+
detected_vendor: z.string().nullable(),
|
|
28154
|
+
assignee_resolution: z.object({
|
|
28155
|
+
column: z.string(),
|
|
28156
|
+
entries: z.array(z.object({
|
|
28157
|
+
sourceValue: z.string(),
|
|
28158
|
+
count: z.number(),
|
|
28159
|
+
kind: z.enum([
|
|
28160
|
+
"existing",
|
|
28161
|
+
"new_email",
|
|
28162
|
+
"unresolved"
|
|
28163
|
+
]),
|
|
28164
|
+
userId: z.string().optional(),
|
|
28165
|
+
userName: z.string().optional(),
|
|
28166
|
+
suggestedEmail: z.string().optional()
|
|
28167
|
+
}))
|
|
28168
|
+
}).nullable()
|
|
28169
|
+
});
|
|
28170
|
+
const zCommitImportDto = z.object({
|
|
28171
|
+
token: z.string().describe(""),
|
|
28172
|
+
confirmed_mapping: z.array(z.object({
|
|
28173
|
+
originalName: z.string(),
|
|
28174
|
+
targetProperty: z.enum([
|
|
28175
|
+
"row_type",
|
|
28176
|
+
"test_id",
|
|
28177
|
+
"test_key",
|
|
28178
|
+
"folder_id",
|
|
28179
|
+
"folder_path",
|
|
28180
|
+
"folder_name",
|
|
28181
|
+
"test_name",
|
|
28182
|
+
"test_description",
|
|
28183
|
+
"test_type",
|
|
28184
|
+
"case_type_id",
|
|
28185
|
+
"case_type_name",
|
|
28186
|
+
"test_priority",
|
|
28187
|
+
"estimate",
|
|
28188
|
+
"is_automated",
|
|
28189
|
+
"assignee_email",
|
|
28190
|
+
"labels",
|
|
28191
|
+
"attachment_filenames",
|
|
28192
|
+
"data_set_names",
|
|
28193
|
+
"sequence",
|
|
28194
|
+
"item_id",
|
|
28195
|
+
"method",
|
|
28196
|
+
"expected_result",
|
|
28197
|
+
"keyword",
|
|
28198
|
+
"shared_step_id",
|
|
28199
|
+
"shared_precondition_id",
|
|
28200
|
+
"data_table",
|
|
28201
|
+
"steps",
|
|
28202
|
+
"preconditions"
|
|
28203
|
+
]).nullable(),
|
|
28204
|
+
matchType: z.enum([
|
|
28205
|
+
"exact",
|
|
28206
|
+
"prefix",
|
|
28207
|
+
"fuzzy",
|
|
28208
|
+
"llm",
|
|
28209
|
+
"unmapped",
|
|
28210
|
+
"manual",
|
|
28211
|
+
"preset"
|
|
28212
|
+
]),
|
|
28213
|
+
confidence: z.number(),
|
|
28214
|
+
fieldType: z.enum([
|
|
28215
|
+
"string",
|
|
28216
|
+
"number",
|
|
28217
|
+
"boolean",
|
|
28218
|
+
"unknown"
|
|
28219
|
+
]).optional(),
|
|
28220
|
+
labelPrefix: z.string().optional().describe(""),
|
|
28221
|
+
descriptionHeading: z.string().optional().describe("")
|
|
28222
|
+
})).optional().describe(""),
|
|
28223
|
+
assignee_plan: z.object({
|
|
28224
|
+
role: z.enum([
|
|
28225
|
+
"owner",
|
|
28226
|
+
"admin",
|
|
28227
|
+
"member",
|
|
28228
|
+
"guest"
|
|
28229
|
+
]).optional(),
|
|
28230
|
+
teamIds: z.array(z.string()).optional(),
|
|
28231
|
+
entries: z.array(z.object({
|
|
28232
|
+
sourceValue: z.string(),
|
|
28233
|
+
action: z.enum([
|
|
28234
|
+
"assign",
|
|
28235
|
+
"create",
|
|
28236
|
+
"skip"
|
|
28237
|
+
]),
|
|
28238
|
+
userId: z.string().optional(),
|
|
28239
|
+
email: z.string().optional()
|
|
28240
|
+
}))
|
|
28241
|
+
}).optional().describe(""),
|
|
28242
|
+
team_ids: z.array(z.string()).optional()
|
|
28243
|
+
});
|
|
28244
|
+
const zTestCaseImportResultDto = z.object({
|
|
28245
|
+
status: z.enum([
|
|
28246
|
+
"completed",
|
|
28247
|
+
"completed_with_warnings",
|
|
28248
|
+
"failed"
|
|
28249
|
+
]),
|
|
28250
|
+
created_tests: z.array(z.object({
|
|
28251
|
+
id: z.string(),
|
|
28252
|
+
name: z.string()
|
|
28253
|
+
})),
|
|
28254
|
+
stats: z.object({
|
|
28255
|
+
rows_processed: z.number(),
|
|
28256
|
+
tests_created: z.number(),
|
|
28257
|
+
folders_created: z.number(),
|
|
28258
|
+
steps_created: z.number(),
|
|
28259
|
+
preconditions_created: z.number(),
|
|
28260
|
+
rows_failed: z.number(),
|
|
28261
|
+
members_provisioned: z.number().optional()
|
|
28262
|
+
}),
|
|
28263
|
+
warnings: z.array(z.object({
|
|
28264
|
+
type: z.enum([
|
|
28265
|
+
"skipped",
|
|
28266
|
+
"invalid",
|
|
28267
|
+
"unresolved",
|
|
28268
|
+
"write_failed"
|
|
28269
|
+
]),
|
|
28270
|
+
message: z.string(),
|
|
28271
|
+
row_index: z.number().optional(),
|
|
28272
|
+
column: z.string().optional(),
|
|
28273
|
+
count: z.number().optional(),
|
|
28274
|
+
values: z.array(z.object({
|
|
28275
|
+
value: z.string(),
|
|
28276
|
+
count: z.number()
|
|
28277
|
+
})).optional()
|
|
28278
|
+
})),
|
|
28279
|
+
errors: z.array(z.object({
|
|
28280
|
+
type: z.enum([
|
|
28281
|
+
"skipped",
|
|
28282
|
+
"invalid",
|
|
28283
|
+
"unresolved",
|
|
28284
|
+
"write_failed"
|
|
28285
|
+
]),
|
|
28286
|
+
message: z.string(),
|
|
28287
|
+
row_index: z.number().optional(),
|
|
28288
|
+
column: z.string().optional(),
|
|
28289
|
+
count: z.number().optional(),
|
|
28290
|
+
values: z.array(z.object({
|
|
28291
|
+
value: z.string(),
|
|
28292
|
+
count: z.number()
|
|
28293
|
+
})).optional()
|
|
28294
|
+
}))
|
|
28295
|
+
});
|
|
28296
|
+
const zTestCaseImportPreviewV1Data = z.object({
|
|
28297
|
+
body: zPreviewImportDto,
|
|
28298
|
+
url: z.literal("/v1/test-case-import/preview")
|
|
28299
|
+
});
|
|
28300
|
+
const zTestCaseImportCommitV1Data = z.object({
|
|
28301
|
+
body: zCommitImportDto,
|
|
28302
|
+
url: z.literal("/v1/test-case-import/commit")
|
|
28303
|
+
});
|
|
28304
|
+
|
|
28003
28305
|
//#endregion
|
|
28004
28306
|
//#region ../sdk/dist/gen/test-comment/zod.js
|
|
28005
28307
|
const zTestCommentFindAllV1Data = z.object({
|
|
@@ -30312,7 +30614,10 @@ const zInviteMultiUserDto = z.object({
|
|
|
30312
30614
|
workspace_ids: z.array(z.string()).describe(""),
|
|
30313
30615
|
team_ids_by_workspace: z.record(z.string(), z.array(z.string())).optional().describe("")
|
|
30314
30616
|
});
|
|
30315
|
-
const zAcceptByTokenDto = z.object({
|
|
30617
|
+
const zAcceptByTokenDto = z.object({
|
|
30618
|
+
token: z.string().describe(""),
|
|
30619
|
+
password: z.string().optional().describe("")
|
|
30620
|
+
});
|
|
30316
30621
|
const zAcceptByTokenResponseDto = z.object({
|
|
30317
30622
|
access_token: z.string().describe(""),
|
|
30318
30623
|
user: z.object({
|
|
@@ -30746,4 +31051,4 @@ function tryReadMessage(err) {
|
|
|
30746
31051
|
}
|
|
30747
31052
|
|
|
30748
31053
|
//#endregion
|
|
30749
|
-
export { authGetProfileV1, authGetSitesV1, client, configureClient, uploadAutomationIngest, uploadImport };
|
|
31054
|
+
export { authGetProfileV1, authGetSitesV1, client, configureClient, testCaseImportCommitV1, testCaseImportPreviewV1, uploadAutomationIngest, uploadImport };
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import "./env-NxtzJJPk.js";
|
|
2
|
-
import { authGetSitesV1, configureClient } from "./sdk-client-
|
|
2
|
+
import { authGetSitesV1, configureClient } from "./sdk-client-DyRTezC5.js";
|
|
3
3
|
import { saveWorkspace } from "./workspace-store-4hfvsEHS.js";
|
|
4
4
|
import "./token-refresh-Cz-FqDtC.js";
|
|
5
|
-
import { resolveToken } from "./resolve-token-
|
|
5
|
+
import { resolveToken } from "./resolve-token-Dq8cAuiu.js";
|
|
6
6
|
|
|
7
7
|
//#region src/commands/workspace/selectHandler.ts
|
|
8
8
|
async function selectHandler(_flags, workspaceId) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { getApiUrl, getPatToken, readCredentials } from "./env-NxtzJJPk.js";
|
|
2
|
-
import { authGetProfileV1, configureClient } from "./sdk-client-
|
|
2
|
+
import { authGetProfileV1, configureClient } from "./sdk-client-DyRTezC5.js";
|
|
3
3
|
import { isTokenExpired } from "./token-refresh-Cz-FqDtC.js";
|
|
4
4
|
import chalk from "chalk";
|
|
5
5
|
|
package/package.json
CHANGED
|
File without changes
|
|
File without changes
|
|
File without changes
|