@allurereport/core 3.8.2 → 3.10.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/report.js CHANGED
@@ -9,11 +9,12 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
9
9
  if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
10
10
  return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
11
11
  };
12
- var _AllureReport_instances, _AllureReport_reportName, _AllureReport_ci, _AllureReport_store, _AllureReport_readers, _AllureReport_plugins, _AllureReport_reportFiles, _AllureReport_realtimeChannel, _AllureReport_realtimeUpdateScheduler, _AllureReport_realTime, _AllureReport_hideLabels, _AllureReport_output, _AllureReport_history, _AllureReport_allureServiceClient, _AllureReport_qualityGate, _AllureReport_dump, _AllureReport_categories, _AllureReport_environments, _AllureReport_globalAttachments, _AllureReport_dumpTempDirs, _AllureReport_state, _AllureReport_executionStage, _AllureReport_publish_get, _AllureReport_runRealtimeUpdate, _AllureReport_eachPlugin, _AllureReport_getPluginState;
12
+ var _AllureReport_instances, _AllureReport_ci, _AllureReport_store, _AllureReport_readers, _AllureReport_plugins, _AllureReport_reportFiles, _AllureReport_realtimeChannel, _AllureReport_realtimeUpdateScheduler, _AllureReport_realTime, _AllureReport_hideLabels, _AllureReport_output, _AllureReport_history, _AllureReport_allureServiceClient, _AllureReport_qualityGate, _AllureReport_dump, _AllureReport_categories, _AllureReport_environments, _AllureReport_globalAttachments, _AllureReport_dumpTempDirs, _AllureReport_state, _AllureReport_executionStage, _AllureReport_historyDataPoint, _AllureReport_summaryPath, _AllureReport_summariesByPluginId, _AllureReport_publishedRemoteHrefs, _AllureReport_published, _AllureReport_endGeneratePerfSpan, _AllureReport_publish, _AllureReport_runRealtimeUpdate, _AllureReport_getReportsToPublish, _AllureReport_cleanupFailedRemoteReport, _AllureReport_logPublishError, _AllureReport_applyPublishLinksToSummaries, _AllureReport_cloneSummariesByPluginId, _AllureReport_writeSummaryFiles, _AllureReport_generateRootSummary, _AllureReport_finishGeneratePerfSpan, _AllureReport_finishPerfMetrics, _AllureReport_eachPlugin, _AllureReport_getPluginState;
13
13
  import console from "node:console";
14
14
  import { randomUUID } from "node:crypto";
15
- import { createWriteStream, existsSync, readFileSync } from "node:fs";
16
- import { lstat, mkdtemp, opendir, readdir, realpath, rename, rm, writeFile } from "node:fs/promises";
15
+ import { once } from "node:events";
16
+ import { createReadStream, createWriteStream, existsSync, readFileSync } from "node:fs";
17
+ import { lstat, mkdtemp, readdir, realpath, rename, rm, writeFile } from "node:fs/promises";
17
18
  import { tmpdir } from "node:os";
18
19
  import { basename, dirname, join, resolve, sep } from "node:path";
19
20
  import { promisify } from "node:util";
@@ -22,37 +23,53 @@ import { normalizeCategoriesConfig } from "@allurereport/core-api";
22
23
  import { AllureStoreDumpFiles, } from "@allurereport/plugin-api";
23
24
  import { allure1, allure2, attachments, cucumberjson, junitXml, readXcResultBundle } from "@allurereport/reader";
24
25
  import { PathResultFile } from "@allurereport/reader-api";
25
- import { AllureRemoteHistory, AllureServiceClient, KnownError, UnknownError, } from "@allurereport/service";
26
+ import { AllureRemoteHistory, AllureServiceClient, AllureTestOpsClient, KnownError, UnknownError, } from "@allurereport/service";
26
27
  import { generateSummary } from "@allurereport/summary";
27
28
  import { glob } from "glob";
28
29
  import ZipReadStream from "node-stream-zip";
29
30
  import pLimit from "p-limit";
30
- import ProgressBar from "progress";
31
31
  import ZipWriteStream from "zip-stream";
32
32
  import { AllureLocalHistory, createHistory } from "./history.js";
33
33
  import { DefaultPluginState, PluginFiles } from "./plugin.js";
34
34
  import { QualityGate } from "./qualityGate/index.js";
35
35
  import { DefaultAllureStore } from "./store/store.js";
36
+ import { createUploadProgressBarCounter } from "./utils/cli.js";
36
37
  import { environmentIdentityById, environmentIdentityByName } from "./utils/environment.js";
38
+ import { measurePerf, PERF_METRIC_NAMES, PERF_METRIC_PREFIXES, startPerfSpan, writePerfMetrics } from "./utils/perf.js";
37
39
  import { RealtimeChannel } from "./utils/realtimeChannel.js";
38
40
  import { RealtimeUpdateScheduler } from "./utils/realtimeUpdateScheduler.js";
39
41
  import { resolveDumpAttachmentPath, UnsafeDumpPathError } from "./utils/safeDumpPath.js";
40
42
  const { version } = JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf8"));
41
43
  const initRequired = "report is not initialised. Call the start() method first.";
44
+ const defaultReadConcurrency = 64;
45
+ const maxReadConcurrency = 256;
46
+ const readConcurrency = () => {
47
+ const parsed = Number.parseInt(process.env.ALLURE_READ_CONCURRENCY ?? "", 10);
48
+ if (!Number.isFinite(parsed)) {
49
+ return defaultReadConcurrency;
50
+ }
51
+ return Math.min(maxReadConcurrency, Math.max(1, parsed));
52
+ };
53
+ const clonePluginSummary = (summary) => structuredClone(summary);
42
54
  const remoteReportParams = (ci) => {
43
55
  const repo = ci?.repoName;
44
56
  const branch = ci?.jobRunBranch;
45
57
  return repo && branch ? { repo, branch } : {};
46
58
  };
47
- const REMOTE_UPLOAD_CONCURRENCY = 50;
48
- const REMOTE_UPLOAD_MAX_ATTEMPTS = 5;
49
- const REMOTE_UPLOAD_MAX_SIMULTANEOUS_FAILED = 5;
50
59
  const errorDetails = (err) => (err instanceof Error ? (err.stack ?? err.message) : String(err));
