@allurereport/core 3.8.2 → 3.9.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_publish, _AllureReport_runRealtimeUpdate, _AllureReport_getReportsToPublish, _AllureReport_cleanupFailedRemoteReport, _AllureReport_logPublishError, _AllureReport_applyPublishLinksToSummaries, _AllureReport_cloneSummariesByPluginId, _AllureReport_writeSummaryFiles, _AllureReport_generateRootSummary, _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,52 @@ 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";
37
38
  import { RealtimeChannel } from "./utils/realtimeChannel.js";
38
39
  import { RealtimeUpdateScheduler } from "./utils/realtimeUpdateScheduler.js";
39
40
  import { resolveDumpAttachmentPath, UnsafeDumpPathError } from "./utils/safeDumpPath.js";
40
41
  const { version } = JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf8"));
41
42
  const initRequired = "report is not initialised. Call the start() method first.";
43
+ const defaultReadConcurrency = 64;
44
+ const maxReadConcurrency = 256;
45
+ const readConcurrency = () => {
46
+ const parsed = Number.parseInt(process.env.ALLURE_READ_CONCURRENCY ?? "", 10);
47
+ if (!Number.isFinite(parsed)) {
48
+ return defaultReadConcurrency;
49
+ }
50
+ return Math.min(maxReadConcurrency, Math.max(1, parsed));
51
+ };
52
+ const clonePluginSummary = (summary) => structuredClone(summary);
42
53
  const remoteReportParams = (ci) => {
43
54
  const repo = ci?.repoName;
44
55
  const branch = ci?.jobRunBranch;
45
56
  return repo && branch ? { repo, branch } : {};
46
57
  };
47
- const REMOTE_UPLOAD_CONCURRENCY = 50;
48
- const REMOTE_UPLOAD_MAX_ATTEMPTS = 5;
49
- const REMOTE_UPLOAD_MAX_SIMULTANEOUS_FAILED = 5;
50
58
  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";
