@allurereport/core 3.8.0 → 3.8.2

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
@@ -22,7 +22,7 @@ import { normalizeCategoriesConfig } from "@allurereport/core-api";
22
22
  import { AllureStoreDumpFiles, } from "@allurereport/plugin-api";
23
23
  import { allure1, allure2, attachments, cucumberjson, junitXml, readXcResultBundle } from "@allurereport/reader";
24
24
  import { PathResultFile } from "@allurereport/reader-api";
25
- import { AllureLegacyServiceClient, AllureRemoteHistory, AllureServiceClient, KnownError, UnknownError, } from "@allurereport/service";
25
+ import { AllureRemoteHistory, AllureServiceClient, KnownError, UnknownError, } from "@allurereport/service";
26
26
  import { generateSummary } from "@allurereport/summary";
27
27
  import { glob } from "glob";
28
28
  import ZipReadStream from "node-stream-zip";
@@ -44,6 +44,11 @@ const remoteReportParams = (ci) => {
44
44
  const branch = ci?.jobRunBranch;
45
45
  return repo && branch ? { repo, branch } : {};
46
46
  };
47
+ const REMOTE_UPLOAD_CONCURRENCY = 50;
48
+ const REMOTE_UPLOAD_MAX_ATTEMPTS = 5;
49
+ const REMOTE_UPLOAD_MAX_SIMULTANEOUS_FAILED = 5;
50
+ 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";
47
52
  export class AllureReport {
48
53
  constructor(opts) {
49
54
  _AllureReport_instances.add(this);
@@ -300,125 +305,152 @@ export class AllureReport {
300
305
  this.restoreState = async (dumps) => {
301
306
  for (const dump of dumps) {
302
307
  if (!existsSync(dump)) {
308
+ console.error(`Failed to restore state from "${dump}", continuing without it`);
309
+ console.error("Dump file does not exist");
303
310
  continue;
304
311
  }
305
- const dumpArchive = new ZipReadStream.async({
306
- file: dump,
307
- });
308
312
  try {
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);
313
+ const dumpArchive = new ZipReadStream.async({
314
+ file: dump,
315
+ });
316
+ let restoreError;
317
+ 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);
340
+ }
341
+ await this.restoreState(nestedDumpPaths);
342
+ continue;
325
343
  }
326
- await this.restoreState(nestedDumpPaths);
327
- continue;
328
344
  }
329
- }
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) {
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:
370
382
  return acc;
371
- }
372
- return Object.assign(acc, {
373
- [entryName]: entry,
374
- });
383
+ default:
384
+ if (entry.isDirectory || !attachmentsLinks[entryName] || attachmentsLinks[entryName].missed) {
385
+ return acc;
386
+ }
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
+ }
375
421
  }
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);
422
+ 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;
428
+ }
429
+ console.error(`Can't restore attachment contents from "${dump}", continuing without them`);
430
+ console.error(errorDetails(err));
405
431
  }
432
+ await __classPrivateFieldGet(this, _AllureReport_store, "f").restoreState(dumpState, resultsAttachments);
433
+ console.info(`Successfully restored state from "${dump}"`);
406
434
  }
407
435
  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;
436
+ restoreError = err;
437
+ throw err;
438
+ }
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
+ }
413
448
  }
414
- console.error(`Can't restore state from "${dump}", continuing without it`);
415
- console.error(err);
416
449
  }
417
- await __classPrivateFieldGet(this, _AllureReport_store, "f").restoreState(dumpState, resultsAttachments);
418
- console.info(`Successfully restored state from "${dump}"`);
419
450
  }
420
- finally {
421
- await dumpArchive.close();
451
+ catch (err) {
452
+ console.error(`Failed to restore state from "${dump}", continuing without it`);
453
+ console.error(errorDetails(err));
422
454
  }
423
455
  }
424
456
  };
@@ -427,6 +459,8 @@ export class AllureReport {
427
459
  const remoteHrefs = new Set();
428
460
  const remoteHrefsByPluginId = {};
429
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));
430
464
  if (__classPrivateFieldGet(this, _AllureReport_executionStage, "f") !== "running") {
431
465
  throw new Error(initRequired);
432
466
  }
@@ -458,59 +492,97 @@ export class AllureReport {
458
492
  width: 20,
459
493
  })
460
494
  : undefined;
461
- const limitFn = pLimit(50);
495
+ const limitFn = pLimit(REMOTE_UPLOAD_CONCURRENCY);
462
496
  const uploadAbortController = new AbortController();