51
- const isAbortError = (err) => typeof err === "object" && err !== null && "name" in err && err?.name === "AbortError";
60
+ const closeReadStream = async (stream) => {
61
+ if (stream.closed) {
62
+ return;
63
+ }
64
+ const closed = once(stream, "close").then(() => undefined);
65
+ if (!stream.destroyed) {
66
+ stream.destroy();
67
+ }
68
+ await closed.catch(() => undefined);
69
+ };
52
70
  export class AllureReport {
53
71
  constructor(opts) {
54
72
  _AllureReport_instances.add(this);
55
- _AllureReport_reportName.set(this, void 0);
56
73
  _AllureReport_ci.set(this, void 0);
57
74
  _AllureReport_store.set(this, void 0);
58
75
  _AllureReport_readers.set(this, void 0);
@@ -73,7 +90,123 @@ export class AllureReport {
73
90
  _AllureReport_dumpTempDirs.set(this, []);
74
91
  _AllureReport_state.set(this, void 0);
75
92
  _AllureReport_executionStage.set(this, "init");
76
- this.readDirectory = async (resultsDir) => {
93
+ _AllureReport_historyDataPoint.set(this, void 0);
94
+ _AllureReport_summaryPath.set(this, void 0);
95
+ _AllureReport_summariesByPluginId.set(this, new Map());
96
+ _AllureReport_publishedRemoteHrefs.set(this, new Set());
97
+ _AllureReport_published.set(this, false);
98
+ _AllureReport_endGeneratePerfSpan.set(this, void 0);
99
+ _AllureReport_publish.set(this, async () => {
100
+ if (__classPrivateFieldGet(this, _AllureReport_published, "f")) {
101
+ return;
102
+ }
103
+ if (__classPrivateFieldGet(this, _AllureReport_executionStage, "f") !== "done") {
104
+ throw new Error("report is not completed. Call the done() method first.");
105
+ }
106
+ let historyPoint = __classPrivateFieldGet(this, _AllureReport_historyDataPoint, "f");
107
+ if (!historyPoint) {
108
+ const allTrs = await __classPrivateFieldGet(this, _AllureReport_store, "f").allTestResults();
109
+ const allTcs = await __classPrivateFieldGet(this, _AllureReport_store, "f").allTestCases();
110
+ historyPoint = createHistory(this.reportUuid, this.reportName, allTcs, allTrs, this.reportUrl);
111
+ __classPrivateFieldSet(this, _AllureReport_historyDataPoint, historyPoint, "f");
112
+ }
113
+ await __classPrivateFieldGet(this, _AllureReport_writeSummaryFiles, "f").call(this);
114
+ await __classPrivateFieldGet(this, _AllureReport_generateRootSummary, "f").call(this);
115
+ if (__classPrivateFieldGet(this, _AllureReport_realTime, "f") || !__classPrivateFieldGet(this, _AllureReport_allureServiceClient, "f")) {
116
+ __classPrivateFieldSet(this, _AllureReport_published, true, "f");
117
+ return;
118
+ }
119
+ const reportsToPublish = (await __classPrivateFieldGet(this, _AllureReport_getReportsToPublish, "f").call(this)).filter((report) => report.publish && Object.keys(report.files).length > 0);
120
+ if (reportsToPublish.length === 0) {
121
+ __classPrivateFieldSet(this, _AllureReport_published, true, "f");
122
+ return;
123
+ }
124
+ const client = __classPrivateFieldGet(this, _AllureReport_allureServiceClient, "f");
125
+ const linksByPluginId = {};
126
+ const summariesSnapshot = __classPrivateFieldGet(this, _AllureReport_cloneSummariesByPluginId, "f").call(this);
127
+ const uploadProgressBar = createUploadProgressBarCounter(reportsToPublish.length === 1 ? `Publishing "${reportsToPublish[0].pluginId}" report` : "Publishing reports", reportsToPublish.reduce((acc, report) => acc + Object.keys(report.files).length, 0));
128
+ let summariesMutated = false;
129
+ let reportCreated = false;
130
+ let publishErrorMessage = "Report upload has failed, the report won't be published";
131
+ const endPublishPerfSpan = startPerfSpan(PERF_METRIC_NAMES.publishUploadTotal);
132
+ try {
133
+ await client.createReport({
134
+ reportUuid: this.reportUuid,
135
+ reportName: this.reportName,
136
+ ...remoteReportParams(__classPrivateFieldGet(this, _AllureReport_ci, "f")),
137
+ });
138
+ reportCreated = true;
139
+ for (const report of reportsToPublish) {
140
+ publishErrorMessage = `Plugin "${report.pluginId}" upload has failed, the plugin won't be published`;
141
+ const uploadResult = await measurePerf(`${PERF_METRIC_PREFIXES.publishUploadPlugin}${report.pluginId}`, () => client.uploadReport({
142
+ reportUuid: this.reportUuid,
143
+ pluginId: report.pluginId,
144
+ files: Object.fromEntries(Object.entries(report.files).filter(([filename]) => filename !== "summary.json")),
145
+ onProgress: () => uploadProgressBar.tick(),
146
+ }));
147
+ if (uploadResult.indexHref) {
148
+ linksByPluginId[report.pluginId] = uploadResult.indexHref;
149
+ }
150
+ }
151
+ const changedPluginIds = __classPrivateFieldGet(this, _AllureReport_applyPublishLinksToSummaries, "f").call(this, linksByPluginId);
152
+ summariesMutated = changedPluginIds.size > 0;
153
+ if (changedPluginIds.size > 0) {
154
+ await __classPrivateFieldGet(this, _AllureReport_writeSummaryFiles, "f").call(this);
155
+ await __classPrivateFieldGet(this, _AllureReport_generateRootSummary, "f").call(this);
156
+ }
157
+ const updatedReports = await __classPrivateFieldGet(this, _AllureReport_getReportsToPublish, "f").call(this);
158
+ const updatedReportsByPluginId = new Map(updatedReports.map((report) => [report.pluginId, report]));
159
+ for (const report of reportsToPublish) {
160
+ const updatedReport = updatedReportsByPluginId.get(report.pluginId) ?? report;
161
+ const summaryFilepath = updatedReport.files["summary.json"];
162
+ if (!summaryFilepath) {
163
+ continue;
164
+ }
165
+ publishErrorMessage = `Plugin "${report.pluginId}" summary upload has failed, the plugin won't be published`;
166
+ await client.uploadReport({
167
+ reportUuid: this.reportUuid,
168
+ pluginId: updatedReport.pluginId,
169
+ files: { "summary.json": summaryFilepath },
170
+ onProgress: () => uploadProgressBar.tick(),
171
+ });
172
+ }
173
+ publishErrorMessage = "Report summary upload has failed, the report won't be published";
174
+ const summaryHref = __classPrivateFieldGet(this, _AllureReport_summaryPath, "f")
175
+ ? (await client.uploadReport({
176
+ reportUuid: this.reportUuid,
177
+ files: { "index.html": __classPrivateFieldGet(this, _AllureReport_summaryPath, "f") },
178
+ })).indexHref
179
+ : undefined;
180
+ publishErrorMessage = "Report completion has failed, the report won't be published";
181
+ await client.completeReport({
182
+ reportUuid: this.reportUuid,
183
+ historyPoint,
184
+ });
185
+ Object.values(linksByPluginId)
186
+ .filter(Boolean)
187
+ .forEach((href) => __classPrivateFieldGet(this, _AllureReport_publishedRemoteHrefs, "f").add(href));
188
+ if (summaryHref) {
189
+ __classPrivateFieldGet(this, _AllureReport_publishedRemoteHrefs, "f").add(summaryHref);
190
+ }
191
+ __classPrivateFieldSet(this, _AllureReport_published, true, "f");
192
+ }
193
+ catch (err) {
194
+ if (reportCreated) {
195
+ await __classPrivateFieldGet(this, _AllureReport_cleanupFailedRemoteReport, "f").call(this, client);
196
+ }
197
+ if (summariesMutated) {
198
+ __classPrivateFieldSet(this, _AllureReport_summariesByPluginId, summariesSnapshot, "f");
199
+ await __classPrivateFieldGet(this, _AllureReport_writeSummaryFiles, "f").call(this);
200
+ await __classPrivateFieldGet(this, _AllureReport_generateRootSummary, "f").call(this);
201
+ }
202
+ __classPrivateFieldGet(this, _AllureReport_logPublishError, "f").call(this, publishErrorMessage, err);
203
+ }
204
+ finally {
205
+ endPublishPerfSpan();
206
+ uploadProgressBar.terminate();
207
+ }
208
+ });
209
+ this.readDirectory = async (resultsDir) => measurePerf(PERF_METRIC_NAMES.generateReadResults, async () => {
77
210
  if (__classPrivateFieldGet(this, _AllureReport_executionStage, "f") !== "running") {
78
211
  throw new Error(initRequired);
79
212
  }
@@ -81,31 +214,40 @@ export class AllureReport {
81
214
  if (await readXcResultBundle(__classPrivateFieldGet(this, _AllureReport_store, "f"), resultsDirPath)) {
82
215
  return;
83
216
  }
84
- const dir = await opendir(resultsDirPath);
85
217
  try {
86
- for await (const dirent of dir) {
87
- if (dirent.isFile()) {
88
- const path = await realpath(join(dirent.parentPath ?? dirent.path, dirent.name));
218
+ const entries = (await readdir(resultsDirPath, { withFileTypes: true }))
219
+ .filter((dirent) => dirent.isFile())
220
+ .sort((a, b) => a.name.localeCompare(b.name));
221
+ const limit = pLimit(readConcurrency());
222
+ await Promise.all(entries.map((dirent) => limit(async () => {
223
+ try {
224
+ const path = await realpath(join(resultsDirPath, dirent.name));
89
225
  await this.readResult(new PathResultFile(path, dirent.name));
90
226
  }
91
- }
227
+ catch (e) {
228
+ console.error(`can't read result file ${dirent.name}`, e);
229
+ }
230
+ })));
92
231
  }
93
232
  catch (e) {
94
233
  console.error("can't read directory", e);
95
234
  }
96
- };
97
- this.readFile = async (resultsFile) => {
235
+ });
236
+ this.readFile = async (resultsFile) => measurePerf(PERF_METRIC_NAMES.generateReadResults, async () => {
98
237
  if (__classPrivateFieldGet(this, _AllureReport_executionStage, "f") !== "running") {
99
238
  throw new Error(initRequired);
100
239
  }
101
240
  await this.readResult(new PathResultFile(resultsFile));
102
- };
241
+ });
103
242
  this.readResult = async (data) => {
104
243
  if (__classPrivateFieldGet(this, _AllureReport_executionStage, "f") !== "running") {
105
244
  throw new Error(initRequired);
106
245
  }
107
246
  for (const reader of __classPrivateFieldGet(this, _AllureReport_readers, "f")) {
108
247
  try {
248
+ if (reader.matches && !(await reader.matches(data))) {
249
+ continue;
250
+ }
109
251
  const processed = await reader.read(__classPrivateFieldGet(this, _AllureReport_store, "f"), data);
110
252
  if (processed) {
111
253
  return;
@@ -129,7 +271,6 @@ export class AllureReport {
129
271
  });
130
272
  };
131
273
  this.start = async () => {
132
- const remoteParams = remoteReportParams(__classPrivateFieldGet(this, _AllureReport_ci, "f"));
133
274
  await __classPrivateFieldGet(this, _AllureReport_store, "f").readHistory();
134
275
  if (__classPrivateFieldGet(this, _AllureReport_executionStage, "f") === "running") {
135
276
  throw new Error("the report is already started");
@@ -138,6 +279,7 @@ export class AllureReport {
138
279
  throw new Error("the report is already stopped, the restart isn't supported at the moment");
139
280
  }
140
281
  __classPrivateFieldSet(this, _AllureReport_executionStage, "running", "f");
282
+ __classPrivateFieldSet(this, _AllureReport_endGeneratePerfSpan, startPerfSpan(PERF_METRIC_NAMES.generateTotal), "f");
141
283
  const cwd = resolve(process.cwd());
142
284
  const cwdWithSep = cwd.endsWith(sep) ? cwd : `${cwd}${sep}`;
143
285
  if (__classPrivateFieldGet(this, _AllureReport_globalAttachments, "f")?.length) {
@@ -156,14 +298,6 @@ export class AllureReport {
156
298
  __classPrivateFieldGet(this, _AllureReport_realtimeChannel, "f").dispatcher.sendGlobalAttachment(new PathResultFile(absoluteFilePath, originalFileName), originalFileName);
157
299
  }
158
300
  }
159
- if (__classPrivateFieldGet(this, _AllureReport_allureServiceClient, "f") && __classPrivateFieldGet(this, _AllureReport_instances, "a", _AllureReport_publish_get)) {
160
- const url = await __classPrivateFieldGet(this, _AllureReport_allureServiceClient, "f").createReport({
161
- reportUuid: this.reportUuid,
162
- reportName: __classPrivateFieldGet(this, _AllureReport_reportName, "f"),
163
- ...remoteParams,
164
- });
165
- this.reportUrl = url.href;
166
- }
167
301
  await __classPrivateFieldGet(this, _AllureReport_eachPlugin, "f").call(this, true, async (plugin, context) => {
168
302
  await plugin.start?.(context, __classPrivateFieldGet(this, _AllureReport_store, "f"), __classPrivateFieldGet(this, _AllureReport_realtimeChannel, "f").subscriber);
169
303
  });
@@ -228,7 +362,7 @@ export class AllureReport {
228
362
  const addJsonDumpEntry = async (entryName, value) => {
229
363
  await addRequiredDumpEntry(Buffer.from(JSON.stringify(value)), entryName);
230
364
  };
231
- const dumpJsonEntries = ({ testResults, testCases, fixtures, attachments, environments, reportVariables, checkResults = [], globalAttachmentIds = [], globalErrors = [], indexAttachmentByTestResult = {}, indexTestResultByHistoryId = {}, indexTestResultByTestCase = {}, indexLatestEnvTestResultByHistoryId = {}, indexAttachmentByFixture = {}, indexFixturesByTestResult = {}, indexKnownByHistoryId = {}, qualityGateResults = [], }) => [
365
+ const dumpJsonEntries = ({ testResults, testCases, fixtures, attachments, environments, reportVariables, checkResults = [], globalAttachmentIds = [], globalErrors = [], indexAttachmentByTestResult = {}, indexTestResultByHistoryId = {}, indexTestResultByTestCase = {}, indexAttachmentByFixture = {}, indexFixturesByTestResult = {}, indexKnownByHistoryId = {}, qualityGateResults = [], testResultIdsIngestOrder = [], }) => [
232
366
  [AllureStoreDumpFiles.TestResults, testResults],
233
367
  [AllureStoreDumpFiles.TestCases, testCases],
234
368
  [AllureStoreDumpFiles.Fixtures, fixtures],
@@ -241,11 +375,11 @@ export class AllureReport {
241
375
  [AllureStoreDumpFiles.IndexAttachmentsByTestResults, indexAttachmentByTestResult],
242
376
  [AllureStoreDumpFiles.IndexTestResultsByHistoryId, indexTestResultByHistoryId],
243
377
  [AllureStoreDumpFiles.IndexTestResultsByTestCase, indexTestResultByTestCase],
244
- [AllureStoreDumpFiles.IndexLatestEnvTestResultsByHistoryId, indexLatestEnvTestResultByHistoryId],
245
378
  [AllureStoreDumpFiles.IndexAttachmentsByFixture, indexAttachmentByFixture],
246
379
  [AllureStoreDumpFiles.IndexFixturesByTestResult, indexFixturesByTestResult],
247
380
  [AllureStoreDumpFiles.IndexKnownByHistoryId, indexKnownByHistoryId],
248
381
  [AllureStoreDumpFiles.QualityGateResults, qualityGateResults],
382
+ [AllureStoreDumpFiles.TestResultIngestOrder, testResultIdsIngestOrder],
249
383
  ];
250
384
  let dumpError;
251
385
  dumpArchive.pipe(dumpArchiveWriteStream);
@@ -263,6 +397,15 @@ export class AllureReport {
263
397
  skipAttachment("attachment content is missing");
264
398
  continue;
265
399
  }
400
+ if (content instanceof PathResultFile) {
401
+ const stream = createReadStream(content.path);
402
+ const err = await addDumpEntry(stream, attachment.id);
403
+ if (err) {
404
+ await closeReadStream(stream);
405
+ skipAttachment(`failed to add attachment entry: ${errMessage(err)}`);
406
+ }
407
+ continue;
408
+ }
266
409
  const data = await content.asBuffer();
267
410
  if (data === undefined) {
268
411
  skipAttachment("attachment content is missing");
@@ -302,382 +445,357 @@ export class AllureReport {
302
445
  }
303
446
  await rename(dumpTempPath, dumpPath);
304
447
  };
305
- this.restoreState = async (dumps) => {
448
+ this.restoreState = async (dumps) => measurePerf(PERF_METRIC_NAMES.restoreStateTotal, async () => {
306
449
  for (const dump of dumps) {
307
- if (!existsSync(dump)) {
308
- console.error(`Failed to restore state from "${dump}", continuing without it`);
309
- console.error("Dump file does not exist");
310
- continue;
311
- }
312
- try {
313
- const dumpArchive = new ZipReadStream.async({
314
- file: dump,
315
- });
316
- let restoreError;
450
+ await measurePerf(PERF_METRIC_NAMES.restoreStateDump, async () => {
451
+ if (!existsSync(dump)) {
452
+ console.error(`Failed to restore state from "${dump}", continuing without it`);
453
+ console.error("Dump file does not exist");
454
+ return;
455
+ }
317
456
  try {
318
- const dumpEntries = await dumpArchive.entries();
319
- const dumpEntriesList = Object.entries(dumpEntries);
320
- const requiredEntryData = async (entryName) => {
321
- if (!dumpEntries[entryName]) {
322
- throw new Error(`Missing required dump entry "${entryName}"`);
323
- }
324
- return dumpArchive.entryData(entryName);
325
- };
326
- const optionalEntryData = async (entryName) => dumpEntries[entryName] ? dumpArchive.entryData(entryName) : undefined;
327
- if (!dumpEntries[AllureStoreDumpFiles.TestResults]) {
328
- const nestedDumpEntries = dumpEntriesList.filter(([entryName, entry]) => !entry.isDirectory &&
329
- !entryName.startsWith("__MACOSX/") &&
330
- !basename(entryName).startsWith("._") &&
331
- entryName.toLowerCase().endsWith(".zip"));
332
- if (nestedDumpEntries.length > 0) {
333
- const nestedDumpsTempDir = await mkdtemp(join(tmpdir(), `${basename(dump, ".zip")}-nested-`));
334
- const nestedDumpPaths = [];
335
- __classPrivateFieldGet(this, _AllureReport_dumpTempDirs, "f").push(nestedDumpsTempDir);
336
- for (const [entryName] of nestedDumpEntries) {
337
- const nestedDumpPath = join(nestedDumpsTempDir, `${nestedDumpPaths.length}-${basename(entryName)}`);
338
- await writeFile(nestedDumpPath, await dumpArchive.entryData(entryName));
339
- nestedDumpPaths.push(nestedDumpPath);
457
+ const dumpArchive = new ZipReadStream.async({
458
+ file: dump,
459
+ });
460
+ let restoreError;
461
+ try {
462
+ const dumpEntries = await dumpArchive.entries();
463
+ const dumpEntriesList = Object.entries(dumpEntries);
464
+ const requiredEntryData = async (entryName) => {
465
+ if (!dumpEntries[entryName]) {
466
+ throw new Error(`Missing required dump entry "${entryName}"`);
467
+ }
468
+ return dumpArchive.entryData(entryName);
469
+ };
470
+ const optionalEntryData = async (entryName) => dumpEntries[entryName] ? dumpArchive.entryData(entryName) : undefined;
471
+ if (!dumpEntries[AllureStoreDumpFiles.TestResults]) {
472
+ const nestedDumpEntries = dumpEntriesList.filter(([entryName, entry]) => !entry.isDirectory &&
473
+ !entryName.startsWith("__MACOSX/") &&
474
+ !basename(entryName).startsWith("._") &&
475
+ entryName.toLowerCase().endsWith(".zip"));
476
+ if (nestedDumpEntries.length > 0) {
477
+ const nestedDumpsTempDir = await mkdtemp(join(tmpdir(), `${basename(dump, ".zip")}-nested-`));
478
+ const nestedDumpPaths = [];
479
+ __classPrivateFieldGet(this, _AllureReport_dumpTempDirs, "f").push(nestedDumpsTempDir);
480
+ for (const [entryName] of nestedDumpEntries) {
481
+ const nestedDumpPath = join(nestedDumpsTempDir, `${nestedDumpPaths.length}-${basename(entryName)}`);
482
+ await writeFile(nestedDumpPath, await dumpArchive.entryData(entryName));
483
+ nestedDumpPaths.push(nestedDumpPath);
484
+ }
485
+ await this.restoreState(nestedDumpPaths);
486
+ return;
340
487
  }
341
- await this.restoreState(nestedDumpPaths);
342
- continue;
343
488
  }
344
- }
345
- const testResultsEntry = await requiredEntryData(AllureStoreDumpFiles.TestResults);
346
- const testCasesEntry = await requiredEntryData(AllureStoreDumpFiles.TestCases);
347
- const fixturesEntry = await requiredEntryData(AllureStoreDumpFiles.Fixtures);
348
- const attachmentsEntry = await requiredEntryData(AllureStoreDumpFiles.Attachments);
349
- const checkResultsEntry = await optionalEntryData(AllureStoreDumpFiles.CheckResults);
350
- const environmentsEntry = await requiredEntryData(AllureStoreDumpFiles.Environments);
351
- const reportVariablesEntry = await requiredEntryData(AllureStoreDumpFiles.ReportVariables);
352
- const globalAttachmentsEntry = await requiredEntryData(AllureStoreDumpFiles.GlobalAttachments);
353
- const globalErrorsEntry = await requiredEntryData(AllureStoreDumpFiles.GlobalErrors);
354
- const indexAttachmentsEntry = await requiredEntryData(AllureStoreDumpFiles.IndexAttachmentsByTestResults);
355
- const indexTestResultsByHistoryId = await requiredEntryData(AllureStoreDumpFiles.IndexTestResultsByHistoryId);
356
- const indexTestResultsByTestCaseEntry = await requiredEntryData(AllureStoreDumpFiles.IndexTestResultsByTestCase);
357
- const indexLatestEnvTestResultsByHistoryIdEntry = await requiredEntryData(AllureStoreDumpFiles.IndexLatestEnvTestResultsByHistoryId);
358
- const indexAttachmentsByFixtureEntry = await requiredEntryData(AllureStoreDumpFiles.IndexAttachmentsByFixture);
359
- const indexFixturesByTestResultEntry = await requiredEntryData(AllureStoreDumpFiles.IndexFixturesByTestResult);
360
- const indexKnownByHistoryIdEntry = await requiredEntryData(AllureStoreDumpFiles.IndexKnownByHistoryId);
361
- const qualityGateResultsEntry = await requiredEntryData(AllureStoreDumpFiles.QualityGateResults);
362
- const attachmentsLinks = JSON.parse(attachmentsEntry.toString("utf8"));
363
- const attachmentsEntries = dumpEntriesList.reduce((acc, [entryName, entry]) => {
364
- switch (entryName) {
365
- case AllureStoreDumpFiles.Attachments:
366
- case AllureStoreDumpFiles.CheckResults:
367
- case AllureStoreDumpFiles.TestResults:
368
- case AllureStoreDumpFiles.TestCases:
369
- case AllureStoreDumpFiles.Fixtures:
370
- case AllureStoreDumpFiles.Environments:
371
- case AllureStoreDumpFiles.ReportVariables:
372
- case AllureStoreDumpFiles.GlobalAttachments:
373
- case AllureStoreDumpFiles.GlobalErrors:
374
- case AllureStoreDumpFiles.IndexAttachmentsByTestResults:
375
- case AllureStoreDumpFiles.IndexTestResultsByHistoryId:
376
- case AllureStoreDumpFiles.IndexTestResultsByTestCase:
377
- case AllureStoreDumpFiles.IndexLatestEnvTestResultsByHistoryId:
378
- case AllureStoreDumpFiles.IndexAttachmentsByFixture:
379
- case AllureStoreDumpFiles.IndexFixturesByTestResult:
380
- case AllureStoreDumpFiles.IndexKnownByHistoryId:
381
- case AllureStoreDumpFiles.QualityGateResults:
382
- return acc;
383
- default:
384
- if (entry.isDirectory || !attachmentsLinks[entryName] || attachmentsLinks[entryName].missed) {
489
+ const testResultsEntry = await requiredEntryData(AllureStoreDumpFiles.TestResults);
490
+ const testCasesEntry = await requiredEntryData(AllureStoreDumpFiles.TestCases);
491
+ const fixturesEntry = await requiredEntryData(AllureStoreDumpFiles.Fixtures);
492
+ const attachmentsEntry = await requiredEntryData(AllureStoreDumpFiles.Attachments);
493
+ const checkResultsEntry = await optionalEntryData(AllureStoreDumpFiles.CheckResults);
494
+ const environmentsEntry = await requiredEntryData(AllureStoreDumpFiles.Environments);
495
+ const reportVariablesEntry = await requiredEntryData(AllureStoreDumpFiles.ReportVariables);
496
+ const globalAttachmentsEntry = await requiredEntryData(AllureStoreDumpFiles.GlobalAttachments);
497
+ const globalErrorsEntry = await requiredEntryData(AllureStoreDumpFiles.GlobalErrors);
498
+ const indexAttachmentsEntry = await requiredEntryData(AllureStoreDumpFiles.IndexAttachmentsByTestResults);
499
+ const indexTestResultsByHistoryId = await requiredEntryData(AllureStoreDumpFiles.IndexTestResultsByHistoryId);
500
+ const indexTestResultsByTestCaseEntry = await requiredEntryData(AllureStoreDumpFiles.IndexTestResultsByTestCase);
501
+ const indexAttachmentsByFixtureEntry = await requiredEntryData(AllureStoreDumpFiles.IndexAttachmentsByFixture);
502
+ const indexFixturesByTestResultEntry = await requiredEntryData(AllureStoreDumpFiles.IndexFixturesByTestResult);
503
+ const indexKnownByHistoryIdEntry = await requiredEntryData(AllureStoreDumpFiles.IndexKnownByHistoryId);
504
+ const qualityGateResultsEntry = await requiredEntryData(AllureStoreDumpFiles.QualityGateResults);
505
+ const testResultIngestOrderEntry = await optionalEntryData(AllureStoreDumpFiles.TestResultIngestOrder);
506
+ const attachmentsLinks = JSON.parse(attachmentsEntry.toString("utf8"));
507
+ const attachmentsEntries = dumpEntriesList.reduce((acc, [entryName, entry]) => {
508
+ switch (entryName) {
509
+ case AllureStoreDumpFiles.Attachments:
510
+ case AllureStoreDumpFiles.CheckResults:
511
+ case AllureStoreDumpFiles.TestResults:
512
+ case AllureStoreDumpFiles.TestCases:
513
+ case AllureStoreDumpFiles.Fixtures:
514
+ case AllureStoreDumpFiles.Environments:
515
+ case AllureStoreDumpFiles.ReportVariables:
516
+ case AllureStoreDumpFiles.GlobalAttachments:
517
+ case AllureStoreDumpFiles.GlobalErrors:
518
+ case AllureStoreDumpFiles.IndexAttachmentsByTestResults:
519
+ case AllureStoreDumpFiles.IndexTestResultsByHistoryId:
520
+ case AllureStoreDumpFiles.IndexTestResultsByTestCase:
521
+ case AllureStoreDumpFiles.IndexAttachmentsByFixture:
522
+ case AllureStoreDumpFiles.IndexFixturesByTestResult:
523
+ case AllureStoreDumpFiles.IndexKnownByHistoryId:
524
+ case AllureStoreDumpFiles.QualityGateResults:
525
+ case AllureStoreDumpFiles.TestResultIngestOrder:
385
526
  return acc;
527
+ default:
528
+ if (entry.isDirectory || !attachmentsLinks[entryName] || attachmentsLinks[entryName].missed) {
529
+ return acc;
530
+ }
531
+ return Object.assign(acc, {
532
+ [entryName]: entry,
533
+ });
534
+ }
535
+ }, {});
536
+ const dumpState = {
537
+ testResults: JSON.parse(testResultsEntry.toString("utf8")),
538
+ testCases: JSON.parse(testCasesEntry.toString("utf8")),
539
+ fixtures: JSON.parse(fixturesEntry.toString("utf8")),
540
+ attachments: attachmentsLinks,
541
+ checkResults: checkResultsEntry ? JSON.parse(checkResultsEntry.toString("utf8")) : [],
542
+ environments: JSON.parse(environmentsEntry.toString("utf8")),
543
+ reportVariables: JSON.parse(reportVariablesEntry.toString("utf8")),
544
+ globalAttachmentIds: JSON.parse(globalAttachmentsEntry.toString("utf8")),
545
+ globalErrors: JSON.parse(globalErrorsEntry.toString("utf8")),
546
+ indexAttachmentByTestResult: JSON.parse(indexAttachmentsEntry.toString("utf8")),
547
+ indexTestResultByHistoryId: JSON.parse(indexTestResultsByHistoryId.toString("utf8")),
548
+ indexTestResultByTestCase: JSON.parse(indexTestResultsByTestCaseEntry.toString("utf8")),
549
+ indexAttachmentByFixture: JSON.parse(indexAttachmentsByFixtureEntry.toString("utf8")),
550
+ indexFixturesByTestResult: JSON.parse(indexFixturesByTestResultEntry.toString("utf8")),
551
+ indexKnownByHistoryId: JSON.parse(indexKnownByHistoryIdEntry.toString("utf8")),
552
+ qualityGateResults: JSON.parse(qualityGateResultsEntry.toString("utf8")),
553
+ testResultIdsIngestOrder: testResultIngestOrderEntry
554
+ ? JSON.parse(testResultIngestOrderEntry.toString("utf8"))
555
+ : [],
556
+ };
557
+ const dumpTempDir = await mkdtemp(join(tmpdir(), basename(dump, ".zip")));
558
+ const resultsAttachments = {};
559
+ __classPrivateFieldGet(this, _AllureReport_dumpTempDirs, "f").push(dumpTempDir);
560
+ await measurePerf(PERF_METRIC_NAMES.restoreStateAttachments, async () => {
561
+ try {
562
+ for (const [attachmentId] of Object.entries(attachmentsEntries)) {
563
+ const attachmentContentEntry = await dumpArchive.entryData(attachmentId);
564
+ const attachmentFilePath = resolveDumpAttachmentPath(dumpTempDir, attachmentId);
565
+ await writeFile(attachmentFilePath, attachmentContentEntry);
566
+ resultsAttachments[attachmentId] = new PathResultFile(attachmentFilePath, attachmentId);
386
567
  }
387
- return Object.assign(acc, {
388
- [entryName]: entry,
389
- });
390
- }
391
- }, {});
392
- const dumpState = {
393
- testResults: JSON.parse(testResultsEntry.toString("utf8")),
394
- testCases: JSON.parse(testCasesEntry.toString("utf8")),
395
- fixtures: JSON.parse(fixturesEntry.toString("utf8")),
396
- attachments: attachmentsLinks,
397
- checkResults: checkResultsEntry ? JSON.parse(checkResultsEntry.toString("utf8")) : [],
398
- environments: JSON.parse(environmentsEntry.toString("utf8")),
399
- reportVariables: JSON.parse(reportVariablesEntry.toString("utf8")),
400
- globalAttachmentIds: JSON.parse(globalAttachmentsEntry.toString("utf8")),
401
- globalErrors: JSON.parse(globalErrorsEntry.toString("utf8")),
402
- indexAttachmentByTestResult: JSON.parse(indexAttachmentsEntry.toString("utf8")),
403
- indexTestResultByHistoryId: JSON.parse(indexTestResultsByHistoryId.toString("utf8")),
404
- indexTestResultByTestCase: JSON.parse(indexTestResultsByTestCaseEntry.toString("utf8")),
405
- indexLatestEnvTestResultByHistoryId: JSON.parse(indexLatestEnvTestResultsByHistoryIdEntry.toString("utf8")),
406
- indexAttachmentByFixture: JSON.parse(indexAttachmentsByFixtureEntry.toString("utf8")),
407
- indexFixturesByTestResult: JSON.parse(indexFixturesByTestResultEntry.toString("utf8")),
408
- indexKnownByHistoryId: JSON.parse(indexKnownByHistoryIdEntry.toString("utf8")),
409
- qualityGateResults: JSON.parse(qualityGateResultsEntry.toString("utf8")),
410
- };
411
- const dumpTempDir = await mkdtemp(join(tmpdir(), basename(dump, ".zip")));
412
- const resultsAttachments = {};
413
- __classPrivateFieldGet(this, _AllureReport_dumpTempDirs, "f").push(dumpTempDir);
414
- try {
415
- for (const [attachmentId] of Object.entries(attachmentsEntries)) {
416
- const attachmentContentEntry = await dumpArchive.entryData(attachmentId);
417
- const attachmentFilePath = resolveDumpAttachmentPath(dumpTempDir, attachmentId);
418
- await writeFile(attachmentFilePath, attachmentContentEntry);
419
- resultsAttachments[attachmentId] = new PathResultFile(attachmentFilePath, attachmentId);
420
- }
568
+ }
569
+ catch (err) {
570
+ if (err instanceof UnsafeDumpPathError) {
571
+ console.error(`Cannot restore dump from "${dump}": the archive lists attachment paths that would write outside the extract directory (unsafe zip paths such as "../" or absolute names).`);
572
+ console.error(err.message);
573
+ console.error("Only use dump archives produced by this tool; do not load untrusted or third-party --dump zip files.");
574
+ throw err;
575
+ }
576
+ console.error(`Can't restore attachment contents from "${dump}", continuing without them`);
577
+ console.error(errorDetails(err));
578
+ }
579
+ });
580
+ await measurePerf(PERF_METRIC_NAMES.restoreStateStoreRestore, async () => __classPrivateFieldGet(this, _AllureReport_store, "f").restoreState(dumpState, resultsAttachments));
581
+ console.info(`Successfully restored state from "${dump}"`);
421
582
  }
422
583
  catch (err) {
423
- if (err instanceof UnsafeDumpPathError) {
424
- console.error(`Cannot restore dump from "${dump}": the archive lists attachment paths that would write outside the extract directory (unsafe zip paths such as "../" or absolute names).`);
425
- console.error(err.message);
426
- console.error("Only use dump archives produced by this tool; do not load untrusted or third-party --dump zip files.");
427
- throw err;
584
+ restoreError = err;
585
+ throw err;
586
+ }
587
+ finally {
588
+ try {
589
+ await dumpArchive.close();
590
+ }
591
+ catch (err) {
592
+ if (!restoreError) {
593
+ console.error(`Failed to close dump archive "${dump}"`);
594
+ console.error(errorDetails(err));
595
+ }
428
596
  }
429
- console.error(`Can't restore attachment contents from "${dump}", continuing without them`);
430
- console.error(errorDetails(err));
431
597
  }
432
- await __classPrivateFieldGet(this, _AllureReport_store, "f").restoreState(dumpState, resultsAttachments);
433
- console.info(`Successfully restored state from "${dump}"`);
434
598
  }
435
599
  catch (err) {
436
- restoreError = err;
437
- throw err;
600
+ console.error(`Failed to restore state from "${dump}", continuing without it`);
601
+ console.error(errorDetails(err));
438
602
  }
439
- finally {
440
- try {
441
- await dumpArchive.close();
442
- }
443
- catch (err) {
444
- if (!restoreError) {
445
- console.error(`Failed to close dump archive "${dump}"`);
446
- console.error(errorDetails(err));
447
- }
448
- }
449
- }
450
- }
451
- catch (err) {
452
- console.error(`Failed to restore state from "${dump}", continuing without it`);
453
- console.error(errorDetails(err));
454
- }
603
+ });
455
604
  }
456
- };
457
- this.done = async () => {
458
- const summaries = [];
459
- const remoteHrefs = new Set();
460
- const remoteHrefsByPluginId = {};
461
- const cancelledPluginsIds = new Set();
462
- let remoteCleanupFailed = false;
463
- const getSuccessfulPublishedPlugins = () => __classPrivateFieldGet(this, _AllureReport_plugins, "f").filter(({ enabled, id, options }) => enabled && !!options?.publish && !cancelledPluginsIds.has(id));
464
- if (__classPrivateFieldGet(this, _AllureReport_executionStage, "f") !== "running") {
465
- throw new Error(initRequired);
605
+ });
606
+ _AllureReport_getReportsToPublish.set(this, async () => {
607
+ const reports = [];
608
+ for (const { enabled, id, options } of __classPrivateFieldGet(this, _AllureReport_plugins, "f")) {
609
+ if (!enabled) {
610
+ continue;
611
+ }
612
+ const files = (await __classPrivateFieldGet(this, _AllureReport_state, "f")?.[id]?.get("files")) ?? {};
613
+ reports.push({
614
+ pluginId: id,
615
+ publish: !!options?.publish,
616
+ files,
617
+ });
466
618
  }
467
- const testResults = await __classPrivateFieldGet(this, _AllureReport_store, "f").allTestResults();
468
- const testCases = await __classPrivateFieldGet(this, _AllureReport_store, "f").allTestCases();
469
- const historyDataPoint = createHistory(this.reportUuid, __classPrivateFieldGet(this, _AllureReport_reportName, "f"), testCases, testResults, this.reportUrl);
470
- __classPrivateFieldGet(this, _AllureReport_realtimeChannel, "f").close();
619
+ return reports;
620
+ });
621
+ _AllureReport_cleanupFailedRemoteReport.set(this, async (client) => {
471
622
  try {
472
- await __classPrivateFieldGet(this, _AllureReport_realtimeUpdateScheduler, "f").close();
623
+ await client.deleteReport({
624
+ reportUuid: this.reportUuid,
625
+ });
473
626
  }
474
- catch (e) {
475
- console.error("realtime update failed during shutdown", e);
627
+ catch (cleanupError) {
628
+ console.error("Failed to clean up failed report upload");
629
+ console.error(errorDetails(cleanupError));
476
630
  }
477
- __classPrivateFieldSet(this, _AllureReport_executionStage, "done", "f");
478
- if (__classPrivateFieldGet(this, _AllureReport_dump, "f")) {
479
- await this.dumpState();
631
+ });
632
+ _AllureReport_logPublishError.set(this, (message, err) => {
633
+ console.error(message);
634
+ if (err instanceof KnownError) {
635
+ console.error(err.message);
636
+ }
637
+ else {
638
+ console.error(errorDetails(err));
639
+ }
640
+ });
641
+ _AllureReport_applyPublishLinksToSummaries.set(this, (linksByPluginId) => {
642
+ const changedPluginIds = new Set();
643
+ if (__classPrivateFieldGet(this, _AllureReport_summariesByPluginId, "f").size === 0) {
644
+ return changedPluginIds;
645
+ }
646
+ for (const [pluginId, remoteHref] of Object.entries(linksByPluginId)) {
647
+ const summary = __classPrivateFieldGet(this, _AllureReport_summariesByPluginId, "f").get(pluginId);
648
+ if (summary && remoteHref) {
649
+ summary.remoteHref = remoteHref;
650
+ changedPluginIds.add(pluginId);
651
+ }
652
+ }
653
+ return changedPluginIds;
654
+ });
655
+ _AllureReport_cloneSummariesByPluginId.set(this, () => new Map([...__classPrivateFieldGet(this, _AllureReport_summariesByPluginId, "f")].map(([pluginId, summary]) => [pluginId, clonePluginSummary(summary)])));
656
+ _AllureReport_writeSummaryFiles.set(this, async (pluginIds) => {
657
+ if (__classPrivateFieldGet(this, _AllureReport_summariesByPluginId, "f").size === 0) {
480
658
  return;
481
659
  }
482
- await __classPrivateFieldGet(this, _AllureReport_eachPlugin, "f").call(this, false, async (plugin, context) => {
483
- await plugin.done?.(context, __classPrivateFieldGet(this, _AllureReport_store, "f"));
484
- });
485
- await __classPrivateFieldGet(this, _AllureReport_eachPlugin, "f").call(this, false, async (plugin, context) => {
486
- if (__classPrivateFieldGet(this, _AllureReport_allureServiceClient, "f") && context.publish) {
487
- const pluginFiles = (await context.state.get("files")) ?? {};
488
- const pluginFilesEntries = Object.entries(pluginFiles);
489
- const progressBar = pluginFilesEntries?.length > 0
490
- ? new ProgressBar(`Publishing "${context.id}" report [:bar] :current/:total`, {
491
- total: pluginFilesEntries.length,
492
- width: 20,
493
- })
494
- : undefined;
495
- const limitFn = pLimit(REMOTE_UPLOAD_CONCURRENCY);
496
- const uploadAbortController = new AbortController();
497
- const failedUploads = new Set();
498
- let terminalUploadError;
499
- let remoteReportDeleted = false;
500
- let fns = [];
501
- const cleanupFailedPluginUpload = async (err) => {
502
- if (remoteReportDeleted) {
503
- return;
504
- }
505
- remoteReportDeleted = true;
506
- cancelledPluginsIds.add(context.id);
507
- uploadAbortController.abort();
508
- await Promise.allSettled(fns);
509
- const pluginRemoteHref = remoteHrefsByPluginId[context.id];
510
- if (pluginRemoteHref) {
511
- remoteHrefs.delete(pluginRemoteHref);
512
- delete remoteHrefsByPluginId[context.id];
513
- }
514
- try {
515
- await __classPrivateFieldGet(this, _AllureReport_allureServiceClient, "f").deleteReport({
516
- reportUuid: this.reportUuid,
517
- pluginId: context.id,
518
- });
519
- }
520
- catch (cleanupErr) {
521
- remoteCleanupFailed = true;
522
- console.error(`Plugin "${context.id}" upload cleanup has failed, the remote report won't be completed`);
523
- console.error(cleanupErr);
524
- }
525
- console.error(`Plugin "${context.id}" upload has failed, the plugin won't be published`);
526
- console.error(err);
527
- };
528
- fns = pluginFilesEntries.map(([filename, filepath]) => limitFn(async () => {
529
- if (cancelledPluginsIds.has(context.id) || uploadAbortController.signal.aborted) {
530
- return;
531
- }
532
- for (let attempt = 1; attempt <= REMOTE_UPLOAD_MAX_ATTEMPTS; attempt++) {
533
- if (cancelledPluginsIds.has(context.id) || uploadAbortController.signal.aborted) {
534
- return;
535
- }
536
- try {
537
- if (/^(data|widgets|index\.html$|summary\.json$)/.test(filename)) {
538
- const uploadedFileUrl = await __classPrivateFieldGet(this, _AllureReport_allureServiceClient, "f").addReportFile({
539
- reportUuid: this.reportUuid,
540
- pluginId: context.id,
541
- filename,
542
- filepath,
543
- signal: uploadAbortController.signal,
544
- });
545
- if (cancelledPluginsIds.has(context.id) || uploadAbortController.signal.aborted) {
546
- return;
547
- }
548
- if (filename === "index.html") {
549
- remoteHrefsByPluginId[context.id] = uploadedFileUrl;
550
- remoteHrefs.add(uploadedFileUrl);
551
- }
552
- }
553
- else {
554
- await __classPrivateFieldGet(this, _AllureReport_allureServiceClient, "f").addReportAsset({
555
- filename,
556
- filepath,
557
- signal: uploadAbortController.signal,
558
- });
559
- }
560
- failedUploads.delete(filename);
561
- progressBar?.tick?.();
562
- return;
563
- }
564
- catch (err) {
565
- if (cancelledPluginsIds.has(context.id) || uploadAbortController.signal.aborted) {
566
- return;
567
- }
568
- if (isAbortError(err)) {
569
- throw err;
570
- }
571
- failedUploads.add(filename);
572
- if (failedUploads.size > REMOTE_UPLOAD_MAX_SIMULTANEOUS_FAILED ||
573
- attempt >= REMOTE_UPLOAD_MAX_ATTEMPTS) {
574
- terminalUploadError ?? (terminalUploadError = err);
575
- throw terminalUploadError;
576
- }
577
- }
578
- }
579
- }));
580
- progressBar?.render?.();
581
- try {
582
- await Promise.all(fns);
583
- }
584
- catch (err) {
585
- await cleanupFailedPluginUpload(terminalUploadError ?? err);
586
- }
660
+ const pluginIdsSet = pluginIds ? new Set(pluginIds) : undefined;
661
+ await __classPrivateFieldGet(this, _AllureReport_eachPlugin, "f").call(this, false, async (_plugin, context) => {
662
+ if (pluginIdsSet && !pluginIdsSet.has(context.id)) {
663
+ return;
587
664
  }
588
- const summary = await plugin?.info?.(context, __classPrivateFieldGet(this, _AllureReport_store, "f"));
665
+ const summary = __classPrivateFieldGet(this, _AllureReport_summariesByPluginId, "f").get(context.id);
589
666
  if (!summary) {
590
667
  return;
591
668
  }
592
- summary.pluginId = context.id;
593
- summary.pullRequestHref = __classPrivateFieldGet(this, _AllureReport_ci, "f")?.pullRequestUrl;
594
- summary.jobHref = __classPrivateFieldGet(this, _AllureReport_ci, "f")?.jobRunUrl;
595
- if (context.publish && !cancelledPluginsIds.has(context.id)) {
596
- summary.remoteHref =
597
- remoteHrefsByPluginId[context.id] ?? (this.reportUrl ? `${this.reportUrl}/${context.id}/` : undefined);
598
- if (summary.remoteHref) {
599
- remoteHrefs.add(summary.remoteHref);
600
- }
601
- }
602
- summaries.push({
603
- ...summary,
604
- href: `${context.id}/`,
605
- });
606
669
  await context.reportFiles.addFile("summary.json", Buffer.from(JSON.stringify(summary)));
607
670
  });
671
+ });
672
+ _AllureReport_generateRootSummary.set(this, async () => {
673
+ const summaries = [...__classPrivateFieldGet(this, _AllureReport_summariesByPluginId, "f").values()].map(clonePluginSummary);
608
674
  if (summaries.length > 1) {
609
- const summaryPath = await generateSummary(__classPrivateFieldGet(this, _AllureReport_output, "f"), summaries);
610
- const publishedReports = getSuccessfulPublishedPlugins();
611
- if (__classPrivateFieldGet(this, _AllureReport_instances, "a", _AllureReport_publish_get) && summaryPath && publishedReports.length > 1) {
612
- await __classPrivateFieldGet(this, _AllureReport_allureServiceClient, "f")?.addReportFile({
613
- reportUuid: this.reportUuid,
614
- filename: "index.html",
615
- filepath: summaryPath,
616
- });
617
- }
675
+ __classPrivateFieldSet(this, _AllureReport_summaryPath, await measurePerf(PERF_METRIC_NAMES.summaryGenerate, async () => generateSummary(__classPrivateFieldGet(this, _AllureReport_output, "f"), summaries)), "f");
618
676
  }
619
- const publishedReports = getSuccessfulPublishedPlugins();
620
- if (__classPrivateFieldGet(this, _AllureReport_instances, "a", _AllureReport_publish_get) && !remoteCleanupFailed && publishedReports.length > 0) {
621
- await __classPrivateFieldGet(this, _AllureReport_allureServiceClient, "f")?.completeReport({
622
- reportUuid: this.reportUuid,
623
- historyPoint: historyDataPoint,
624
- });
677
+ else {
678
+ __classPrivateFieldSet(this, _AllureReport_summaryPath, undefined, "f");
625
679
  }
626
- let outputDirFiles = [];
627
- try {
628
- outputDirFiles = await readdir(__classPrivateFieldGet(this, _AllureReport_output, "f"));
629
- }
630
- catch { }
631
- if (outputDirFiles.length === 0) {
632
- return;
680
+ });
681
+ this.done = async () => {
682
+ const summaries = [];
683
+ if (__classPrivateFieldGet(this, _AllureReport_executionStage, "f") !== "running") {
684
+ throw new Error(initRequired);
633
685
  }
634
- const reportPath = join(__classPrivateFieldGet(this, _AllureReport_output, "f"), outputDirFiles[0]);
635
- const reportStats = await lstat(reportPath);
636
- const outputEntriesStats = await Promise.all(outputDirFiles.map((file) => lstat(join(__classPrivateFieldGet(this, _AllureReport_output, "f"), file))));
637
- const outputDirectoryEntries = outputEntriesStats.filter((entry) => entry.isDirectory());
638
- if (reportStats.isDirectory() && outputDirectoryEntries.length === 1) {
639
- const reportContent = await readdir(reportPath);
640
- for (const entry of reportContent) {
641
- const currentFilePath = join(reportPath, entry);
642
- const newFilePath = resolve(dirname(currentFilePath), "..", entry);
643
- await rename(currentFilePath, newFilePath);
686
+ try {
687
+ const testResults = await __classPrivateFieldGet(this, _AllureReport_store, "f").allTestResults();
688
+ const testCases = await __classPrivateFieldGet(this, _AllureReport_store, "f").allTestCases();
689
+ __classPrivateFieldSet(this, _AllureReport_historyDataPoint, createHistory(this.reportUuid, this.reportName, testCases, testResults, this.reportUrl), "f");
690
+ __classPrivateFieldGet(this, _AllureReport_realtimeChannel, "f").close();
691
+ try {
692
+ await __classPrivateFieldGet(this, _AllureReport_realtimeUpdateScheduler, "f").close();
644
693
  }
645
- await rm(reportPath, { recursive: true });
646
- }
647
- for (const dir of __classPrivateFieldGet(this, _AllureReport_dumpTempDirs, "f")) {
694
+ catch (e) {
695
+ console.error("realtime update failed during shutdown", e);
696
+ }
697
+ __classPrivateFieldSet(this, _AllureReport_executionStage, "done", "f");
698
+ if (__classPrivateFieldGet(this, _AllureReport_dump, "f")) {
699
+ await this.dumpState();
700
+ return;
701
+ }
702
+ await measurePerf(PERF_METRIC_NAMES.generatePluginsDone, async () => {
703
+ await __classPrivateFieldGet(this, _AllureReport_eachPlugin, "f").call(this, false, async (plugin, context) => {
704
+ await measurePerf(`${PERF_METRIC_PREFIXES.generatePluginDone}${context.id}`, async () => {
705
+ await plugin.done?.(context, __classPrivateFieldGet(this, _AllureReport_store, "f"));
706
+ });
707
+ });
708
+ });
709
+ __classPrivateFieldGet(this, _AllureReport_finishGeneratePerfSpan, "f").call(this);
710
+ await __classPrivateFieldGet(this, _AllureReport_eachPlugin, "f").call(this, false, async (plugin, context) => {
711
+ const summary = await plugin?.info?.(context, __classPrivateFieldGet(this, _AllureReport_store, "f"));
712
+ if (!summary) {
713
+ return;
714
+ }
715
+ summary.pluginId = context.id;
716
+ summary.pullRequestHref = __classPrivateFieldGet(this, _AllureReport_ci, "f")?.pullRequestUrl;
717
+ summary.jobHref = __classPrivateFieldGet(this, _AllureReport_ci, "f")?.jobRunUrl;
718
+ summaries.push({
719
+ ...summary,
720
+ href: `${context.id}/`,
721
+ });
722
+ });
723
+ __classPrivateFieldSet(this, _AllureReport_summariesByPluginId, new Map(summaries
724
+ .filter((summary) => !!summary.pluginId)
725
+ .map((summary) => [summary.pluginId, summary])), "f");
726
+ await __classPrivateFieldGet(this, _AllureReport_publish, "f").call(this);
727
+ let outputDirFiles = [];
648
728
  try {
649
- await rm(dir, { recursive: true });
729
+ outputDirFiles = await readdir(__classPrivateFieldGet(this, _AllureReport_output, "f"));
650
730
  }
651
731
  catch { }
652
- }
653
- if (__classPrivateFieldGet(this, _AllureReport_history, "f")) {
654
- try {
655
- await __classPrivateFieldGet(this, _AllureReport_store, "f").appendHistory(historyDataPoint);
732
+ if (outputDirFiles.length === 0) {
733
+ return;
656
734
  }
657
- catch (err) {
658
- if (err instanceof KnownError) {
659
- console.error("Failed to append history", err.message);
735
+ const reportPath = join(__classPrivateFieldGet(this, _AllureReport_output, "f"), outputDirFiles[0]);
736
+ const reportStats = await lstat(reportPath);
737
+ const outputEntriesStats = await Promise.all(outputDirFiles.map((file) => lstat(join(__classPrivateFieldGet(this, _AllureReport_output, "f"), file))));
738
+ const outputDirectoryEntries = outputEntriesStats.filter((entry) => entry.isDirectory());
739
+ if (reportStats.isDirectory() && outputDirectoryEntries.length === 1) {
740
+ const reportContent = await readdir(reportPath);
741
+ for (const entry of reportContent) {
742
+ const currentFilePath = join(reportPath, entry);
743
+ const newFilePath = resolve(dirname(currentFilePath), "..", entry);
744
+ await rename(currentFilePath, newFilePath);
660
745
  }
661
- else if (err instanceof UnknownError) {
662
- console.error("Failed to append history due to unexpected error", err.message);
746
+ await rm(reportPath, { recursive: true });
747
+ }
748
+ for (const dir of __classPrivateFieldGet(this, _AllureReport_dumpTempDirs, "f")) {
749
+ try {
750
+ await rm(dir, { recursive: true });
751
+ }
752
+ catch { }
753
+ }
754
+ if (__classPrivateFieldGet(this, _AllureReport_history, "f")) {
755
+ try {
756
+ await __classPrivateFieldGet(this, _AllureReport_store, "f").appendHistory(__classPrivateFieldGet(this, _AllureReport_historyDataPoint, "f"));
663
757
  }
664
- else {
665
- throw err;
758
+ catch (err) {
759
+ if (err instanceof KnownError) {
760
+ console.error("Failed to append history", err.message);
761
+ }
762
+ else if (err instanceof UnknownError) {
763
+ console.error("Failed to append history due to unexpected error", err.message);
764
+ }
765
+ else {
766
+ throw err;
767
+ }
666
768
  }
667
769
  }
770
+ if (__classPrivateFieldGet(this, _AllureReport_publishedRemoteHrefs, "f").size > 0) {
771
+ console.info("Next reports have been published:");
772
+ __classPrivateFieldGet(this, _AllureReport_publishedRemoteHrefs, "f").forEach((href) => {
773
+ console.info(`- ${href}`);
774
+ });
775
+ }
776
+ if (!__classPrivateFieldGet(this, _AllureReport_qualityGate, "f")) {
777
+ return;
778
+ }
779
+ const qualityGateResults = await __classPrivateFieldGet(this, _AllureReport_store, "f").qualityGateResultsByEnv();
780
+ await writeFile(join(__classPrivateFieldGet(this, _AllureReport_output, "f"), "quality-gate.json"), JSON.stringify(qualityGateResults));
668
781
  }
669
- if (!remoteCleanupFailed && remoteHrefs.size > 0) {
670
- console.info("Next reports have been published:");
671
- remoteHrefs.forEach((href) => {
672
- console.info(`- ${href}`);
673
- });
674
- }
675
- if (!__classPrivateFieldGet(this, _AllureReport_qualityGate, "f")) {
676
- return;
782
+ finally {
783
+ await __classPrivateFieldGet(this, _AllureReport_finishPerfMetrics, "f").call(this);
677
784
  }
678
- const qualityGateResults = await __classPrivateFieldGet(this, _AllureReport_store, "f").qualityGateResultsByEnv();
679
- await writeFile(join(__classPrivateFieldGet(this, _AllureReport_output, "f"), "quality-gate.json"), JSON.stringify(qualityGateResults));
680
785
  };
786
+ _AllureReport_finishGeneratePerfSpan.set(this, () => {
787
+ __classPrivateFieldGet(this, _AllureReport_endGeneratePerfSpan, "f")?.call(this);
788
+ __classPrivateFieldSet(this, _AllureReport_endGeneratePerfSpan, undefined, "f");
789
+ });
790
+ _AllureReport_finishPerfMetrics.set(this, async () => {
791
+ __classPrivateFieldGet(this, _AllureReport_finishGeneratePerfSpan, "f").call(this);
792
+ try {
793
+ await writePerfMetrics(__classPrivateFieldGet(this, _AllureReport_output, "f"));
794
+ }
795
+ catch (err) {
796
+ console.error("Failed to write Allure performance metrics", err);
797
+ }
798
+ });
681
799
  _AllureReport_eachPlugin.set(this, async (initState, consumer) => {
682
800
  if (initState) {
683
801
  __classPrivateFieldSet(this, _AllureReport_state, {}, "f");
@@ -707,11 +825,12 @@ export class AllureReport {
707
825
  publish: !!options?.publish,
708
826
  allureVersion: version,
709
827
  reportUuid: this.reportUuid,
710
- reportName: __classPrivateFieldGet(this, _AllureReport_reportName, "f"),
828
+ reportName: this.reportName,
711
829
  hideLabels: __classPrivateFieldGet(this, _AllureReport_hideLabels, "f"),
712
830
  state: pluginState,
713
831
  reportFiles: pluginFiles,
714
832
  reportUrl: this.reportUrl,
833
+ realTime: !!__classPrivateFieldGet(this, _AllureReport_realTime, "f"),
715
834
  output: __classPrivateFieldGet(this, _AllureReport_output, "f"),
716
835
  ci: __classPrivateFieldGet(this, _AllureReport_ci, "f"),
717
836
  categories: __classPrivateFieldGet(this, _AllureReport_categories, "f"),
@@ -719,6 +838,7 @@ export class AllureReport {
719
838
  };
720
839
  try {
721
840
  await consumer.call(this, plugin, pluginContext);
841
+ this.reportUrl = pluginContext.reportUrl ?? this.reportUrl;
722
842
  if (initState) {
723
843
  __classPrivateFieldGet(this, _AllureReport_state, "f")[id] = pluginState;
724
844
  }
@@ -728,14 +848,23 @@ export class AllureReport {
728
848
  }
729
849
  }
730
850
  });
731
- const { name, readers = [allure1, allure2, cucumberjson, junitXml, attachments], plugins = [], known, reportFiles, realTime, historyPath, historyLimit, defaultLabels = {}, variables = {}, environment, allowedEnvironments, environments, output, hideLabels, qualityGate, dump, categories, allureService: allureServiceConfig, globalAttachments, } = opts;
732
- if (allureServiceConfig?.accessToken) {
733
- __classPrivateFieldSet(this, _AllureReport_allureServiceClient, new AllureServiceClient(allureServiceConfig), "f");
851
+ const { name, readers = [allure1, allure2, cucumberjson, junitXml, attachments], plugins = [], known, reportFiles, realTime, historyPath, historyLimit, defaultLabels = {}, variables = {}, environment, allowedEnvironments, environments, output, hideLabels, qualityGate, dump, categories, allureService, globalAttachments, } = opts;
852
+ const allureServiceAccessToken = allureService?.accessToken;
853
+ if (allureServiceAccessToken) {
854
+ const allureServiceClientConfig = {
855
+ ...allureService,
856
+ accessToken: allureServiceAccessToken,
857
+ };
858
+ __classPrivateFieldSet(this, _AllureReport_allureServiceClient, allureServiceAccessToken.startsWith("ato1.")
859
+ ? new AllureTestOpsClient(allureServiceClientConfig)
860
+ : allureServiceAccessToken.startsWith("ars1.")
861
+ ? new AllureServiceClient(allureServiceClientConfig)
862
+ : undefined, "f");
734
863
  }
735
864
  this.reportUuid = randomUUID();
736
865
  __classPrivateFieldSet(this, _AllureReport_ci, detect(), "f");
737
866
  const reportTitleSuffix = __classPrivateFieldGet(this, _AllureReport_ci, "f")?.pullRequestName ?? __classPrivateFieldGet(this, _AllureReport_ci, "f")?.jobRunName;
738
- __classPrivateFieldSet(this, _AllureReport_reportName, [name, reportTitleSuffix].filter(Boolean).join(" – "), "f");
867
+ this.reportName = [name, reportTitleSuffix].filter(Boolean).join(" – ");
739
868
  __classPrivateFieldSet(this, _AllureReport_realtimeChannel, new RealtimeChannel(), "f");
740
869
  __classPrivateFieldSet(this, _AllureReport_realtimeUpdateScheduler, new RealtimeUpdateScheduler(__classPrivateFieldGet(this, _AllureReport_runRealtimeUpdate, "f")), "f");
741
870
  __classPrivateFieldSet(this, _AllureReport_realTime, realTime, "f");
@@ -789,8 +918,6 @@ export class AllureReport {
789
918
  return __classPrivateFieldGet(this, _AllureReport_realtimeChannel, "f").dispatcher;
790
919
  }
791
920
  }
792
- _AllureReport_reportName = new WeakMap(), _AllureReport_ci = new WeakMap(), _AllureReport_store = new WeakMap(), _AllureReport_readers = new WeakMap(), _AllureReport_plugins = new WeakMap(), _AllureReport_reportFiles = new WeakMap(), _AllureReport_realtimeChannel = new WeakMap(), _AllureReport_realtimeUpdateScheduler = new WeakMap(), _AllureReport_realTime = new WeakMap(), _AllureReport_hideLabels = new WeakMap(), _AllureReport_output = new WeakMap(), _AllureReport_history = new WeakMap(), _AllureReport_allureServiceClient = new WeakMap(), _AllureReport_qualityGate = new WeakMap(), _AllureReport_dump = new WeakMap(), _AllureReport_categories = new WeakMap(), _AllureReport_environments = new WeakMap(), _AllureReport_globalAttachments = new WeakMap(), _AllureReport_dumpTempDirs = new WeakMap(), _AllureReport_state = new WeakMap(), _AllureReport_executionStage = new WeakMap(), _AllureReport_runRealtimeUpdate = new WeakMap(), _AllureReport_eachPlugin = new WeakMap(), _AllureReport_instances = new WeakSet(), _AllureReport_publish_get = function _AllureReport_publish_get() {
793
- return __classPrivateFieldGet(this, _AllureReport_plugins, "f").some(({ enabled, options }) => enabled && options.publish);
794
- }, _AllureReport_getPluginState = function _AllureReport_getPluginState(init, id) {
921
+ _AllureReport_ci = new WeakMap(), _AllureReport_store = new WeakMap(), _AllureReport_readers = new WeakMap(), _AllureReport_plugins = new WeakMap(), _AllureReport_reportFiles = new WeakMap(), _AllureReport_realtimeChannel = new WeakMap(), _AllureReport_realtimeUpdateScheduler = new WeakMap(), _AllureReport_realTime = new WeakMap(), _AllureReport_hideLabels = new WeakMap(), _AllureReport_output = new WeakMap(), _AllureReport_history = new WeakMap(), _AllureReport_allureServiceClient = new WeakMap(), _AllureReport_qualityGate = new WeakMap(), _AllureReport_dump = new WeakMap(), _AllureReport_categories = new WeakMap(), _AllureReport_environments = new WeakMap(), _AllureReport_globalAttachments = new WeakMap(), _AllureReport_dumpTempDirs = new WeakMap(), _AllureReport_state = new WeakMap(), _AllureReport_executionStage = new WeakMap(), _AllureReport_historyDataPoint = new WeakMap(), _AllureReport_summaryPath = new WeakMap(), _AllureReport_summariesByPluginId = new WeakMap(), _AllureReport_publishedRemoteHrefs = new WeakMap(), _AllureReport_published = new WeakMap(), _AllureReport_endGeneratePerfSpan = new WeakMap(), _AllureReport_publish = new WeakMap(), _AllureReport_runRealtimeUpdate = new WeakMap(), _AllureReport_getReportsToPublish = new WeakMap(), _AllureReport_cleanupFailedRemoteReport = new WeakMap(), _AllureReport_logPublishError = new WeakMap(), _AllureReport_applyPublishLinksToSummaries = new WeakMap(), _AllureReport_cloneSummariesByPluginId = new WeakMap(), _AllureReport_writeSummaryFiles = new WeakMap(), _AllureReport_generateRootSummary = new WeakMap(), _AllureReport_finishGeneratePerfSpan = new WeakMap(), _AllureReport_finishPerfMetrics = new WeakMap(), _AllureReport_eachPlugin = new WeakMap(), _AllureReport_instances = new WeakSet(), _AllureReport_getPluginState = function _AllureReport_getPluginState(init, id) {
795
922
  return init ? new DefaultPluginState({}) : __classPrivateFieldGet(this, _AllureReport_state, "f")?.[id];
796
923
  };