@allurereport/core 3.0.0-beta.14 → 3.0.0-beta.16

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/api.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { DefaultLabelsConfig, EnvironmentsConfig, HistoryDataPoint, KnownTestFailure, ReportVariables } from "@allurereport/core-api";
1
+ import type { DefaultLabelsConfig, EnvironmentsConfig, KnownTestFailure, ReportVariables } from "@allurereport/core-api";
2
2
  import type { Plugin, QualityGateConfig, ReportFiles } from "@allurereport/plugin-api";
3
3
  import type { ResultsReader } from "@allurereport/reader-api";
4
4
  export interface PluginInstance {
@@ -19,8 +19,12 @@ export interface FullConfig {
19
19
  reportFiles: ReportFiles;
20
20
  readers?: ResultsReader[];
21
21
  plugins?: PluginInstance[];
22
- history: HistoryDataPoint[];
23
22
  appendHistory?: boolean;
24
23
  known?: KnownTestFailure[];
25
24
  realTime?: any;
25
+ allureService?: {
26
+ url?: string;
27
+ project?: string;
28
+ accessToken?: string;
29
+ };
26
30
  }
package/dist/config.d.ts CHANGED
@@ -1,12 +1,13 @@
1
1
  import type { Config } from "@allurereport/plugin-api";
2
- import type { FullConfig } from "./api.js";
2
+ import type { FullConfig, PluginInstance } from "./api.js";
3
3
  export declare const getPluginId: (key: string) => string;
4
4
  export declare const findConfig: (cwd: string, configPath?: string) => Promise<string | undefined>;
5
5
  export interface ConfigOverride {
6
- name?: string;
7
- output?: string;
8
- historyPath?: string;
9
- knownIssuesPath?: string;
6
+ name?: Config["name"];
7
+ output?: Config["output"];
8
+ historyPath?: Config["historyPath"];
9
+ knownIssuesPath?: Config["knownIssuesPath"];
10
+ plugins?: Config["plugins"];
10
11
  }
11
12
  export declare const validateConfig: (config: Config) => {
12
13
  valid: boolean;
@@ -15,4 +16,26 @@ export declare const validateConfig: (config: Config) => {
15
16
  export declare const loadConfig: (configPath: string) => Promise<Config>;
16
17
  export declare const resolveConfig: (config: Config, override?: ConfigOverride) => Promise<FullConfig>;
17
18
  export declare const readConfig: (cwd?: string, configPath?: string, override?: ConfigOverride) => Promise<FullConfig>;
19
+ export declare const getPluginInstance: (config: FullConfig, predicate: (plugin: PluginInstance) => boolean) => PluginInstance | undefined;
20
+ export declare const enforcePlugin: (config: FullConfig, pluginInstance: PluginInstance) => {
21
+ name: string;
22
+ output: string;
23
+ historyPath: string;
24
+ knownIssuesPath: string;
25
+ qualityGate?: import("@allurereport/plugin-api").QualityGateConfig;
26
+ defaultLabels?: import("@allurereport/core-api").DefaultLabelsConfig;
27
+ environments?: import("@allurereport/core-api").EnvironmentsConfig;
28
+ variables?: import("@allurereport/core-api").ReportVariables;
29
+ reportFiles: import("@allurereport/plugin-api").ReportFiles;
30
+ readers?: import("@allurereport/reader-api").ResultsReader[];
31
+ plugins?: PluginInstance[];
32
+ appendHistory?: boolean;
33
+ known?: import("@allurereport/core-api").KnownTestFailure[];
34
+ realTime?: any;
35
+ allureService?: {
36
+ url?: string;
37
+ project?: string;
38
+ accessToken?: string;
39
+ };
40
+ };
18
41
  export declare const resolvePlugin: (path: string) => Promise<any>;
package/dist/config.js CHANGED
@@ -2,7 +2,6 @@ import * as console from "node:console";
2
2
  import { stat } from "node:fs/promises";
3
3
  import { resolve } from "node:path";
4
4
  import * as process from "node:process";
5
- import { readHistory } from "./history.js";
6
5
  import { readKnownIssues } from "./known.js";
7
6
  import { FileSystemReportFiles } from "./plugin.js";
8
7
  import { importWrapper } from "./utils/module.js";
@@ -50,6 +49,7 @@ export const validateConfig = (config) => {
50
49
  "variables",
51
50
  "environments",
52
51
  "appendHistory",
52
+ "allureService",
53
53
  ];
54
54
  const unsupportedFields = Object.keys(config).filter((key) => !supportedFields.includes(key));
55
55
  return {
@@ -70,11 +70,10 @@ export const resolveConfig = async (config, override = {}) => {
70
70
  const appendHistory = config.appendHistory ?? true;
71
71
  const knownIssuesPath = resolve(override.knownIssuesPath ?? config.knownIssuesPath ?? "./allure/known.json");
72
72
  const output = resolve(override.output ?? config.output ?? "./allure-report");
73
- const history = await readHistory(historyPath);
74
73
  const known = await readKnownIssues(knownIssuesPath);
75
74
  const variables = config.variables ?? {};
76
75
  const environments = config.environments ?? {};
77
- const plugins = Object.keys(config?.plugins ?? {}).length === 0
76
+ const plugins = Object.keys(override?.plugins ?? config?.plugins ?? {}).length === 0
78
77
  ? {
79
78
  awesome: {
80
79
  options: {},
@@ -85,7 +84,6 @@ export const resolveConfig = async (config, override = {}) => {
85
84
  return {
86
85
  name,
87
86
  output,
88
- history,
89
87
  historyPath,
90
88
  knownIssuesPath,
91
89
  known,
@@ -95,6 +93,7 @@ export const resolveConfig = async (config, override = {}) => {
95
93
  reportFiles: new FileSystemReportFiles(output),
96
94
  plugins: pluginInstances,
97
95
  qualityGate: config.qualityGate,
96
+ allureService: config.allureService,
98
97
  };
99
98
  };
100
99
  export const readConfig = async (cwd = process.cwd(), configPath, override) => {
@@ -102,6 +101,20 @@ export const readConfig = async (cwd = process.cwd(), configPath, override) => {
102
101
  const config = cfg ? await loadConfig(cfg) : { ...defaultConfig };
103
102
  return await resolveConfig(config, override);
104
103
  };
104
+ export const getPluginInstance = (config, predicate) => {
105
+ return config?.plugins?.find(predicate);
106
+ };
107
+ export const enforcePlugin = (config, pluginInstance) => {
108
+ const newConfig = { ...config };
109
+ const instance = getPluginInstance(newConfig, (item) => item.plugin.constructor === pluginInstance.plugin.constructor);
110
+ if (!instance) {
111
+ newConfig.plugins = [pluginInstance];
112
+ }
113
+ else {
114
+ newConfig.plugins = [instance];
115
+ }
116
+ return newConfig;
117
+ };
105
118
  export const resolvePlugin = async (path) => {
106
119
  if (!path.startsWith("@allurereport/plugin-")) {
107
120
  try {
@@ -122,9 +135,10 @@ const resolvePlugins = async (plugins) => {
122
135
  const pluginInstances = [];
123
136
  for (const id in plugins) {
124
137
  const pluginConfig = plugins[id];
138
+ const pluginId = getPluginId(id);
125
139
  const Plugin = await resolvePlugin(pluginConfig.import ?? id);
126
140
  pluginInstances.push({
127
- id: getPluginId(id),
141
+ id: pluginId,
128
142
  enabled: pluginConfig.enabled ?? true,
129
143
  options: pluginConfig.options ?? {},
130
144
  plugin: new Plugin(pluginConfig.options),
package/dist/history.d.ts CHANGED
@@ -1,4 +1,9 @@
1
- import type { HistoryDataPoint, TestCase, TestResult } from "@allurereport/core-api";
2
- export declare const createHistory: (reportUuid: string, reportName: string | undefined, testCases: TestCase[], testResults: TestResult[]) => HistoryDataPoint;
3
- export declare const readHistory: (historyPath: string) => Promise<HistoryDataPoint[]>;
1
+ import type { AllureHistory, HistoryDataPoint, TestCase, TestResult } from "@allurereport/core-api";
2
+ export declare const createHistory: (reportUuid: string, reportName: string | undefined, testCases: TestCase[], testResults: TestResult[], remoteUrl?: string) => HistoryDataPoint;
4
3
  export declare const writeHistory: (historyPath: string, data: HistoryDataPoint) => Promise<void>;
4
+ export declare class AllureLocalHistory implements AllureHistory {
5
+ private readonly historyPath;
6
+ constructor(historyPath: string);
7
+ readHistory(): Promise<HistoryDataPoint[]>;
8
+ appendHistory(data: HistoryDataPoint): Promise<void>;
9
+ }
package/dist/history.js CHANGED
@@ -20,12 +20,15 @@ const createHistoryItems = (testResults) => {
20
20
  reportLinks: [],
21
21
  };
22
22
  })
23
- .reduce((previousValue, currentValue) => {
24
- previousValue[currentValue.historyId] = currentValue;
25
- return previousValue;
23
+ .reduce((acc, item) => {
24
+ acc[item.historyId] = {
25
+ ...item,
26
+ url: "",
27
+ };
28
+ return acc;
26
29
  }, {});
27
30
  };
28
- export const createHistory = (reportUuid, reportName = "Allure Report", testCases, testResults) => {
31
+ export const createHistory = (reportUuid, reportName = "Allure Report", testCases, testResults, remoteUrl = "") => {
29
32
  const knownTestCaseIds = testCases.map((tc) => tc.id);
30
33
  return {
31
34
  uuid: reportUuid,
@@ -34,26 +37,38 @@ export const createHistory = (reportUuid, reportName = "Allure Report", testCase
34
37
  knownTestCaseIds,
35
38
  testResults: createHistoryItems(testResults),
36
39
  metrics: {},
40
+ url: remoteUrl,
37
41
  };
38
42
  };
39
- export const readHistory = async (historyPath) => {
40
- const path = resolve(historyPath);
41
- try {
42
- return (await readFile(path, { encoding: "utf-8" }))
43
- .split("\n")
44
- .filter((line) => line && line.trim() !== "")
45
- .map((line) => JSON.parse(line));
46
- }
47
- catch (e) {
48
- if (isFileNotFoundError(e)) {
49
- return [];
50
- }
51
- throw e;
52
- }
53
- };
54
43
  export const writeHistory = async (historyPath, data) => {
55
44
  const path = resolve(historyPath);
56
45
  const parentDir = dirname(path);
57
46
  await mkdir(parentDir, { recursive: true });
58
47
  await writeFile(path, `${JSON.stringify(data)}\n`, { encoding: "utf-8", flag: "a+" });
59
48
  };
49
+ export class AllureLocalHistory {
50
+ constructor(historyPath) {
51
+ this.historyPath = historyPath;
52
+ }
53
+ async readHistory() {
54
+ const path = resolve(this.historyPath);
55
+ try {
56
+ return (await readFile(path, { encoding: "utf-8" }))
57
+ .split("\n")
58
+ .filter((line) => line && line.trim() !== "")
59
+ .map((line) => JSON.parse(line));
60
+ }
61
+ catch (e) {
62
+ if (isFileNotFoundError(e)) {
63
+ return [];
64
+ }
65
+ throw e;
66
+ }
67
+ }
68
+ async appendHistory(data) {
69
+ const path = resolve(this.historyPath);
70
+ const parentDir = dirname(path);
71
+ await mkdir(parentDir, { recursive: true });
72
+ await writeFile(path, `${JSON.stringify(data)}\n`, { encoding: "utf-8", flag: "a+" });
73
+ }
74
+ }
package/dist/index.d.ts CHANGED
@@ -3,9 +3,12 @@ export * from "./utils/misc.js";
3
3
  export * from "./utils/crypto.js";
4
4
  export * from "./utils/path.js";
5
5
  export * from "./utils/stats.js";
6
+ export * from "./utils/git.js";
7
+ export * from "./utils/new.js";
8
+ export * from "./utils/flaky.js";
6
9
  export * from "./history.js";
7
10
  export * from "./known.js";
8
- export { resolveConfig, readConfig } from "./config.js";
11
+ export { resolveConfig, readConfig, getPluginInstance, enforcePlugin } from "./config.js";
9
12
  export * from "./report.js";
10
13
  export * from "./plugin.js";
11
14
  export * from "./qualityGate.js";
package/dist/index.js CHANGED
@@ -2,9 +2,12 @@ export * from "./utils/misc.js";
2
2
  export * from "./utils/crypto.js";
3
3
  export * from "./utils/path.js";
4
4
  export * from "./utils/stats.js";
5
+ export * from "./utils/git.js";
6
+ export * from "./utils/new.js";
7
+ export * from "./utils/flaky.js";
5
8
  export * from "./history.js";
6
9
  export * from "./known.js";
7
- export { resolveConfig, readConfig } from "./config.js";
10
+ export { resolveConfig, readConfig, getPluginInstance, enforcePlugin } from "./config.js";
8
11
  export * from "./report.js";
9
12
  export * from "./plugin.js";
10
13
  export * from "./qualityGate.js";
package/dist/plugin.d.ts CHANGED
@@ -3,20 +3,21 @@ export declare class DefaultPluginState implements PluginState {
3
3
  #private;
4
4
  constructor(state: Record<string, any>);
5
5
  set: (key: string, value: any) => Promise<void>;
6
- get: (key: string) => Promise<void>;
6
+ get: <T>(key: string) => Promise<T>;
7
7
  unset: (key: string) => Promise<void>;
8
8
  }
9
9
  export declare class PluginFiles implements ReportFiles {
10
10
  #private;
11
- constructor(parent: ReportFiles, pluginId: string);
12
- addFile: (key: string, data: Buffer) => Promise<void>;
11
+ readonly callback?: ((key: string, path: string) => void) | undefined;
12
+ constructor(parent: ReportFiles, pluginId: string, callback?: ((key: string, path: string) => void) | undefined);
13
+ addFile: (key: string, data: Buffer) => Promise<string>;
13
14
  }
14
15
  export declare class InMemoryReportFiles implements ReportFiles {
15
16
  #private;
16
- addFile: (path: string, data: Buffer) => Promise<void>;
17
+ addFile: (path: string, data: Buffer) => Promise<string>;
17
18
  }
18
19
  export declare class FileSystemReportFiles implements ReportFiles {
19
20
  #private;
20
21
  constructor(output: string);
21
- addFile: (path: string, data: Buffer) => Promise<void>;
22
+ addFile: (path: string, data: Buffer) => Promise<string>;
22
23
  }
package/dist/plugin.js CHANGED
@@ -30,11 +30,14 @@ export class DefaultPluginState {
30
30
  }
31
31
  _DefaultPluginState_state = new WeakMap();
32
32
  export class PluginFiles {
33
- constructor(parent, pluginId) {
33
+ constructor(parent, pluginId, callback) {
34
+ this.callback = callback;
34
35
  _PluginFiles_parent.set(this, void 0);
35
36
  _PluginFiles_pluginId.set(this, void 0);
36
37
  this.addFile = async (key, data) => {
37
- await __classPrivateFieldGet(this, _PluginFiles_parent, "f").addFile(joinPosix(__classPrivateFieldGet(this, _PluginFiles_pluginId, "f"), key), data);
38
+ const filepath = await __classPrivateFieldGet(this, _PluginFiles_parent, "f").addFile(joinPosix(__classPrivateFieldGet(this, _PluginFiles_pluginId, "f"), key), data);
39
+ this.callback?.(key, filepath);
40
+ return filepath;
38
41
  };
39
42
  __classPrivateFieldSet(this, _PluginFiles_parent, parent, "f");
40
43
  __classPrivateFieldSet(this, _PluginFiles_pluginId, pluginId, "f");
@@ -46,6 +49,7 @@ export class InMemoryReportFiles {
46
49
  _InMemoryReportFiles_state.set(this, {});
47
50
  this.addFile = async (path, data) => {
48
51
  __classPrivateFieldGet(this, _InMemoryReportFiles_state, "f")[path] = data;
52
+ return path;
49
53
  };
50
54
  }
51
55
  }
@@ -58,6 +62,7 @@ export class FileSystemReportFiles {
58
62
  const targetDirPath = dirname(targetPath);
59
63
  await mkdir(targetDirPath, { recursive: true });
60
64
  await writeFile(targetPath, data, { encoding: "utf-8" });
65
+ return targetPath;
61
66
  };
62
67
  __classPrivateFieldSet(this, _FileSystemReportFiles_output, resolve(output), "f");
63
68
  }
package/dist/report.d.ts CHANGED
@@ -3,6 +3,8 @@ import type { FullConfig } from "./api.js";
3
3
  import { DefaultAllureStore } from "./store/store.js";
4
4
  export declare class AllureReport {
5
5
  #private;
6
+ readonly reportUuid: string;
7
+ reportUrl?: string;
6
8
  constructor(opts: FullConfig);
7
9
  get store(): DefaultAllureStore;
8
10
  get exitCode(): 0 | 1;
package/dist/report.js CHANGED
@@ -9,9 +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_reportUuid, _AllureReport_reportName, _AllureReport_store, _AllureReport_readers, _AllureReport_plugins, _AllureReport_reportFiles, _AllureReport_eventEmitter, _AllureReport_events, _AllureReport_qualityGate, _AllureReport_appendHistory, _AllureReport_historyPath, _AllureReport_realTime, _AllureReport_output, _AllureReport_state, _AllureReport_stage, _AllureReport_update, _AllureReport_eachPlugin, _AllureReport_getPluginState;
12
+ var _AllureReport_instances, _AllureReport_reportName, _AllureReport_store, _AllureReport_readers, _AllureReport_plugins, _AllureReport_reportFiles, _AllureReport_eventEmitter, _AllureReport_events, _AllureReport_qualityGate, _AllureReport_realTime, _AllureReport_output, _AllureReport_history, _AllureReport_allureServiceClient, _AllureReport_state, _AllureReport_stage, _AllureReport_publish_get, _AllureReport_update, _AllureReport_eachPlugin, _AllureReport_getPluginState;
13
13
  import { allure1, allure2, attachments, cucumberjson, junitXml, readXcResultBundle } from "@allurereport/reader";
14
14
  import { PathResultFile } from "@allurereport/reader-api";
15
+ import { AllureRemoteHistory, AllureServiceClient, KnownError, UnknownError } from "@allurereport/service";
15
16
  import { generateSummary } from "@allurereport/summary";
16
17
  import console from "node:console";
17
18
  import { randomUUID } from "node:crypto";
@@ -19,7 +20,7 @@ import { EventEmitter } from "node:events";
19
20
  import { readFileSync } from "node:fs";
20
21
  import { lstat, opendir, readdir, realpath, rename, rm } from "node:fs/promises";
21
22
  import { dirname, join, resolve } from "node:path";
22
- import { createHistory, writeHistory } from "./history.js";
23
+ import { AllureLocalHistory, createHistory } from "./history.js";
23
24
  import { DefaultPluginState, PluginFiles } from "./plugin.js";
24
25
  import { QualityGate } from "./qualityGate.js";
25
26
  import { DefaultAllureStore } from "./store/store.js";
@@ -29,7 +30,6 @@ const initRequired = "report is not initialised. Call the start() method first."
29
30
  export class AllureReport {
30
31
  constructor(opts) {
31
32
  _AllureReport_instances.add(this);
32
- _AllureReport_reportUuid.set(this, void 0);
33
33
  _AllureReport_reportName.set(this, void 0);
34
34
  _AllureReport_store.set(this, void 0);
35
35
  _AllureReport_readers.set(this, void 0);
@@ -38,10 +38,10 @@ export class AllureReport {
38
38
  _AllureReport_eventEmitter.set(this, void 0);
39
39
  _AllureReport_events.set(this, void 0);
40
40
  _AllureReport_qualityGate.set(this, void 0);
41
- _AllureReport_appendHistory.set(this, void 0);
42
- _AllureReport_historyPath.set(this, void 0);
43
41
  _AllureReport_realTime.set(this, void 0);
44
42
  _AllureReport_output.set(this, void 0);
43
+ _AllureReport_history.set(this, void 0);
44
+ _AllureReport_allureServiceClient.set(this, void 0);
45
45
  _AllureReport_state.set(this, void 0);
46
46
  _AllureReport_stage.set(this, "init");
47
47
  this.readDirectory = async (resultsDir) => {
@@ -86,6 +86,7 @@ export class AllureReport {
86
86
  }
87
87
  };
88
88
  this.start = async () => {
89
+ await __classPrivateFieldGet(this, _AllureReport_store, "f").readHistory();
89
90
  if (__classPrivateFieldGet(this, _AllureReport_stage, "f") === "running") {
90
91
  throw new Error("the report is already started");
91
92
  }
@@ -93,6 +94,13 @@ export class AllureReport {
93
94
  throw new Error("the report is already stopped, the restart isn't supported at the moment");
94
95
  }
95
96
  __classPrivateFieldSet(this, _AllureReport_stage, "running", "f");
97
+ if (__classPrivateFieldGet(this, _AllureReport_allureServiceClient, "f") && __classPrivateFieldGet(this, _AllureReport_instances, "a", _AllureReport_publish_get)) {
98
+ const { url } = await __classPrivateFieldGet(this, _AllureReport_allureServiceClient, "f").createReport({
99
+ reportUuid: this.reportUuid,
100
+ reportName: __classPrivateFieldGet(this, _AllureReport_reportName, "f"),
101
+ });
102
+ this.reportUrl = url;
103
+ }
96
104
  await __classPrivateFieldGet(this, _AllureReport_eachPlugin, "f").call(this, true, async (plugin, context) => {
97
105
  await plugin.start?.(context, __classPrivateFieldGet(this, _AllureReport_store, "f"), __classPrivateFieldGet(this, _AllureReport_events, "f"));
98
106
  });
@@ -113,27 +121,51 @@ export class AllureReport {
113
121
  });
114
122
  this.done = async () => {
115
123
  const summaries = [];
124
+ const remoteHrefs = [];
116
125
  if (__classPrivateFieldGet(this, _AllureReport_stage, "f") !== "running") {
117
126
  throw new Error(initRequired);
118
127
  }
119
128
  __classPrivateFieldGet(this, _AllureReport_events, "f").offAll();
120
129
  __classPrivateFieldSet(this, _AllureReport_stage, "done", "f");
121
- await __classPrivateFieldGet(this, _AllureReport_eachPlugin, "f").call(this, false, async (plugin, context, id) => {
130
+ await __classPrivateFieldGet(this, _AllureReport_eachPlugin, "f").call(this, false, async (plugin, context) => {
122
131
  await plugin.done?.(context, __classPrivateFieldGet(this, _AllureReport_store, "f"));
132
+ if (__classPrivateFieldGet(this, _AllureReport_allureServiceClient, "f") && context.publish) {
133
+ const pluginFiles = (await context.state.get("files")) ?? {};
134
+ for (const [filename, filepath] of Object.entries(pluginFiles)) {
135
+ if (/^(data|widgets|index\.html$)/.test(filename)) {
136
+ __classPrivateFieldGet(this, _AllureReport_allureServiceClient, "f").addReportFile({
137
+ reportUuid: this.reportUuid,
138
+ pluginId: context.id,
139
+ filename,
140
+ filepath,
141
+ });
142
+ }
143
+ else {
144
+ __classPrivateFieldGet(this, _AllureReport_allureServiceClient, "f").addReportAsset({
145
+ filename,
146
+ filepath,
147
+ });
148
+ }
149
+ }
150
+ }
123
151
  const summary = await plugin?.info?.(context, __classPrivateFieldGet(this, _AllureReport_store, "f"));
124
152
  if (!summary) {
125
153
  return;
126
154
  }
155
+ if (context.publish) {
156
+ summary.remoteHref = `${this.reportUrl}/${context.id}/`;
157
+ remoteHrefs.push(summary.remoteHref);
158
+ }
127
159
  summaries.push({
128
160
  ...summary,
129
- href: `${id}/`,
161
+ href: `${context.id}/`,
130
162
  });
163
+ context.reportFiles.addFile("summary.json", Buffer.from(JSON.stringify(summary)));
131
164
  });
132
- if (__classPrivateFieldGet(this, _AllureReport_appendHistory, "f")) {
133
- const testResults = await __classPrivateFieldGet(this, _AllureReport_store, "f").allTestResults();
134
- const testCases = await __classPrivateFieldGet(this, _AllureReport_store, "f").allTestCases();
135
- const historyDataPoint = createHistory(__classPrivateFieldGet(this, _AllureReport_reportUuid, "f"), __classPrivateFieldGet(this, _AllureReport_reportName, "f"), testCases, testResults);
136
- await writeHistory(__classPrivateFieldGet(this, _AllureReport_historyPath, "f"), historyDataPoint);
165
+ if (__classPrivateFieldGet(this, _AllureReport_instances, "a", _AllureReport_publish_get)) {
166
+ await __classPrivateFieldGet(this, _AllureReport_allureServiceClient, "f")?.completeReport({
167
+ reportUuid: this.reportUuid,
168
+ });
137
169
  }
138
170
  const outputDirFiles = await readdir(__classPrivateFieldGet(this, _AllureReport_output, "f"));
139
171
  if (outputDirFiles.length === 0) {
@@ -150,37 +182,71 @@ export class AllureReport {
150
182
  await rename(currentFilePath, newFilePath);
151
183
  }
152
184
  await rm(reportPath, { recursive: true });
153
- return;
185
+ }
186
+ if (__classPrivateFieldGet(this, _AllureReport_history, "f")) {
187
+ const testResults = await __classPrivateFieldGet(this, _AllureReport_store, "f").allTestResults();
188
+ const testCases = await __classPrivateFieldGet(this, _AllureReport_store, "f").allTestCases();
189
+ const historyDataPoint = createHistory(this.reportUuid, __classPrivateFieldGet(this, _AllureReport_reportName, "f"), testCases, testResults, this.reportUrl);
190
+ try {
191
+ await __classPrivateFieldGet(this, _AllureReport_store, "f").appendHistory(historyDataPoint);
192
+ }
193
+ catch (err) {
194
+ if (err instanceof KnownError) {
195
+ console.error("Failed to append history", err.message);
196
+ }
197
+ else if (err instanceof UnknownError) {
198
+ console.error("Failed to append history due to unexpected error", err.message);
199
+ }
200
+ else {
201
+ throw err;
202
+ }
203
+ }
154
204
  }
155
205
  if (summaries.length > 1) {
156
206
  await generateSummary(__classPrivateFieldGet(this, _AllureReport_output, "f"), summaries);
157
207
  }
208
+ if (remoteHrefs.length > 0) {
209
+ console.info("Next reports have been published:");
210
+ remoteHrefs.forEach((href) => {
211
+ console.info(`- ${href}`);
212
+ });
213
+ }
158
214
  };
159
215
  _AllureReport_eachPlugin.set(this, async (initState, consumer) => {
160
216
  if (initState) {
161
217
  __classPrivateFieldSet(this, _AllureReport_state, {}, "f");
162
218
  }
163
- for (const descriptor of __classPrivateFieldGet(this, _AllureReport_plugins, "f")) {
164
- if (!descriptor.enabled) {
219
+ for (const { enabled, id, plugin, options } of __classPrivateFieldGet(this, _AllureReport_plugins, "f")) {
220
+ if (!enabled) {
165
221
  continue;
166
222
  }
167
- const id = descriptor.id;
168
- const plugin = descriptor.plugin;
169
223
  const pluginState = __classPrivateFieldGet(this, _AllureReport_instances, "m", _AllureReport_getPluginState).call(this, initState, id);
170
224
  if (!pluginState) {
171
225
  console.error("plugin error: state is empty");
172
226
  continue;
173
227
  }
174
- const pluginFiles = new PluginFiles(__classPrivateFieldGet(this, _AllureReport_reportFiles, "f"), id);
228
+ if (initState) {
229
+ await pluginState.set("files", {});
230
+ }
231
+ const pluginFiles = new PluginFiles(__classPrivateFieldGet(this, _AllureReport_reportFiles, "f"), id, async (key, filepath) => {
232
+ const currentPluginState = __classPrivateFieldGet(this, _AllureReport_instances, "m", _AllureReport_getPluginState).call(this, false, id);
233
+ const files = await currentPluginState?.get("files");
234
+ if (!files) {
235
+ return;
236
+ }
237
+ files[key] = filepath;
238
+ });
175
239
  const pluginContext = {
240
+ id,
241
+ publish: !!options?.publish,
176
242
  allureVersion: version,
177
- reportUuid: __classPrivateFieldGet(this, _AllureReport_reportUuid, "f"),
243
+ reportUuid: this.reportUuid,
178
244
  reportName: __classPrivateFieldGet(this, _AllureReport_reportName, "f"),
179
245
  state: pluginState,
180
246
  reportFiles: pluginFiles,
181
247
  };
182
248
  try {
183
- await consumer.call(this, plugin, pluginContext, id);
249
+ await consumer.call(this, plugin, pluginContext);
184
250
  if (initState) {
185
251
  __classPrivateFieldGet(this, _AllureReport_state, "f")[id] = pluginState;
186
252
  }
@@ -193,19 +259,24 @@ export class AllureReport {
193
259
  this.validate = async () => {
194
260
  await __classPrivateFieldGet(this, _AllureReport_qualityGate, "f").validate(__classPrivateFieldGet(this, _AllureReport_store, "f"));
195
261
  };
196
- const { name, readers = [allure1, allure2, cucumberjson, junitXml, attachments], plugins = [], history, known, reportFiles, qualityGate, realTime, appendHistory, historyPath, defaultLabels = {}, variables = {}, environments, output, } = opts;
197
- __classPrivateFieldSet(this, _AllureReport_reportUuid, randomUUID(), "f");
262
+ const { name, readers = [allure1, allure2, cucumberjson, junitXml, attachments], plugins = [], known, reportFiles, qualityGate, realTime, historyPath, defaultLabels = {}, variables = {}, environments, output, allureService: allureServiceConfig, } = opts;
263
+ __classPrivateFieldSet(this, _AllureReport_allureServiceClient, allureServiceConfig?.url ? new AllureServiceClient(allureServiceConfig) : undefined, "f");
264
+ this.reportUuid = randomUUID();
198
265
  __classPrivateFieldSet(this, _AllureReport_reportName, name, "f");
199
266
  __classPrivateFieldSet(this, _AllureReport_eventEmitter, new EventEmitter(), "f");
200
267
  __classPrivateFieldSet(this, _AllureReport_events, new Events(__classPrivateFieldGet(this, _AllureReport_eventEmitter, "f")), "f");
201
268
  __classPrivateFieldSet(this, _AllureReport_realTime, realTime, "f");
202
- __classPrivateFieldSet(this, _AllureReport_appendHistory, appendHistory ?? true, "f");
203
- __classPrivateFieldSet(this, _AllureReport_historyPath, historyPath, "f");
269
+ if (__classPrivateFieldGet(this, _AllureReport_allureServiceClient, "f")) {
270
+ __classPrivateFieldSet(this, _AllureReport_history, new AllureRemoteHistory(__classPrivateFieldGet(this, _AllureReport_allureServiceClient, "f")), "f");
271
+ }
272
+ else if (historyPath) {
273
+ __classPrivateFieldSet(this, _AllureReport_history, new AllureLocalHistory(historyPath), "f");
274
+ }
204
275
  __classPrivateFieldSet(this, _AllureReport_store, new DefaultAllureStore({
205
276
  eventEmitter: __classPrivateFieldGet(this, _AllureReport_eventEmitter, "f"),
206
277
  reportVariables: variables,
207
278
  environmentsConfig: environments,
208
- history,
279
+ history: __classPrivateFieldGet(this, _AllureReport_history, "f"),
209
280
  known,
210
281
  defaultLabels,
211
282
  }), "f");
@@ -214,6 +285,9 @@ export class AllureReport {
214
285
  __classPrivateFieldSet(this, _AllureReport_reportFiles, reportFiles, "f");
215
286
  __classPrivateFieldSet(this, _AllureReport_output, output, "f");
216
287
  __classPrivateFieldSet(this, _AllureReport_qualityGate, new QualityGate(qualityGate), "f");
288
+ __classPrivateFieldSet(this, _AllureReport_history, __classPrivateFieldGet(this, _AllureReport_allureServiceClient, "f")
289
+ ? new AllureRemoteHistory(__classPrivateFieldGet(this, _AllureReport_allureServiceClient, "f"))
290
+ : new AllureLocalHistory(historyPath), "f");
217
291
  }
218
292
  get store() {
219
293
  return __classPrivateFieldGet(this, _AllureReport_store, "f");
@@ -225,6 +299,8 @@ export class AllureReport {
225
299
  return __classPrivateFieldGet(this, _AllureReport_qualityGate, "f").result;
226
300
  }
227
301
  }
228
- _AllureReport_reportUuid = new WeakMap(), _AllureReport_reportName = new WeakMap(), _AllureReport_store = new WeakMap(), _AllureReport_readers = new WeakMap(), _AllureReport_plugins = new WeakMap(), _AllureReport_reportFiles = new WeakMap(), _AllureReport_eventEmitter = new WeakMap(), _AllureReport_events = new WeakMap(), _AllureReport_qualityGate = new WeakMap(), _AllureReport_appendHistory = new WeakMap(), _AllureReport_historyPath = new WeakMap(), _AllureReport_realTime = new WeakMap(), _AllureReport_output = new WeakMap(), _AllureReport_state = new WeakMap(), _AllureReport_stage = new WeakMap(), _AllureReport_update = new WeakMap(), _AllureReport_eachPlugin = new WeakMap(), _AllureReport_instances = new WeakSet(), _AllureReport_getPluginState = function _AllureReport_getPluginState(init, id) {
302
+ _AllureReport_reportName = new WeakMap(), _AllureReport_store = new WeakMap(), _AllureReport_readers = new WeakMap(), _AllureReport_plugins = new WeakMap(), _AllureReport_reportFiles = new WeakMap(), _AllureReport_eventEmitter = new WeakMap(), _AllureReport_events = new WeakMap(), _AllureReport_qualityGate = new WeakMap(), _AllureReport_realTime = new WeakMap(), _AllureReport_output = new WeakMap(), _AllureReport_history = new WeakMap(), _AllureReport_allureServiceClient = new WeakMap(), _AllureReport_state = new WeakMap(), _AllureReport_stage = new WeakMap(), _AllureReport_update = new WeakMap(), _AllureReport_eachPlugin = new WeakMap(), _AllureReport_instances = new WeakSet(), _AllureReport_publish_get = function _AllureReport_publish_get() {
303
+ return __classPrivateFieldGet(this, _AllureReport_plugins, "f").some(({ enabled, options }) => enabled && options.publish);
304
+ }, _AllureReport_getPluginState = function _AllureReport_getPluginState(init, id) {
229
305
  return init ? new DefaultPluginState({}) : __classPrivateFieldGet(this, _AllureReport_state, "f")?.[id];
230
306
  };
@@ -19,7 +19,7 @@ export const testFixtureResultRawToState = (stateData, raw, context) => {
19
19
  ...(raw.actual && raw.expected ? { expected: raw.expected, actual: raw.actual } : {}),
20
20
  },
21
21
  ...processTimings(raw),
22
- steps: convertSteps(stateData, raw.steps),
22
+ steps: convertSteps(stateData, raw.steps).convertedSteps,
23
23
  sourceMetadata: {
24
24
  readerId: context.readerId,
25
25
  metadata: context.metadata ?? {},
@@ -57,7 +57,7 @@ export const testResultRawToState = (stateData, raw, context) => {
57
57
  known: raw.known ?? false,
58
58
  hidden: false,
59
59
  labels,
60
- steps: convertSteps(stateData, raw.steps),
60
+ steps: convertSteps(stateData, raw.steps).convertedSteps,
61
61
  parameters,
62
62
  links: convertLinks(raw.links),
63
63
  hostId,
@@ -172,26 +172,46 @@ const convertLabel = (label) => {
172
172
  value: label.value,
173
173
  };
174
174
  };
175
- const convertSteps = (stateData, steps) => steps?.filter(notNull)?.map((step) => convertStep(stateData, step)) ?? [];
175
+ const convertSteps = (stateData, steps) => {
176
+ const convertedStepData = steps?.filter(notNull)?.map((step) => convertStep(stateData, step)) ?? [];
177
+ return {
178
+ convertedSteps: convertedStepData.map(({ convertedStep }) => convertedStep),
179
+ messages: new Set(convertedStepData.reduce((acc, { messages }) => {
180
+ if (messages) {
181
+ acc.push(...messages);
182
+ }
183
+ return acc;
184
+ }, [])),
185
+ };
186
+ };
176
187
  const convertStep = (stateData, step) => {
177
188
  if (step.type === "step") {
178
- const subSteps = convertSteps(stateData, step.steps);
179
- const isMessageInSubSteps = !!step.message && subSteps.some((s) => s.type === "step" && s?.message === step.message);
189
+ const { message } = step;
190
+ const { convertedSteps: subSteps, messages } = convertSteps(stateData, step.steps);
191
+ const hasSimilarErrorInSubSteps = !!message && messages.has(message);
192
+ if (message && !hasSimilarErrorInSubSteps) {
193
+ messages.add(message);
194
+ }
180
195
  return {
181
- stepId: md5(`${step.name}${step.start}`),
182
- name: step.name ?? __unknown,
183
- status: step.status ?? defaultStatus,
184
- steps: subSteps,
185
- parameters: convertParameters(step.parameters),
186
- ...processTimings(step),
187
- type: "step",
188
- hasSimilarErrorInSubSteps: isMessageInSubSteps ?? undefined,
189
- message: isMessageInSubSteps ? undefined : step.message,
190
- trace: isMessageInSubSteps ? undefined : step.trace,
196
+ convertedStep: {
197
+ stepId: md5(`${step.name}${step.start}`),
198
+ name: step.name ?? __unknown,
199
+ status: step.status ?? defaultStatus,
200
+ steps: subSteps,
201
+ parameters: convertParameters(step.parameters),
202
+ ...processTimings(step),
203
+ type: "step",
204
+ message,
205
+ trace: step.trace,
206
+ hasSimilarErrorInSubSteps,
207
+ },
208
+ messages,
191
209
  };
192
210
  }
193
211
  return {
194
- ...processAttachmentLink(stateData, step),
212
+ convertedStep: {
213
+ ...processAttachmentLink(stateData, step),
214
+ },
195
215
  };
196
216
  };
197
217
  const convertParameters = (parameters) => parameters
@@ -1,4 +1,4 @@
1
- import { type AttachmentLink, type DefaultLabelsConfig, type EnvironmentsConfig, type HistoryDataPoint, type HistoryTestResult, type KnownTestFailure, type ReportVariables, type TestCase, type TestEnvGroup, type TestFixtureResult, type TestResult } from "@allurereport/core-api";
1
+ import { type AllureHistory, type AttachmentLink, type DefaultLabelsConfig, type EnvironmentsConfig, type HistoryDataPoint, type HistoryTestResult, type KnownTestFailure, type RepoData, type ReportVariables, type TestCase, type TestEnvGroup, type TestFixtureResult, type TestResult } from "@allurereport/core-api";
2
2
  import { type AllureStore, type ResultFile, type TestResultFilter } from "@allurereport/plugin-api";
3
3
  import type { RawFixtureResult, RawMetadata, RawTestResult, ReaderContext, ResultsVisitor } from "@allurereport/reader-api";
4
4
  import type { EventEmitter } from "node:events";
@@ -13,13 +13,16 @@ export declare class DefaultAllureStore implements AllureStore, ResultsVisitor {
13
13
  readonly indexFixturesByTestResult: Map<string, TestFixtureResult[]>;
14
14
  readonly indexKnownByHistoryId: Map<string, KnownTestFailure[]>;
15
15
  constructor(params?: {
16
- history?: HistoryDataPoint[];
16
+ history?: AllureHistory;
17
17
  known?: KnownTestFailure[];
18
18
  eventEmitter?: EventEmitter<AllureStoreEvents>;
19
19
  defaultLabels?: DefaultLabelsConfig;
20
20
  environmentsConfig?: EnvironmentsConfig;
21
21
  reportVariables?: ReportVariables;
22
22
  });
23
+ readHistory(): Promise<HistoryDataPoint[]>;
24
+ appendHistory(history: HistoryDataPoint): Promise<void>;
25
+ repoData(): Promise<RepoData | undefined>;
23
26
  visitTestResult(raw: RawTestResult, context: ReaderContext): Promise<void>;
24
27
  visitTestFixtureResult(result: RawFixtureResult, context: ReaderContext): Promise<void>;
25
28
  visitAttachmentFile(resultFile: ResultFile, context: ReaderContext): Promise<void>;
@@ -9,10 +9,12 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
9
9
  if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
10
10
  return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
11
11
  };
12
- var _DefaultAllureStore_testResults, _DefaultAllureStore_attachments, _DefaultAllureStore_attachmentContents, _DefaultAllureStore_testCases, _DefaultAllureStore_metadata, _DefaultAllureStore_history, _DefaultAllureStore_known, _DefaultAllureStore_fixtures, _DefaultAllureStore_defaultLabels, _DefaultAllureStore_environmentsConfig, _DefaultAllureStore_reportVariables, _DefaultAllureStore_eventEmitter;
12
+ var _DefaultAllureStore_testResults, _DefaultAllureStore_attachments, _DefaultAllureStore_attachmentContents, _DefaultAllureStore_testCases, _DefaultAllureStore_metadata, _DefaultAllureStore_history, _DefaultAllureStore_known, _DefaultAllureStore_fixtures, _DefaultAllureStore_defaultLabels, _DefaultAllureStore_environmentsConfig, _DefaultAllureStore_reportVariables, _DefaultAllureStore_eventEmitter, _DefaultAllureStore_historyPoints, _DefaultAllureStore_repoData;
13
13
  import { compareBy, getWorstStatus, matchEnvironment, nullsLast, ordinal, reverse, } from "@allurereport/core-api";
14
14
  import { md5 } from "@allurereport/plugin-api";
15
15
  import { isFlaky } from "../utils/flaky.js";
16
+ import { getGitBranch, getGitRepoName } from "../utils/git.js";
17
+ import { getStatusTransition } from "../utils/new.js";
16
18
  import { getTestResultsStats } from "../utils/stats.js";
17
19
  import { testFixtureResultRawToState, testResultRawToState } from "./convert.js";
18
20
  const index = (indexMap, key, ...items) => {
@@ -44,14 +46,16 @@ export class DefaultAllureStore {
44
46
  this.indexAttachmentByFixture = new Map();
45
47
  this.indexFixturesByTestResult = new Map();
46
48
  this.indexKnownByHistoryId = new Map();
47
- const { history = [], known = [], eventEmitter, defaultLabels = {}, environmentsConfig = {}, reportVariables = {}, } = params ?? {};
49
+ _DefaultAllureStore_historyPoints.set(this, []);
50
+ _DefaultAllureStore_repoData.set(this, void 0);
51
+ const { history, known = [], eventEmitter, defaultLabels = {}, environmentsConfig = {}, reportVariables = {}, } = params ?? {};
48
52
  __classPrivateFieldSet(this, _DefaultAllureStore_testResults, new Map(), "f");
49
53
  __classPrivateFieldSet(this, _DefaultAllureStore_attachments, new Map(), "f");
50
54
  __classPrivateFieldSet(this, _DefaultAllureStore_attachmentContents, new Map(), "f");
51
55
  __classPrivateFieldSet(this, _DefaultAllureStore_testCases, new Map(), "f");
52
56
  __classPrivateFieldSet(this, _DefaultAllureStore_metadata, new Map(), "f");
53
57
  __classPrivateFieldSet(this, _DefaultAllureStore_fixtures, new Map(), "f");
54
- __classPrivateFieldSet(this, _DefaultAllureStore_history, [...history].sort(compareBy("timestamp", reverse(ordinal()))), "f");
58
+ __classPrivateFieldSet(this, _DefaultAllureStore_history, history, "f");
55
59
  __classPrivateFieldSet(this, _DefaultAllureStore_known, [...known], "f");
56
60
  __classPrivateFieldGet(this, _DefaultAllureStore_known, "f").forEach((ktf) => index(this.indexKnownByHistoryId, ktf.historyId, ktf));
57
61
  __classPrivateFieldSet(this, _DefaultAllureStore_eventEmitter, eventEmitter, "f");
@@ -65,6 +69,38 @@ export class DefaultAllureStore {
65
69
  this.indexLatestEnvTestResultByHistoryId.set(key, new Map());
66
70
  });
67
71
  }
72
+ async readHistory() {
73
+ if (!__classPrivateFieldGet(this, _DefaultAllureStore_history, "f")) {
74
+ return [];
75
+ }
76
+ const repoData = await this.repoData();
77
+ __classPrivateFieldSet(this, _DefaultAllureStore_historyPoints, (await __classPrivateFieldGet(this, _DefaultAllureStore_history, "f").readHistory(repoData?.branch)) ?? [], "f");
78
+ __classPrivateFieldGet(this, _DefaultAllureStore_historyPoints, "f").sort(compareBy("timestamp", reverse(ordinal())));
79
+ return __classPrivateFieldGet(this, _DefaultAllureStore_historyPoints, "f");
80
+ }
81
+ async appendHistory(history) {
82
+ if (!__classPrivateFieldGet(this, _DefaultAllureStore_history, "f")) {
83
+ return;
84
+ }
85
+ const repoData = await this.repoData();
86
+ __classPrivateFieldGet(this, _DefaultAllureStore_historyPoints, "f").push(history);
87
+ await __classPrivateFieldGet(this, _DefaultAllureStore_history, "f").appendHistory(history, repoData?.branch);
88
+ }
89
+ async repoData() {
90
+ if (__classPrivateFieldGet(this, _DefaultAllureStore_repoData, "f")) {
91
+ return __classPrivateFieldGet(this, _DefaultAllureStore_repoData, "f");
92
+ }
93
+ try {
94
+ __classPrivateFieldSet(this, _DefaultAllureStore_repoData, {
95
+ name: await getGitRepoName(),
96
+ branch: await getGitBranch(),
97
+ }, "f");
98
+ return __classPrivateFieldGet(this, _DefaultAllureStore_repoData, "f");
99
+ }
100
+ catch (err) {
101
+ return undefined;
102
+ }
103
+ }
68
104
  async visitTestResult(raw, context) {
69
105
  const attachmentLinks = [];
70
106
  const testResult = testResultRawToState({
@@ -88,6 +124,7 @@ export class DefaultAllureStore {
88
124
  }
89
125
  testResult.environment = matchEnvironment(__classPrivateFieldGet(this, _DefaultAllureStore_environmentsConfig, "f"), testResult);
90
126
  const trHistory = await this.historyByTr(testResult);
127
+ testResult.transition = getStatusTransition(testResult, trHistory);
91
128
  testResult.flaky = isFlaky(testResult, trHistory);
92
129
  __classPrivateFieldGet(this, _DefaultAllureStore_testResults, "f").set(testResult.id, testResult);
93
130
  if (testResult.historyId) {
@@ -177,7 +214,7 @@ export class DefaultAllureStore {
177
214
  return Array.from(__classPrivateFieldGet(this, _DefaultAllureStore_fixtures, "f").values());
178
215
  }
179
216
  async allHistoryDataPoints() {
180
- return __classPrivateFieldGet(this, _DefaultAllureStore_history, "f");
217
+ return __classPrivateFieldGet(this, _DefaultAllureStore_historyPoints, "f");
181
218
  }
182
219
  async allKnownIssues() {
183
220
  return __classPrivateFieldGet(this, _DefaultAllureStore_known, "f");
@@ -219,9 +256,19 @@ export class DefaultAllureStore {
219
256
  if (!tr?.historyId) {
220
257
  return [];
221
258
  }
222
- return [...__classPrivateFieldGet(this, _DefaultAllureStore_history, "f")]
259
+ return [...__classPrivateFieldGet(this, _DefaultAllureStore_historyPoints, "f")]
223
260
  .filter((dp) => !!dp.testResults[tr.historyId])
224
- .map((dp) => ({ ...dp.testResults[tr.historyId] }));
261
+ .map((dp) => {
262
+ if (!dp.url) {
263
+ return dp.testResults[tr.historyId];
264
+ }
265
+ const url = new URL(dp.url);
266
+ url.hash = tr.id;
267
+ return {
268
+ ...dp.testResults[tr.historyId],
269
+ url: url.toString(),
270
+ };
271
+ });
225
272
  }
226
273
  async historyByTrId(trId) {
227
274
  const tr = await this.testResultById(trId);
@@ -265,11 +312,9 @@ export class DefaultAllureStore {
265
312
  async testsStatistic(filter) {
266
313
  const all = await this.allTestResults();
267
314
  const allWithStats = await Promise.all(all.map(async (tr) => {
268
- const trHistory = await this.historyByTr(tr);
269
315
  const retries = await this.retriesByTr(tr);
270
316
  return {
271
317
  ...tr,
272
- flaky: isFlaky(tr, trHistory),
273
318
  retries,
274
319
  };
275
320
  }));
@@ -327,4 +372,4 @@ export class DefaultAllureStore {
327
372
  };
328
373
  }
329
374
  }
330
- _DefaultAllureStore_testResults = new WeakMap(), _DefaultAllureStore_attachments = new WeakMap(), _DefaultAllureStore_attachmentContents = new WeakMap(), _DefaultAllureStore_testCases = new WeakMap(), _DefaultAllureStore_metadata = new WeakMap(), _DefaultAllureStore_history = new WeakMap(), _DefaultAllureStore_known = new WeakMap(), _DefaultAllureStore_fixtures = new WeakMap(), _DefaultAllureStore_defaultLabels = new WeakMap(), _DefaultAllureStore_environmentsConfig = new WeakMap(), _DefaultAllureStore_reportVariables = new WeakMap(), _DefaultAllureStore_eventEmitter = new WeakMap();
375
+ _DefaultAllureStore_testResults = new WeakMap(), _DefaultAllureStore_attachments = new WeakMap(), _DefaultAllureStore_attachmentContents = new WeakMap(), _DefaultAllureStore_testCases = new WeakMap(), _DefaultAllureStore_metadata = new WeakMap(), _DefaultAllureStore_history = new WeakMap(), _DefaultAllureStore_known = new WeakMap(), _DefaultAllureStore_fixtures = new WeakMap(), _DefaultAllureStore_defaultLabels = new WeakMap(), _DefaultAllureStore_environmentsConfig = new WeakMap(), _DefaultAllureStore_reportVariables = new WeakMap(), _DefaultAllureStore_eventEmitter = new WeakMap(), _DefaultAllureStore_historyPoints = new WeakMap(), _DefaultAllureStore_repoData = new WeakMap();
@@ -4,7 +4,7 @@ const isAllureClassicFlaky = (tr, history) => {
4
4
  if (history.length === 0 || !badStatuses.includes(tr.status)) {
5
5
  return false;
6
6
  }
7
- const limitedLastHistory = history.slice(-MAX_LAST_HISTORY_SIZE);
7
+ const limitedLastHistory = history.slice(0, MAX_LAST_HISTORY_SIZE);
8
8
  const limitedLastHistoryStatuses = limitedLastHistory.map((h) => h.status);
9
9
  return (limitedLastHistoryStatuses.includes("passed") &&
10
10
  limitedLastHistoryStatuses.indexOf("passed") < limitedLastHistoryStatuses.lastIndexOf("failed"));
@@ -0,0 +1,2 @@
1
+ export declare const getGitBranch: (cwd?: string) => Promise<string>;
2
+ export declare const getGitRepoName: (cwd?: string) => Promise<string>;
@@ -0,0 +1,46 @@
1
+ import { spawn } from "node:child_process";
2
+ import { basename } from "node:path";
3
+ export const getGitBranch = (cwd) => {
4
+ return new Promise((resolve, reject) => {
5
+ const git = spawn("git", ["rev-parse", "--abbrev-ref", "HEAD"], { cwd });
6
+ let output = "";
7
+ let errorOutput = "";
8
+ git.stdout.on("data", (data) => {
9
+ output += data;
10
+ });
11
+ git.stderr.on("data", (data) => {
12
+ errorOutput += data;
13
+ });
14
+ git.on("close", (code) => {
15
+ if (code !== 0) {
16
+ return reject(new Error(errorOutput || "Git command failed"));
17
+ }
18
+ return resolve(output.trim());
19
+ });
20
+ git.on("error", (err) => {
21
+ return reject(err);
22
+ });
23
+ });
24
+ };
25
+ export const getGitRepoName = (cwd) => {
26
+ return new Promise((resolve, reject) => {
27
+ const git = spawn("git", ["rev-parse", "--show-toplevel"], { cwd });
28
+ let output = "";
29
+ let errorOutput = "";
30
+ git.stdout.on("data", (data) => {
31
+ output += data;
32
+ });
33
+ git.stderr.on("data", (data) => {
34
+ errorOutput += data;
35
+ });
36
+ git.on("close", (code) => {
37
+ if (code !== 0) {
38
+ return reject(new Error(errorOutput || "Git command failed"));
39
+ }
40
+ return resolve(basename(output.trim()));
41
+ });
42
+ git.on("error", (err) => {
43
+ return reject(err);
44
+ });
45
+ });
46
+ };
@@ -0,0 +1,4 @@
1
+ import type { HistoryTestResult, TestResult, TestStatusTransition } from "@allurereport/core-api";
2
+ export declare const isNew: (history?: HistoryTestResult[]) => boolean;
3
+ export declare const getLastSignificantStatus: (history?: HistoryTestResult[]) => string | undefined;
4
+ export declare const getStatusTransition: (tr: TestResult, history?: HistoryTestResult[]) => TestStatusTransition | undefined;
@@ -0,0 +1,23 @@
1
+ const NON_SIGNIFICANT_HISTORY_STATUSES = ["unknown", "skipped"];
2
+ export const isNew = (history = []) => history.length === 0;
3
+ const hasSignificantStatus = (htr) => !NON_SIGNIFICANT_HISTORY_STATUSES.includes(htr.status);
4
+ export const getLastSignificantStatus = (history = []) => {
5
+ const significantHtr = history.find(hasSignificantStatus);
6
+ return significantHtr?.status;
7
+ };
8
+ export const getStatusTransition = (tr, history = []) => {
9
+ if (isNew(history)) {
10
+ return "new";
11
+ }
12
+ const lastStatus = getLastSignificantStatus(history);
13
+ if (lastStatus !== tr.status) {
14
+ switch (tr.status) {
15
+ case "passed":
16
+ return "fixed";
17
+ case "failed":
18
+ return "regressed";
19
+ case "broken":
20
+ return "malfunctioned";
21
+ }
22
+ }
23
+ };
@@ -10,6 +10,9 @@ export const getTestResultsStats = (trs, filter = () => true) => {
10
10
  if (tr.flaky) {
11
11
  acc.flaky = (acc.flaky ?? 0) + 1;
12
12
  }
13
+ if (tr.transition === "new") {
14
+ acc.new = (acc.new ?? 0) + 1;
15
+ }
13
16
  if (!acc[tr.status]) {
14
17
  acc[tr.status] = 0;
15
18
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@allurereport/core",
3
- "version": "3.0.0-beta.14",
3
+ "version": "3.0.0-beta.16",
4
4
  "description": "Collection of generic Allure utilities used across the entire project",
5
5
  "keywords": [
6
6
  "allure"
@@ -25,20 +25,21 @@
25
25
  "test": "vitest run"
26
26
  },
27
27
  "dependencies": {
28
- "@allurereport/core-api": "3.0.0-beta.14",
29
- "@allurereport/plugin-allure2": "3.0.0-beta.14",
30
- "@allurereport/plugin-api": "3.0.0-beta.14",
31
- "@allurereport/plugin-awesome": "3.0.0-beta.14",
32
- "@allurereport/plugin-classic": "3.0.0-beta.14",
33
- "@allurereport/plugin-csv": "3.0.0-beta.14",
34
- "@allurereport/plugin-dashboard": "3.0.0-beta.14",
35
- "@allurereport/plugin-log": "3.0.0-beta.14",
36
- "@allurereport/plugin-progress": "3.0.0-beta.14",
37
- "@allurereport/plugin-slack": "3.0.0-beta.14",
38
- "@allurereport/plugin-testplan": "3.0.0-beta.14",
39
- "@allurereport/reader": "3.0.0-beta.14",
40
- "@allurereport/reader-api": "3.0.0-beta.14",
41
- "@allurereport/summary": "3.0.0-beta.14",
28
+ "@allurereport/core-api": "3.0.0-beta.16",
29
+ "@allurereport/plugin-allure2": "3.0.0-beta.16",
30
+ "@allurereport/plugin-api": "3.0.0-beta.16",
31
+ "@allurereport/plugin-awesome": "3.0.0-beta.16",
32
+ "@allurereport/plugin-classic": "3.0.0-beta.16",
33
+ "@allurereport/plugin-csv": "3.0.0-beta.16",
34
+ "@allurereport/plugin-dashboard": "3.0.0-beta.16",
35
+ "@allurereport/plugin-log": "3.0.0-beta.16",
36
+ "@allurereport/plugin-progress": "3.0.0-beta.16",
37
+ "@allurereport/plugin-slack": "3.0.0-beta.16",
38
+ "@allurereport/plugin-testplan": "3.0.0-beta.16",
39
+ "@allurereport/reader": "3.0.0-beta.16",
40
+ "@allurereport/reader-api": "3.0.0-beta.16",
41
+ "@allurereport/service": "3.0.0-beta.16",
42
+ "@allurereport/summary": "3.0.0-beta.16",
42
43
  "handlebars": "^4.7.8",
43
44
  "markdown-it": "^14.1.0"
44
45
  },
@@ -50,8 +51,8 @@
50
51
  "@types/node": "^20.17.9",
51
52
  "@typescript-eslint/eslint-plugin": "^8.0.0",
52
53
  "@typescript-eslint/parser": "^8.0.0",
53
- "@vitest/runner": "^2.1.8",
54
- "@vitest/snapshot": "^2.1.8",
54
+ "@vitest/runner": "^2.1.9",
55
+ "@vitest/snapshot": "^2.1.9",
55
56
  "allure-js-commons": "^3.0.9",
56
57
  "allure-vitest": "^3.0.9",
57
58
  "eslint": "^8.57.0",
@@ -64,6 +65,6 @@
64
65
  "rimraf": "^6.0.1",
65
66
  "tslib": "^2.7.0",
66
67
  "typescript": "^5.6.3",
67
- "vitest": "^2.1.8"
68
+ "vitest": "^2.1.9"
68
69
  }
69
70
  }