@levr-one/cli 0.7.7 → 0.8.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/dist/cli.js +102 -12
- package/dist/{importHandler-B2zyKkUX.js → importHandler-zfgrGCyh.js} +184 -6
- package/dist/{listHandler-BaXnaQkv.js → listHandler-B5KqRcYG.js} +1 -1
- package/dist/loginHandler-BE9JX12M.js +388 -0
- package/dist/{pushHandler-DD18UAh3.js → pushHandler-BukCooiv.js} +2 -2
- package/dist/{resolve-workspace-anULXxRH.js → resolve-workspace-NupdkCvd.js} +1 -1
- package/dist/{sdk-client-BLUjDoCb.js → sdk-client-CATjlmyX.js} +44 -23
- package/dist/{selectHandler-CH0fcc2P.js → selectHandler-CXwxIKL9.js} +1 -1
- package/dist/{statusHandler-DBC29FE4.js → statusHandler-CyhoTEEI.js} +1 -1
- package/package.json +2 -1
- package/dist/loginHandler-swasPGVn.js +0 -388
package/dist/cli.js
CHANGED
|
@@ -2,6 +2,9 @@
|
|
|
2
2
|
import { COMPLETION_SHELLS } from "./completionHandler-O2G_WZLf.js";
|
|
3
3
|
import { buildApplication, buildCommand, buildRouteMap, proposeCompletions, run, text_en } from "@stricli/core";
|
|
4
4
|
import chalk from "chalk";
|
|
5
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
6
|
+
import { isAbsolute, resolve } from "node:path";
|
|
7
|
+
import { parse } from "dotenv";
|
|
5
8
|
|
|
6
9
|
//#region src/utils/logger.ts
|
|
7
10
|
var Logger = class {
|
|
@@ -210,7 +213,7 @@ Examples:
|
|
|
210
213
|
aliases: { d: "device-code" }
|
|
211
214
|
},
|
|
212
215
|
loader: async () => {
|
|
213
|
-
const { loginHandler } = await import("./loginHandler-
|
|
216
|
+
const { loginHandler } = await import("./loginHandler-BE9JX12M.js");
|
|
214
217
|
return loginHandler;
|
|
215
218
|
}
|
|
216
219
|
});
|
|
@@ -249,7 +252,7 @@ Examples:
|
|
|
249
252
|
},
|
|
250
253
|
parameters: {},
|
|
251
254
|
loader: async () => {
|
|
252
|
-
const { statusHandler } = await import("./statusHandler-
|
|
255
|
+
const { statusHandler } = await import("./statusHandler-CyhoTEEI.js");
|
|
253
256
|
return statusHandler;
|
|
254
257
|
}
|
|
255
258
|
});
|
|
@@ -361,7 +364,7 @@ Examples:
|
|
|
361
364
|
}
|
|
362
365
|
},
|
|
363
366
|
loader: async () => {
|
|
364
|
-
const { pushHandler } = await import("./pushHandler-
|
|
367
|
+
const { pushHandler } = await import("./pushHandler-BukCooiv.js");
|
|
365
368
|
return pushHandler;
|
|
366
369
|
}
|
|
367
370
|
});
|
|
@@ -382,9 +385,9 @@ Required-field rule: a column must map to test_name or the commit is
|
|
|
382
385
|
rejected — interactive mode will ask; non-interactive runs exit 1.
|
|
383
386
|
|
|
384
387
|
Examples:
|
|
385
|
-
levr import ./testrail-export.csv --team-
|
|
386
|
-
levr import ./cases.xlsx --team-
|
|
387
|
-
levr import --sheets-url "https://docs.google.com/spreadsheets/d/..." --team-
|
|
388
|
+
levr import ./testrail-export.csv --team-key ENG
|
|
389
|
+
levr import ./cases.xlsx --team-key ENG --map "Title=test_name"
|
|
390
|
+
levr import --sheets-url "https://docs.google.com/spreadsheets/d/..." --team-key ENG --yes
|
|
388
391
|
levr import ./cases.csv --team-id <uuid> --save-mapping mapping.json
|
|
389
392
|
levr import ./cases.csv --team-id <uuid> --mapping-file mapping.json --yes # CI replay`
|
|
390
393
|
},
|
|
@@ -409,9 +412,16 @@ Examples:
|
|
|
409
412
|
"team-id": {
|
|
410
413
|
kind: "parsed",
|
|
411
414
|
parse: String,
|
|
412
|
-
brief: "Team the
|
|
415
|
+
brief: "Team doing the import, by UUID. Optional: use --team-key instead, or omit both when the workspace has one team",
|
|
413
416
|
placeholder: "uuid",
|
|
414
|
-
optional:
|
|
417
|
+
optional: true
|
|
418
|
+
},
|
|
419
|
+
"team-key": {
|
|
420
|
+
kind: "parsed",
|
|
421
|
+
parse: String,
|
|
422
|
+
brief: "Team doing the import, by key (e.g. ENG). Case-insensitive. Alternative to --team-id",
|
|
423
|
+
placeholder: "key",
|
|
424
|
+
optional: true
|
|
415
425
|
},
|
|
416
426
|
"sheets-url": {
|
|
417
427
|
kind: "parsed",
|
|
@@ -466,6 +476,7 @@ Examples:
|
|
|
466
476
|
aliases: {
|
|
467
477
|
w: "workspace-id",
|
|
468
478
|
t: "team-id",
|
|
479
|
+
k: "team-key",
|
|
469
480
|
f: "format",
|
|
470
481
|
m: "map",
|
|
471
482
|
y: "yes",
|
|
@@ -473,7 +484,7 @@ Examples:
|
|
|
473
484
|
}
|
|
474
485
|
},
|
|
475
486
|
loader: async () => {
|
|
476
|
-
const { importHandler } = await import("./importHandler-
|
|
487
|
+
const { importHandler } = await import("./importHandler-zfgrGCyh.js");
|
|
477
488
|
return importHandler;
|
|
478
489
|
}
|
|
479
490
|
});
|
|
@@ -494,7 +505,7 @@ Examples:
|
|
|
494
505
|
},
|
|
495
506
|
parameters: {},
|
|
496
507
|
loader: async () => {
|
|
497
|
-
const { listHandler } = await import("./listHandler-
|
|
508
|
+
const { listHandler } = await import("./listHandler-B5KqRcYG.js");
|
|
498
509
|
return listHandler;
|
|
499
510
|
}
|
|
500
511
|
});
|
|
@@ -527,7 +538,7 @@ Examples:
|
|
|
527
538
|
flags: {}
|
|
528
539
|
},
|
|
529
540
|
loader: async () => {
|
|
530
|
-
const { selectHandler } = await import("./selectHandler-
|
|
541
|
+
const { selectHandler } = await import("./selectHandler-CXwxIKL9.js");
|
|
531
542
|
return selectHandler;
|
|
532
543
|
}
|
|
533
544
|
});
|
|
@@ -551,7 +562,7 @@ Examples:
|
|
|
551
562
|
|
|
552
563
|
//#endregion
|
|
553
564
|
//#region package.json
|
|
554
|
-
var version = "0.
|
|
565
|
+
var version = "0.8.0";
|
|
555
566
|
|
|
556
567
|
//#endregion
|
|
557
568
|
//#region src/app.ts
|
|
@@ -622,9 +633,88 @@ async function proposeCompletionLines(rawArgs, compLine, context) {
|
|
|
622
633
|
}
|
|
623
634
|
}
|
|
624
635
|
|
|
636
|
+
//#endregion
|
|
637
|
+
//#region src/utils/load-env-file.ts
|
|
638
|
+
/**
|
|
639
|
+
* Only `LEVR_`-prefixed keys are taken from a `.env` file.
|
|
640
|
+
*
|
|
641
|
+
* `dotenv.config()` would merge EVERY key into `process.env`, which is more
|
|
642
|
+
* than this CLI needs and more than a user consents to by running it in a
|
|
643
|
+
* directory. A checkout's `.env` routinely carries things that change how Node
|
|
644
|
+
* itself behaves — `NODE_TLS_REJECT_UNAUTHORIZED`, `HTTP_PROXY`,
|
|
645
|
+
* `NODE_OPTIONS` — and none of them are ours to apply. Parsing and filtering
|
|
646
|
+
* means an unrelated project's `.env` cannot reach this process at all; only
|
|
647
|
+
* keys deliberately namespaced for this CLI have any effect.
|
|
648
|
+
*/
|
|
649
|
+
const LEVR_KEY = /^LEVR_[A-Z0-9_]*$/;
|
|
650
|
+
/**
|
|
651
|
+
* Where to look. `LEVR_ENV_FILE` names an explicit file (absolute, or relative
|
|
652
|
+
* to cwd); otherwise `.env` in the working directory.
|
|
653
|
+
*/
|
|
654
|
+
function envFilePath(cwd, env) {
|
|
655
|
+
const explicit = env["LEVR_ENV_FILE"];
|
|
656
|
+
if (explicit) return isAbsolute(explicit) ? explicit : resolve(cwd, explicit);
|
|
657
|
+
return resolve(cwd, ".env");
|
|
658
|
+
}
|
|
659
|
+
/**
|
|
660
|
+
* Merge `LEVR_*` variables from a `.env` file into `process.env`.
|
|
661
|
+
*
|
|
662
|
+
* A real environment variable ALWAYS wins: an already-set key is left alone,
|
|
663
|
+
* so `LEVR_URL=… levr push` still overrides the file, and CI variables are
|
|
664
|
+
* never shadowed by a checked-in `.env`. This matches dotenv's own precedence
|
|
665
|
+
* and is the behaviour anyone who has used a `.env` expects — the file is a
|
|
666
|
+
* default, not an override.
|
|
667
|
+
*
|
|
668
|
+
* Missing or unreadable files are not an error: `.env` is optional by nature,
|
|
669
|
+
* and a CLI that refused to start because a directory has no `.env` would be
|
|
670
|
+
* broken for every user who does not use one. An explicitly requested
|
|
671
|
+
* `LEVR_ENV_FILE` that does not exist IS reported, because naming a file and
|
|
672
|
+
* getting silence is the one case where quiet failure hides a real mistake.
|
|
673
|
+
*/
|
|
674
|
+
function loadEnvFile(cwd = process.cwd(), env = process.env) {
|
|
675
|
+
const path = envFilePath(cwd, env);
|
|
676
|
+
const explicitlyRequested = Boolean(env["LEVR_ENV_FILE"]);
|
|
677
|
+
if (!existsSync(path)) {
|
|
678
|
+
if (explicitlyRequested) throw new Error(`LEVR_ENV_FILE points at "${path}", which does not exist.`);
|
|
679
|
+
return {
|
|
680
|
+
path: null,
|
|
681
|
+
applied: []
|
|
682
|
+
};
|
|
683
|
+
}
|
|
684
|
+
let parsed;
|
|
685
|
+
try {
|
|
686
|
+
parsed = parse(readFileSync(path, "utf8"));
|
|
687
|
+
} catch (error) {
|
|
688
|
+
if (explicitlyRequested) throw error;
|
|
689
|
+
return {
|
|
690
|
+
path: null,
|
|
691
|
+
applied: []
|
|
692
|
+
};
|
|
693
|
+
}
|
|
694
|
+
const applied = [];
|
|
695
|
+
for (const [key, value] of Object.entries(parsed)) {
|
|
696
|
+
if (!LEVR_KEY.test(key)) continue;
|
|
697
|
+
if (env[key] !== void 0 && env[key] !== "") continue;
|
|
698
|
+
env[key] = value;
|
|
699
|
+
applied.push(key);
|
|
700
|
+
}
|
|
701
|
+
return {
|
|
702
|
+
path,
|
|
703
|
+
applied
|
|
704
|
+
};
|
|
705
|
+
}
|
|
706
|
+
|
|
625
707
|
//#endregion
|
|
626
708
|
//#region src/bin/cli.ts
|
|
627
709
|
const argv = process.argv.slice(2);
|
|
710
|
+
try {
|
|
711
|
+
loadEnvFile();
|
|
712
|
+
} catch (err) {
|
|
713
|
+
if (argv[0] !== "__complete") {
|
|
714
|
+
process.stderr.write(`${err instanceof Error ? err.message : String(err)}\n`);
|
|
715
|
+
process.exit(1);
|
|
716
|
+
}
|
|
717
|
+
}
|
|
628
718
|
if (argv[0] === "__complete") for (const line of await proposeCompletionLines(argv, process.env["COMP_LINE"], buildContext(process))) process.stdout.write(`${line}\n`);
|
|
629
719
|
else {
|
|
630
720
|
let savedExitCode;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { getApiUrl } from "./env-CHeKHu5S.js";
|
|
2
|
-
import { configureClient, testCaseImportCommitV1, testCaseImportPreviewV1 } from "./sdk-client-
|
|
1
|
+
import { getApiUrl, getTeamId } from "./env-CHeKHu5S.js";
|
|
2
|
+
import { authGetProfileV1, configureClient, teamFindAllV1, testCaseImportCommitV1, testCaseImportPreviewV1 } from "./sdk-client-CATjlmyX.js";
|
|
3
3
|
import "./workspace-store-DDOxnut1.js";
|
|
4
|
-
import { resolveWorkspace } from "./resolve-workspace-
|
|
4
|
+
import { resolveWorkspace } from "./resolve-workspace-NupdkCvd.js";
|
|
5
5
|
import "./token-refresh-Cu5RpkLJ.js";
|
|
6
6
|
import { resolveToken } from "./resolve-token-DbQsmn03.js";
|
|
7
7
|
import chalk from "chalk";
|
|
@@ -11,8 +11,167 @@ import { readFile, writeFile } from "node:fs/promises";
|
|
|
11
11
|
import { createInterface } from "node:readline/promises";
|
|
12
12
|
import ora from "ora";
|
|
13
13
|
|
|
14
|
+
//#region src/commands/resolve-team.ts
|
|
15
|
+
/**
|
|
16
|
+
* The importing team — NOT the same thing as the `teams` column in the file.
|
|
17
|
+
*
|
|
18
|
+
* `teams` is OWNERSHIP: which teams the imported tests belong to. The
|
|
19
|
+
* importing team is who is doing the import, and the backend uses it as
|
|
20
|
+
* `primaryTeamId` for decisions the file cannot answer:
|
|
21
|
+
*
|
|
22
|
+
* - where an UNQUALIFIED `estimate` column lands (ENG-4396) — a bare
|
|
23
|
+
* `estimate` is not team-neutral, it sizes one specific team;
|
|
24
|
+
* - the guaranteed owner when the file names no teams at all
|
|
25
|
+
* (`ensureMinimumOfOneOwner`);
|
|
26
|
+
* - which team is excluded from the "extra teams" set.
|
|
27
|
+
*
|
|
28
|
+
* So it is not redundant with the file. It IS unreasonable to demand a UUID
|
|
29
|
+
* for it when the file speaks in keys, which is what `--team-key` fixes.
|
|
30
|
+
*
|
|
31
|
+
* Deliberately NOT inferred from the file's first `teams` value. That value
|
|
32
|
+
* decides where an unqualified estimate lands, and row order is a proxy for
|
|
33
|
+
* that question, not an answer to it — a reordered export would silently size
|
|
34
|
+
* a different team. When it cannot be determined, ask.
|
|
35
|
+
*/
|
|
36
|
+
async function fetchTeams() {
|
|
37
|
+
const PAGE_SIZE = 200;
|
|
38
|
+
const MAX_PAGES = 25;
|
|
39
|
+
const out = [];
|
|
40
|
+
for (let page = 1; page <= MAX_PAGES; page++) {
|
|
41
|
+
const result = await teamFindAllV1({ query: {
|
|
42
|
+
limit: PAGE_SIZE,
|
|
43
|
+
page
|
|
44
|
+
} });
|
|
45
|
+
if (result.error || !result.data) throw new Error(`Failed to list teams (${describeError(result.error)}).`);
|
|
46
|
+
const body = result.data;
|
|
47
|
+
const rows = body.data ?? [];
|
|
48
|
+
for (const r of rows) if (r.id && r.key) out.push({
|
|
49
|
+
id: r.id,
|
|
50
|
+
key: r.key,
|
|
51
|
+
name: r.name ?? r.key
|
|
52
|
+
});
|
|
53
|
+
const totalPages = body.meta?.totalPages;
|
|
54
|
+
if (rows.length === 0) break;
|
|
55
|
+
if (totalPages !== void 0 ? page >= totalPages : rows.length < PAGE_SIZE) break;
|
|
56
|
+
if (page === MAX_PAGES) process.stderr.write(`[levr] Warning: stopped after ${MAX_PAGES} pages of teams; a --team-key may not resolve.\n`);
|
|
57
|
+
}
|
|
58
|
+
return out;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* The caller's ACTIVE team, when it belongs to this workspace.
|
|
62
|
+
*
|
|
63
|
+
* `active_team_id` is the user's HOME team, not "the team they are looking
|
|
64
|
+
* at" — a distinction `apps/client/CLAUDE.md` is emphatic about. That makes it
|
|
65
|
+
* a fair default for "who is importing" and a poor one for anything scoped to
|
|
66
|
+
* a view, so it is used here and reported, never assumed silently.
|
|
67
|
+
*
|
|
68
|
+
* MUST be checked against this workspace's teams. A user can belong to several
|
|
69
|
+
* workspaces while their home team lives in one of them; adopting it unchecked
|
|
70
|
+
* would import into a team that is not in the workspace being imported to.
|
|
71
|
+
*
|
|
72
|
+
* A failure here is not fatal — it just means no default. The explicit flags
|
|
73
|
+
* and the single-team case still work without a profile call succeeding.
|
|
74
|
+
*/
|
|
75
|
+
async function activeTeamIn(teams) {
|
|
76
|
+
let activeId;
|
|
77
|
+
try {
|
|
78
|
+
const result = await authGetProfileV1();
|
|
79
|
+
if (result.error || !result.data) return null;
|
|
80
|
+
activeId = result.data.active_team_id ?? void 0;
|
|
81
|
+
} catch {
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
if (!activeId) return null;
|
|
85
|
+
return teams.some((t) => t.id === activeId) ? activeId : null;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* F-012: `JSON.stringify(new Error("boom"))` is `"{}"` — Error's own fields are
|
|
89
|
+
* non-enumerable. The detail that was meant to end the misdirection produced
|
|
90
|
+
* "Failed to list teams ({})", which is worse than saying nothing.
|
|
91
|
+
*/
|
|
92
|
+
function describeError(error) {
|
|
93
|
+
if (error === void 0 || error === null) return "no data returned";
|
|
94
|
+
if (error instanceof Error) return error.message;
|
|
95
|
+
if (typeof error === "string") return error;
|
|
96
|
+
try {
|
|
97
|
+
const json = JSON.stringify(error);
|
|
98
|
+
if (json !== void 0 && json !== "{}") return json;
|
|
99
|
+
} catch {}
|
|
100
|
+
return "unserialisable error";
|
|
101
|
+
}
|
|
102
|
+
function describe(teams) {
|
|
103
|
+
return teams.map((t) => ` ${t.key} ${t.name}`).join("\n");
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Resolve the importing team from `--team-id`, `--team-key`, or the workspace.
|
|
107
|
+
*
|
|
108
|
+
* Key matching is case-insensitive: the file writes `ENG`, and a user typing
|
|
109
|
+
* `eng` means the same team. Errors list the valid keys, because "no team
|
|
110
|
+
* matched" without saying what would have is the least useful thing this can
|
|
111
|
+
* print.
|
|
112
|
+
*/
|
|
113
|
+
async function resolveTeamId(teamId, teamKey, envTeamId) {
|
|
114
|
+
if (teamId && teamKey) throw new Error("Pass either --team-id or --team-key, not both — they can disagree, and there is no sensible winner.");
|
|
115
|
+
if (teamId) return {
|
|
116
|
+
teamId,
|
|
117
|
+
source: "team-id"
|
|
118
|
+
};
|
|
119
|
+
const teams = await fetchTeams();
|
|
120
|
+
if (teams.length === 0) throw new Error("No teams found in this workspace.");
|
|
121
|
+
if (teamKey) {
|
|
122
|
+
const wanted = teamKey.trim().toLowerCase();
|
|
123
|
+
const matches = teams.filter((t) => t.key.toLowerCase() === wanted);
|
|
124
|
+
if (matches.length === 1) return {
|
|
125
|
+
teamId: matches[0].id,
|
|
126
|
+
source: "team-key"
|
|
127
|
+
};
|
|
128
|
+
if (matches.length === 0) throw new Error(`No team with key "${teamKey}" in this workspace. Available:\n${describe(teams)}`);
|
|
129
|
+
throw new Error(`More than one team has key "${teamKey}" in this workspace — refusing to guess.`);
|
|
130
|
+
}
|
|
131
|
+
if (envTeamId) {
|
|
132
|
+
if (teams.some((t) => t.id === envTeamId)) return {
|
|
133
|
+
teamId: envTeamId,
|
|
134
|
+
source: "env"
|
|
135
|
+
};
|
|
136
|
+
throw new Error(`LEVR_TEAM_ID (${envTeamId}) is not a team in this workspace. Available:\n${describe(teams)}`);
|
|
137
|
+
}
|
|
138
|
+
const active = await activeTeamIn(teams);
|
|
139
|
+
if (active) return {
|
|
140
|
+
teamId: active,
|
|
141
|
+
source: "active-team"
|
|
142
|
+
};
|
|
143
|
+
if (teams.length === 1) return {
|
|
144
|
+
teamId: teams[0].id,
|
|
145
|
+
source: "only-team"
|
|
146
|
+
};
|
|
147
|
+
throw new Error(`--team-key or --team-id is required: this workspace has ${teams.length} teams and you have no active team here.\n${describe(teams)}`);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
//#endregion
|
|
14
151
|
//#region src/utils/import-mapping.ts
|
|
15
|
-
|
|
152
|
+
/**
|
|
153
|
+
* Every import target the CLI will accept for `--map`.
|
|
154
|
+
*
|
|
155
|
+
* ENG-3857 shipped a `teams` target on the server and in the web client, and
|
|
156
|
+
* this list was left behind — so `levr import --map "Team=teams"` threw
|
|
157
|
+
* "Invalid --map target" and team ownership was simply unreachable from the
|
|
158
|
+
* CLI. Nothing caught it: this is the THIRD hand-maintained copy of the
|
|
159
|
+
* target list (backend `IMPORT_TARGET_PROPERTIES`, client
|
|
160
|
+
* `TEST_CASE_KNOWN_PROPERTIES`, here), and while the ELEMENT type is derived
|
|
161
|
+
* from the SDK, TypeScript cannot see that an array literal omits a member of
|
|
162
|
+
* a union — `ImportTarget[]` is satisfied by any subset, including `[]`.
|
|
163
|
+
*
|
|
164
|
+
* So the literal is `as const` and the exhaustiveness assertions below turn a
|
|
165
|
+
* missing target into a COMPILE error naming it, rather than a runtime
|
|
166
|
+
* rejection the user discovers. Adding a target server-side now breaks this
|
|
167
|
+
* build until it is listed here.
|
|
168
|
+
*
|
|
169
|
+
* Caveat worth knowing: `@levr/sdk` resolves to `dist/`, so the union this
|
|
170
|
+
* is checked against is only as fresh as the last SDK build. A regenerated
|
|
171
|
+
* but unbuilt SDK delays detection to the next build — it does not restore
|
|
172
|
+
* the old failure, where the omission was invisible indefinitely.
|
|
173
|
+
*/
|
|
174
|
+
const IMPORT_TARGET_LIST = [
|
|
16
175
|
"row_type",
|
|
17
176
|
"test_id",
|
|
18
177
|
"test_key",
|
|
@@ -29,6 +188,7 @@ const IMPORT_TARGETS = [
|
|
|
29
188
|
"is_automated",
|
|
30
189
|
"assignee_email",
|
|
31
190
|
"labels",
|
|
191
|
+
"teams",
|
|
32
192
|
"attachment_filenames",
|
|
33
193
|
"data_set_names",
|
|
34
194
|
"sequence",
|
|
@@ -42,6 +202,7 @@ const IMPORT_TARGETS = [
|
|
|
42
202
|
"steps",
|
|
43
203
|
"preconditions"
|
|
44
204
|
];
|
|
205
|
+
const IMPORT_TARGETS = IMPORT_TARGET_LIST;
|
|
45
206
|
const REQUIRED_TARGETS = ["test_name"];
|
|
46
207
|
/**
|
|
47
208
|
* Parse a --map value: "Source Column=target", "Source Column=" (drop),
|
|
@@ -166,16 +327,33 @@ async function importHandler(flags, file) {
|
|
|
166
327
|
this.logger.debug(`API: ${getApiUrl()}`);
|
|
167
328
|
}
|
|
168
329
|
if (auth.type === "jwt") {
|
|
169
|
-
|
|
330
|
+
let workspace;
|
|
331
|
+
try {
|
|
332
|
+
workspace = await resolveWorkspace.call(this, flags["workspace-id"]);
|
|
333
|
+
} catch (err) {
|
|
334
|
+
this.logger.error(err instanceof Error ? err.message : "Could not resolve the workspace.");
|
|
170
335
|
this.process.exitCode = 1;
|
|
171
336
|
return;
|
|
172
337
|
}
|
|
338
|
+
configureClient(auth, workspace.workspaceId);
|
|
339
|
+
}
|
|
340
|
+
let teamId;
|
|
341
|
+
try {
|
|
342
|
+
const team = await resolveTeamId(flags["team-id"], flags["team-key"], getTeamId());
|
|
343
|
+
teamId = team.teamId;
|
|
344
|
+
if (team.source === "active-team") this.logger.info(`Importing as your active team (${teamId}).`);
|
|
345
|
+
else if (team.source === "env") this.logger.info(`Importing as LEVR_TEAM_ID (${teamId}).`);
|
|
346
|
+
else if (team.source === "only-team") this.logger.info(`Importing as the only team in this workspace.`);
|
|
347
|
+
} catch (err) {
|
|
348
|
+
this.logger.error(err instanceof Error ? err.message : "Could not resolve the team.");
|
|
349
|
+
this.process.exitCode = 1;
|
|
350
|
+
return;
|
|
173
351
|
}
|
|
174
352
|
const spinner = ora("Uploading and analyzing the file…").start();
|
|
175
353
|
let preview;
|
|
176
354
|
try {
|
|
177
355
|
const body = {
|
|
178
|
-
team_id:
|
|
356
|
+
team_id: teamId,
|
|
179
357
|
format: flags.format,
|
|
180
358
|
sheets_url: flags["sheets-url"]
|
|
181
359
|
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import "./env-CHeKHu5S.js";
|
|
2
|
-
import { authGetSitesV1, configureClient } from "./sdk-client-
|
|
2
|
+
import { authGetSitesV1, configureClient } from "./sdk-client-CATjlmyX.js";
|
|
3
3
|
import { loadWorkspace } from "./workspace-store-DDOxnut1.js";
|
|
4
4
|
import "./token-refresh-Cu5RpkLJ.js";
|
|
5
5
|
import { resolveToken } from "./resolve-token-DbQsmn03.js";
|