463
- const fns = pluginFilesEntries.map(([filename, filepath]) => limitFn(async () => {
464
- if (cancelledPluginsIds.has(context.id) || uploadAbortController.signal.aborted) {
497
+ const failedUploads = new Set();
498
+ let terminalUploadError;
499
+ let remoteReportDeleted = false;
500
+ let fns = [];
501
+ const cleanupFailedPluginUpload = async (err) => {
502
+ if (remoteReportDeleted) {
465
503
  return;
466
504
  }
467
- if (/^(data|widgets|index\.html$|summary\.json$)/.test(filename)) {
468
- const uploadedFileUrl = await __classPrivateFieldGet(this, _AllureReport_allureServiceClient, "f").addReportFile({
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({
469
516
  reportUuid: this.reportUuid,
470
517
  pluginId: context.id,
471
- filename,
472
- filepath,
473
- signal: uploadAbortController.signal,
474
518
  });
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
- }
482
519
  }
483
- else {
484
- await __classPrivateFieldGet(this, _AllureReport_allureServiceClient, "f").addReportAsset({
485
- filename,
486
- filepath,
487
- signal: uploadAbortController.signal,
488
- });
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);
489
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 () => {
490
529
  if (cancelledPluginsIds.has(context.id) || uploadAbortController.signal.aborted) {
491
530
  return;
492
531
  }
493
- progressBar?.tick?.();
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
+ }
494
579
  }));
495
580
  progressBar?.render?.();
496
581
  try {
497
582
  await Promise.all(fns);
498
583
  }
499
584
  catch (err) {
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
- }
508
- await __classPrivateFieldGet(this, _AllureReport_allureServiceClient, "f").deleteReport({
509
- reportUuid: this.reportUuid,
510
- pluginId: context.id,
511
- });
512
- console.error(`Plugin "${context.id}" upload has failed, the plugin won't be published`);
513
- console.error(err);
585
+ await cleanupFailedPluginUpload(terminalUploadError ?? err);
514
586
  }
515
587
  }
516
588
  const summary = await plugin?.info?.(context, __classPrivateFieldGet(this, _AllureReport_store, "f"));
@@ -535,9 +607,7 @@ export class AllureReport {
535
607
  });
