@tlog/cli 0.1.3
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 +307 -0
- package/bin/.gitkeep +0 -0
- package/bin/tlog.js +4 -0
- package/dist/commands/delete.d.ts +8 -0
- package/dist/commands/delete.d.ts.map +1 -0
- package/dist/commands/delete.js +104 -0
- package/dist/commands/delete.js.map +1 -0
- package/dist/commands/init-template.d.ts +12 -0
- package/dist/commands/init-template.d.ts.map +1 -0
- package/dist/commands/init-template.js +168 -0
- package/dist/commands/init-template.js.map +1 -0
- package/dist/commands/related.d.ts +13 -0
- package/dist/commands/related.d.ts.map +1 -0
- package/dist/commands/related.js +193 -0
- package/dist/commands/related.js.map +1 -0
- package/dist/commands/stats.d.ts +8 -0
- package/dist/commands/stats.d.ts.map +1 -0
- package/dist/commands/stats.js +62 -0
- package/dist/commands/stats.js.map +1 -0
- package/dist/commands/suite-case.d.ts +20 -0
- package/dist/commands/suite-case.d.ts.map +1 -0
- package/dist/commands/suite-case.js +83 -0
- package/dist/commands/suite-case.js.map +1 -0
- package/dist/commands/update.d.ts +33 -0
- package/dist/commands/update.d.ts.map +1 -0
- package/dist/commands/update.js +159 -0
- package/dist/commands/update.js.map +1 -0
- package/dist/commands/validate-list.d.ts +36 -0
- package/dist/commands/validate-list.d.ts.map +1 -0
- package/dist/commands/validate-list.js +270 -0
- package/dist/commands/validate-list.js.map +1 -0
- package/dist/core.d.ts +30 -0
- package/dist/core.d.ts.map +1 -0
- package/dist/core.js +143 -0
- package/dist/core.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +218 -0
- package/dist/index.js.map +1 -0
- package/package.json +39 -0
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { mkdirSync, readFileSync, renameSync, writeFileSync } from "node:fs";
|
|
3
|
+
import { dirname, resolve } from "node:path";
|
|
4
|
+
import { detectEntityType, normalizeTlogPath, parseYaml, stringifyYaml, validateCase, validateSuite } from "@tlog/shared";
|
|
5
|
+
import { CliError, emitSuccess, ensureDirectory, formatOf, walkYamlFiles } from "../core.js";
|
|
6
|
+
function writeYamlFileAtomicSync(path, value) {
|
|
7
|
+
const content = stringifyYaml(value);
|
|
8
|
+
const parent = dirname(path);
|
|
9
|
+
mkdirSync(parent, { recursive: true });
|
|
10
|
+
const tempPath = `${path}.${randomUUID()}.tmp`;
|
|
11
|
+
writeFileSync(tempPath, content, "utf8");
|
|
12
|
+
renameSync(tempPath, path);
|
|
13
|
+
}
|
|
14
|
+
function unique(values) {
|
|
15
|
+
return Array.from(new Set(values));
|
|
16
|
+
}
|
|
17
|
+
function csvCell(value) {
|
|
18
|
+
if (value.includes(",") || value.includes("\"") || value.includes("\n")) {
|
|
19
|
+
return `"${value.replaceAll("\"", "\"\"")}"`;
|
|
20
|
+
}
|
|
21
|
+
return value;
|
|
22
|
+
}
|
|
23
|
+
function toCsv(headers, rows) {
|
|
24
|
+
return [headers.join(","), ...rows.map((row) => row.map(csvCell).join(","))].join("\n");
|
|
25
|
+
}
|
|
26
|
+
function toAlignedTable(headers, rows) {
|
|
27
|
+
const widths = headers.map((header, index) => Math.max(header.length, ...rows.map((row) => (row[index] ?? "").length)));
|
|
28
|
+
const padRow = (row) => row.map((cell, index) => cell.padEnd(widths[index])).join(" ");
|
|
29
|
+
return [padRow(headers), ...rows.map((row) => padRow(row))].join("\n");
|
|
30
|
+
}
|
|
31
|
+
export function runRelatedSync(cwd, options, globalOptions) {
|
|
32
|
+
const format = formatOf(globalOptions);
|
|
33
|
+
const rootDir = resolve(cwd, options.dir);
|
|
34
|
+
ensureDirectory(rootDir, "Related sync directory does not exist");
|
|
35
|
+
const entities = walkYamlFiles(rootDir)
|
|
36
|
+
.map((path) => {
|
|
37
|
+
const type = detectEntityType(path);
|
|
38
|
+
if (type !== "suite" && type !== "case") {
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
try {
|
|
42
|
+
const raw = parseYaml(readFileSync(path, "utf8"));
|
|
43
|
+
const id = typeof raw.id === "string" ? raw.id : "";
|
|
44
|
+
const related = Array.isArray(raw.related)
|
|
45
|
+
? raw.related.filter((value) => typeof value === "string")
|
|
46
|
+
: [];
|
|
47
|
+
if (!id) {
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
return { id, path, type, related, raw };
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
})
|
|
56
|
+
.filter((item) => item !== null);
|
|
57
|
+
const index = new Map();
|
|
58
|
+
const duplicateIds = [];
|
|
59
|
+
for (const entity of entities) {
|
|
60
|
+
if (index.has(entity.id)) {
|
|
61
|
+
duplicateIds.push(entity.id);
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
index.set(entity.id, entity);
|
|
65
|
+
}
|
|
66
|
+
if (duplicateIds.length > 0) {
|
|
67
|
+
throw new CliError("Duplicate ids found. related sync requires unique ids.", {
|
|
68
|
+
details: unique(duplicateIds)
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
const sources = options.id !== undefined
|
|
72
|
+
? (() => {
|
|
73
|
+
const entity = index.get(options.id);
|
|
74
|
+
if (!entity) {
|
|
75
|
+
throw new CliError(`id not found: ${options.id}`);
|
|
76
|
+
}
|
|
77
|
+
return [entity];
|
|
78
|
+
})()
|
|
79
|
+
: entities;
|
|
80
|
+
const unresolved = [];
|
|
81
|
+
const additions = new Map();
|
|
82
|
+
for (const source of sources) {
|
|
83
|
+
for (const targetId of source.related) {
|
|
84
|
+
const target = index.get(targetId);
|
|
85
|
+
if (!target) {
|
|
86
|
+
unresolved.push({ sourceId: source.id, targetId });
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
if (target.id === source.id || target.related.includes(source.id)) {
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
const set = additions.get(target.path) ?? new Set();
|
|
93
|
+
set.add(source.id);
|
|
94
|
+
additions.set(target.path, set);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
const changedFiles = [];
|
|
98
|
+
for (const [targetPath, sourceIds] of additions.entries()) {
|
|
99
|
+
const entity = entities.find((item) => item.path === targetPath);
|
|
100
|
+
if (!entity) {
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
const next = {
|
|
104
|
+
...entity.raw,
|
|
105
|
+
related: unique([...(entity.related ?? []), ...Array.from(sourceIds)])
|
|
106
|
+
};
|
|
107
|
+
const validation = entity.type === "suite" ? validateSuite(next) : validateCase(next);
|
|
108
|
+
if (!validation.ok || !validation.data) {
|
|
109
|
+
throw new CliError(`Related sync validation failed: ${entity.id}`, {
|
|
110
|
+
details: validation.errors.map((item) => `${item.path}: ${item.message}`)
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
if (!globalOptions.dryRun) {
|
|
114
|
+
writeYamlFileAtomicSync(targetPath, next);
|
|
115
|
+
}
|
|
116
|
+
changedFiles.push(normalizeTlogPath(targetPath));
|
|
117
|
+
}
|
|
118
|
+
emitSuccess("related sync", {
|
|
119
|
+
dir: normalizeTlogPath(rootDir),
|
|
120
|
+
targetId: options.id ?? null,
|
|
121
|
+
dryRun: globalOptions.dryRun,
|
|
122
|
+
syncedCount: changedFiles.length,
|
|
123
|
+
changedFiles,
|
|
124
|
+
unresolved
|
|
125
|
+
}, format, [
|
|
126
|
+
`${globalOptions.dryRun ? "Would sync" : "Synced"} related links: ${changedFiles.length}`,
|
|
127
|
+
...(unresolved.length > 0 ? unresolved.map((item) => `UNRESOLVED ${item.sourceId} -> ${item.targetId}`) : [])
|
|
128
|
+
]);
|
|
129
|
+
}
|
|
130
|
+
export function runRelatedList(cwd, options, globalOptions) {
|
|
131
|
+
const format = formatOf(globalOptions, options.format);
|
|
132
|
+
const rootDir = resolve(cwd, options.dir);
|
|
133
|
+
ensureDirectory(rootDir, "Related list directory does not exist");
|
|
134
|
+
const entities = walkYamlFiles(rootDir)
|
|
135
|
+
.map((path) => {
|
|
136
|
+
const type = detectEntityType(path);
|
|
137
|
+
if (type !== "suite" && type !== "case") {
|
|
138
|
+
return null;
|
|
139
|
+
}
|
|
140
|
+
try {
|
|
141
|
+
const raw = parseYaml(readFileSync(path, "utf8"));
|
|
142
|
+
const id = typeof raw.id === "string" ? raw.id : "";
|
|
143
|
+
const related = Array.isArray(raw.related)
|
|
144
|
+
? raw.related.filter((value) => typeof value === "string")
|
|
145
|
+
: [];
|
|
146
|
+
if (!id) {
|
|
147
|
+
return null;
|
|
148
|
+
}
|
|
149
|
+
return { id, path, type, related };
|
|
150
|
+
}
|
|
151
|
+
catch {
|
|
152
|
+
return null;
|
|
153
|
+
}
|
|
154
|
+
})
|
|
155
|
+
.filter((item) => item !== null);
|
|
156
|
+
const index = new Map(entities.map((item) => [item.id, item]));
|
|
157
|
+
const source = index.get(options.id);
|
|
158
|
+
if (!source) {
|
|
159
|
+
throw new CliError(`id not found: ${options.id}`);
|
|
160
|
+
}
|
|
161
|
+
const resolved = [];
|
|
162
|
+
const unresolved = [];
|
|
163
|
+
for (const relatedId of source.related) {
|
|
164
|
+
const target = index.get(relatedId);
|
|
165
|
+
if (!target) {
|
|
166
|
+
unresolved.push(relatedId);
|
|
167
|
+
continue;
|
|
168
|
+
}
|
|
169
|
+
resolved.push({
|
|
170
|
+
type: target.type,
|
|
171
|
+
id: target.id,
|
|
172
|
+
path: normalizeTlogPath(target.path)
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
const payload = {
|
|
176
|
+
id: source.id,
|
|
177
|
+
path: normalizeTlogPath(source.path),
|
|
178
|
+
resolved,
|
|
179
|
+
unresolved
|
|
180
|
+
};
|
|
181
|
+
if (format === "json") {
|
|
182
|
+
process.stdout.write(`${JSON.stringify({ ok: true, command: "related list", data: payload }, null, 2)}\n`);
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
const headers = ["status", "type", "id", "path"];
|
|
186
|
+
const rows = [
|
|
187
|
+
...resolved.map((item) => ["resolved", item.type, item.id, item.path]),
|
|
188
|
+
...unresolved.map((item) => ["unresolved", "-", item, "-"])
|
|
189
|
+
];
|
|
190
|
+
const content = format === "csv" ? toCsv(headers, rows) : toAlignedTable(headers, rows);
|
|
191
|
+
process.stdout.write(`${content}\n`);
|
|
192
|
+
}
|
|
193
|
+
//# sourceMappingURL=related.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"related.js","sourceRoot":"","sources":["../../src/commands/related.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type GlobalOptions } from "../core.js";
|
|
2
|
+
export interface SuiteStatsOptions {
|
|
3
|
+
dir: string;
|
|
4
|
+
id: string;
|
|
5
|
+
format?: string;
|
|
6
|
+
}
|
|
7
|
+
export declare function runSuiteStats(cwd: string, options: SuiteStatsOptions, globalOptions: GlobalOptions): void;
|
|
8
|
+
//# sourceMappingURL=stats.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stats.d.ts","sourceRoot":"","sources":["../../src/commands/stats.ts"],"names":[],"mappings":"AAUA,OAAO,EAAmE,KAAK,aAAa,EAAE,MAAM,YAAY,CAAC;AAEjH,MAAM,WAAW,iBAAiB;IAChC,GAAG,EAAE,MAAM,CAAC;IACZ,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AA0BD,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,iBAAiB,EAAE,aAAa,EAAE,aAAa,GAAG,IAAI,CA4CzG"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { dirname, resolve } from "node:path";
|
|
3
|
+
import { calculateBurndown, detectEntityType, normalizeTlogPath, parseYaml } from "@tlog/shared";
|
|
4
|
+
import { CliError, emitSuccess, ensureDirectory, formatOf, walkYamlFiles } from "../core.js";
|
|
5
|
+
function findSuitePath(rootDir, id) {
|
|
6
|
+
const matches = walkYamlFiles(rootDir).filter((path) => {
|
|
7
|
+
if (detectEntityType(path) !== "suite") {
|
|
8
|
+
return false;
|
|
9
|
+
}
|
|
10
|
+
try {
|
|
11
|
+
const raw = parseYaml(readFileSync(path, "utf8"));
|
|
12
|
+
return raw.id === id;
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
if (matches.length === 0) {
|
|
19
|
+
throw new CliError(`suite not found: ${id}`);
|
|
20
|
+
}
|
|
21
|
+
if (matches.length > 1) {
|
|
22
|
+
throw new CliError(`Multiple suite entries found for id: ${id}`, {
|
|
23
|
+
details: matches.map((item) => normalizeTlogPath(item))
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
return matches[0];
|
|
27
|
+
}
|
|
28
|
+
export function runSuiteStats(cwd, options, globalOptions) {
|
|
29
|
+
const format = formatOf(globalOptions, options.format);
|
|
30
|
+
const rootDir = resolve(cwd, options.dir);
|
|
31
|
+
ensureDirectory(rootDir, "Suite search directory does not exist");
|
|
32
|
+
const suitePath = findSuitePath(rootDir, options.id);
|
|
33
|
+
const suite = parseYaml(readFileSync(suitePath, "utf8"));
|
|
34
|
+
const suiteDir = dirname(suitePath);
|
|
35
|
+
const cases = walkYamlFiles(suiteDir)
|
|
36
|
+
.filter((path) => detectEntityType(path) === "case")
|
|
37
|
+
.map((path) => parseYaml(readFileSync(path, "utf8")));
|
|
38
|
+
const scopedCases = suite.scoped === true ? cases.filter((item) => item.scoped === true) : [];
|
|
39
|
+
const statusCounts = {
|
|
40
|
+
todo: scopedCases.filter((item) => item.status === "todo").length,
|
|
41
|
+
doing: scopedCases.filter((item) => item.status === "doing").length,
|
|
42
|
+
done: scopedCases.filter((item) => item.status === "done").length,
|
|
43
|
+
null: scopedCases.filter((item) => item.status === null).length,
|
|
44
|
+
total: scopedCases.length
|
|
45
|
+
};
|
|
46
|
+
const scheduled = calculateBurndown(scopedCases, suite.duration.scheduled.start, suite.duration.scheduled.end);
|
|
47
|
+
const actual = calculateBurndown(scopedCases, suite.duration.actual.start, suite.duration.actual.end);
|
|
48
|
+
emitSuccess("suite stats", {
|
|
49
|
+
id: suite.id,
|
|
50
|
+
path: normalizeTlogPath(suitePath),
|
|
51
|
+
statusCounts,
|
|
52
|
+
duration: suite.duration,
|
|
53
|
+
scheduled,
|
|
54
|
+
actual
|
|
55
|
+
}, format, [
|
|
56
|
+
`suite=${suite.id}`,
|
|
57
|
+
`status todo=${statusCounts.todo} doing=${statusCounts.doing} done=${statusCounts.done} null=${statusCounts.null} total=${statusCounts.total}`,
|
|
58
|
+
`scheduled ${suite.duration.scheduled.start}..${suite.duration.scheduled.end} buckets=${scheduled.buckets.length}`,
|
|
59
|
+
`actual ${suite.duration.actual.start}..${suite.duration.actual.end} buckets=${actual.buckets.length}`
|
|
60
|
+
]);
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=stats.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stats.js","sourceRoot":"","sources":["../../src/commands/stats.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { type GlobalOptions } from "../core.js";
|
|
2
|
+
export interface SuiteCreateOptions {
|
|
3
|
+
dir: string;
|
|
4
|
+
id: string;
|
|
5
|
+
title: string;
|
|
6
|
+
owners?: string;
|
|
7
|
+
tags?: string;
|
|
8
|
+
scheduledStart?: string;
|
|
9
|
+
scheduledEnd?: string;
|
|
10
|
+
}
|
|
11
|
+
export interface CaseCreateOptions {
|
|
12
|
+
suiteDir: string;
|
|
13
|
+
id: string;
|
|
14
|
+
title: string;
|
|
15
|
+
status?: string;
|
|
16
|
+
tags?: string;
|
|
17
|
+
}
|
|
18
|
+
export declare function runSuiteCreate(cwd: string, options: SuiteCreateOptions, globalOptions: GlobalOptions): void;
|
|
19
|
+
export declare function runCaseCreate(cwd: string, options: CaseCreateOptions, globalOptions: GlobalOptions): void;
|
|
20
|
+
//# sourceMappingURL=suite-case.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"suite-case.d.ts","sourceRoot":"","sources":["../../src/commands/suite-case.ts"],"names":[],"mappings":"AAQA,OAAO,EASL,KAAK,aAAa,EACnB,MAAM,YAAY,CAAC;AAEpB,MAAM,WAAW,kBAAkB;IACjC,GAAG,EAAE,MAAM,CAAC;IACZ,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAMD,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,aAAa,GAAG,IAAI,CAqD3G;AAED,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,iBAAiB,EAAE,aAAa,EAAE,aAAa,GAAG,IAAI,CAyCzG"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { dirname, join, normalize, resolve } from "node:path";
|
|
3
|
+
import { asTlogDateString, buildDefaultCase, buildDefaultSuite, stringifyYaml } from "@tlog/shared";
|
|
4
|
+
import { CliError, emitSuccess, ensureDirectory, ensureValidId, findDuplicateId, formatOf, splitCsv, toStatus } from "../core.js";
|
|
5
|
+
function safePath(path) {
|
|
6
|
+
return normalize(path).split("\\").join("/");
|
|
7
|
+
}
|
|
8
|
+
export function runSuiteCreate(cwd, options, globalOptions) {
|
|
9
|
+
const format = formatOf(globalOptions);
|
|
10
|
+
const rootDir = resolve(cwd, options.dir);
|
|
11
|
+
mkdirSync(rootDir, { recursive: true });
|
|
12
|
+
ensureValidId(options.id, "suite id");
|
|
13
|
+
const existing = findDuplicateId(rootDir, options.id);
|
|
14
|
+
if (existing) {
|
|
15
|
+
throw new CliError(`ID already exists: ${options.id}`, {
|
|
16
|
+
details: [safePath(existing)]
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
const suiteDir = join(rootDir, options.id);
|
|
20
|
+
const indexPath = join(suiteDir, "index.yaml");
|
|
21
|
+
if (existsSync(indexPath)) {
|
|
22
|
+
throw new CliError(`Suite file already exists: ${safePath(indexPath)}`);
|
|
23
|
+
}
|
|
24
|
+
const today = new Date().toISOString().slice(0, 10);
|
|
25
|
+
const suite = buildDefaultSuite({
|
|
26
|
+
id: options.id,
|
|
27
|
+
title: options.title,
|
|
28
|
+
owners: splitCsv(options.owners),
|
|
29
|
+
tags: splitCsv(options.tags),
|
|
30
|
+
duration: {
|
|
31
|
+
scheduled: {
|
|
32
|
+
start: asTlogDateString(options.scheduledStart ?? today),
|
|
33
|
+
end: asTlogDateString(options.scheduledEnd ?? options.scheduledStart ?? today)
|
|
34
|
+
},
|
|
35
|
+
actual: {
|
|
36
|
+
start: asTlogDateString(today),
|
|
37
|
+
end: asTlogDateString(today)
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
if (!globalOptions.dryRun) {
|
|
42
|
+
mkdirSync(suiteDir, { recursive: true });
|
|
43
|
+
writeFileSync(indexPath, stringifyYaml(suite), "utf8");
|
|
44
|
+
}
|
|
45
|
+
emitSuccess("suite create", {
|
|
46
|
+
id: options.id,
|
|
47
|
+
path: safePath(indexPath),
|
|
48
|
+
dryRun: globalOptions.dryRun
|
|
49
|
+
}, format, [`${globalOptions.dryRun ? "Would create" : "Created"}: ${safePath(indexPath)}`]);
|
|
50
|
+
}
|
|
51
|
+
export function runCaseCreate(cwd, options, globalOptions) {
|
|
52
|
+
const format = formatOf(globalOptions);
|
|
53
|
+
const suiteDir = resolve(cwd, options.suiteDir);
|
|
54
|
+
ensureDirectory(suiteDir, "Suite directory does not exist");
|
|
55
|
+
ensureValidId(options.id, "case id");
|
|
56
|
+
const rootDir = dirname(suiteDir);
|
|
57
|
+
const existing = findDuplicateId(rootDir, options.id);
|
|
58
|
+
if (existing) {
|
|
59
|
+
throw new CliError(`ID already exists: ${options.id}`, {
|
|
60
|
+
details: [safePath(existing)]
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
const casePath = join(suiteDir, `${options.id}.testcase.yaml`);
|
|
64
|
+
if (existsSync(casePath)) {
|
|
65
|
+
throw new CliError(`Case file already exists: ${safePath(casePath)}`);
|
|
66
|
+
}
|
|
67
|
+
const status = options.status === undefined ? undefined : toStatus(options.status);
|
|
68
|
+
const testCase = buildDefaultCase({
|
|
69
|
+
id: options.id,
|
|
70
|
+
title: options.title,
|
|
71
|
+
status: status === null ? undefined : status,
|
|
72
|
+
tags: splitCsv(options.tags)
|
|
73
|
+
});
|
|
74
|
+
if (!globalOptions.dryRun) {
|
|
75
|
+
writeFileSync(casePath, stringifyYaml(testCase), "utf8");
|
|
76
|
+
}
|
|
77
|
+
emitSuccess("case create", {
|
|
78
|
+
id: options.id,
|
|
79
|
+
path: safePath(casePath),
|
|
80
|
+
dryRun: globalOptions.dryRun
|
|
81
|
+
}, format, [`${globalOptions.dryRun ? "Would create" : "Created"}: ${safePath(casePath)}`]);
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=suite-case.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"suite-case.js","sourceRoot":"","sources":["../../src/commands/suite-case.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { type GlobalOptions } from "../core.js";
|
|
2
|
+
export interface SuiteUpdateOptions {
|
|
3
|
+
dir: string;
|
|
4
|
+
id: string;
|
|
5
|
+
title?: string;
|
|
6
|
+
description?: string;
|
|
7
|
+
tags?: string;
|
|
8
|
+
owners?: string;
|
|
9
|
+
related?: string;
|
|
10
|
+
remarks?: string;
|
|
11
|
+
scoped?: string;
|
|
12
|
+
scheduledStart?: string;
|
|
13
|
+
scheduledEnd?: string;
|
|
14
|
+
actualStart?: string;
|
|
15
|
+
actualEnd?: string;
|
|
16
|
+
}
|
|
17
|
+
export interface CaseUpdateOptions {
|
|
18
|
+
dir: string;
|
|
19
|
+
id: string;
|
|
20
|
+
status?: string;
|
|
21
|
+
tags?: string;
|
|
22
|
+
description?: string;
|
|
23
|
+
operations?: string;
|
|
24
|
+
related?: string;
|
|
25
|
+
remarks?: string;
|
|
26
|
+
scoped?: string;
|
|
27
|
+
completedDay?: string;
|
|
28
|
+
testsFile?: string;
|
|
29
|
+
issuesFile?: string;
|
|
30
|
+
}
|
|
31
|
+
export declare function runSuiteUpdate(cwd: string, options: SuiteUpdateOptions, globalOptions: GlobalOptions): void;
|
|
32
|
+
export declare function runCaseUpdate(cwd: string, options: CaseUpdateOptions, globalOptions: GlobalOptions): void;
|
|
33
|
+
//# sourceMappingURL=update.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"update.d.ts","sourceRoot":"","sources":["../../src/commands/update.ts"],"names":[],"mappings":"AAgBA,OAAO,EAOL,KAAK,aAAa,EACnB,MAAM,YAAY,CAAC;AAEpB,MAAM,WAAW,kBAAkB;IACjC,GAAG,EAAE,MAAM,CAAC;IACZ,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,iBAAiB;IAChC,GAAG,EAAE,MAAM,CAAC;IACZ,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAsED,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,aAAa,GAAG,IAAI,CAsD3G;AAED,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,iBAAiB,EAAE,aAAa,EAAE,aAAa,GAAG,IAAI,CAmDzG"}
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from "node:fs";
|
|
3
|
+
import { dirname, resolve } from "node:path";
|
|
4
|
+
import { asTlogDateString, detectEntityType, normalizeTlogPath, parseYaml, stringifyYaml, validateCase, validateSuite } from "@tlog/shared";
|
|
5
|
+
import { CliError, emitSuccess, formatOf, splitCsv, toStatus, walkYamlFiles } from "../core.js";
|
|
6
|
+
function parseOptionalBoolean(value, optionName) {
|
|
7
|
+
if (value === undefined) {
|
|
8
|
+
return undefined;
|
|
9
|
+
}
|
|
10
|
+
if (value === "true") {
|
|
11
|
+
return true;
|
|
12
|
+
}
|
|
13
|
+
if (value === "false") {
|
|
14
|
+
return false;
|
|
15
|
+
}
|
|
16
|
+
throw new CliError(`Invalid ${optionName}: ${value}. Expected true|false.`);
|
|
17
|
+
}
|
|
18
|
+
function writeYamlFileAtomicSync(path, value) {
|
|
19
|
+
const content = stringifyYaml(value);
|
|
20
|
+
const parent = dirname(path);
|
|
21
|
+
mkdirSync(parent, { recursive: true });
|
|
22
|
+
const tempPath = `${path}.${randomUUID()}.tmp`;
|
|
23
|
+
writeFileSync(tempPath, content, "utf8");
|
|
24
|
+
renameSync(tempPath, path);
|
|
25
|
+
}
|
|
26
|
+
function findById(rootDir, id, type) {
|
|
27
|
+
const matches = walkYamlFiles(rootDir).filter((path) => {
|
|
28
|
+
if (detectEntityType(path) !== type) {
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
try {
|
|
32
|
+
const raw = parseYaml(readFileSync(path, "utf8"));
|
|
33
|
+
return raw.id === id;
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
if (matches.length === 0) {
|
|
40
|
+
throw new CliError(`${type} not found: ${id}`);
|
|
41
|
+
}
|
|
42
|
+
if (matches.length > 1) {
|
|
43
|
+
throw new CliError(`Multiple ${type} entries found for id: ${id}`, {
|
|
44
|
+
details: matches.map((item) => normalizeTlogPath(item))
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
return matches[0];
|
|
48
|
+
}
|
|
49
|
+
function readJsonArrayFile(cwd, path, label) {
|
|
50
|
+
if (!path) {
|
|
51
|
+
return undefined;
|
|
52
|
+
}
|
|
53
|
+
const fullPath = resolve(cwd, path);
|
|
54
|
+
if (!existsSync(fullPath)) {
|
|
55
|
+
throw new CliError(`${label} file not found: ${fullPath}`);
|
|
56
|
+
}
|
|
57
|
+
try {
|
|
58
|
+
const data = JSON.parse(readFileSync(fullPath, "utf8"));
|
|
59
|
+
if (!Array.isArray(data)) {
|
|
60
|
+
throw new CliError(`${label} must be an array: ${fullPath}`);
|
|
61
|
+
}
|
|
62
|
+
return data;
|
|
63
|
+
}
|
|
64
|
+
catch (error) {
|
|
65
|
+
if (error instanceof CliError) {
|
|
66
|
+
throw error;
|
|
67
|
+
}
|
|
68
|
+
throw new CliError(`Invalid ${label} JSON: ${fullPath}`);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
export function runSuiteUpdate(cwd, options, globalOptions) {
|
|
72
|
+
const format = formatOf(globalOptions);
|
|
73
|
+
const rootDir = resolve(cwd, options.dir);
|
|
74
|
+
const targetPath = findById(rootDir, options.id, "suite");
|
|
75
|
+
const current = parseYaml(readFileSync(targetPath, "utf8"));
|
|
76
|
+
const scoped = parseOptionalBoolean(options.scoped, "scoped");
|
|
77
|
+
const updated = {
|
|
78
|
+
...current,
|
|
79
|
+
...(options.title !== undefined ? { title: options.title } : {}),
|
|
80
|
+
...(options.description !== undefined ? { description: options.description } : {}),
|
|
81
|
+
...(options.tags !== undefined ? { tags: splitCsv(options.tags) } : {}),
|
|
82
|
+
...(options.owners !== undefined ? { owners: splitCsv(options.owners) } : {}),
|
|
83
|
+
...(options.related !== undefined ? { related: splitCsv(options.related) } : {}),
|
|
84
|
+
...(options.remarks !== undefined ? { remarks: splitCsv(options.remarks) } : {}),
|
|
85
|
+
...(scoped !== undefined ? { scoped } : {}),
|
|
86
|
+
duration: {
|
|
87
|
+
scheduled: {
|
|
88
|
+
start: asTlogDateString(options.scheduledStart ?? current.duration.scheduled.start),
|
|
89
|
+
end: asTlogDateString(options.scheduledEnd ?? current.duration.scheduled.end)
|
|
90
|
+
},
|
|
91
|
+
actual: {
|
|
92
|
+
start: asTlogDateString(options.actualStart ?? current.duration.actual.start),
|
|
93
|
+
end: asTlogDateString(options.actualEnd ?? current.duration.actual.end)
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
const validation = validateSuite(updated);
|
|
98
|
+
if (!validation.ok || !validation.data) {
|
|
99
|
+
throw new CliError("Suite update validation failed", {
|
|
100
|
+
details: validation.errors.map((item) => `${item.path}: ${item.message}`)
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
if (!globalOptions.dryRun) {
|
|
104
|
+
writeYamlFileAtomicSync(targetPath, updated);
|
|
105
|
+
}
|
|
106
|
+
emitSuccess("suite update", {
|
|
107
|
+
id: updated.id,
|
|
108
|
+
path: normalizeTlogPath(targetPath),
|
|
109
|
+
dryRun: globalOptions.dryRun,
|
|
110
|
+
validation: {
|
|
111
|
+
ok: true,
|
|
112
|
+
errorCount: 0,
|
|
113
|
+
warningCount: validation.warnings.length
|
|
114
|
+
}
|
|
115
|
+
}, format, [`${globalOptions.dryRun ? "Would update" : "Updated"}: ${normalizeTlogPath(targetPath)}`]);
|
|
116
|
+
}
|
|
117
|
+
export function runCaseUpdate(cwd, options, globalOptions) {
|
|
118
|
+
const format = formatOf(globalOptions);
|
|
119
|
+
const rootDir = resolve(cwd, options.dir);
|
|
120
|
+
const targetPath = findById(rootDir, options.id, "case");
|
|
121
|
+
const current = parseYaml(readFileSync(targetPath, "utf8"));
|
|
122
|
+
const scoped = parseOptionalBoolean(options.scoped, "scoped");
|
|
123
|
+
const testItems = readJsonArrayFile(cwd, options.testsFile, "tests");
|
|
124
|
+
const issues = readJsonArrayFile(cwd, options.issuesFile, "issues");
|
|
125
|
+
const status = options.status === undefined ? undefined : toStatus(options.status);
|
|
126
|
+
const updated = {
|
|
127
|
+
...current,
|
|
128
|
+
...(options.description !== undefined ? { description: options.description } : {}),
|
|
129
|
+
...(options.tags !== undefined ? { tags: splitCsv(options.tags) } : {}),
|
|
130
|
+
...(options.operations !== undefined ? { operations: splitCsv(options.operations) } : {}),
|
|
131
|
+
...(options.related !== undefined ? { related: splitCsv(options.related) } : {}),
|
|
132
|
+
...(options.remarks !== undefined ? { remarks: splitCsv(options.remarks) } : {}),
|
|
133
|
+
...(scoped !== undefined ? { scoped } : {}),
|
|
134
|
+
...(status !== undefined ? { status } : {}),
|
|
135
|
+
...(options.completedDay !== undefined ? { completedDay: options.completedDay === "null" ? null : asTlogDateString(options.completedDay) } : {}),
|
|
136
|
+
...(testItems !== undefined ? { tests: testItems } : {}),
|
|
137
|
+
...(issues !== undefined ? { issues } : {})
|
|
138
|
+
};
|
|
139
|
+
const validation = validateCase(updated);
|
|
140
|
+
if (!validation.ok || !validation.data) {
|
|
141
|
+
throw new CliError("Case update validation failed", {
|
|
142
|
+
details: validation.errors.map((item) => `${item.path}: ${item.message}`)
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
if (!globalOptions.dryRun) {
|
|
146
|
+
writeYamlFileAtomicSync(targetPath, updated);
|
|
147
|
+
}
|
|
148
|
+
emitSuccess("case update", {
|
|
149
|
+
id: updated.id,
|
|
150
|
+
path: normalizeTlogPath(targetPath),
|
|
151
|
+
dryRun: globalOptions.dryRun,
|
|
152
|
+
validation: {
|
|
153
|
+
ok: true,
|
|
154
|
+
errorCount: 0,
|
|
155
|
+
warningCount: validation.warnings.length
|
|
156
|
+
}
|
|
157
|
+
}, format, [`${globalOptions.dryRun ? "Would update" : "Updated"}: ${normalizeTlogPath(targetPath)}`]);
|
|
158
|
+
}
|
|
159
|
+
//# sourceMappingURL=update.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"update.js","sourceRoot":"","sources":["../../src/commands/update.ts"],"names":[],"mappings":"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"}
|