@allurereport/core 3.6.2 → 3.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/report.js CHANGED
@@ -9,11 +9,10 @@ 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_reportVariables, _AllureReport_ci, _AllureReport_store, _AllureReport_readers, _AllureReport_plugins, _AllureReport_reportFiles, _AllureReport_eventEmitter, _AllureReport_realtimeSubscriber, _AllureReport_realtimeDispatcher, _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_update, _AllureReport_eachPlugin, _AllureReport_getPluginState;
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;
13
13
  import console from "node:console";
14
14
  import { randomUUID } from "node:crypto";
15
- import { EventEmitter } from "node:events";
16
- import { createReadStream, createWriteStream, existsSync, readFileSync } from "node:fs";
15
+ import { createWriteStream, existsSync, readFileSync } from "node:fs";
17
16
  import { lstat, mkdtemp, opendir, readdir, realpath, rename, rm, writeFile } from "node:fs/promises";
18
17
  import { tmpdir } from "node:os";
19
18
  import { basename, dirname, join, resolve, sep } from "node:path";
@@ -23,7 +22,7 @@ import { normalizeCategoriesConfig } from "@allurereport/core-api";
23
22
  import { AllureStoreDumpFiles, } from "@allurereport/plugin-api";
24
23
  import { allure1, allure2, attachments, cucumberjson, junitXml, readXcResultBundle } from "@allurereport/reader";
25
24
  import { PathResultFile } from "@allurereport/reader-api";
26
- import { AllureRemoteHistory, AllureServiceClient, KnownError, UnknownError } from "@allurereport/service";
25
+ import { AllureLegacyServiceClient, AllureRemoteHistory, AllureServiceClient, KnownError, UnknownError, } from "@allurereport/service";
27
26
  import { generateSummary } from "@allurereport/summary";
28
27
  import { glob } from "glob";
29
28
  import ZipReadStream from "node-stream-zip";
@@ -35,23 +34,27 @@ import { DefaultPluginState, PluginFiles } from "./plugin.js";
35
34
  import { QualityGate } from "./qualityGate/index.js";
36
35
  import { DefaultAllureStore } from "./store/store.js";
37
36
  import { environmentIdentityById, environmentIdentityByName } from "./utils/environment.js";
38
- import { RealtimeEventsDispatcher, RealtimeSubscriber } from "./utils/event.js";
37
+ import { RealtimeChannel } from "./utils/realtimeChannel.js";
38
+ import { RealtimeUpdateScheduler } from "./utils/realtimeUpdateScheduler.js";
39
39
  import { resolveDumpAttachmentPath, UnsafeDumpPathError } from "./utils/safeDumpPath.js";
40
40
  const { version } = JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf8"));
41
41
  const initRequired = "report is not initialised. Call the start() method first.";
42
+ const remoteReportParams = (ci) => {
43
+ const repo = ci?.repoName;
44
+ const branch = ci?.jobRunBranch;
45
+ return repo && branch ? { repo, branch } : {};
46
+ };
42
47
  export class AllureReport {
43
48
  constructor(opts) {
44
49
  _AllureReport_instances.add(this);
45
50
  _AllureReport_reportName.set(this, void 0);
46
- _AllureReport_reportVariables.set(this, void 0);
47
51
  _AllureReport_ci.set(this, void 0);
48
52
  _AllureReport_store.set(this, void 0);
49
53
  _AllureReport_readers.set(this, void 0);
50
54
  _AllureReport_plugins.set(this, void 0);
51
55
  _AllureReport_reportFiles.set(this, void 0);
52
- _AllureReport_eventEmitter.set(this, void 0);
53
- _AllureReport_realtimeSubscriber.set(this, void 0);
54
- _AllureReport_realtimeDispatcher.set(this, void 0);
56
+ _AllureReport_realtimeChannel.set(this, void 0);
57
+ _AllureReport_realtimeUpdateScheduler.set(this, void 0);
55
58
  _AllureReport_realTime.set(this, void 0);
56
59
  _AllureReport_hideLabels.set(this, void 0);
57
60
  _AllureReport_output.set(this, void 0);
@@ -121,7 +124,7 @@ export class AllureReport {
121
124
  });
122
125
  };
123
126
  this.start = async () => {
124
- const branch = __classPrivateFieldGet(this, _AllureReport_ci, "f")?.jobRunBranch;
127
+ const remoteParams = remoteReportParams(__classPrivateFieldGet(this, _AllureReport_ci, "f"));
125
128
  await __classPrivateFieldGet(this, _AllureReport_store, "f").readHistory();
126
129
  if (__classPrivateFieldGet(this, _AllureReport_executionStage, "f") === "running") {
127
130
  throw new Error("the report is already started");
@@ -145,28 +148,28 @@ export class AllureReport {
145
148
  continue;
146
149
  }
147
150
  const originalFileName = basename(absoluteFilePath);
148
- __classPrivateFieldGet(this, _AllureReport_realtimeDispatcher, "f").sendGlobalAttachment(new PathResultFile(absoluteFilePath, originalFileName), originalFileName);
151
+ __classPrivateFieldGet(this, _AllureReport_realtimeChannel, "f").dispatcher.sendGlobalAttachment(new PathResultFile(absoluteFilePath, originalFileName), originalFileName);
149
152
  }
150
153
  }
