@allurereport/core 3.9.0 → 3.11.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 +256 -224
- package/dist/utils/perf.d.ts +42 -0
- package/dist/utils/perf.js +122 -0
- package/package.json +27 -27
package/dist/report.js
CHANGED
|
@@ -9,7 +9,7 @@ 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_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;
|
|
12
|
+
var _AllureReport_instances, _AllureReport_ci, _AllureReport_store, _AllureReport_readers, _AllureReport_plugins, _AllureReport_reportFiles, _AllureReport_realtimeChannel, _AllureReport_realtimeUpdateScheduler, _AllureReport_realTime, _AllureReport_hideLabels, _AllureReport_output, _AllureReport_history, _AllureReport_allureServiceClient, _AllureReport_qualityGate, _AllureReport_dump, _AllureReport_categories, _AllureReport_environments, _AllureReport_globalAttachments, _AllureReport_dumpTempDirs, _AllureReport_state, _AllureReport_executionStage, _AllureReport_historyDataPoint, _AllureReport_summaryPath, _AllureReport_summariesByPluginId, _AllureReport_publishedRemoteHrefs, _AllureReport_published, _AllureReport_endGeneratePerfSpan, _AllureReport_publish, _AllureReport_runRealtimeUpdate, _AllureReport_getReportsToPublish, _AllureReport_cleanupFailedRemoteReport, _AllureReport_logPublishError, _AllureReport_applyPublishLinksToSummaries, _AllureReport_cloneSummariesByPluginId, _AllureReport_writeSummaryFiles, _AllureReport_generateRootSummary, _AllureReport_finishGeneratePerfSpan, _AllureReport_finishPerfMetrics, _AllureReport_eachPlugin, _AllureReport_getPluginState;
|
|
13
13
|
import console from "node:console";
|
|
14
14
|
import { randomUUID } from "node:crypto";
|
|
15
15
|
import { once } from "node:events";
|
|
@@ -35,6 +35,7 @@ import { QualityGate } from "./qualityGate/index.js";
|
|
|
35
35
|
import { DefaultAllureStore } from "./store/store.js";
|
|
36
36
|
import { createUploadProgressBarCounter } from "./utils/cli.js";
|
|
37
37
|
import { environmentIdentityById, environmentIdentityByName } from "./utils/environment.js";
|
|
38
|
+
import { measurePerf, PERF_METRIC_NAMES, PERF_METRIC_PREFIXES, startPerfSpan, writePerfMetrics } from "./utils/perf.js";
|
|
38
39
|
import { RealtimeChannel } from "./utils/realtimeChannel.js";
|
|
39
40
|
import { RealtimeUpdateScheduler } from "./utils/realtimeUpdateScheduler.js";
|
|
40
41
|
import { resolveDumpAttachmentPath, UnsafeDumpPathError } from "./utils/safeDumpPath.js";
|
|
@@ -94,6 +95,7 @@ export class AllureReport {
|
|
|
94
95
|
_AllureReport_summariesByPluginId.set(this, new Map());
|
|
95
96
|
_AllureReport_publishedRemoteHrefs.set(this, new Set());
|
|
96
97
|
_AllureReport_published.set(this, false);
|
|
98
|
+
_AllureReport_endGeneratePerfSpan.set(this, void 0);
|
|
97
99
|
_AllureReport_publish.set(this, async () => {
|
|
98
100
|
if (__classPrivateFieldGet(this, _AllureReport_published, "f")) {
|
|
99
101
|
return;
|
|
@@ -126,6 +128,7 @@ export class AllureReport {
|
|
|
126
128
|
let summariesMutated = false;
|
|
127
129
|
let reportCreated = false;
|
|
128
130
|
let publishErrorMessage = "Report upload has failed, the report won't be published";
|
|
131
|
+
const endPublishPerfSpan = startPerfSpan(PERF_METRIC_NAMES.publishUploadTotal);
|
|
129
132
|
try {
|
|
130
133
|
await client.createReport({
|
|
131
134
|
reportUuid: this.reportUuid,
|
|
@@ -135,12 +138,12 @@ export class AllureReport {
|
|
|
135
138
|
reportCreated = true;
|
|
136
139
|
for (const report of reportsToPublish) {
|
|
137
140
|
publishErrorMessage = `Plugin "${report.pluginId}" upload has failed, the plugin won't be published`;
|
|
138
|
-
const uploadResult = await client.uploadReport({
|
|
141
|
+
const uploadResult = await measurePerf(`${PERF_METRIC_PREFIXES.publishUploadPlugin}${report.pluginId}`, () => client.uploadReport({
|
|
139
142
|
reportUuid: this.reportUuid,
|
|
140
143
|
pluginId: report.pluginId,
|
|
141
144
|
files: Object.fromEntries(Object.entries(report.files).filter(([filename]) => filename !== "summary.json")),
|
|
142
145
|
onProgress: () => uploadProgressBar.tick(),
|
|
143
|
-
});
|
|
146
|
+
}));
|
|
144
147
|
if (uploadResult.indexHref) {
|
|
145
148
|
linksByPluginId[report.pluginId] = uploadResult.indexHref;
|
|
146
149
|
}
|
|
@@ -199,10 +202,11 @@ export class AllureReport {
|
|
|
199
202
|
__classPrivateFieldGet(this, _AllureReport_logPublishError, "f").call(this, publishErrorMessage, err);
|
|
200
203
|
}
|
|
201
204
|
finally {
|
|
205
|
+
endPublishPerfSpan();
|
|
202
206
|
uploadProgressBar.terminate();
|
|
203
207
|
}
|
|
204
208
|
});
|
|
205
|
-
this.readDirectory = async (resultsDir) => {
|
|
209
|
+
this.readDirectory = async (resultsDir) => measurePerf(PERF_METRIC_NAMES.generateReadResults, async () => {
|
|
206
210
|
if (__classPrivateFieldGet(this, _AllureReport_executionStage, "f") !== "running") {
|
|
207
211
|
throw new Error(initRequired);
|
|
208
212
|
}
|
|
@@ -228,13 +232,13 @@ export class AllureReport {
|
|
|
228
232
|
catch (e) {
|
|
229
233
|
console.error("can't read directory", e);
|
|
230
234
|
}
|
|
231
|
-
};
|
|
232
|
-
this.readFile = async (resultsFile) => {
|
|
235
|
+
});
|
|
236
|
+
this.readFile = async (resultsFile) => measurePerf(PERF_METRIC_NAMES.generateReadResults, async () => {
|
|
233
237
|
if (__classPrivateFieldGet(this, _AllureReport_executionStage, "f") !== "running") {
|
|
234
238
|
throw new Error(initRequired);
|
|
235
239
|
}
|
|
236
240
|
await this.readResult(new PathResultFile(resultsFile));
|
|
237
|
-
};
|
|
241
|
+
});
|
|
238
242
|
this.readResult = async (data) => {
|
|
239
243
|
if (__classPrivateFieldGet(this, _AllureReport_executionStage, "f") !== "running") {
|
|
240
244
|
throw new Error(initRequired);
|
|
@@ -275,6 +279,7 @@ export class AllureReport {
|
|
|
275
279
|
throw new Error("the report is already stopped, the restart isn't supported at the moment");
|
|
276
280
|
}
|
|
277
281
|
__classPrivateFieldSet(this, _AllureReport_executionStage, "running", "f");
|
|
282
|
+
__classPrivateFieldSet(this, _AllureReport_endGeneratePerfSpan, startPerfSpan(PERF_METRIC_NAMES.generateTotal), "f");
|
|
278
283
|
const cwd = resolve(process.cwd());
|
|
279
284
|
const cwdWithSep = cwd.endsWith(sep) ? cwd : `${cwd}${sep}`;
|
|
280
285
|
if (__classPrivateFieldGet(this, _AllureReport_globalAttachments, "f")?.length) {
|
|
@@ -440,160 +445,164 @@ export class AllureReport {
|
|
|
440
445
|
}
|
|
441
446
|
await rename(dumpTempPath, dumpPath);
|
|
442
447
|
};
|
|
443
|
-
this.restoreState = async (dumps) => {
|
|
448
|
+
this.restoreState = async (dumps) => measurePerf(PERF_METRIC_NAMES.restoreStateTotal, async () => {
|
|
444
449
|
for (const dump of dumps) {
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
const dumpArchive = new ZipReadStream.async({
|
|
452
|
-
file: dump,
|
|
453
|
-
});
|
|
454
|
-
let restoreError;
|
|
450
|
+
await measurePerf(PERF_METRIC_NAMES.restoreStateDump, async () => {
|
|
451
|
+
if (!existsSync(dump)) {
|
|
452
|
+
console.error(`Failed to restore state from "${dump}", continuing without it`);
|
|
453
|
+
console.error("Dump file does not exist");
|
|
454
|
+
return;
|
|
455
|
+
}
|
|
455
456
|
try {
|
|
456
|
-
const
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
if (
|
|
471
|
-
const
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
await
|
|
477
|
-
nestedDumpPaths
|
|
457
|
+
const dumpArchive = new ZipReadStream.async({
|
|
458
|
+
file: dump,
|
|
459
|
+
});
|
|
460
|
+
let restoreError;
|
|
461
|
+
try {
|
|
462
|
+
const dumpEntries = await dumpArchive.entries();
|
|
463
|
+
const dumpEntriesList = Object.entries(dumpEntries);
|
|
464
|
+
const requiredEntryData = async (entryName) => {
|
|
465
|
+
if (!dumpEntries[entryName]) {
|
|
466
|
+
throw new Error(`Missing required dump entry "${entryName}"`);
|
|
467
|
+
}
|
|
468
|
+
return dumpArchive.entryData(entryName);
|
|
469
|
+
};
|
|
470
|
+
const optionalEntryData = async (entryName) => dumpEntries[entryName] ? dumpArchive.entryData(entryName) : undefined;
|
|
471
|
+
if (!dumpEntries[AllureStoreDumpFiles.TestResults]) {
|
|
472
|
+
const nestedDumpEntries = dumpEntriesList.filter(([entryName, entry]) => !entry.isDirectory &&
|
|
473
|
+
!entryName.startsWith("__MACOSX/") &&
|
|
474
|
+
!basename(entryName).startsWith("._") &&
|
|
475
|
+
entryName.toLowerCase().endsWith(".zip"));
|
|
476
|
+
if (nestedDumpEntries.length > 0) {
|
|
477
|
+
const nestedDumpsTempDir = await mkdtemp(join(tmpdir(), `${basename(dump, ".zip")}-nested-`));
|
|
478
|
+
const nestedDumpPaths = [];
|
|
479
|
+
__classPrivateFieldGet(this, _AllureReport_dumpTempDirs, "f").push(nestedDumpsTempDir);
|
|
480
|
+
for (const [entryName] of nestedDumpEntries) {
|
|
481
|
+
const nestedDumpPath = join(nestedDumpsTempDir, `${nestedDumpPaths.length}-${basename(entryName)}`);
|
|
482
|
+
await writeFile(nestedDumpPath, await dumpArchive.entryData(entryName));
|
|
483
|
+
nestedDumpPaths.push(nestedDumpPath);
|
|
484
|
+
}
|
|
485
|
+
await this.restoreState(nestedDumpPaths);
|
|
486
|
+
return;
|
|
478
487
|
}
|
|
479
|
-
await this.restoreState(nestedDumpPaths);
|
|
480
|
-
continue;
|
|
481
488
|
}
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
case AllureStoreDumpFiles.TestResultIngestOrder:
|
|
520
|
-
return acc;
|
|
521
|
-
default:
|
|
522
|
-
if (entry.isDirectory || !attachmentsLinks[entryName] || attachmentsLinks[entryName].missed) {
|
|
489
|
+
const testResultsEntry = await requiredEntryData(AllureStoreDumpFiles.TestResults);
|
|
490
|
+
const testCasesEntry = await requiredEntryData(AllureStoreDumpFiles.TestCases);
|
|
491
|
+
const fixturesEntry = await requiredEntryData(AllureStoreDumpFiles.Fixtures);
|
|
492
|
+
const attachmentsEntry = await requiredEntryData(AllureStoreDumpFiles.Attachments);
|
|
493
|
+
const checkResultsEntry = await optionalEntryData(AllureStoreDumpFiles.CheckResults);
|
|
494
|
+
const environmentsEntry = await requiredEntryData(AllureStoreDumpFiles.Environments);
|
|
495
|
+
const reportVariablesEntry = await requiredEntryData(AllureStoreDumpFiles.ReportVariables);
|
|
496
|
+
const globalAttachmentsEntry = await requiredEntryData(AllureStoreDumpFiles.GlobalAttachments);
|
|
497
|
+
const globalErrorsEntry = await requiredEntryData(AllureStoreDumpFiles.GlobalErrors);
|
|
498
|
+
const indexAttachmentsEntry = await requiredEntryData(AllureStoreDumpFiles.IndexAttachmentsByTestResults);
|
|
499
|
+
const indexTestResultsByHistoryId = await requiredEntryData(AllureStoreDumpFiles.IndexTestResultsByHistoryId);
|
|
500
|
+
const indexTestResultsByTestCaseEntry = await requiredEntryData(AllureStoreDumpFiles.IndexTestResultsByTestCase);
|
|
501
|
+
const indexAttachmentsByFixtureEntry = await requiredEntryData(AllureStoreDumpFiles.IndexAttachmentsByFixture);
|
|
502
|
+
const indexFixturesByTestResultEntry = await requiredEntryData(AllureStoreDumpFiles.IndexFixturesByTestResult);
|
|
503
|
+
const indexKnownByHistoryIdEntry = await requiredEntryData(AllureStoreDumpFiles.IndexKnownByHistoryId);
|
|
504
|
+
const qualityGateResultsEntry = await requiredEntryData(AllureStoreDumpFiles.QualityGateResults);
|
|
505
|
+
const testResultIngestOrderEntry = await optionalEntryData(AllureStoreDumpFiles.TestResultIngestOrder);
|
|
506
|
+
const attachmentsLinks = JSON.parse(attachmentsEntry.toString("utf8"));
|
|
507
|
+
const attachmentsEntries = dumpEntriesList.reduce((acc, [entryName, entry]) => {
|
|
508
|
+
switch (entryName) {
|
|
509
|
+
case AllureStoreDumpFiles.Attachments:
|
|
510
|
+
case AllureStoreDumpFiles.CheckResults:
|
|
511
|
+
case AllureStoreDumpFiles.TestResults:
|
|
512
|
+
case AllureStoreDumpFiles.TestCases:
|
|
513
|
+
case AllureStoreDumpFiles.Fixtures:
|
|
514
|
+
case AllureStoreDumpFiles.Environments:
|
|
515
|
+
case AllureStoreDumpFiles.ReportVariables:
|
|
516
|
+
case AllureStoreDumpFiles.GlobalAttachments:
|
|
517
|
+
case AllureStoreDumpFiles.GlobalErrors:
|
|
518
|
+
case AllureStoreDumpFiles.IndexAttachmentsByTestResults:
|
|
519
|
+
case AllureStoreDumpFiles.IndexTestResultsByHistoryId:
|
|
520
|
+
case AllureStoreDumpFiles.IndexTestResultsByTestCase:
|
|
521
|
+
case AllureStoreDumpFiles.IndexAttachmentsByFixture:
|
|
522
|
+
case AllureStoreDumpFiles.IndexFixturesByTestResult:
|
|
523
|
+
case AllureStoreDumpFiles.IndexKnownByHistoryId:
|
|
524
|
+
case AllureStoreDumpFiles.QualityGateResults:
|
|
525
|
+
case AllureStoreDumpFiles.TestResultIngestOrder:
|
|
523
526
|
return acc;
|
|
527
|
+
default:
|
|
528
|
+
if (entry.isDirectory || !attachmentsLinks[entryName] || attachmentsLinks[entryName].missed) {
|
|
529
|
+
return acc;
|
|
530
|
+
}
|
|
531
|
+
return Object.assign(acc, {
|
|
532
|
+
[entryName]: entry,
|
|
533
|
+
});
|
|
534
|
+
}
|
|
535
|
+
}, {});
|
|
536
|
+
const dumpState = {
|
|
537
|
+
testResults: JSON.parse(testResultsEntry.toString("utf8")),
|
|
538
|
+
testCases: JSON.parse(testCasesEntry.toString("utf8")),
|
|
539
|
+
fixtures: JSON.parse(fixturesEntry.toString("utf8")),
|
|
540
|
+
attachments: attachmentsLinks,
|
|
541
|
+
checkResults: checkResultsEntry ? JSON.parse(checkResultsEntry.toString("utf8")) : [],
|
|
542
|
+
environments: JSON.parse(environmentsEntry.toString("utf8")),
|
|
543
|
+
reportVariables: JSON.parse(reportVariablesEntry.toString("utf8")),
|
|
544
|
+
globalAttachmentIds: JSON.parse(globalAttachmentsEntry.toString("utf8")),
|
|
545
|
+
globalErrors: JSON.parse(globalErrorsEntry.toString("utf8")),
|
|
546
|
+
indexAttachmentByTestResult: JSON.parse(indexAttachmentsEntry.toString("utf8")),
|
|
547
|
+
indexTestResultByHistoryId: JSON.parse(indexTestResultsByHistoryId.toString("utf8")),
|
|
548
|
+
indexTestResultByTestCase: JSON.parse(indexTestResultsByTestCaseEntry.toString("utf8")),
|
|
549
|
+
indexAttachmentByFixture: JSON.parse(indexAttachmentsByFixtureEntry.toString("utf8")),
|
|
550
|
+
indexFixturesByTestResult: JSON.parse(indexFixturesByTestResultEntry.toString("utf8")),
|
|
551
|
+
indexKnownByHistoryId: JSON.parse(indexKnownByHistoryIdEntry.toString("utf8")),
|
|
552
|
+
qualityGateResults: JSON.parse(qualityGateResultsEntry.toString("utf8")),
|
|
553
|
+
testResultIdsIngestOrder: testResultIngestOrderEntry
|
|
554
|
+
? JSON.parse(testResultIngestOrderEntry.toString("utf8"))
|
|
555
|
+
: [],
|
|
556
|
+
};
|
|
557
|
+
const dumpTempDir = await mkdtemp(join(tmpdir(), basename(dump, ".zip")));
|
|
558
|
+
const resultsAttachments = {};
|
|
559
|
+
__classPrivateFieldGet(this, _AllureReport_dumpTempDirs, "f").push(dumpTempDir);
|
|
560
|
+
await measurePerf(PERF_METRIC_NAMES.restoreStateAttachments, async () => {
|
|
561
|
+
try {
|
|
562
|
+
for (const [attachmentId] of Object.entries(attachmentsEntries)) {
|
|
563
|
+
const attachmentContentEntry = await dumpArchive.entryData(attachmentId);
|
|
564
|
+
const attachmentFilePath = resolveDumpAttachmentPath(dumpTempDir, attachmentId);
|
|
565
|
+
await writeFile(attachmentFilePath, attachmentContentEntry);
|
|
566
|
+
resultsAttachments[attachmentId] = new PathResultFile(attachmentFilePath, attachmentId);
|
|
524
567
|
}
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
globalErrors: JSON.parse(globalErrorsEntry.toString("utf8")),
|
|
540
|
-
indexAttachmentByTestResult: JSON.parse(indexAttachmentsEntry.toString("utf8")),
|
|
541
|
-
indexTestResultByHistoryId: JSON.parse(indexTestResultsByHistoryId.toString("utf8")),
|
|
542
|
-
indexTestResultByTestCase: JSON.parse(indexTestResultsByTestCaseEntry.toString("utf8")),
|
|
543
|
-
indexAttachmentByFixture: JSON.parse(indexAttachmentsByFixtureEntry.toString("utf8")),
|
|
544
|
-
indexFixturesByTestResult: JSON.parse(indexFixturesByTestResultEntry.toString("utf8")),
|
|
545
|
-
indexKnownByHistoryId: JSON.parse(indexKnownByHistoryIdEntry.toString("utf8")),
|
|
546
|
-
qualityGateResults: JSON.parse(qualityGateResultsEntry.toString("utf8")),
|
|
547
|
-
testResultIdsIngestOrder: testResultIngestOrderEntry
|
|
548
|
-
? JSON.parse(testResultIngestOrderEntry.toString("utf8"))
|
|
549
|
-
: [],
|
|
550
|
-
};
|
|
551
|
-
const dumpTempDir = await mkdtemp(join(tmpdir(), basename(dump, ".zip")));
|
|
552
|
-
const resultsAttachments = {};
|
|
553
|
-
__classPrivateFieldGet(this, _AllureReport_dumpTempDirs, "f").push(dumpTempDir);
|
|
554
|
-
try {
|
|
555
|
-
for (const [attachmentId] of Object.entries(attachmentsEntries)) {
|
|
556
|
-
const attachmentContentEntry = await dumpArchive.entryData(attachmentId);
|
|
557
|
-
const attachmentFilePath = resolveDumpAttachmentPath(dumpTempDir, attachmentId);
|
|
558
|
-
await writeFile(attachmentFilePath, attachmentContentEntry);
|
|
559
|
-
resultsAttachments[attachmentId] = new PathResultFile(attachmentFilePath, attachmentId);
|
|
560
|
-
}
|
|
568
|
+
}
|
|
569
|
+
catch (err) {
|
|
570
|
+
if (err instanceof UnsafeDumpPathError) {
|
|
571
|
+
console.error(`Cannot restore dump from "${dump}": the archive lists attachment paths that would write outside the extract directory (unsafe zip paths such as "../" or absolute names).`);
|
|
572
|
+
console.error(err.message);
|
|
573
|
+
console.error("Only use dump archives produced by this tool; do not load untrusted or third-party --dump zip files.");
|
|
574
|
+
throw err;
|
|
575
|
+
}
|
|
576
|
+
console.error(`Can't restore attachment contents from "${dump}", continuing without them`);
|
|
577
|
+
console.error(errorDetails(err));
|
|
578
|
+
}
|
|
579
|
+
});
|
|
580
|
+
await measurePerf(PERF_METRIC_NAMES.restoreStateStoreRestore, async () => __classPrivateFieldGet(this, _AllureReport_store, "f").restoreState(dumpState, resultsAttachments));
|
|
581
|
+
console.info(`Successfully restored state from "${dump}"`);
|
|
561
582
|
}
|
|
562
583
|
catch (err) {
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
584
|
+
restoreError = err;
|
|
585
|
+
throw err;
|
|
586
|
+
}
|
|
587
|
+
finally {
|
|
588
|
+
try {
|
|
589
|
+
await dumpArchive.close();
|
|
590
|
+
}
|
|
591
|
+
catch (err) {
|
|
592
|
+
if (!restoreError) {
|
|
593
|
+
console.error(`Failed to close dump archive "${dump}"`);
|
|
594
|
+
console.error(errorDetails(err));
|
|
595
|
+
}
|
|
568
596
|
}
|
|
569
|
-
console.error(`Can't restore attachment contents from "${dump}", continuing without them`);
|
|
570
|
-
console.error(errorDetails(err));
|
|
571
597
|
}
|
|
572
|
-
await __classPrivateFieldGet(this, _AllureReport_store, "f").restoreState(dumpState, resultsAttachments);
|
|
573
|
-
console.info(`Successfully restored state from "${dump}"`);
|
|
574
598
|
}
|
|
575
599
|
catch (err) {
|
|
576
|
-
|
|
577
|
-
|
|
600
|
+
console.error(`Failed to restore state from "${dump}", continuing without it`);
|
|
601
|
+
console.error(errorDetails(err));
|
|
578
602
|
}
|
|
579
|
-
|
|
580
|
-
try {
|
|
581
|
-
await dumpArchive.close();
|
|
582
|
-
}
|
|
583
|
-
catch (err) {
|
|
584
|
-
if (!restoreError) {
|
|
585
|
-
console.error(`Failed to close dump archive "${dump}"`);
|
|
586
|
-
console.error(errorDetails(err));
|
|
587
|
-
}
|
|
588
|
-
}
|
|
589
|
-
}
|
|
590
|
-
}
|
|
591
|
-
catch (err) {
|
|
592
|
-
console.error(`Failed to restore state from "${dump}", continuing without it`);
|
|
593
|
-
console.error(errorDetails(err));
|
|
594
|
-
}
|
|
603
|
+
});
|
|
595
604
|
}
|
|
596
|
-
};
|
|
605
|
+
});
|
|
597
606
|
_AllureReport_getReportsToPublish.set(this, async () => {
|
|
598
607
|
const reports = [];
|
|
599
608
|
for (const { enabled, id, options } of __classPrivateFieldGet(this, _AllureReport_plugins, "f")) {
|
|
@@ -663,7 +672,7 @@ export class AllureReport {
|
|
|
663
672
|
_AllureReport_generateRootSummary.set(this, async () => {
|
|
664
673
|
const summaries = [...__classPrivateFieldGet(this, _AllureReport_summariesByPluginId, "f").values()].map(clonePluginSummary);
|
|
665
674
|
if (summaries.length > 1) {
|
|
666
|
-
__classPrivateFieldSet(this, _AllureReport_summaryPath, await generateSummary(__classPrivateFieldGet(this, _AllureReport_output, "f"), summaries), "f");
|
|
675
|
+
__classPrivateFieldSet(this, _AllureReport_summaryPath, await measurePerf(PERF_METRIC_NAMES.summaryGenerate, async () => generateSummary(__classPrivateFieldGet(this, _AllureReport_output, "f"), summaries)), "f");
|
|
667
676
|
}
|
|
668
677
|
else {
|
|
669
678
|
__classPrivateFieldSet(this, _AllureReport_summaryPath, undefined, "f");
|
|
@@ -674,96 +683,119 @@ export class AllureReport {
|
|
|
674
683
|
if (__classPrivateFieldGet(this, _AllureReport_executionStage, "f") !== "running") {
|
|
675
684
|
throw new Error(initRequired);
|
|
676
685
|
}
|
|
677
|
-
const testResults = await __classPrivateFieldGet(this, _AllureReport_store, "f").allTestResults();
|
|
678
|
-
const testCases = await __classPrivateFieldGet(this, _AllureReport_store, "f").allTestCases();
|
|
679
|
-
__classPrivateFieldSet(this, _AllureReport_historyDataPoint, createHistory(this.reportUuid, this.reportName, testCases, testResults, this.reportUrl), "f");
|
|
680
|
-
__classPrivateFieldGet(this, _AllureReport_realtimeChannel, "f").close();
|
|
681
686
|
try {
|
|
682
|
-
await __classPrivateFieldGet(this,
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
await __classPrivateFieldGet(this, _AllureReport_eachPlugin, "f").call(this, false, async (plugin, context) => {
|
|
696
|
-
const summary = await plugin?.info?.(context, __classPrivateFieldGet(this, _AllureReport_store, "f"));
|
|
697
|
-
if (!summary) {
|
|
687
|
+
const testResults = await __classPrivateFieldGet(this, _AllureReport_store, "f").allTestResults();
|
|
688
|
+
const testCases = await __classPrivateFieldGet(this, _AllureReport_store, "f").allTestCases();
|
|
689
|
+
__classPrivateFieldSet(this, _AllureReport_historyDataPoint, createHistory(this.reportUuid, this.reportName, testCases, testResults, this.reportUrl), "f");
|
|
690
|
+
__classPrivateFieldGet(this, _AllureReport_realtimeChannel, "f").close();
|
|
691
|
+
try {
|
|
692
|
+
await __classPrivateFieldGet(this, _AllureReport_realtimeUpdateScheduler, "f").close();
|
|
693
|
+
}
|
|
694
|
+
catch (e) {
|
|
695
|
+
console.error("realtime update failed during shutdown", e);
|
|
696
|
+
}
|
|
697
|
+
__classPrivateFieldSet(this, _AllureReport_executionStage, "done", "f");
|
|
698
|
+
if (__classPrivateFieldGet(this, _AllureReport_dump, "f")) {
|
|
699
|
+
await this.dumpState();
|
|
698
700
|
return;
|
|
699
701
|
}
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
702
|
+
await measurePerf(PERF_METRIC_NAMES.generatePluginsDone, async () => {
|
|
703
|
+
await __classPrivateFieldGet(this, _AllureReport_eachPlugin, "f").call(this, false, async (plugin, context) => {
|
|
704
|
+
await measurePerf(`${PERF_METRIC_PREFIXES.generatePluginDone}${context.id}`, async () => {
|
|
705
|
+
await plugin.done?.(context, __classPrivateFieldGet(this, _AllureReport_store, "f"));
|
|
706
|
+
});
|
|
707
|
+
});
|
|
706
708
|
});
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
for (const entry of reportContent) {
|
|
727
|
-
const currentFilePath = join(reportPath, entry);
|
|
728
|
-
const newFilePath = resolve(dirname(currentFilePath), "..", entry);
|
|
729
|
-
await rename(currentFilePath, newFilePath);
|
|
730
|
-
}
|
|
731
|
-
await rm(reportPath, { recursive: true });
|
|
732
|
-
}
|
|
733
|
-
for (const dir of __classPrivateFieldGet(this, _AllureReport_dumpTempDirs, "f")) {
|
|
709
|
+
__classPrivateFieldGet(this, _AllureReport_finishGeneratePerfSpan, "f").call(this);
|
|
710
|
+
await __classPrivateFieldGet(this, _AllureReport_eachPlugin, "f").call(this, false, async (plugin, context) => {
|
|
711
|
+
const summary = await plugin?.info?.(context, __classPrivateFieldGet(this, _AllureReport_store, "f"));
|
|
712
|
+
if (!summary) {
|
|
713
|
+
return;
|
|
714
|
+
}
|
|
715
|
+
summary.pluginId = context.id;
|
|
716
|
+
summary.pullRequestHref = __classPrivateFieldGet(this, _AllureReport_ci, "f")?.pullRequestUrl;
|
|
717
|
+
summary.jobHref = __classPrivateFieldGet(this, _AllureReport_ci, "f")?.jobRunUrl;
|
|
718
|
+
summaries.push({
|
|
719
|
+
...summary,
|
|
720
|
+
href: `${context.id}/`,
|
|
721
|
+
});
|
|
722
|
+
});
|
|
723
|
+
__classPrivateFieldSet(this, _AllureReport_summariesByPluginId, new Map(summaries
|
|
724
|
+
.filter((summary) => !!summary.pluginId)
|
|
725
|
+
.map((summary) => [summary.pluginId, summary])), "f");
|
|
726
|
+
await __classPrivateFieldGet(this, _AllureReport_publish, "f").call(this);
|
|
727
|
+
let outputDirFiles = [];
|
|
734
728
|
try {
|
|
735
|
-
await
|
|
729
|
+
outputDirFiles = await readdir(__classPrivateFieldGet(this, _AllureReport_output, "f"));
|
|
736
730
|
}
|
|
737
731
|
catch { }
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
try {
|
|
741
|
-
await __classPrivateFieldGet(this, _AllureReport_store, "f").appendHistory(__classPrivateFieldGet(this, _AllureReport_historyDataPoint, "f"));
|
|
732
|
+
if (outputDirFiles.length === 0) {
|
|
733
|
+
return;
|
|
742
734
|
}
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
735
|
+
const reportPath = join(__classPrivateFieldGet(this, _AllureReport_output, "f"), outputDirFiles[0]);
|
|
736
|
+
const reportStats = await lstat(reportPath);
|
|
737
|
+
const outputEntriesStats = await Promise.all(outputDirFiles.map((file) => lstat(join(__classPrivateFieldGet(this, _AllureReport_output, "f"), file))));
|
|
738
|
+
const outputDirectoryEntries = outputEntriesStats.filter((entry) => entry.isDirectory());
|
|
739
|
+
if (reportStats.isDirectory() && outputDirectoryEntries.length === 1) {
|
|
740
|
+
const reportContent = await readdir(reportPath);
|
|
741
|
+
for (const entry of reportContent) {
|
|
742
|
+
const currentFilePath = join(reportPath, entry);
|
|
743
|
+
const newFilePath = resolve(dirname(currentFilePath), "..", entry);
|
|
744
|
+
await rename(currentFilePath, newFilePath);
|
|
746
745
|
}
|
|
747
|
-
|
|
748
|
-
|
|
746
|
+
await rm(reportPath, { recursive: true });
|
|
747
|
+
}
|
|
748
|
+
for (const dir of __classPrivateFieldGet(this, _AllureReport_dumpTempDirs, "f")) {
|
|
749
|
+
try {
|
|
750
|
+
await rm(dir, { recursive: true });
|
|
749
751
|
}
|
|
750
|
-
|
|
751
|
-
|
|
752
|
+
catch { }
|
|
753
|
+
}
|
|
754
|
+
if (__classPrivateFieldGet(this, _AllureReport_history, "f")) {
|
|
755
|
+
try {
|
|
756
|
+
await __classPrivateFieldGet(this, _AllureReport_store, "f").appendHistory(__classPrivateFieldGet(this, _AllureReport_historyDataPoint, "f"));
|
|
757
|
+
}
|
|
758
|
+
catch (err) {
|
|
759
|
+
if (err instanceof KnownError) {
|
|
760
|
+
console.error("Failed to append history", err.message);
|
|
761
|
+
}
|
|
762
|
+
else if (err instanceof UnknownError) {
|
|
763
|
+
console.error("Failed to append history due to unexpected error", err.message);
|
|
764
|
+
}
|
|
765
|
+
else {
|
|
766
|
+
throw err;
|
|
767
|
+
}
|
|
752
768
|
}
|
|
753
769
|
}
|
|
770
|
+
if (__classPrivateFieldGet(this, _AllureReport_publishedRemoteHrefs, "f").size > 0) {
|
|
771
|
+
console.info("Next reports have been published:");
|
|
772
|
+
__classPrivateFieldGet(this, _AllureReport_publishedRemoteHrefs, "f").forEach((href) => {
|
|
773
|
+
console.info(`- ${href}`);
|
|
774
|
+
});
|
|
775
|
+
}
|
|
776
|
+
if (!__classPrivateFieldGet(this, _AllureReport_qualityGate, "f")) {
|
|
777
|
+
return;
|
|
778
|
+
}
|
|
779
|
+
const qualityGateResults = await __classPrivateFieldGet(this, _AllureReport_store, "f").qualityGateResultsByEnv();
|
|
780
|
+
await writeFile(join(__classPrivateFieldGet(this, _AllureReport_output, "f"), "quality-gate.json"), JSON.stringify(qualityGateResults));
|
|
754
781
|
}
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
__classPrivateFieldGet(this, _AllureReport_publishedRemoteHrefs, "f").forEach((href) => {
|
|
758
|
-
console.info(`- ${href}`);
|
|
759
|
-
});
|
|
760
|
-
}
|
|
761
|
-
if (!__classPrivateFieldGet(this, _AllureReport_qualityGate, "f")) {
|
|
762
|
-
return;
|
|
782
|
+
finally {
|
|
783
|
+
await __classPrivateFieldGet(this, _AllureReport_finishPerfMetrics, "f").call(this);
|
|
763
784
|
}
|
|
764
|
-
const qualityGateResults = await __classPrivateFieldGet(this, _AllureReport_store, "f").qualityGateResultsByEnv();
|
|
765
|
-
await writeFile(join(__classPrivateFieldGet(this, _AllureReport_output, "f"), "quality-gate.json"), JSON.stringify(qualityGateResults));
|
|
766
785
|
};
|
|
786
|
+
_AllureReport_finishGeneratePerfSpan.set(this, () => {
|
|
787
|
+
__classPrivateFieldGet(this, _AllureReport_endGeneratePerfSpan, "f")?.call(this);
|
|
788
|
+
__classPrivateFieldSet(this, _AllureReport_endGeneratePerfSpan, undefined, "f");
|
|
789
|
+
});
|
|
790
|
+
_AllureReport_finishPerfMetrics.set(this, async () => {
|
|
791
|
+
__classPrivateFieldGet(this, _AllureReport_finishGeneratePerfSpan, "f").call(this);
|
|
792
|
+
try {
|
|
793
|
+
await writePerfMetrics(__classPrivateFieldGet(this, _AllureReport_output, "f"));
|
|
794
|
+
}
|
|
795
|
+
catch (err) {
|
|
796
|
+
console.error("Failed to write Allure performance metrics", err);
|
|
797
|
+
}
|
|
798
|
+
});
|
|
767
799
|
_AllureReport_eachPlugin.set(this, async (initState, consumer) => {
|
|
768
800
|
if (initState) {
|
|
769
801
|
__classPrivateFieldSet(this, _AllureReport_state, {}, "f");
|
|
@@ -886,6 +918,6 @@ export class AllureReport {
|
|
|
886
918
|
return __classPrivateFieldGet(this, _AllureReport_realtimeChannel, "f").dispatcher;
|
|
887
919
|
}
|
|
888
920
|
}
|
|
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) {
|
|
921
|
+
_AllureReport_ci = new WeakMap(), _AllureReport_store = new WeakMap(), _AllureReport_readers = new WeakMap(), _AllureReport_plugins = new WeakMap(), _AllureReport_reportFiles = new WeakMap(), _AllureReport_realtimeChannel = new WeakMap(), _AllureReport_realtimeUpdateScheduler = new WeakMap(), _AllureReport_realTime = new WeakMap(), _AllureReport_hideLabels = new WeakMap(), _AllureReport_output = new WeakMap(), _AllureReport_history = new WeakMap(), _AllureReport_allureServiceClient = new WeakMap(), _AllureReport_qualityGate = new WeakMap(), _AllureReport_dump = new WeakMap(), _AllureReport_categories = new WeakMap(), _AllureReport_environments = new WeakMap(), _AllureReport_globalAttachments = new WeakMap(), _AllureReport_dumpTempDirs = new WeakMap(), _AllureReport_state = new WeakMap(), _AllureReport_executionStage = new WeakMap(), _AllureReport_historyDataPoint = new WeakMap(), _AllureReport_summaryPath = new WeakMap(), _AllureReport_summariesByPluginId = new WeakMap(), _AllureReport_publishedRemoteHrefs = new WeakMap(), _AllureReport_published = new WeakMap(), _AllureReport_endGeneratePerfSpan = new WeakMap(), _AllureReport_publish = new WeakMap(), _AllureReport_runRealtimeUpdate = new WeakMap(), _AllureReport_getReportsToPublish = new WeakMap(), _AllureReport_cleanupFailedRemoteReport = new WeakMap(), _AllureReport_logPublishError = new WeakMap(), _AllureReport_applyPublishLinksToSummaries = new WeakMap(), _AllureReport_cloneSummariesByPluginId = new WeakMap(), _AllureReport_writeSummaryFiles = new WeakMap(), _AllureReport_generateRootSummary = new WeakMap(), _AllureReport_finishGeneratePerfSpan = new WeakMap(), _AllureReport_finishPerfMetrics = new WeakMap(), _AllureReport_eachPlugin = new WeakMap(), _AllureReport_instances = new WeakSet(), _AllureReport_getPluginState = function _AllureReport_getPluginState(init, id) {
|
|
890
922
|
return init ? new DefaultPluginState({}) : __classPrivateFieldGet(this, _AllureReport_state, "f")?.[id];
|
|
891
923
|
};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
export declare const PERF_METRICS_FILE = "allure-perf-metrics.json";
|
|
2
|
+
export type PerfMetricSpan = {
|
|
3
|
+
name: string;
|
|
4
|
+
startTimeMs: number;
|
|
5
|
+
durationMs: number;
|
|
6
|
+
};
|
|
7
|
+
export type PerfMetricSummary = {
|
|
8
|
+
name: string;
|
|
9
|
+
count: number;
|
|
10
|
+
totalMs: number;
|
|
11
|
+
minMs: number;
|
|
12
|
+
maxMs: number;
|
|
13
|
+
avgMs: number;
|
|
14
|
+
};
|
|
15
|
+
export type PerfMetricsPayload = {
|
|
16
|
+
version: 1;
|
|
17
|
+
generatedAt: string;
|
|
18
|
+
timeOriginMs: number;
|
|
19
|
+
spans: PerfMetricSpan[];
|
|
20
|
+
summary: PerfMetricSummary[];
|
|
21
|
+
};
|
|
22
|
+
export declare const PERF_METRIC_NAMES: {
|
|
23
|
+
readonly restoreStateTotal: "restoreState.total";
|
|
24
|
+
readonly restoreStateDump: "restoreState.dump";
|
|
25
|
+
readonly restoreStateAttachments: "restoreState.attachments";
|
|
26
|
+
readonly restoreStateStoreRestore: "restoreState.storeRestore";
|
|
27
|
+
readonly generateTotal: "generate.total";
|
|
28
|
+
readonly generateReadResults: "generate.readResults";
|
|
29
|
+
readonly generatePluginsDone: "generate.plugins.done";
|
|
30
|
+
readonly publishUploadTotal: "publish.upload.total";
|
|
31
|
+
readonly summaryGenerate: "summary.generate";
|
|
32
|
+
};
|
|
33
|
+
export declare const PERF_METRIC_PREFIXES: {
|
|
34
|
+
readonly generatePluginDone: "generate.plugin.done.";
|
|
35
|
+
readonly publishUploadPlugin: "publish.upload.plugin.";
|
|
36
|
+
};
|
|
37
|
+
export declare const isPerfMetricsEnabled: () => boolean;
|
|
38
|
+
export declare const startPerfSpan: (name: string) => (() => void);
|
|
39
|
+
export declare const measurePerf: <T>(name: string, fn: () => Promise<T>) => Promise<T>;
|
|
40
|
+
export declare const getPerfMetricsPayload: () => PerfMetricsPayload;
|
|
41
|
+
export declare const writePerfMetrics: (output: string) => Promise<boolean>;
|
|
42
|
+
export declare const resetPerfMetrics: () => void;
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { mkdir, writeFile } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { performance } from "node:perf_hooks";
|
|
4
|
+
export const PERF_METRICS_FILE = "allure-perf-metrics.json";
|
|
5
|
+
const MARK_PREFIX = "allure:perf:";
|
|
6
|
+
const ENABLED_VALUES = new Set(["1", "true", "yes", "on"]);
|
|
7
|
+
const SPANS = [];
|
|
8
|
+
const MARKS = new Set();
|
|
9
|
+
const MEASURES = new Set();
|
|
10
|
+
let sequence = 0;
|
|
11
|
+
const round = (value) => Number(value.toFixed(3));
|
|
12
|
+
export const PERF_METRIC_NAMES = {
|
|
13
|
+
restoreStateTotal: "restoreState.total",
|
|
14
|
+
restoreStateDump: "restoreState.dump",
|
|
15
|
+
restoreStateAttachments: "restoreState.attachments",
|
|
16
|
+
restoreStateStoreRestore: "restoreState.storeRestore",
|
|
17
|
+
generateTotal: "generate.total",
|
|
18
|
+
generateReadResults: "generate.readResults",
|
|
19
|
+
generatePluginsDone: "generate.plugins.done",
|
|
20
|
+
publishUploadTotal: "publish.upload.total",
|
|
21
|
+
summaryGenerate: "summary.generate",
|
|
22
|
+
};
|
|
23
|
+
export const PERF_METRIC_PREFIXES = {
|
|
24
|
+
generatePluginDone: "generate.plugin.done.",
|
|
25
|
+
publishUploadPlugin: "publish.upload.plugin.",
|
|
26
|
+
};
|
|
27
|
+
export const isPerfMetricsEnabled = () => ENABLED_VALUES.has((process.env.ALLURE_PERF_METRICS ?? "").toLowerCase());
|
|
28
|
+
export const startPerfSpan = (name) => {
|
|
29
|
+
if (!isPerfMetricsEnabled()) {
|
|
30
|
+
return () => { };
|
|
31
|
+
}
|
|
32
|
+
const id = `${MARK_PREFIX}${sequence++}:${name}`;
|
|
33
|
+
const startMark = `${id}:start`;
|
|
34
|
+
const endMark = `${id}:end`;
|
|
35
|
+
let ended = false;
|
|
36
|
+
MARKS.add(startMark);
|
|
37
|
+
MARKS.add(endMark);
|
|
38
|
+
MEASURES.add(id);
|
|
39
|
+
performance.mark(startMark);
|
|
40
|
+
return () => {
|
|
41
|
+
if (ended) {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
ended = true;
|
|
45
|
+
performance.mark(endMark);
|
|
46
|
+
performance.measure(id, startMark, endMark);
|
|
47
|
+
const entry = performance.getEntriesByName(id, "measure").at(-1);
|
|
48
|
+
if (entry) {
|
|
49
|
+
SPANS.push({
|
|
50
|
+
name,
|
|
51
|
+
startTimeMs: round(entry.startTime),
|
|
52
|
+
durationMs: round(entry.duration),
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
performance.clearMarks(startMark);
|
|
56
|
+
performance.clearMarks(endMark);
|
|
57
|
+
performance.clearMeasures(id);
|
|
58
|
+
MARKS.delete(startMark);
|
|
59
|
+
MARKS.delete(endMark);
|
|
60
|
+
MEASURES.delete(id);
|
|
61
|
+
};
|
|
62
|
+
};
|
|
63
|
+
export const measurePerf = async (name, fn) => {
|
|
64
|
+
if (!isPerfMetricsEnabled()) {
|
|
65
|
+
return fn();
|
|
66
|
+
}
|
|
67
|
+
const end = startPerfSpan(name);
|
|
68
|
+
try {
|
|
69
|
+
return await fn();
|
|
70
|
+
}
|
|
71
|
+
finally {
|
|
72
|
+
end();
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
export const getPerfMetricsPayload = () => {
|
|
76
|
+
const byName = new Map();
|
|
77
|
+
for (const span of SPANS) {
|
|
78
|
+
const current = byName.get(span.name) ?? [];
|
|
79
|
+
current.push(span);
|
|
80
|
+
byName.set(span.name, current);
|
|
81
|
+
}
|
|
82
|
+
return {
|
|
83
|
+
version: 1,
|
|
84
|
+
generatedAt: new Date().toISOString(),
|
|
85
|
+
timeOriginMs: round(performance.timeOrigin),
|
|
86
|
+
spans: [...SPANS],
|
|
87
|
+
summary: [...byName.entries()].map(([name, group]) => {
|
|
88
|
+
const durations = group.map(({ durationMs }) => durationMs);
|
|
89
|
+
const totalMs = durations.reduce((acc, duration) => acc + duration, 0);
|
|
90
|
+
return {
|
|
91
|
+
name,
|
|
92
|
+
count: group.length,
|
|
93
|
+
totalMs: round(totalMs),
|
|
94
|
+
minMs: round(Math.min(...durations)),
|
|
95
|
+
maxMs: round(Math.max(...durations)),
|
|
96
|
+
avgMs: round(totalMs / group.length),
|
|
97
|
+
};
|
|
98
|
+
}),
|
|
99
|
+
};
|
|
100
|
+
};
|
|
101
|
+
export const writePerfMetrics = async (output) => {
|
|
102
|
+
if (!isPerfMetricsEnabled()) {
|
|
103
|
+
return false;
|
|
104
|
+
}
|
|
105
|
+
const payload = getPerfMetricsPayload();
|
|
106
|
+
await mkdir(output, { recursive: true });
|
|
107
|
+
await writeFile(join(output, PERF_METRICS_FILE), `${JSON.stringify(payload, null, 2)}\n`, "utf8");
|
|
108
|
+
resetPerfMetrics();
|
|
109
|
+
return true;
|
|
110
|
+
};
|
|
111
|
+
export const resetPerfMetrics = () => {
|
|
112
|
+
SPANS.length = 0;
|
|
113
|
+
sequence = 0;
|
|
114
|
+
for (const mark of MARKS) {
|
|
115
|
+
performance.clearMarks(mark);
|
|
116
|
+
}
|
|
117
|
+
for (const measure of MEASURES) {
|
|
118
|
+
performance.clearMeasures(measure);
|
|
119
|
+
}
|
|
120
|
+
MARKS.clear();
|
|
121
|
+
MEASURES.clear();
|
|
122
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@allurereport/core",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.11.0",
|
|
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.
|
|
29
|
-
"@allurereport/core-api": "3.
|
|
30
|
-
"@allurereport/plugin-agent": "3.
|
|
31
|
-
"@allurereport/plugin-allure2": "3.
|
|
32
|
-
"@allurereport/plugin-api": "3.
|
|
33
|
-
"@allurereport/plugin-awesome": "3.
|
|
34
|
-
"@allurereport/plugin-classic": "3.
|
|
35
|
-
"@allurereport/plugin-csv": "3.
|
|
36
|
-
"@allurereport/plugin-dashboard": "3.
|
|
37
|
-
"@allurereport/plugin-jira": "3.
|
|
38
|
-
"@allurereport/plugin-log": "3.
|
|
39
|
-
"@allurereport/plugin-progress": "3.
|
|
40
|
-
"@allurereport/plugin-slack": "3.
|
|
41
|
-
"@allurereport/plugin-testops": "3.
|
|
42
|
-
"@allurereport/plugin-testplan": "3.
|
|
43
|
-
"@allurereport/reader": "3.
|
|
44
|
-
"@allurereport/reader-api": "3.
|
|
45
|
-
"@allurereport/service": "3.
|
|
46
|
-
"@allurereport/summary": "3.
|
|
28
|
+
"@allurereport/ci": "3.11.0",
|
|
29
|
+
"@allurereport/core-api": "3.11.0",
|
|
30
|
+
"@allurereport/plugin-agent": "3.11.0",
|
|
31
|
+
"@allurereport/plugin-allure2": "3.11.0",
|
|
32
|
+
"@allurereport/plugin-api": "3.11.0",
|
|
33
|
+
"@allurereport/plugin-awesome": "3.11.0",
|
|
34
|
+
"@allurereport/plugin-classic": "3.11.0",
|
|
35
|
+
"@allurereport/plugin-csv": "3.11.0",
|
|
36
|
+
"@allurereport/plugin-dashboard": "3.11.0",
|
|
37
|
+
"@allurereport/plugin-jira": "3.11.0",
|
|
38
|
+
"@allurereport/plugin-log": "3.11.0",
|
|
39
|
+
"@allurereport/plugin-progress": "3.11.0",
|
|
40
|
+
"@allurereport/plugin-slack": "3.11.0",
|
|
41
|
+
"@allurereport/plugin-testops": "3.11.0",
|
|
42
|
+
"@allurereport/plugin-testplan": "3.11.0",
|
|
43
|
+
"@allurereport/reader": "3.11.0",
|
|
44
|
+
"@allurereport/reader-api": "3.11.0",
|
|
45
|
+
"@allurereport/service": "3.11.0",
|
|
46
|
+
"@allurereport/summary": "3.11.0",
|
|
47
47
|
"glob": "^13.0.6",
|
|
48
48
|
"handlebars": "^4.7.9",
|
|
49
49
|
"node-stream-zip": "^1.15.0",
|
|
@@ -53,15 +53,15 @@
|
|
|
53
53
|
"zip-stream": "^7.0.2"
|
|
54
54
|
},
|
|
55
55
|
"devDependencies": {
|
|
56
|
-
"@types/node": "^20
|
|
56
|
+
"@types/node": "^20",
|
|
57
57
|
"@types/zip-stream": "^7.0.0",
|
|
58
|
-
"@vitest/runner": "^2
|
|
58
|
+
"@vitest/runner": "^2",
|
|
59
59
|
"@vitest/snapshot": "^2.1.9",
|
|
60
|
-
"allure-js-commons": "^3
|
|
61
|
-
"allure-vitest": "^3
|
|
62
|
-
"rimraf": "^6
|
|
60
|
+
"allure-js-commons": "^3",
|
|
61
|
+
"allure-vitest": "^3",
|
|
62
|
+
"rimraf": "^6",
|
|
63
63
|
"tslib": "^2.7.0",
|
|
64
|
-
"typescript": "^5
|
|
65
|
-
"vitest": "^
|
|
64
|
+
"typescript": "^5",
|
|
65
|
+
"vitest": "^4.1.0"
|
|
66
66
|
}
|
|
67
67
|
}
|