ortoni-report 4.0.1-beta.0 → 4.0.1-beta.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/dist/chunk-4RZ5C7KY.mjs +744 -0
- package/dist/{chunk-MPZLDOCN.mjs → chunk-HOOC3MDY.mjs} +305 -304
- package/dist/chunk-ISCRDMPY.mjs +693 -0
- package/dist/{chunk-INS3E7E6.mjs → chunk-P72FKFLZ.mjs} +352 -298
- package/dist/chunk-S45BZGXX.mjs +744 -0
- package/dist/{chunk-OZS6QIJS.mjs → chunk-ZG4JPYLC.mjs} +352 -298
- package/dist/{chunk-TI33PMMQ.mjs → chunk-ZSPTPISU.mjs} +352 -299
- package/dist/{cli/cli.js → cli.js} +403 -189
- package/dist/cli.mjs +206 -0
- package/dist/index.html +2 -2
- package/dist/ortoni-report.d.mts +7 -0
- package/dist/ortoni-report.d.ts +7 -0
- package/dist/ortoni-report.js +189 -72
- package/dist/ortoni-report.mjs +9 -5
- package/package.json +11 -4
- package/dist/chunk-45EJSEX2.mjs +0 -632
- package/dist/chunk-75EAJL2U.mjs +0 -632
- package/dist/chunk-A6HCKATU.mjs +0 -76
- package/dist/chunk-FGIYOFIC.mjs +0 -632
- package/dist/chunk-FHKWBHU6.mjs +0 -633
- package/dist/chunk-GLICR3VS.mjs +0 -637
- package/dist/chunk-HFO6XSKC.mjs +0 -633
- package/dist/chunk-HOZD6YIV.mjs +0 -634
- package/dist/chunk-IJO2YIFE.mjs +0 -637
- package/dist/chunk-JEIWNUQY.mjs +0 -632
- package/dist/chunk-JPLAGYR7.mjs +0 -632
- package/dist/chunk-NM6ULN2O.mjs +0 -632
- package/dist/chunk-P57227VN.mjs +0 -633
- package/dist/chunk-QMTRYN5N.js +0 -635
- package/dist/chunk-Z5NBP5TS.mjs +0 -635
- package/dist/cli/cli.cjs +0 -678
- package/dist/cli/cli.d.cts +0 -1
- package/dist/cli/cli.mjs +0 -103
- package/dist/ortoni-report.cjs +0 -2134
- package/dist/ortoni-report.d.cts +0 -111
- /package/dist/{cli/cli.d.mts → cli.d.mts} +0 -0
- /package/dist/{cli/cli.d.ts → cli.d.ts} +0 -0
package/dist/cli.mjs
ADDED
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
DatabaseManager,
|
|
4
|
+
FileManager,
|
|
5
|
+
HTMLGenerator,
|
|
6
|
+
startReportServer
|
|
7
|
+
} from "./chunk-4RZ5C7KY.mjs";
|
|
8
|
+
|
|
9
|
+
// src/cli.ts
|
|
10
|
+
import { program } from "commander";
|
|
11
|
+
import * as fs2 from "fs";
|
|
12
|
+
import * as path2 from "path";
|
|
13
|
+
|
|
14
|
+
// src/mergeData.ts
|
|
15
|
+
import * as fs from "fs";
|
|
16
|
+
import * as path from "path";
|
|
17
|
+
async function mergeAllData(options = {}) {
|
|
18
|
+
const folderPath = options.dir || "ortoni-report";
|
|
19
|
+
console.info(`Ortoni Report: Merging shard files in folder: ${folderPath}`);
|
|
20
|
+
if (!fs.existsSync(folderPath)) {
|
|
21
|
+
console.error(`Ortoni Report: folder "${folderPath}" does not exist.`);
|
|
22
|
+
process.exitCode = 1;
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
const filenames = fs.readdirSync(folderPath).filter((f) => f.startsWith("ortoni-shard-") && f.endsWith(".json"));
|
|
26
|
+
if (filenames.length === 0) {
|
|
27
|
+
console.error("Ortoni Report: \u274C No shard files found to merge.");
|
|
28
|
+
process.exitCode = 1;
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
const shardFileIndex = (name) => {
|
|
32
|
+
const m = name.match(/ortoni-shard-(\d+)-of-(\d+)\.json$/);
|
|
33
|
+
return m ? parseInt(m[1], 10) : null;
|
|
34
|
+
};
|
|
35
|
+
const sortedFiles = filenames.map((f) => ({ f, idx: shardFileIndex(f) })).sort((a, b) => {
|
|
36
|
+
if (a.idx === null && b.idx === null) return a.f.localeCompare(b.f);
|
|
37
|
+
if (a.idx === null) return 1;
|
|
38
|
+
if (b.idx === null) return -1;
|
|
39
|
+
return a.idx - b.idx;
|
|
40
|
+
}).map((x) => x.f);
|
|
41
|
+
const dedupeByTestId = true;
|
|
42
|
+
const resultsById = /* @__PURE__ */ new Map();
|
|
43
|
+
const projectSet = /* @__PURE__ */ new Set();
|
|
44
|
+
let totalDurationSum = 0;
|
|
45
|
+
let totalDurationMax = 0;
|
|
46
|
+
let mergedUserConfig = null;
|
|
47
|
+
let mergedUserMeta = null;
|
|
48
|
+
const badShards = [];
|
|
49
|
+
for (const file of sortedFiles) {
|
|
50
|
+
const fullPath = path.join(folderPath, file);
|
|
51
|
+
try {
|
|
52
|
+
const shardRaw = fs.readFileSync(fullPath, "utf-8");
|
|
53
|
+
const shardData = JSON.parse(shardRaw);
|
|
54
|
+
if (!Array.isArray(shardData.results)) {
|
|
55
|
+
console.warn(
|
|
56
|
+
`Ortoni Report: Shard ${file} missing results array \u2014 skipping.`
|
|
57
|
+
);
|
|
58
|
+
badShards.push(file);
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
for (const r of shardData.results) {
|
|
62
|
+
const id = r.key;
|
|
63
|
+
if (dedupeByTestId) {
|
|
64
|
+
if (!resultsById.has(id)) {
|
|
65
|
+
resultsById.set(id, r);
|
|
66
|
+
} else {
|
|
67
|
+
console.info(
|
|
68
|
+
`Ortoni Report: Duplicate test ${id} found in ${file} \u2014 keeping first occurrence.`
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
} else {
|
|
72
|
+
resultsById.set(`${id}::${Math.random().toString(36).slice(2)}`, r);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
if (Array.isArray(shardData.projectSet)) {
|
|
76
|
+
for (const p of shardData.projectSet) projectSet.add(p);
|
|
77
|
+
}
|
|
78
|
+
const dur = Number(shardData.duration) || 0;
|
|
79
|
+
totalDurationSum += dur;
|
|
80
|
+
if (dur > totalDurationMax) totalDurationMax = dur;
|
|
81
|
+
if (shardData.userConfig) {
|
|
82
|
+
if (!mergedUserConfig) mergedUserConfig = { ...shardData.userConfig };
|
|
83
|
+
else {
|
|
84
|
+
Object.keys(shardData.userConfig).forEach((k) => {
|
|
85
|
+
if (mergedUserConfig[k] === void 0 || mergedUserConfig[k] === null || mergedUserConfig[k] === "") {
|
|
86
|
+
mergedUserConfig[k] = shardData.userConfig[k];
|
|
87
|
+
} else if (shardData.userConfig[k] !== mergedUserConfig[k]) {
|
|
88
|
+
console.warn(
|
|
89
|
+
`Ortoni Report: userConfig mismatch for key "${k}" between shards. Using first value "${mergedUserConfig[k]}".`
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
if (shardData.userMeta) {
|
|
96
|
+
if (!mergedUserMeta) mergedUserMeta = { ...shardData.userMeta };
|
|
97
|
+
else {
|
|
98
|
+
mergedUserMeta.meta = {
|
|
99
|
+
...mergedUserMeta.meta || {},
|
|
100
|
+
...shardData.userMeta.meta || {}
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
} catch (err) {
|
|
105
|
+
console.error(`Ortoni Report: Failed to parse shard ${file}:`, err);
|
|
106
|
+
badShards.push(file);
|
|
107
|
+
continue;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
if (badShards.length > 0) {
|
|
111
|
+
console.warn(
|
|
112
|
+
`Ortoni Report: Completed merge with ${badShards.length} bad shard(s) skipped:`,
|
|
113
|
+
badShards
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
const allResults = Array.from(resultsById.values());
|
|
117
|
+
const totalDuration = totalDurationSum;
|
|
118
|
+
const saveHistoryFromOptions = typeof options.saveHistory === "boolean" ? options.saveHistory : void 0;
|
|
119
|
+
const saveHistoryFromShard = mergedUserConfig && typeof mergedUserConfig.saveHistory === "boolean" ? mergedUserConfig.saveHistory : void 0;
|
|
120
|
+
const saveHistory = saveHistoryFromOptions ?? saveHistoryFromShard ?? true;
|
|
121
|
+
let dbManager;
|
|
122
|
+
let runId;
|
|
123
|
+
if (saveHistory) {
|
|
124
|
+
try {
|
|
125
|
+
dbManager = new DatabaseManager();
|
|
126
|
+
const dbPath = path.join(folderPath, "ortoni-data-history.sqlite");
|
|
127
|
+
await dbManager.initialize(dbPath);
|
|
128
|
+
runId = await dbManager.saveTestRun();
|
|
129
|
+
if (typeof runId === "number") {
|
|
130
|
+
await dbManager.saveTestResults(runId, allResults);
|
|
131
|
+
console.info(
|
|
132
|
+
`Ortoni Report: Saved ${allResults.length} results to DB (runId=${runId}).`
|
|
133
|
+
);
|
|
134
|
+
} else {
|
|
135
|
+
console.warn(
|
|
136
|
+
"Ortoni Report: Failed to create test run in DB; proceeding without saving results."
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
} catch (err) {
|
|
140
|
+
console.error(
|
|
141
|
+
"Ortoni Report: Error while saving history to DB. Proceeding without DB:",
|
|
142
|
+
err
|
|
143
|
+
);
|
|
144
|
+
dbManager = void 0;
|
|
145
|
+
runId = void 0;
|
|
146
|
+
}
|
|
147
|
+
} else {
|
|
148
|
+
console.info(
|
|
149
|
+
"Ortoni Report: Skipping history save (saveHistory=false). (Typical for CI runs)"
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
const htmlGenerator = new HTMLGenerator(
|
|
153
|
+
{ ...mergedUserConfig || {}, meta: mergedUserMeta?.meta },
|
|
154
|
+
dbManager
|
|
155
|
+
);
|
|
156
|
+
const finalReportData = await htmlGenerator.generateFinalReport(
|
|
157
|
+
allResults.filter((r) => r.status !== "skipped"),
|
|
158
|
+
totalDuration,
|
|
159
|
+
allResults,
|
|
160
|
+
projectSet
|
|
161
|
+
);
|
|
162
|
+
const fileManager = new FileManager(folderPath);
|
|
163
|
+
const outputFileName = options.file || "ortoni-report.html";
|
|
164
|
+
const outputPath = await fileManager.writeReportFile(
|
|
165
|
+
outputFileName,
|
|
166
|
+
finalReportData
|
|
167
|
+
);
|
|
168
|
+
console.log(`\u2705 Final merged report generated at ${outputPath}`);
|
|
169
|
+
if (runId) console.log(`\u2705 DB runId: ${runId}`);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// src/cli.ts
|
|
173
|
+
program.version("4.0.1").description("Ortoni Report - CLI");
|
|
174
|
+
program.command("show-report").description("Open Ortoni Report").option(
|
|
175
|
+
"-d, --dir <path>",
|
|
176
|
+
"Path to the folder containing the report",
|
|
177
|
+
"ortoni-report"
|
|
178
|
+
).option(
|
|
179
|
+
"-f, --file <filename>",
|
|
180
|
+
"Name of the report file",
|
|
181
|
+
"ortoni-report.html"
|
|
182
|
+
).option("-p, --port <port>", "Port to run the server", "2004").action((options) => {
|
|
183
|
+
const projectRoot = process.cwd();
|
|
184
|
+
const folderPath = path2.resolve(projectRoot, options.dir);
|
|
185
|
+
const filePath = path2.resolve(folderPath, options.file);
|
|
186
|
+
const port = parseInt(options.port) || 2004;
|
|
187
|
+
if (!fs2.existsSync(filePath)) {
|
|
188
|
+
console.error(
|
|
189
|
+
`\u274C Error: The file "${filePath}" does not exist in "${folderPath}".`
|
|
190
|
+
);
|
|
191
|
+
process.exit(1);
|
|
192
|
+
}
|
|
193
|
+
startReportServer(folderPath, path2.basename(filePath), port, "always");
|
|
194
|
+
});
|
|
195
|
+
program.command("merge-report").description("Merge sharded reports into one final report").option(
|
|
196
|
+
"-d, --dir <path>",
|
|
197
|
+
"Path to the folder containing shard files",
|
|
198
|
+
"ortoni-report"
|
|
199
|
+
).option("-f, --file <filename>", "Output report file", "ortoni-report.html").action(async (options) => {
|
|
200
|
+
await mergeAllData({
|
|
201
|
+
dir: options.dir,
|
|
202
|
+
file: options.file,
|
|
203
|
+
saveHistory: false
|
|
204
|
+
});
|
|
205
|
+
});
|
|
206
|
+
program.parse(process.argv);
|