151
- if (__classPrivateFieldGet(this, _AllureReport_allureServiceClient, "f") && __classPrivateFieldGet(this, _AllureReport_instances, "a", _AllureReport_publish_get) && branch) {
152
- const { url } = await __classPrivateFieldGet(this, _AllureReport_allureServiceClient, "f").createReport({
154
+ if (__classPrivateFieldGet(this, _AllureReport_allureServiceClient, "f") && __classPrivateFieldGet(this, _AllureReport_instances, "a", _AllureReport_publish_get)) {
155
+ const url = await __classPrivateFieldGet(this, _AllureReport_allureServiceClient, "f").createReport({
153
156
  reportUuid: this.reportUuid,
154
157
  reportName: __classPrivateFieldGet(this, _AllureReport_reportName, "f"),
155
- branch,
158
+ ...remoteParams,
156
159
  });
157
- this.reportUrl = url;
160
+ this.reportUrl = url.href;
158
161
  }
159
162
  await __classPrivateFieldGet(this, _AllureReport_eachPlugin, "f").call(this, true, async (plugin, context) => {
160
- await plugin.start?.(context, __classPrivateFieldGet(this, _AllureReport_store, "f"), __classPrivateFieldGet(this, _AllureReport_realtimeSubscriber, "f"));
163
+ await plugin.start?.(context, __classPrivateFieldGet(this, _AllureReport_store, "f"), __classPrivateFieldGet(this, _AllureReport_realtimeChannel, "f").subscriber);
161
164
  });
162
165
  if (__classPrivateFieldGet(this, _AllureReport_realTime, "f")) {
163
- await __classPrivateFieldGet(this, _AllureReport_update, "f").call(this);
164
- __classPrivateFieldGet(this, _AllureReport_realtimeSubscriber, "f").onAll(async () => {
165
- await __classPrivateFieldGet(this, _AllureReport_update, "f").call(this);
166
+ await __classPrivateFieldGet(this, _AllureReport_runRealtimeUpdate, "f").call(this);
167
+ __classPrivateFieldGet(this, _AllureReport_realtimeChannel, "f").onResultLikeChanged(() => {
168
+ __classPrivateFieldGet(this, _AllureReport_realtimeUpdateScheduler, "f").request();
166
169
  });
167
170
  }
168
171
  };
169
- _AllureReport_update.set(this, async () => {
172
+ _AllureReport_runRealtimeUpdate.set(this, async () => {
170
173
  if (__classPrivateFieldGet(this, _AllureReport_executionStage, "f") !== "running") {
171
174
  return;
172
175
  }
@@ -175,85 +178,124 @@ export class AllureReport {
175
178
  });
176
179
  });
177
180
  this.dumpState = async () => {
178
- const { testResults, testCases, fixtures, attachments: attachmentsLinks, environments, globalAttachmentIds = [], globalErrors = [], indexAttachmentByTestResult = {}, indexTestResultByHistoryId = {}, indexTestResultByTestCase = {}, indexLatestEnvTestResultByHistoryId = {}, indexAttachmentByFixture = {}, indexFixturesByTestResult = {}, indexKnownByHistoryId = {}, qualityGateResults = [], } = __classPrivateFieldGet(this, _AllureReport_store, "f").dumpState();
179
- const allAttachments = await __classPrivateFieldGet(this, _AllureReport_store, "f").allAttachments();
180
181
  const dumpArchive = new ZipWriteStream({
181
182
  zlib: { level: 5 },
182
183
  });
183
184
  const addEntry = promisify(dumpArchive.entry.bind(dumpArchive));
184
- const dumpArchiveWriteStream = createWriteStream(`${__classPrivateFieldGet(this, _AllureReport_dump, "f")}.zip`);
185
- const promise = new Promise((res, rej) => {
186
- dumpArchive.on("error", (err) => rej(err));
187
- dumpArchiveWriteStream.on("finish", () => res(void 0));
188
- dumpArchiveWriteStream.on("error", (err) => rej(err));
185
+ const dumpPath = `${__classPrivateFieldGet(this, _AllureReport_dump, "f")}.zip`;
186
+ const dumpTempPath = `${dumpPath}.${randomUUID()}.tmp`;
187
+ const dumpArchiveWriteStream = createWriteStream(dumpTempPath);
188
+ let dumpArchiveError;
189
+ let dumpArchiveFinished = false;
190
+ let resolveDumpArchivePromise;
191
+ const finishDumpArchive = (err) => {
192
+ dumpArchiveError ?? (dumpArchiveError = err);
193
+ if (!dumpArchiveFinished) {
194
+ dumpArchiveFinished = true;
195
+ resolveDumpArchivePromise?.();
196
+ }
197
+ };
198
+ const dumpArchivePromise = new Promise((res) => {
199
+ resolveDumpArchivePromise = res;
200
+ dumpArchive.on("error", (err) => {
201
+ dumpArchiveWriteStream.destroy();
202
+ finishDumpArchive(err);
203
+ });
204
+ dumpArchiveWriteStream.on("finish", () => finishDumpArchive());
205
+ dumpArchiveWriteStream.on("error", (err) => finishDumpArchive(err));
189
206
  });
207
+ const errMessage = (err) => (err instanceof Error ? err.message : String(err));
208
+ const addDumpEntry = async (data, entryName) => {
209
+ try {
210
+ await addEntry(data, { name: entryName });
211
+ return undefined;
212
+ }
213
+ catch (err) {
214
+ return err;
215
+ }
216
+ };
217
+ const addRequiredDumpEntry = async (data, entryName) => {
218
+ const err = await addDumpEntry(data, entryName);
219
+ if (err) {
220
+ throw new Error(`Failed to write dump entry "${entryName}": ${errMessage(err)}`);
221
+ }
222
+ };
223
+ const addJsonDumpEntry = async (entryName, value) => {
224
+ await addRequiredDumpEntry(Buffer.from(JSON.stringify(value)), entryName);
225
+ };
226
+ const dumpJsonEntries = ({ testResults, testCases, fixtures, attachments, environments, reportVariables, checkResults = [], globalAttachmentIds = [], globalErrors = [], indexAttachmentByTestResult = {}, indexTestResultByHistoryId = {}, indexTestResultByTestCase = {}, indexLatestEnvTestResultByHistoryId = {}, indexAttachmentByFixture = {}, indexFixturesByTestResult = {}, indexKnownByHistoryId = {}, qualityGateResults = [], }) => [
227
+ [AllureStoreDumpFiles.TestResults, testResults],
228
+ [AllureStoreDumpFiles.TestCases, testCases],
229
+ [AllureStoreDumpFiles.Fixtures, fixtures],
230
+ [AllureStoreDumpFiles.Attachments, attachments],
231
+ [AllureStoreDumpFiles.CheckResults, checkResults],
232
+ [AllureStoreDumpFiles.Environments, environments],
233
+ [AllureStoreDumpFiles.ReportVariables, reportVariables],
234
+ [AllureStoreDumpFiles.GlobalAttachments, globalAttachmentIds],
235
+ [AllureStoreDumpFiles.GlobalErrors, globalErrors],
236
+ [AllureStoreDumpFiles.IndexAttachmentsByTestResults, indexAttachmentByTestResult],
237
+ [AllureStoreDumpFiles.IndexTestResultsByHistoryId, indexTestResultByHistoryId],
238
+ [AllureStoreDumpFiles.IndexTestResultsByTestCase, indexTestResultByTestCase],
239
+ [AllureStoreDumpFiles.IndexLatestEnvTestResultsByHistoryId, indexLatestEnvTestResultByHistoryId],
240
+ [AllureStoreDumpFiles.IndexAttachmentsByFixture, indexAttachmentByFixture],
241
+ [AllureStoreDumpFiles.IndexFixturesByTestResult, indexFixturesByTestResult],
242
+ [AllureStoreDumpFiles.IndexKnownByHistoryId, indexKnownByHistoryId],
243
+ [AllureStoreDumpFiles.QualityGateResults, qualityGateResults],
244
+ ];
245
+ let dumpError;
190
246
  dumpArchive.pipe(dumpArchiveWriteStream);
191
- await addEntry(Buffer.from(JSON.stringify(testResults)), {
192
- name: AllureStoreDumpFiles.TestResults,
193
- });
194
- await addEntry(Buffer.from(JSON.stringify(testCases)), {
195
- name: AllureStoreDumpFiles.TestCases,
196
- });
197
- await addEntry(Buffer.from(JSON.stringify(fixtures)), {
198
- name: AllureStoreDumpFiles.Fixtures,
199
- });
200
- await addEntry(Buffer.from(JSON.stringify(attachmentsLinks)), {
201
- name: AllureStoreDumpFiles.Attachments,
202
- });
203
- await addEntry(Buffer.from(JSON.stringify(environments)), {
204
- name: AllureStoreDumpFiles.Environments,
205
- });
206
- await addEntry(Buffer.from(JSON.stringify(__classPrivateFieldGet(this, _AllureReport_reportVariables, "f"))), {
207
- name: AllureStoreDumpFiles.ReportVariables,
208
- });
209
- await addEntry(Buffer.from(JSON.stringify(globalAttachmentIds)), {
210
- name: AllureStoreDumpFiles.GlobalAttachments,
211
- });
212
- await addEntry(Buffer.from(JSON.stringify(globalErrors)), {
213
- name: AllureStoreDumpFiles.GlobalErrors,
214
- });
215
- await addEntry(Buffer.from(JSON.stringify(indexAttachmentByTestResult)), {
216
- name: AllureStoreDumpFiles.IndexAttachmentsByTestResults,
217
- });
218
- await addEntry(Buffer.from(JSON.stringify(indexTestResultByHistoryId)), {
219
- name: AllureStoreDumpFiles.IndexTestResultsByHistoryId,
220
- });
221
- await addEntry(Buffer.from(JSON.stringify(indexTestResultByTestCase)), {
222
- name: AllureStoreDumpFiles.IndexTestResultsByTestCase,
223
- });
224
- await addEntry(Buffer.from(JSON.stringify(indexLatestEnvTestResultByHistoryId)), {
225
- name: AllureStoreDumpFiles.IndexLatestEnvTestResultsByHistoryId,
226
- });
227
- await addEntry(Buffer.from(JSON.stringify(indexAttachmentByFixture)), {
228
- name: AllureStoreDumpFiles.IndexAttachmentsByFixture,
229
- });
230
- await addEntry(Buffer.from(JSON.stringify(indexFixturesByTestResult)), {
231
- name: AllureStoreDumpFiles.IndexFixturesByTestResult,
232
- });
233
- await addEntry(Buffer.from(JSON.stringify(indexKnownByHistoryId)), {
234
- name: AllureStoreDumpFiles.IndexKnownByHistoryId,
235
- });
236
- await addEntry(Buffer.from(JSON.stringify(qualityGateResults)), {
237
- name: AllureStoreDumpFiles.QualityGateResults,
238
- });
239
- for (const attachment of allAttachments) {
240
- const content = await __classPrivateFieldGet(this, _AllureReport_store, "f").attachmentContentById(attachment.id);
241
- if (!content) {
242
- continue;
247
+ try {
248
+ const allAttachments = await __classPrivateFieldGet(this, _AllureReport_store, "f").allAttachments();
249
+ for (const attachment of allAttachments) {
250
+ const skipAttachment = (message) => {
251
+ const originalFileName = attachment.originalFileName ? ` (${attachment.originalFileName})` : "";
252
+ __classPrivateFieldGet(this, _AllureReport_store, "f").markAttachmentMissed(attachment.id);
253
+ console.warn(`Skipping attachment while writing dump: ${attachment.id}${originalFileName}. ${message}`);
254
+ };
255
+ try {
256
+ const content = await __classPrivateFieldGet(this, _AllureReport_store, "f").attachmentContentById(attachment.id);
257
+ if (!content) {
258
+ skipAttachment("attachment content is missing");
259
+ continue;
260
+ }
261
+ const data = await content.asBuffer();
262
+ if (data === undefined) {
263
+ skipAttachment("attachment content is missing");
264
+ continue;
265
+ }
266
+ const err = await addDumpEntry(data, attachment.id);
267
+ if (err) {
268
+ skipAttachment(`failed to add attachment entry: ${errMessage(err)}`);
269
+ }
270
+ }
271
+ catch (err) {
272
+ skipAttachment(errMessage(err));
273
+ }
243
274
  }
244
- if (content instanceof PathResultFile) {
245
- await addEntry(createReadStream(content.path), {
246
- name: attachment.id,
247
- });
275
+ for (const [entryName, value] of dumpJsonEntries(__classPrivateFieldGet(this, _AllureReport_store, "f").dumpState())) {
276
+ await addJsonDumpEntry(entryName, value);
248
277
  }
249
- else {
250
- await addEntry(await content.asBuffer(), {
251
- name: attachment.id,
252
- });
278
+ }
279
+ catch (err) {
280
+ dumpError = err;
281
+ }
282
+ finally {
283
+ try {
284
+ dumpArchive.finalize();
253
285
  }
286
+ catch (err) {
287
+ dumpError ?? (dumpError = err);
288
+ dumpArchiveWriteStream.destroy();
289
+ finishDumpArchive(err);
290
+ }
291
+ await dumpArchivePromise;
292
+ }
293
+ dumpError ?? (dumpError = dumpArchiveError);
294
+ if (dumpError) {
295
+ await rm(dumpTempPath, { force: true });
296
+ throw dumpError;
254
297
  }
255
- dumpArchive.finalize();
256
- return promise;
298
+ await rename(dumpTempPath, dumpPath);
257
299
  };
258
300
  this.restoreState = async (dumps) => {
259
301
  for (const dump of dumps) {
@@ -263,93 +305,127 @@ export class AllureReport {
263
305
  const dumpArchive = new ZipReadStream.async({
264
306
  file: dump,
265
307
  });
266
- const testResultsEntry = await dumpArchive.entryData(AllureStoreDumpFiles.TestResults);
267
- const testCasesEntry = await dumpArchive.entryData(AllureStoreDumpFiles.TestCases);
268
- const fixturesEntry = await dumpArchive.entryData(AllureStoreDumpFiles.Fixtures);
269
- const attachmentsEntry = await dumpArchive.entryData(AllureStoreDumpFiles.Attachments);
270
- const environmentsEntry = await dumpArchive.entryData(AllureStoreDumpFiles.Environments);
271
- const reportVariablesEntry = await dumpArchive.entryData(AllureStoreDumpFiles.ReportVariables);
272
- const globalAttachmentsEntry = await dumpArchive.entryData(AllureStoreDumpFiles.GlobalAttachments);
273
- const globalErrorsEntry = await dumpArchive.entryData(AllureStoreDumpFiles.GlobalErrors);
274
- const indexAttachmentsEntry = await dumpArchive.entryData(AllureStoreDumpFiles.IndexAttachmentsByTestResults);
275
- const indexTestResultsByHistoryId = await dumpArchive.entryData(AllureStoreDumpFiles.IndexTestResultsByHistoryId);
276
- const indexTestResultsByTestCaseEntry = await dumpArchive.entryData(AllureStoreDumpFiles.IndexTestResultsByTestCase);
277
- const indexLatestEnvTestResultsByHistoryIdEntry = await dumpArchive.entryData(AllureStoreDumpFiles.IndexLatestEnvTestResultsByHistoryId);
278
- const indexAttachmentsByFixtureEntry = await dumpArchive.entryData(AllureStoreDumpFiles.IndexAttachmentsByFixture);
279
- const indexFixturesByTestResultEntry = await dumpArchive.entryData(AllureStoreDumpFiles.IndexFixturesByTestResult);
280
- const indexKnownByHistoryIdEntry = await dumpArchive.entryData(AllureStoreDumpFiles.IndexKnownByHistoryId);
281
- const qualityGateResultsEntry = await dumpArchive.entryData(AllureStoreDumpFiles.QualityGateResults);
282
- const attachmentsEntries = Object.entries(await dumpArchive.entries()).reduce((acc, [entryName, entry]) => {
283
- switch (entryName) {
284
- case AllureStoreDumpFiles.Attachments:
285
- case AllureStoreDumpFiles.TestResults:
286
- case AllureStoreDumpFiles.TestCases:
287
- case AllureStoreDumpFiles.Fixtures:
288
- case AllureStoreDumpFiles.Environments:
289
- case AllureStoreDumpFiles.ReportVariables:
290
- case AllureStoreDumpFiles.GlobalAttachments:
291
- case AllureStoreDumpFiles.GlobalErrors:
292
- case AllureStoreDumpFiles.IndexAttachmentsByTestResults:
293
- case AllureStoreDumpFiles.IndexTestResultsByHistoryId:
294
- case AllureStoreDumpFiles.IndexTestResultsByTestCase:
295
- case AllureStoreDumpFiles.IndexLatestEnvTestResultsByHistoryId:
296
- case AllureStoreDumpFiles.IndexAttachmentsByFixture:
297
- case AllureStoreDumpFiles.IndexFixturesByTestResult:
298
- case AllureStoreDumpFiles.IndexKnownByHistoryId:
299
- case AllureStoreDumpFiles.QualityGateResults:
300
- return acc;
301
- default:
302
- return Object.assign(acc, {
303
- [entryName]: entry,
304
- });
305
- }
306
- }, {});
307
- const dumpState = {
308
- testResults: JSON.parse(testResultsEntry.toString("utf8")),
309
- testCases: JSON.parse(testCasesEntry.toString("utf8")),
310
- fixtures: JSON.parse(fixturesEntry.toString("utf8")),
311
- attachments: JSON.parse(attachmentsEntry.toString("utf8")),
312
- environments: JSON.parse(environmentsEntry.toString("utf8")),
313
- reportVariables: JSON.parse(reportVariablesEntry.toString("utf8")),
314
- globalAttachmentIds: JSON.parse(globalAttachmentsEntry.toString("utf8")),
315
- globalErrors: JSON.parse(globalErrorsEntry.toString("utf8")),
316
- indexAttachmentByTestResult: JSON.parse(indexAttachmentsEntry.toString("utf8")),
317
- indexTestResultByHistoryId: JSON.parse(indexTestResultsByHistoryId.toString("utf8")),
318
- indexTestResultByTestCase: JSON.parse(indexTestResultsByTestCaseEntry.toString("utf8")),
319
- indexLatestEnvTestResultByHistoryId: JSON.parse(indexLatestEnvTestResultsByHistoryIdEntry.toString("utf8")),
320
- indexAttachmentByFixture: JSON.parse(indexAttachmentsByFixtureEntry.toString("utf8")),
321
- indexFixturesByTestResult: JSON.parse(indexFixturesByTestResultEntry.toString("utf8")),
322
- indexKnownByHistoryId: JSON.parse(indexKnownByHistoryIdEntry.toString("utf8")),
323
- qualityGateResults: JSON.parse(qualityGateResultsEntry.toString("utf8")),
324
- };
325
- const dumpTempDir = await mkdtemp(join(tmpdir(), basename(dump, ".zip")));
326
- const resultsAttachments = {};
327
- __classPrivateFieldGet(this, _AllureReport_dumpTempDirs, "f").push(dumpTempDir);
328
308
  try {
329
- for (const [attachmentId] of Object.entries(attachmentsEntries)) {
330
- const attachmentContentEntry = await dumpArchive.entryData(attachmentId);
331
- const attachmentFilePath = resolveDumpAttachmentPath(dumpTempDir, attachmentId);
332
- await writeFile(attachmentFilePath, attachmentContentEntry);
333
- resultsAttachments[attachmentId] = new PathResultFile(attachmentFilePath, attachmentId);
309
+ const dumpEntries = await dumpArchive.entries();
310
+ const dumpEntriesList = Object.entries(dumpEntries);
311
+ const optionalEntryData = async (entryName) => dumpEntries[entryName] ? dumpArchive.entryData(entryName) : undefined;
312
+ if (!dumpEntries[AllureStoreDumpFiles.TestResults]) {
313
+ const nestedDumpEntries = dumpEntriesList.filter(([entryName, entry]) => !entry.isDirectory &&
314
+ !entryName.startsWith("__MACOSX/") &&
315
+ !basename(entryName).startsWith("._") &&
316
+ entryName.toLowerCase().endsWith(".zip"));
317
+ if (nestedDumpEntries.length > 0) {
318
+ const nestedDumpsTempDir = await mkdtemp(join(tmpdir(), `${basename(dump, ".zip")}-nested-`));
319
+ const nestedDumpPaths = [];
320
+ __classPrivateFieldGet(this, _AllureReport_dumpTempDirs, "f").push(nestedDumpsTempDir);
321
+ for (const [entryName] of nestedDumpEntries) {
322
+ const nestedDumpPath = join(nestedDumpsTempDir, `${nestedDumpPaths.length}-${basename(entryName)}`);
323
+ await writeFile(nestedDumpPath, await dumpArchive.entryData(entryName));
324
+ nestedDumpPaths.push(nestedDumpPath);
325
+ }
326
+ await this.restoreState(nestedDumpPaths);
327
+ continue;
328
+ }
334
329
  }
335
- }
336
- catch (err) {
337
- if (err instanceof UnsafeDumpPathError) {
338
- 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).`);
339
- console.error(err.message);
340
- console.error("Only use dump archives produced by this tool; do not load untrusted or third-party --dump zip files.");
341
- throw err;
330
+ const testResultsEntry = await dumpArchive.entryData(AllureStoreDumpFiles.TestResults);
331
+ const testCasesEntry = await dumpArchive.entryData(AllureStoreDumpFiles.TestCases);
332
+ const fixturesEntry = await dumpArchive.entryData(AllureStoreDumpFiles.Fixtures);
333
+ const attachmentsEntry = await dumpArchive.entryData(AllureStoreDumpFiles.Attachments);
334
+ const checkResultsEntry = await optionalEntryData(AllureStoreDumpFiles.CheckResults);
335
+ const environmentsEntry = await dumpArchive.entryData(AllureStoreDumpFiles.Environments);
336
+ const reportVariablesEntry = await dumpArchive.entryData(AllureStoreDumpFiles.ReportVariables);
337
+ const globalAttachmentsEntry = await dumpArchive.entryData(AllureStoreDumpFiles.GlobalAttachments);
338
+ const globalErrorsEntry = await dumpArchive.entryData(AllureStoreDumpFiles.GlobalErrors);
339
+ const indexAttachmentsEntry = await dumpArchive.entryData(AllureStoreDumpFiles.IndexAttachmentsByTestResults);
340
+ const indexTestResultsByHistoryId = await dumpArchive.entryData(AllureStoreDumpFiles.IndexTestResultsByHistoryId);
341
+ const indexTestResultsByTestCaseEntry = await dumpArchive.entryData(AllureStoreDumpFiles.IndexTestResultsByTestCase);
342
+ const indexLatestEnvTestResultsByHistoryIdEntry = await dumpArchive.entryData(AllureStoreDumpFiles.IndexLatestEnvTestResultsByHistoryId);
343
+ const indexAttachmentsByFixtureEntry = await dumpArchive.entryData(AllureStoreDumpFiles.IndexAttachmentsByFixture);
344
+ const indexFixturesByTestResultEntry = await dumpArchive.entryData(AllureStoreDumpFiles.IndexFixturesByTestResult);
345
+ const indexKnownByHistoryIdEntry = await dumpArchive.entryData(AllureStoreDumpFiles.IndexKnownByHistoryId);
346
+ const qualityGateResultsEntry = await dumpArchive.entryData(AllureStoreDumpFiles.QualityGateResults);
347
+ const attachmentsLinks = JSON.parse(attachmentsEntry.toString("utf8"));
348
+ const attachmentsEntries = dumpEntriesList.reduce((acc, [entryName, entry]) => {
349
+ switch (entryName) {
350
+ case AllureStoreDumpFiles.Attachments:
351
+ case AllureStoreDumpFiles.CheckResults:
352
+ case AllureStoreDumpFiles.TestResults:
353
+ case AllureStoreDumpFiles.TestCases:
354
+ case AllureStoreDumpFiles.Fixtures:
355
+ case AllureStoreDumpFiles.Environments:
356
+ case AllureStoreDumpFiles.ReportVariables:
357
+ case AllureStoreDumpFiles.GlobalAttachments:
358
+ case AllureStoreDumpFiles.GlobalErrors:
359
+ case AllureStoreDumpFiles.IndexAttachmentsByTestResults:
360
+ case AllureStoreDumpFiles.IndexTestResultsByHistoryId:
361
+ case AllureStoreDumpFiles.IndexTestResultsByTestCase:
362
+ case AllureStoreDumpFiles.IndexLatestEnvTestResultsByHistoryId:
363
+ case AllureStoreDumpFiles.IndexAttachmentsByFixture:
364
+ case AllureStoreDumpFiles.IndexFixturesByTestResult:
365
+ case AllureStoreDumpFiles.IndexKnownByHistoryId:
366
+ case AllureStoreDumpFiles.QualityGateResults:
367
+ return acc;
368
+ default:
369
+ if (entry.isDirectory || !attachmentsLinks[entryName] || attachmentsLinks[entryName].missed) {
370
+ return acc;
371
+ }
372
+ return Object.assign(acc, {
373
+ [entryName]: entry,
374
+ });
375
+ }
376
+ }, {});
377
+ const dumpState = {
378
+ testResults: JSON.parse(testResultsEntry.toString("utf8")),
379
+ testCases: JSON.parse(testCasesEntry.toString("utf8")),
380
+ fixtures: JSON.parse(fixturesEntry.toString("utf8")),
381
+ attachments: attachmentsLinks,
382
+ checkResults: checkResultsEntry ? JSON.parse(checkResultsEntry.toString("utf8")) : [],
383
+ environments: JSON.parse(environmentsEntry.toString("utf8")),
384
+ reportVariables: JSON.parse(reportVariablesEntry.toString("utf8")),
385
+ globalAttachmentIds: JSON.parse(globalAttachmentsEntry.toString("utf8")),
386
+ globalErrors: JSON.parse(globalErrorsEntry.toString("utf8")),
387
+ indexAttachmentByTestResult: JSON.parse(indexAttachmentsEntry.toString("utf8")),
388
+ indexTestResultByHistoryId: JSON.parse(indexTestResultsByHistoryId.toString("utf8")),
389
+ indexTestResultByTestCase: JSON.parse(indexTestResultsByTestCaseEntry.toString("utf8")),
390
+ indexLatestEnvTestResultByHistoryId: JSON.parse(indexLatestEnvTestResultsByHistoryIdEntry.toString("utf8")),
391
+ indexAttachmentByFixture: JSON.parse(indexAttachmentsByFixtureEntry.toString("utf8")),
392
+ indexFixturesByTestResult: JSON.parse(indexFixturesByTestResultEntry.toString("utf8")),
393
+ indexKnownByHistoryId: JSON.parse(indexKnownByHistoryIdEntry.toString("utf8")),
394
+ qualityGateResults: JSON.parse(qualityGateResultsEntry.toString("utf8")),
395
+ };
396
+ const dumpTempDir = await mkdtemp(join(tmpdir(), basename(dump, ".zip")));
397
+ const resultsAttachments = {};
398
+ __classPrivateFieldGet(this, _AllureReport_dumpTempDirs, "f").push(dumpTempDir);
399
+ try {
400
+ for (const [attachmentId] of Object.entries(attachmentsEntries)) {
401
+ const attachmentContentEntry = await dumpArchive.entryData(attachmentId);
402
+ const attachmentFilePath = resolveDumpAttachmentPath(dumpTempDir, attachmentId);
403
+ await writeFile(attachmentFilePath, attachmentContentEntry);
404
+ resultsAttachments[attachmentId] = new PathResultFile(attachmentFilePath, attachmentId);
405
+ }
342
406
  }
343
- console.error(`Can't restore state from "${dump}", continuing without it`);
344
- console.error(err);
407
+ catch (err) {
408
+ if (err instanceof UnsafeDumpPathError) {
409
+ 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).`);
410
+ console.error(err.message);
411
+ console.error("Only use dump archives produced by this tool; do not load untrusted or third-party --dump zip files.");
412
+ throw err;
413
+ }
414
+ console.error(`Can't restore state from "${dump}", continuing without it`);
415
+ console.error(err);
416
+ }
417
+ await __classPrivateFieldGet(this, _AllureReport_store, "f").restoreState(dumpState, resultsAttachments);
418
+ console.info(`Successfully restored state from "${dump}"`);
419
+ }
420
+ finally {
421
+ await dumpArchive.close();
345
422
  }
346
- await __classPrivateFieldGet(this, _AllureReport_store, "f").restoreState(dumpState, resultsAttachments);
347
- console.info(`Successfully restored state from "${dump}"`);
348
423
  }
349
424
  };
350
425
  this.done = async () => {
351
426
  const summaries = [];
352
- const remoteHrefs = [];
427
+ const remoteHrefs = new Set();
428
+ const remoteHrefsByPluginId = {};
353
429
  const cancelledPluginsIds = new Set();
354
430
  if (__classPrivateFieldGet(this, _AllureReport_executionStage, "f") !== "running") {
355
431
  throw new Error(initRequired);
@@ -357,7 +433,13 @@ export class AllureReport {
357
433
  const testResults = await __classPrivateFieldGet(this, _AllureReport_store, "f").allTestResults();
358
434
  const testCases = await __classPrivateFieldGet(this, _AllureReport_store, "f").allTestCases();
359
435
  const historyDataPoint = createHistory(this.reportUuid, __classPrivateFieldGet(this, _AllureReport_reportName, "f"), testCases, testResults, this.reportUrl);
360
- __classPrivateFieldGet(this, _AllureReport_realtimeSubscriber, "f").offAll();
436
+ __classPrivateFieldGet(this, _AllureReport_realtimeChannel, "f").close();
437
+ try {
438
+ await __classPrivateFieldGet(this, _AllureReport_realtimeUpdateScheduler, "f").close();
439
+ }
440
+ catch (e) {
441
+ console.error("realtime update failed during shutdown", e);
442
+ }
361
443
  __classPrivateFieldSet(this, _AllureReport_executionStage, "done", "f");
362
444
  if (__classPrivateFieldGet(this, _AllureReport_dump, "f")) {
363
445
  await this.dumpState();
@@ -377,24 +459,37 @@ export class AllureReport {
377
459
  })
378
460
  : undefined;
379
461
  const limitFn = pLimit(50);
462
+ const uploadAbortController = new AbortController();
380
463
  const fns = pluginFilesEntries.map(([filename, filepath]) => limitFn(async () => {
381
- if (cancelledPluginsIds.has(context.id)) {
464
+ if (cancelledPluginsIds.has(context.id) || uploadAbortController.signal.aborted) {
382
465
  return;
383
466
  }
384
467
  if (/^(data|widgets|index\.html$|summary\.json$)/.test(filename)) {
385
- await __classPrivateFieldGet(this, _AllureReport_allureServiceClient, "f").addReportFile({
468
+ const uploadedFileUrl = await __classPrivateFieldGet(this, _AllureReport_allureServiceClient, "f").addReportFile({
386
469
  reportUuid: this.reportUuid,
387
470
  pluginId: context.id,
388
471
  filename,
389
472
  filepath,
473
+ signal: uploadAbortController.signal,
390
474
  });
475
+ if (cancelledPluginsIds.has(context.id) || uploadAbortController.signal.aborted) {
476
+ return;
477
+ }
478
+ if (filename === "index.html") {
479
+ remoteHrefsByPluginId[context.id] = uploadedFileUrl;
480
+ remoteHrefs.add(uploadedFileUrl);
481
+ }
391
482
  }
392
483
  else {
393
484
  await __classPrivateFieldGet(this, _AllureReport_allureServiceClient, "f").addReportAsset({
394
485
  filename,
395
486
  filepath,
487
+ signal: uploadAbortController.signal,
396
488
  });
397
489
  }
490
+ if (cancelledPluginsIds.has(context.id) || uploadAbortController.signal.aborted) {
491
+ return;
492
+ }
398
493
  progressBar?.tick?.();
399
494
  }));
400
495
  progressBar?.render?.();
@@ -403,6 +498,13 @@ export class AllureReport {
403
498
  }
404
499
  catch (err) {
405
500
  cancelledPluginsIds.add(context.id);
501
+ uploadAbortController.abort();
502
+ await Promise.allSettled(fns);
503
+ const pluginRemoteHref = remoteHrefsByPluginId[context.id];
504
+ if (pluginRemoteHref) {
505
+ remoteHrefs.delete(pluginRemoteHref);
506
+ delete remoteHrefsByPluginId[context.id];
507
+ }
406
508
  await __classPrivateFieldGet(this, _AllureReport_allureServiceClient, "f").deleteReport({
407
509
  reportUuid: this.reportUuid,
408
510
  pluginId: context.id,
@@ -418,9 +520,12 @@ export class AllureReport {
418
520
  summary.pluginId = context.id;
419
521
  summary.pullRequestHref = __classPrivateFieldGet(this, _AllureReport_ci, "f")?.pullRequestUrl;
420
522
  summary.jobHref = __classPrivateFieldGet(this, _AllureReport_ci, "f")?.jobRunUrl;
421
- if (context.publish && this.reportUrl && !cancelledPluginsIds.has(context.id)) {
422
- summary.remoteHref = `${this.reportUrl}/${context.id}/`;
423
- remoteHrefs.push(summary.remoteHref);
523
+ if (context.publish && !cancelledPluginsIds.has(context.id)) {
524
+ summary.remoteHref =
525
+ remoteHrefsByPluginId[context.id] ?? (this.reportUrl ? `${this.reportUrl}/${context.id}/` : undefined);
526
+ if (summary.remoteHref) {
527
+ remoteHrefs.add(summary.remoteHref);
528
+ }
424
529
  }
425
530
  summaries.push({
426
531
  ...summary,
@@ -490,7 +595,7 @@ export class AllureReport {
490
595
  }
491
596
  }
492
597
  }
493
- if (remoteHrefs.length > 0) {
598
+ if (remoteHrefs.size > 0) {
494
599
  console.info("Next reports have been published:");
495
600
  remoteHrefs.forEach((href) => {
496
601
  console.info(`- ${href}`);
@@ -553,17 +658,20 @@ export class AllureReport {
553
658
  }
554
659
  });
555
660
  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;
556
- __classPrivateFieldSet(this, _AllureReport_allureServiceClient, allureServiceConfig?.accessToken
557
- ? new AllureServiceClient(allureServiceConfig)
558
- : undefined, "f");
661
+ if (allureServiceConfig?.accessToken) {
662
+ if (allureServiceConfig?.legacy) {
663
+ __classPrivateFieldSet(this, _AllureReport_allureServiceClient, new AllureLegacyServiceClient(allureServiceConfig), "f");
664
+ }
665
+ else {
666
+ __classPrivateFieldSet(this, _AllureReport_allureServiceClient, new AllureServiceClient(allureServiceConfig), "f");
667
+ }
668
+ }
559
669
  this.reportUuid = randomUUID();
560
670
  __classPrivateFieldSet(this, _AllureReport_ci, detect(), "f");
561
671
  const reportTitleSuffix = __classPrivateFieldGet(this, _AllureReport_ci, "f")?.pullRequestName ?? __classPrivateFieldGet(this, _AllureReport_ci, "f")?.jobRunName;
562
672
  __classPrivateFieldSet(this, _AllureReport_reportName, [name, reportTitleSuffix].filter(Boolean).join(" – "), "f");
563
- __classPrivateFieldSet(this, _AllureReport_reportVariables, variables, "f");
564
- __classPrivateFieldSet(this, _AllureReport_eventEmitter, new EventEmitter(), "f");
565
- __classPrivateFieldSet(this, _AllureReport_realtimeDispatcher, new RealtimeEventsDispatcher(__classPrivateFieldGet(this, _AllureReport_eventEmitter, "f")), "f");
566
- __classPrivateFieldSet(this, _AllureReport_realtimeSubscriber, new RealtimeSubscriber(__classPrivateFieldGet(this, _AllureReport_eventEmitter, "f")), "f");
673
+ __classPrivateFieldSet(this, _AllureReport_realtimeChannel, new RealtimeChannel(), "f");
674
+ __classPrivateFieldSet(this, _AllureReport_realtimeUpdateScheduler, new RealtimeUpdateScheduler(__classPrivateFieldGet(this, _AllureReport_runRealtimeUpdate, "f")), "f");
567
675
  __classPrivateFieldSet(this, _AllureReport_realTime, realTime, "f");
568
676
  __classPrivateFieldSet(this, _AllureReport_dump, dump, "f");
569
677
  __classPrivateFieldSet(this, _AllureReport_hideLabels, hideLabels, "f");
@@ -576,7 +684,7 @@ export class AllureReport {
576
684
  if (__classPrivateFieldGet(this, _AllureReport_allureServiceClient, "f")) {
577
685
  __classPrivateFieldSet(this, _AllureReport_history, new AllureRemoteHistory({
578
686
  limit: historyLimit,
579
- branch: __classPrivateFieldGet(this, _AllureReport_ci, "f")?.jobRunBranch,
687
+ ...remoteReportParams(__classPrivateFieldGet(this, _AllureReport_ci, "f")),
580
688
  allureServiceClient: __classPrivateFieldGet(this, _AllureReport_allureServiceClient, "f"),
581
689
  }), "f");
582
690
  }
@@ -587,8 +695,8 @@ export class AllureReport {
587
695
  }), "f");
588
696
  }
589
697
  __classPrivateFieldSet(this, _AllureReport_store, new DefaultAllureStore({
590
- realtimeSubscriber: __classPrivateFieldGet(this, _AllureReport_realtimeSubscriber, "f"),
591
- realtimeDispatcher: __classPrivateFieldGet(this, _AllureReport_realtimeDispatcher, "f"),
698
+ realtimeSubscriber: __classPrivateFieldGet(this, _AllureReport_realtimeChannel, "f").subscriber,
699
+ realtimeDispatcher: __classPrivateFieldGet(this, _AllureReport_realtimeChannel, "f").dispatcher,
592
700
  reportVariables: variables,
593
701
  environmentsConfig: environments,
594
702
  history: __classPrivateFieldGet(this, _AllureReport_history, "f"),
@@ -609,13 +717,13 @@ export class AllureReport {
609
717
  return __classPrivateFieldGet(this, _AllureReport_store, "f");
610
718
  }
611
719
  get realtimeSubscriber() {
612
- return __classPrivateFieldGet(this, _AllureReport_realtimeSubscriber, "f");
720
+ return __classPrivateFieldGet(this, _AllureReport_realtimeChannel, "f").subscriber;
613
721
  }
614
722
  get realtimeDispatcher() {
615
- return __classPrivateFieldGet(this, _AllureReport_realtimeDispatcher, "f");
723
+ return __classPrivateFieldGet(this, _AllureReport_realtimeChannel, "f").dispatcher;
616
724
  }
617
725
  }
618
- _AllureReport_reportName = new WeakMap(), _AllureReport_reportVariables = new WeakMap(), _AllureReport_ci = new WeakMap(), _AllureReport_store = new WeakMap(), _AllureReport_readers = new WeakMap(), _AllureReport_plugins = new WeakMap(), _AllureReport_reportFiles = new WeakMap(), _AllureReport_eventEmitter = new WeakMap(), _AllureReport_realtimeSubscriber = new WeakMap(), _AllureReport_realtimeDispatcher = 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_update = new WeakMap(), _AllureReport_eachPlugin = new WeakMap(), _AllureReport_instances = new WeakSet(), _AllureReport_publish_get = function _AllureReport_publish_get() {
726
+ _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() {
619
727
  return __classPrivateFieldGet(this, _AllureReport_plugins, "f").some(({ enabled, options }) => enabled && options.publish);
620
728
  }, _AllureReport_getPluginState = function _AllureReport_getPluginState(init, id) {
621
729
  return init ? new DefaultPluginState({}) : __classPrivateFieldGet(this, _AllureReport_state, "f")?.[id];