59
+ const closeReadStream = async (stream) => {
60
+ if (stream.closed) {
61
+ return;
62
+ }
63
+ const closed = once(stream, "close").then(() => undefined);
64
+ if (!stream.destroyed) {
65
+ stream.destroy();
66
+ }
67
+ await closed.catch(() => undefined);
68
+ };
52
69
  export class AllureReport {
53
70
  constructor(opts) {
54
71
  _AllureReport_instances.add(this);
55
- _AllureReport_reportName.set(this, void 0);
56
72
  _AllureReport_ci.set(this, void 0);
57
73
  _AllureReport_store.set(this, void 0);
58
74
  _AllureReport_readers.set(this, void 0);
@@ -73,6 +89,119 @@ export class AllureReport {
73
89
  _AllureReport_dumpTempDirs.set(this, []);
74
90
  _AllureReport_state.set(this, void 0);
75
91
  _AllureReport_executionStage.set(this, "init");
92
+ _AllureReport_historyDataPoint.set(this, void 0);
93
+ _AllureReport_summaryPath.set(this, void 0);
94
+ _AllureReport_summariesByPluginId.set(this, new Map());
95
+ _AllureReport_publishedRemoteHrefs.set(this, new Set());
96
+ _AllureReport_published.set(this, false);
97
+ _AllureReport_publish.set(this, async () => {
98
+ if (__classPrivateFieldGet(this, _AllureReport_published, "f")) {
99
+ return;
100
+ }
101
+ if (__classPrivateFieldGet(this, _AllureReport_executionStage, "f") !== "done") {
102
+ throw new Error("report is not completed. Call the done() method first.");
103
+ }
104
+ let historyPoint = __classPrivateFieldGet(this, _AllureReport_historyDataPoint, "f");
105
+ if (!historyPoint) {
106
+ const allTrs = await __classPrivateFieldGet(this, _AllureReport_store, "f").allTestResults();
107
+ const allTcs = await __classPrivateFieldGet(this, _AllureReport_store, "f").allTestCases();
108
+ historyPoint = createHistory(this.reportUuid, this.reportName, allTcs, allTrs, this.reportUrl);
109
+ __classPrivateFieldSet(this, _AllureReport_historyDataPoint, historyPoint, "f");
110
+ }
111
+ await __classPrivateFieldGet(this, _AllureReport_writeSummaryFiles, "f").call(this);
112
+ await __classPrivateFieldGet(this, _AllureReport_generateRootSummary, "f").call(this);
113
+ if (__classPrivateFieldGet(this, _AllureReport_realTime, "f") || !__classPrivateFieldGet(this, _AllureReport_allureServiceClient, "f")) {
114
+ __classPrivateFieldSet(this, _AllureReport_published, true, "f");
115
+ return;
116
+ }
117
+ const reportsToPublish = (await __classPrivateFieldGet(this, _AllureReport_getReportsToPublish, "f").call(this)).filter((report) => report.publish && Object.keys(report.files).length > 0);
118
+ if (reportsToPublish.length === 0) {
119
+ __classPrivateFieldSet(this, _AllureReport_published, true, "f");
120
+ return;
121
+ }
122
+ const client = __classPrivateFieldGet(this, _AllureReport_allureServiceClient, "f");
123
+ const linksByPluginId = {};
124
+ const summariesSnapshot = __classPrivateFieldGet(this, _AllureReport_cloneSummariesByPluginId, "f").call(this);
125
+ const uploadProgressBar = createUploadProgressBarCounter(reportsToPublish.length === 1 ? `Publishing "${reportsToPublish[0].pluginId}" report` : "Publishing reports", reportsToPublish.reduce((acc, report) => acc + Object.keys(report.files).length, 0));
126
+ let summariesMutated = false;
127
+ let reportCreated = false;
128
+ let publishErrorMessage = "Report upload has failed, the report won't be published";
129
+ try {
130
+ await client.createReport({
131
+ reportUuid: this.reportUuid,
132
+ reportName: this.reportName,
133
+ ...remoteReportParams(__classPrivateFieldGet(this, _AllureReport_ci, "f")),
134
+ });
135
+ reportCreated = true;
136
+ for (const report of reportsToPublish) {
137
+ publishErrorMessage = `Plugin "${report.pluginId}" upload has failed, the plugin won't be published`;
138
+ const uploadResult = await client.uploadReport({
139
+ reportUuid: this.reportUuid,
140
+ pluginId: report.pluginId,
141
+ files: Object.fromEntries(Object.entries(report.files).filter(([filename]) => filename !== "summary.json")),
142
+ onProgress: () => uploadProgressBar.tick(),
143
+ });
144
+ if (uploadResult.indexHref) {
145
+ linksByPluginId[report.pluginId] = uploadResult.indexHref;
146
+ }
147
+ }
148
+ const changedPluginIds = __classPrivateFieldGet(this, _AllureReport_applyPublishLinksToSummaries, "f").call(this, linksByPluginId);
149
+ summariesMutated = changedPluginIds.size > 0;
150
+ if (changedPluginIds.size > 0) {
151
+ await __classPrivateFieldGet(this, _AllureReport_writeSummaryFiles, "f").call(this);
152
+ await __classPrivateFieldGet(this, _AllureReport_generateRootSummary, "f").call(this);
153
+ }
154
+ const updatedReports = await __classPrivateFieldGet(this, _AllureReport_getReportsToPublish, "f").call(this);
155
+ const updatedReportsByPluginId = new Map(updatedReports.map((report) => [report.pluginId, report]));
156
+ for (const report of reportsToPublish) {
157
+ const updatedReport = updatedReportsByPluginId.get(report.pluginId) ?? report;
158
+ const summaryFilepath = updatedReport.files["summary.json"];
159
+ if (!summaryFilepath) {
160
+ continue;
161
+ }
162
+ publishErrorMessage = `Plugin "${report.pluginId}" summary upload has failed, the plugin won't be published`;
163
+ await client.uploadReport({
164
+ reportUuid: this.reportUuid,
165
+ pluginId: updatedReport.pluginId,
166
+ files: { "summary.json": summaryFilepath },
167
+ onProgress: () => uploadProgressBar.tick(),
168
+ });
169
+ }
170
+ publishErrorMessage = "Report summary upload has failed, the report won't be published";
171
+ const summaryHref = __classPrivateFieldGet(this, _AllureReport_summaryPath, "f")
172
+ ? (await client.uploadReport({
173
+ reportUuid: this.reportUuid,
174
+ files: { "index.html": __classPrivateFieldGet(this, _AllureReport_summaryPath, "f") },
175
+ })).indexHref
176
+ : undefined;
177
+ publishErrorMessage = "Report completion has failed, the report won't be published";
178
+ await client.completeReport({
179
+ reportUuid: this.reportUuid,
180
+ historyPoint,
181
+ });
182
+ Object.values(linksByPluginId)
183
+ .filter(Boolean)
184
+ .forEach((href) => __classPrivateFieldGet(this, _AllureReport_publishedRemoteHrefs, "f").add(href));
185
+ if (summaryHref) {
186
+ __classPrivateFieldGet(this, _AllureReport_publishedRemoteHrefs, "f").add(summaryHref);
187
+ }
188
+ __classPrivateFieldSet(this, _AllureReport_published, true, "f");
189
+ }
190
+ catch (err) {
191
+ if (reportCreated) {
192
+ await __classPrivateFieldGet(this, _AllureReport_cleanupFailedRemoteReport, "f").call(this, client);
193
+ }
194
+ if (summariesMutated) {
195
+ __classPrivateFieldSet(this, _AllureReport_summariesByPluginId, summariesSnapshot, "f");
196
+ await __classPrivateFieldGet(this, _AllureReport_writeSummaryFiles, "f").call(this);
197
+ await __classPrivateFieldGet(this, _AllureReport_generateRootSummary, "f").call(this);
198
+ }
199
+ __classPrivateFieldGet(this, _AllureReport_logPublishError, "f").call(this, publishErrorMessage, err);
200
+ }
201
+ finally {
202
+ uploadProgressBar.terminate();
203
+ }
204
+ });
76
205
  this.readDirectory = async (resultsDir) => {
77
206
  if (__classPrivateFieldGet(this, _AllureReport_executionStage, "f") !== "running") {
78
207
  throw new Error(initRequired);
@@ -81,14 +210,20 @@ export class AllureReport {
81
210
  if (await readXcResultBundle(__classPrivateFieldGet(this, _AllureReport_store, "f"), resultsDirPath)) {
82
211
  return;
83
212
  }
84
- const dir = await opendir(resultsDirPath);
85
213
  try {
86
- for await (const dirent of dir) {
87
- if (dirent.isFile()) {
88
- const path = await realpath(join(dirent.parentPath ?? dirent.path, dirent.name));
214
+ const entries = (await readdir(resultsDirPath, { withFileTypes: true }))
215
+ .filter((dirent) => dirent.isFile())
216
+ .sort((a, b) => a.name.localeCompare(b.name));
217
+ const limit = pLimit(readConcurrency());
218
+ await Promise.all(entries.map((dirent) => limit(async () => {
219
+ try {
220
+ const path = await realpath(join(resultsDirPath, dirent.name));
89
221
  await this.readResult(new PathResultFile(path, dirent.name));
90
222
  }
91
- }
223
+ catch (e) {
224
+ console.error(`can't read result file ${dirent.name}`, e);
225
+ }
226
+ })));
92
227
  }
93
228
  catch (e) {
94
229
  console.error("can't read directory", e);
@@ -106,6 +241,9 @@ export class AllureReport {
106
241
  }
107
242
  for (const reader of __classPrivateFieldGet(this, _AllureReport_readers, "f")) {
108
243
  try {
244
+ if (reader.matches && !(await reader.matches(data))) {
245
+ continue;
246
+ }
109
247
  const processed = await reader.read(__classPrivateFieldGet(this, _AllureReport_store, "f"), data);
110
248
  if (processed) {
111
249
  return;
@@ -129,7 +267,6 @@ export class AllureReport {
129
267
  });
130
268
  };
131
269
  this.start = async () => {
132
- const remoteParams = remoteReportParams(__classPrivateFieldGet(this, _AllureReport_ci, "f"));
133
270
  await __classPrivateFieldGet(this, _AllureReport_store, "f").readHistory();
134
271
  if (__classPrivateFieldGet(this, _AllureReport_executionStage, "f") === "running") {
135
272
  throw new Error("the report is already started");
@@ -156,14 +293,6 @@ export class AllureReport {
156
293
  __classPrivateFieldGet(this, _AllureReport_realtimeChannel, "f").dispatcher.sendGlobalAttachment(new PathResultFile(absoluteFilePath, originalFileName), originalFileName);
157
294
  }
158
295
  }
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
296
  await __classPrivateFieldGet(this, _AllureReport_eachPlugin, "f").call(this, true, async (plugin, context) => {
168
297
  await plugin.start?.(context, __classPrivateFieldGet(this, _AllureReport_store, "f"), __classPrivateFieldGet(this, _AllureReport_realtimeChannel, "f").subscriber);
169
298
  });
@@ -228,7 +357,7 @@ export class AllureReport {
228
357
  const addJsonDumpEntry = async (entryName, value) => {
229
358
  await addRequiredDumpEntry(Buffer.from(JSON.stringify(value)), entryName);
230
359
  };
231
- const dumpJsonEntries = ({ testResults, testCases, fixtures, attachments, environments, reportVariables, checkResults = [], globalAttachmentIds = [], globalErrors = [], indexAttachmentByTestResult = {}, indexTestResultByHistoryId = {}, indexTestResultByTestCase = {}, indexLatestEnvTestResultByHistoryId = {}, indexAttachmentByFixture = {}, indexFixturesByTestResult = {}, indexKnownByHistoryId = {}, qualityGateResults = [], }) => [
360
+ const dumpJsonEntries = ({ testResults, testCases, fixtures, attachments, environments, reportVariables, checkResults = [], globalAttachmentIds = [], globalErrors = [], indexAttachmentByTestResult = {}, indexTestResultByHistoryId = {}, indexTestResultByTestCase = {}, indexAttachmentByFixture = {}, indexFixturesByTestResult = {}, indexKnownByHistoryId = {}, qualityGateResults = [], testResultIdsIngestOrder = [], }) => [
232
361
  [AllureStoreDumpFiles.TestResults, testResults],
233
362
  [AllureStoreDumpFiles.TestCases, testCases],
234
363
  [AllureStoreDumpFiles.Fixtures, fixtures],
@@ -241,11 +370,11 @@ export class AllureReport {
241
370
  [AllureStoreDumpFiles.IndexAttachmentsByTestResults, indexAttachmentByTestResult],
242
371
  [AllureStoreDumpFiles.IndexTestResultsByHistoryId, indexTestResultByHistoryId],
243
372
  [AllureStoreDumpFiles.IndexTestResultsByTestCase, indexTestResultByTestCase],
244
- [AllureStoreDumpFiles.IndexLatestEnvTestResultsByHistoryId, indexLatestEnvTestResultByHistoryId],
245
373
  [AllureStoreDumpFiles.IndexAttachmentsByFixture, indexAttachmentByFixture],
246
374
  [AllureStoreDumpFiles.IndexFixturesByTestResult, indexFixturesByTestResult],
247
375
  [AllureStoreDumpFiles.IndexKnownByHistoryId, indexKnownByHistoryId],
248
376
  [AllureStoreDumpFiles.QualityGateResults, qualityGateResults],
377
+ [AllureStoreDumpFiles.TestResultIngestOrder, testResultIdsIngestOrder],
249
378
  ];
250
379
  let dumpError;
251
380
  dumpArchive.pipe(dumpArchiveWriteStream);
@@ -263,6 +392,15 @@ export class AllureReport {
263
392
  skipAttachment("attachment content is missing");
264
393
  continue;
265
394
  }
395
+ if (content instanceof PathResultFile) {
396
+ const stream = createReadStream(content.path);
397
+ const err = await addDumpEntry(stream, attachment.id);
398
+ if (err) {
399
+ await closeReadStream(stream);
400
+ skipAttachment(`failed to add attachment entry: ${errMessage(err)}`);
401
+ }
402
+ continue;
403
+ }
266
404
  const data = await content.asBuffer();
267
405
  if (data === undefined) {
268
406
  skipAttachment("attachment content is missing");
@@ -354,11 +492,11 @@ export class AllureReport {
354
492
  const indexAttachmentsEntry = await requiredEntryData(AllureStoreDumpFiles.IndexAttachmentsByTestResults);
355
493
  const indexTestResultsByHistoryId = await requiredEntryData(AllureStoreDumpFiles.IndexTestResultsByHistoryId);
356
494
  const indexTestResultsByTestCaseEntry = await requiredEntryData(AllureStoreDumpFiles.IndexTestResultsByTestCase);
357
- const indexLatestEnvTestResultsByHistoryIdEntry = await requiredEntryData(AllureStoreDumpFiles.IndexLatestEnvTestResultsByHistoryId);
358
495
  const indexAttachmentsByFixtureEntry = await requiredEntryData(AllureStoreDumpFiles.IndexAttachmentsByFixture);
359
496
  const indexFixturesByTestResultEntry = await requiredEntryData(AllureStoreDumpFiles.IndexFixturesByTestResult);
360
497
  const indexKnownByHistoryIdEntry = await requiredEntryData(AllureStoreDumpFiles.IndexKnownByHistoryId);
361
498
  const qualityGateResultsEntry = await requiredEntryData(AllureStoreDumpFiles.QualityGateResults);
499
+ const testResultIngestOrderEntry = await optionalEntryData(AllureStoreDumpFiles.TestResultIngestOrder);
362
500
  const attachmentsLinks = JSON.parse(attachmentsEntry.toString("utf8"));
363
501
  const attachmentsEntries = dumpEntriesList.reduce((acc, [entryName, entry]) => {
364
502
  switch (entryName) {
@@ -374,11 +512,11 @@ export class AllureReport {
374
512
  case AllureStoreDumpFiles.IndexAttachmentsByTestResults:
375
513
  case AllureStoreDumpFiles.IndexTestResultsByHistoryId:
376
514
  case AllureStoreDumpFiles.IndexTestResultsByTestCase:
377
- case AllureStoreDumpFiles.IndexLatestEnvTestResultsByHistoryId:
378
515
  case AllureStoreDumpFiles.IndexAttachmentsByFixture:
379
516
  case AllureStoreDumpFiles.IndexFixturesByTestResult:
380
517
  case AllureStoreDumpFiles.IndexKnownByHistoryId:
381
518
  case AllureStoreDumpFiles.QualityGateResults:
519
+ case AllureStoreDumpFiles.TestResultIngestOrder:
382
520
  return acc;
383
521
  default:
384
522
  if (entry.isDirectory || !attachmentsLinks[entryName] || attachmentsLinks[entryName].missed) {
@@ -402,11 +540,13 @@ export class AllureReport {
402
540
  indexAttachmentByTestResult: JSON.parse(indexAttachmentsEntry.toString("utf8")),
403
541
  indexTestResultByHistoryId: JSON.parse(indexTestResultsByHistoryId.toString("utf8")),
404
542
  indexTestResultByTestCase: JSON.parse(indexTestResultsByTestCaseEntry.toString("utf8")),
405
- indexLatestEnvTestResultByHistoryId: JSON.parse(indexLatestEnvTestResultsByHistoryIdEntry.toString("utf8")),
406
543
  indexAttachmentByFixture: JSON.parse(indexAttachmentsByFixtureEntry.toString("utf8")),
407
544
  indexFixturesByTestResult: JSON.parse(indexFixturesByTestResultEntry.toString("utf8")),
408
545
  indexKnownByHistoryId: JSON.parse(indexKnownByHistoryIdEntry.toString("utf8")),
409
546
  qualityGateResults: JSON.parse(qualityGateResultsEntry.toString("utf8")),
547
+ testResultIdsIngestOrder: testResultIngestOrderEntry
548
+ ? JSON.parse(testResultIngestOrderEntry.toString("utf8"))
549
+ : [],
410
550
  };
411
551
  const dumpTempDir = await mkdtemp(join(tmpdir(), basename(dump, ".zip")));
412
552
  const resultsAttachments = {};
@@ -454,19 +594,89 @@ export class AllureReport {
454
594
  }
455
595
  }
456
596
  };
597
+ _AllureReport_getReportsToPublish.set(this, async () => {
598
+ const reports = [];
599
+ for (const { enabled, id, options } of __classPrivateFieldGet(this, _AllureReport_plugins, "f")) {
600
+ if (!enabled) {
601
+ continue;
602
+ }
603
+ const files = (await __classPrivateFieldGet(this, _AllureReport_state, "f")?.[id]?.get("files")) ?? {};
604
+ reports.push({
605
+ pluginId: id,
606
+ publish: !!options?.publish,
607
+ files,
608
+ });
609
+ }
610
+ return reports;
611
+ });
612
+ _AllureReport_cleanupFailedRemoteReport.set(this, async (client) => {
613
+ try {
614
+ await client.deleteReport({
615
+ reportUuid: this.reportUuid,
616
+ });
617
+ }
618
+ catch (cleanupError) {
619
+ console.error("Failed to clean up failed report upload");
620
+ console.error(errorDetails(cleanupError));
621
+ }
622
+ });
623
+ _AllureReport_logPublishError.set(this, (message, err) => {
624
+ console.error(message);
625
+ if (err instanceof KnownError) {
626
+ console.error(err.message);
627
+ }
628
+ else {
629
+ console.error(errorDetails(err));
630
+ }
631
+ });
632
+ _AllureReport_applyPublishLinksToSummaries.set(this, (linksByPluginId) => {
633
+ const changedPluginIds = new Set();
634
+ if (__classPrivateFieldGet(this, _AllureReport_summariesByPluginId, "f").size === 0) {
635
+ return changedPluginIds;
636
+ }
637
+ for (const [pluginId, remoteHref] of Object.entries(linksByPluginId)) {
638
+ const summary = __classPrivateFieldGet(this, _AllureReport_summariesByPluginId, "f").get(pluginId);
639
+ if (summary && remoteHref) {
640
+ summary.remoteHref = remoteHref;
641
+ changedPluginIds.add(pluginId);
642
+ }
643
+ }
644
+ return changedPluginIds;
645
+ });
646
+ _AllureReport_cloneSummariesByPluginId.set(this, () => new Map([...__classPrivateFieldGet(this, _AllureReport_summariesByPluginId, "f")].map(([pluginId, summary]) => [pluginId, clonePluginSummary(summary)])));
647
+ _AllureReport_writeSummaryFiles.set(this, async (pluginIds) => {
648
+ if (__classPrivateFieldGet(this, _AllureReport_summariesByPluginId, "f").size === 0) {
649
+ return;
650
+ }
651
+ const pluginIdsSet = pluginIds ? new Set(pluginIds) : undefined;
652
+ await __classPrivateFieldGet(this, _AllureReport_eachPlugin, "f").call(this, false, async (_plugin, context) => {
653
+ if (pluginIdsSet && !pluginIdsSet.has(context.id)) {
654
+ return;
655
+ }
656
+ const summary = __classPrivateFieldGet(this, _AllureReport_summariesByPluginId, "f").get(context.id);
657
+ if (!summary) {
658
+ return;
659
+ }
660
+ await context.reportFiles.addFile("summary.json", Buffer.from(JSON.stringify(summary)));
661
+ });
662
+ });
663
+ _AllureReport_generateRootSummary.set(this, async () => {
664
+ const summaries = [...__classPrivateFieldGet(this, _AllureReport_summariesByPluginId, "f").values()].map(clonePluginSummary);
665
+ if (summaries.length > 1) {
666
+ __classPrivateFieldSet(this, _AllureReport_summaryPath, await generateSummary(__classPrivateFieldGet(this, _AllureReport_output, "f"), summaries), "f");
667
+ }
668
+ else {
669
+ __classPrivateFieldSet(this, _AllureReport_summaryPath, undefined, "f");
670
+ }
671
+ });
457
672
  this.done = async () => {
458
673
  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
674
  if (__classPrivateFieldGet(this, _AllureReport_executionStage, "f") !== "running") {
465
675
  throw new Error(initRequired);
466
676
  }
467
677
  const testResults = await __classPrivateFieldGet(this, _AllureReport_store, "f").allTestResults();
468
678
  const testCases = await __classPrivateFieldGet(this, _AllureReport_store, "f").allTestCases();
469
- const historyDataPoint = createHistory(this.reportUuid, __classPrivateFieldGet(this, _AllureReport_reportName, "f"), testCases, testResults, this.reportUrl);
679
+ __classPrivateFieldSet(this, _AllureReport_historyDataPoint, createHistory(this.reportUuid, this.reportName, testCases, testResults, this.reportUrl), "f");
470
680
  __classPrivateFieldGet(this, _AllureReport_realtimeChannel, "f").close();
471
681
  try {
472
682
  await __classPrivateFieldGet(this, _AllureReport_realtimeUpdateScheduler, "f").close();
@@ -483,108 +693,6 @@ export class AllureReport {
483
693
  await plugin.done?.(context, __classPrivateFieldGet(this, _AllureReport_store, "f"));
484
694
  });
485
695
  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
- }
587
- }
588
696
  const summary = await plugin?.info?.(context, __classPrivateFieldGet(this, _AllureReport_store, "f"));
589
697
  if (!summary) {
590
698
  return;
@@ -592,37 +700,15 @@ export class AllureReport {
592
700
  summary.pluginId = context.id;
593
701
  summary.pullRequestHref = __classPrivateFieldGet(this, _AllureReport_ci, "f")?.pullRequestUrl;
594
702
  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
703
  summaries.push({
603
704
  ...summary,
604
705
  href: `${context.id}/`,
605
706
  });
606
- await context.reportFiles.addFile("summary.json", Buffer.from(JSON.stringify(summary)));
607
707
  });
608
- 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
- }
618
- }
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
- });
625
- }
708
+ __classPrivateFieldSet(this, _AllureReport_summariesByPluginId, new Map(summaries
709
+ .filter((summary) => !!summary.pluginId)
710
+ .map((summary) => [summary.pluginId, summary])), "f");
711
+ await __classPrivateFieldGet(this, _AllureReport_publish, "f").call(this);
626
712
  let outputDirFiles = [];
627
713
  try {
628
714
  outputDirFiles = await readdir(__classPrivateFieldGet(this, _AllureReport_output, "f"));
@@ -652,7 +738,7 @@ export class AllureReport {
652
738
  }
653
739
  if (__classPrivateFieldGet(this, _AllureReport_history, "f")) {
654
740
  try {
655
- await __classPrivateFieldGet(this, _AllureReport_store, "f").appendHistory(historyDataPoint);
741
+ await __classPrivateFieldGet(this, _AllureReport_store, "f").appendHistory(__classPrivateFieldGet(this, _AllureReport_historyDataPoint, "f"));
656
742
  }
657
743
  catch (err) {
658
744
  if (err instanceof KnownError) {
@@ -666,9 +752,9 @@ export class AllureReport {
666
752
  }
667
753
  }
668
754
  }
669
- if (!remoteCleanupFailed && remoteHrefs.size > 0) {
755
+ if (__classPrivateFieldGet(this, _AllureReport_publishedRemoteHrefs, "f").size > 0) {
670
756
  console.info("Next reports have been published:");
671
- remoteHrefs.forEach((href) => {
757
+ __classPrivateFieldGet(this, _AllureReport_publishedRemoteHrefs, "f").forEach((href) => {
672
758
  console.info(`- ${href}`);
673
759
  });
674
760
  }
@@ -707,11 +793,12 @@ export class AllureReport {
707
793
  publish: !!options?.publish,
708
794
  allureVersion: version,
709
795
  reportUuid: this.reportUuid,
710
- reportName: __classPrivateFieldGet(this, _AllureReport_reportName, "f"),
796
+ reportName: this.reportName,
711
797
  hideLabels: __classPrivateFieldGet(this, _AllureReport_hideLabels, "f"),
712
798
  state: pluginState,
713
799
  reportFiles: pluginFiles,
714
800
  reportUrl: this.reportUrl,
801
+ realTime: !!__classPrivateFieldGet(this, _AllureReport_realTime, "f"),
715
802
  output: __classPrivateFieldGet(this, _AllureReport_output, "f"),
716
803
  ci: __classPrivateFieldGet(this, _AllureReport_ci, "f"),
717
804
  categories: __classPrivateFieldGet(this, _AllureReport_categories, "f"),
@@ -719,6 +806,7 @@ export class AllureReport {
719
806
  };
720
807
  try {
721
808
  await consumer.call(this, plugin, pluginContext);
809
+ this.reportUrl = pluginContext.reportUrl ?? this.reportUrl;
722
810
  if (initState) {
723
811
  __classPrivateFieldGet(this, _AllureReport_state, "f")[id] = pluginState;
724
812
  }
@@ -728,14 +816,23 @@ export class AllureReport {
728
816
  }
729
817
  }
730
818
  });
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");
819
+ 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;
820
+ const allureServiceAccessToken = allureService?.accessToken;
821
+ if (allureServiceAccessToken) {
822
+ const allureServiceClientConfig = {
823
+ ...allureService,
824
+ accessToken: allureServiceAccessToken,
825
+ };
826
+ __classPrivateFieldSet(this, _AllureReport_allureServiceClient, allureServiceAccessToken.startsWith("ato1.")
827
+ ? new AllureTestOpsClient(allureServiceClientConfig)
828
+ : allureServiceAccessToken.startsWith("ars1.")
829
+ ? new AllureServiceClient(allureServiceClientConfig)
830
+ : undefined, "f");
734
831
  }
735
832
  this.reportUuid = randomUUID();
736
833
  __classPrivateFieldSet(this, _AllureReport_ci, detect(), "f");
737
834
  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");
835
+ this.reportName = [name, reportTitleSuffix].filter(Boolean).join(" – ");
739
836
  __classPrivateFieldSet(this, _AllureReport_realtimeChannel, new RealtimeChannel(), "f");
740
837
  __classPrivateFieldSet(this, _AllureReport_realtimeUpdateScheduler, new RealtimeUpdateScheduler(__classPrivateFieldGet(this, _AllureReport_runRealtimeUpdate, "f")), "f");
741
838
  __classPrivateFieldSet(this, _AllureReport_realTime, realTime, "f");
@@ -789,8 +886,6 @@ export class AllureReport {
789
886
  return __classPrivateFieldGet(this, _AllureReport_realtimeChannel, "f").dispatcher;
790
887
  }
791
888
  }
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) {
889
+ _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_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_eachPlugin = new WeakMap(), _AllureReport_instances = new WeakSet(), _AllureReport_getPluginState = function _AllureReport_getPluginState(init, id) {
795
890
  return init ? new DefaultPluginState({}) : __classPrivateFieldGet(this, _AllureReport_state, "f")?.[id];
796
891
  };