536
608
  if (summaries.length > 1) {
537
609
  const summaryPath = await generateSummary(__classPrivateFieldGet(this, _AllureReport_output, "f"), summaries);
538
- const publishedReports = __classPrivateFieldGet(this, _AllureReport_plugins, "f")
539
- .map((plugin) => !!plugin?.options?.publish && !cancelledPluginsIds.has(plugin.id))
540
- .filter(Boolean);
610
+ const publishedReports = getSuccessfulPublishedPlugins();
541
611
  if (__classPrivateFieldGet(this, _AllureReport_instances, "a", _AllureReport_publish_get) && summaryPath && publishedReports.length > 1) {
542
612
  await __classPrivateFieldGet(this, _AllureReport_allureServiceClient, "f")?.addReportFile({
543
613
  reportUuid: this.reportUuid,
@@ -546,7 +616,8 @@ export class AllureReport {
546
616
  });
547
617
  }
548
618
  }
549
- if (__classPrivateFieldGet(this, _AllureReport_instances, "a", _AllureReport_publish_get)) {
619
+ const publishedReports = getSuccessfulPublishedPlugins();
620
+ if (__classPrivateFieldGet(this, _AllureReport_instances, "a", _AllureReport_publish_get) && !remoteCleanupFailed && publishedReports.length > 0) {
550
621
  await __classPrivateFieldGet(this, _AllureReport_allureServiceClient, "f")?.completeReport({
551
622
  reportUuid: this.reportUuid,
552
623
  historyPoint: historyDataPoint,
@@ -595,7 +666,7 @@ export class AllureReport {
595
666
  }
596
667
  }
597
668
  }
598
- if (remoteHrefs.size > 0) {
669
+ if (!remoteCleanupFailed && remoteHrefs.size > 0) {
599
670
  console.info("Next reports have been published:");
600
671
  remoteHrefs.forEach((href) => {
601
672
  console.info(`- ${href}`);
@@ -659,12 +730,7 @@ export class AllureReport {
659
730
  });
660
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;
661
732
  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
- }
733
+ __classPrivateFieldSet(this, _AllureReport_allureServiceClient, new AllureServiceClient(allureServiceConfig), "f");
668
734
  }
669
735
  this.reportUuid = randomUUID();
670
736
  __classPrivateFieldSet(this, _AllureReport_ci, detect(), "f");
@@ -11,7 +11,7 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
11
11
  };
12
12
  var _DefaultAllureStore_instances, _DefaultAllureStore_testResults, _DefaultAllureStore_environmentDisplayNames, _DefaultAllureStore_environmentNameToId, _DefaultAllureStore_attachments, _DefaultAllureStore_attachmentContents, _DefaultAllureStore_testCases, _DefaultAllureStore_metadata, _DefaultAllureStore_history, _DefaultAllureStore_known, _DefaultAllureStore_fixtures, _DefaultAllureStore_defaultLabels, _DefaultAllureStore_environment, _DefaultAllureStore_environmentsConfig, _DefaultAllureStore_reportVariables, _DefaultAllureStore_realtimeDispatcher, _DefaultAllureStore_realtimeSubscriber, _DefaultAllureStore_allowedEnvironmentIds, _DefaultAllureStore_globalAttachmentIds, _DefaultAllureStore_globalAttachmentIdsByEnv, _DefaultAllureStore_globalErrors, _DefaultAllureStore_globalErrorsByEnv, _DefaultAllureStore_globalExitCode, _DefaultAllureStore_checkResults, _DefaultAllureStore_qualityGateResults, _DefaultAllureStore_historyPoints, _DefaultAllureStore_environments, _DefaultAllureStore_mergeEnvironmentIdentity, _DefaultAllureStore_environmentIdForLookup, _DefaultAllureStore_addEnvironments, _DefaultAllureStore_environmentIdByName, _DefaultAllureStore_setTestResultEnvironmentId, _DefaultAllureStore_assertAllowedEnvironmentId, _DefaultAllureStore_assertAllowedStoredEnvironment, _DefaultAllureStore_environmentIdByTestResult, _DefaultAllureStore_resolveGlobalEnvironmentIdentity, _DefaultAllureStore_globalAttachmentId, _DefaultAllureStore_indexGlobalError, _DefaultAllureStore_addGlobalError, _DefaultAllureStore_indexGlobalAttachment, _DefaultAllureStore_addGlobalAttachment, _DefaultAllureStore_restoreAttachmentContent, _DefaultAllureStore_relinkRestoredAttachmentSteps;
13
13
  import { extname } from "node:path";
14
- import { DEFAULT_ENVIRONMENT, DEFAULT_ENVIRONMENT_IDENTITY, compareBy, createDictionary, getHistoryIdCandidates, getWorstStatus, nullsLast, ordinal, reverse, selectHistoryTestResults, validateEnvironmentId, validateEnvironmentName, } from "@allurereport/core-api";
14
+ import { DEFAULT_ENVIRONMENT, DEFAULT_ENVIRONMENT_IDENTITY, compareBy, createDictionary, getHistoryIdCandidates, getWorstStatus, nullsLast, normalizeHistoryDataPoint, ordinal, reverse, selectHistoryTestResults, validateEnvironmentId, validateEnvironmentName, } from "@allurereport/core-api";
15
15
  import { md5, } from "@allurereport/plugin-api";
16
16
  import { environmentIdentityById, normalizeEnvironmentDescriptorMap, resolveEnvironmentIdentity, resolveStoredEnvironmentIdentity, validateAllowedEnvironmentId, } from "../utils/environment.js";
17
17
  import { isFlaky } from "../utils/flaky.js";
@@ -196,7 +196,9 @@ export class DefaultAllureStore {
196
196
  if (!__classPrivateFieldGet(this, _DefaultAllureStore_history, "f")) {
197
197
  return [];
198
198
  }
199
- __classPrivateFieldSet(this, _DefaultAllureStore_historyPoints, (await __classPrivateFieldGet(this, _DefaultAllureStore_history, "f").readHistory()) ?? [], "f");
199
+ __classPrivateFieldSet(this, _DefaultAllureStore_historyPoints, ((await __classPrivateFieldGet(this, _DefaultAllureStore_history, "f").readHistory()) ?? [])
200
+ .filter((historyPoint) => typeof historyPoint === "object" && historyPoint !== null)
201
+ .map(normalizeHistoryDataPoint), "f");
200
202
  __classPrivateFieldGet(this, _DefaultAllureStore_historyPoints, "f").sort(compareBy("timestamp", reverse(ordinal())));
201
203
  return __classPrivateFieldGet(this, _DefaultAllureStore_historyPoints, "f");
202
204
  }
@@ -488,7 +490,7 @@ export class DefaultAllureStore {
488
490
  }
489
491
  return __classPrivateFieldGet(this, _DefaultAllureStore_historyPoints, "f").reduce((result, dp) => {
490
492
  const filteredTestResults = [];
491
- for (const tr of Object.values(dp.testResults)) {
493
+ for (const tr of Object.values(dp.testResults ?? {})) {
492
494
  const storedEnvironmentKey = typeof tr.environment === "string" ? tr.environment : undefined;
493
495
  const trEnvId = (storedEnvironmentKey ? __classPrivateFieldGet(this, _DefaultAllureStore_instances, "m", _DefaultAllureStore_environmentIdByName).call(this, storedEnvironmentKey) : undefined) ??
494
496
  resolveStoredEnvironmentIdentity({
@@ -526,7 +528,7 @@ export class DefaultAllureStore {
526
528
  if (allHistoryDps.length === 0) {
527
529
  return Array.from(__classPrivateFieldGet(this, _DefaultAllureStore_testResults, "f").values());
528
530
  }
529
- const historicalIds = new Set(allHistoryDps.flatMap((dp) => Object.keys(dp.testResults)));
531
+ const historicalIds = new Set(allHistoryDps.flatMap((dp) => Object.keys(dp.testResults ?? {})));
530
532
  const newTrs = [];
531
533
  for (const [, tr] of __classPrivateFieldGet(this, _DefaultAllureStore_testResults, "f")) {
532
534
  if (tr.hidden) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@allurereport/core",
3
- "version": "3.8.0",
3
+ "version": "3.8.2",
4
4
  "description": "Collection of generic Allure utilities used across the entire project",
5
5
  "keywords": [
6
6
  "allure"
@@ -25,25 +25,25 @@
25
25
  "lint:fix": "oxlint --import-plugin --fix src test features stories"
26
26
  },
27
27
  "dependencies": {
28
- "@allurereport/ci": "3.8.0",
29
- "@allurereport/core-api": "3.8.0",
30
- "@allurereport/plugin-agent": "3.8.0",
31
- "@allurereport/plugin-allure2": "3.8.0",
32
- "@allurereport/plugin-api": "3.8.0",
33
- "@allurereport/plugin-awesome": "3.8.0",
34
- "@allurereport/plugin-classic": "3.8.0",
35
- "@allurereport/plugin-csv": "3.8.0",
36
- "@allurereport/plugin-dashboard": "3.8.0",
37
- "@allurereport/plugin-jira": "3.8.0",
38
- "@allurereport/plugin-log": "3.8.0",
39
- "@allurereport/plugin-progress": "3.8.0",
40
- "@allurereport/plugin-slack": "3.8.0",
41
- "@allurereport/plugin-testops": "3.8.0",
42
- "@allurereport/plugin-testplan": "3.8.0",
43
- "@allurereport/reader": "3.8.0",
44
- "@allurereport/reader-api": "3.8.0",
45
- "@allurereport/service": "3.8.0",
46
- "@allurereport/summary": "3.8.0",
28
+ "@allurereport/ci": "3.8.2",
29
+ "@allurereport/core-api": "3.8.2",
30
+ "@allurereport/plugin-agent": "3.8.2",
31
+ "@allurereport/plugin-allure2": "3.8.2",
32
+ "@allurereport/plugin-api": "3.8.2",
33
+ "@allurereport/plugin-awesome": "3.8.2",
34
+ "@allurereport/plugin-classic": "3.8.2",
35
+ "@allurereport/plugin-csv": "3.8.2",
36
+ "@allurereport/plugin-dashboard": "3.8.2",
37
+ "@allurereport/plugin-jira": "3.8.2",
38
+ "@allurereport/plugin-log": "3.8.2",
39
+ "@allurereport/plugin-progress": "3.8.2",
40
+ "@allurereport/plugin-slack": "3.8.2",
41
+ "@allurereport/plugin-testops": "3.8.2",
42
+ "@allurereport/plugin-testplan": "3.8.2",
43
+ "@allurereport/reader": "3.8.2",
44
+ "@allurereport/reader-api": "3.8.2",
45
+ "@allurereport/service": "3.8.2",
46
+ "@allurereport/summary": "3.8.2",
47
47
  "glob": "^13.0.6",
48
48
  "handlebars": "^4.7.9",
49
49
  "node-stream-zip": "^1.15.0",