@allurereport/core 3.3.1 → 3.4.1

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
@@ -12,6 +12,7 @@ export interface FullConfig {
12
12
  output: string;
13
13
  open: boolean;
14
14
  port: string | undefined;
15
+ hideLabels?: (string | RegExp)[];
15
16
  historyPath?: string;
16
17
  historyLimit?: number;
17
18
  knownIssuesPath: string;
package/dist/config.d.ts CHANGED
@@ -5,11 +5,13 @@ export interface ConfigOverride {
5
5
  output?: Config["output"];
6
6
  open?: Config["open"];
7
7
  port?: Config["port"];
8
+ hideLabels?: Config["hideLabels"];
8
9
  historyPath?: Config["historyPath"];
9
10
  historyLimit?: Config["historyLimit"];
10
11
  knownIssuesPath?: Config["knownIssuesPath"];
11
12
  plugins?: Config["plugins"];
12
13
  }
14
+ export declare const assertValidPluginId: (id: string) => void;
13
15
  export declare const getPluginId: (key: string) => string;
14
16
  export declare const findConfig: (cwd: string, configPath?: string) => Promise<string | undefined>;
15
17
  export declare const validateConfig: (config: Config) => {
package/dist/config.js CHANGED
@@ -2,11 +2,14 @@ import * as console from "node:console";
2
2
  import { readFile, stat } from "node:fs/promises";
3
3
  import { extname, resolve } from "node:path";
4
4
  import * as process from "node:process";
5
+ import { validateEnvironmentName } from "@allurereport/core-api";
5
6
  import { parse } from "yaml";
6
7
  import { readKnownIssues } from "./known.js";
7
8
  import { FileSystemReportFiles } from "./plugin.js";
9
+ import { environmentIdentityById, environmentIdentityByName, normalizeEnvironmentDescriptorMap, } from "./utils/environment.js";
8
10
  import { importWrapper } from "./utils/module.js";
9
11
  import { normalizeImportPath } from "./utils/path.js";
12
+ import { assertValidPluginIdForWindows, isWindows } from "./utils/windows.js";
10
13
  const CONFIG_FILENAMES = [
11
14
  "allurerc.js",
12
15
  "allurerc.mjs",
@@ -16,8 +19,31 @@ const CONFIG_FILENAMES = [
16
19
  "allurerc.yml",
17
20
  ];
18
21
  const DEFAULT_CONFIG = {};
22
+ export const assertValidPluginId = (id) => {
23
+ if (id.length === 0) {
24
+ throw new Error("Invalid plugin id: must not be empty");
25
+ }
26
+ if (id === "." || id === "..") {
27
+ throw new Error(`Invalid plugin id ${JSON.stringify(id)}: must not be "." or ".."`);
28
+ }
29
+ if (id.includes("..")) {
30
+ throw new Error(`Invalid plugin id ${JSON.stringify(id)}: must not contain ".."`);
31
+ }
32
+ if (/[/\\]/.test(id)) {
33
+ throw new Error(`Invalid plugin id ${JSON.stringify(id)}: must not contain path separators`);
34
+ }
35
+ if (isWindows()) {
36
+ assertValidPluginIdForWindows(id);
37
+ }
38
+ };
19
39
  export const getPluginId = (key) => {
20
- return key.replace(/^@.*\//, "").replace(/[/\\]/g, "-");
40
+ const trimmed = key.trim();
41
+ if (trimmed.length === 0) {
42
+ throw new Error(`Invalid plugin key ${JSON.stringify(key)}: must not be empty or whitespace-only`);
43
+ }
44
+ const id = trimmed.replace(/^@.*\//, "").replace(/[/\\]/g, "-");
45
+ assertValidPluginId(id);
46
+ return id;
21
47
  };
22
48
  export const findConfig = async (cwd, configPath) => {
23
49
  if (configPath) {
@@ -51,12 +77,14 @@ export const validateConfig = (config) => {
51
77
  "output",
52
78
  "open",
53
79
  "port",
80
+ "hideLabels",
54
81
  "historyPath",
55
82
  "historyLimit",
56
83
  "knownIssuesPath",
57
84
  "plugins",
58
85
  "defaultLabels",
59
86
  "variables",
87
+ "environment",
60
88
  "environments",
61
89
  "appendHistory",
62
90
  "qualityGate",
@@ -98,14 +126,42 @@ export const loadJsonConfig = async (configPath) => {
98
126
  export const loadJsConfig = async (configPath) => {
99
127
  return (await import(normalizeImportPath(configPath))).default;
100
128
  };
129
+ const resolveConfigEnvironments = (config) => {
130
+ const errors = [];
131
+ const { normalized: environments, errors: environmentErrors } = normalizeEnvironmentDescriptorMap(config.environments ?? {}, "config.environments");
132
+ let environment;
133
+ errors.push(...environmentErrors);
134
+ if (config.environment !== undefined) {
135
+ const environmentResult = validateEnvironmentName(config.environment);
136
+ if (!environmentResult.valid) {
137
+ errors.push(`environment ${environmentResult.reason}`);
138
+ }
139
+ else {
140
+ const normalizedEnvironment = environmentResult.normalized;
141
+ environment =
142
+ environmentIdentityById(environments, normalizedEnvironment)?.id ??
143
+ environmentIdentityByName(environments, normalizedEnvironment)?.id ??
144
+ normalizedEnvironment;
145
+ }
146
+ }
147
+ if (errors.length > 0) {
148
+ throw new Error(`The provided Allure config contains invalid environments: ${errors.join("; ")}`);
149
+ }
150
+ return {
151
+ environments,
152
+ environment,
153
+ };
154
+ };
101
155
  export const resolveConfig = async (config, override = {}) => {
102
156
  const validationResult = validateConfig(config);
103
157
  if (!validationResult.valid) {
104
158
  throw new Error(`The provided Allure config contains unsupported fields: ${validationResult.fields.join(", ")}`);
105
159
  }
160
+ const { environments, environment } = resolveConfigEnvironments(config);
106
161
  const name = override.name ?? config.name ?? "Allure Report";
107
162
  const open = override.open ?? config.open ?? false;
108
163
  const port = override.port ?? config.port ?? undefined;
164
+ const hideLabels = override.hideLabels ?? config.hideLabels;
109
165
  const historyPath = override.historyPath ?? config.historyPath;
110
166
  const historyLimit = override.historyLimit ?? config.historyLimit;
111
167
  const appendHistory = config.appendHistory ?? true;
@@ -113,22 +169,24 @@ export const resolveConfig = async (config, override = {}) => {
113
169
  const output = resolve(override.output ?? config.output ?? "./allure-report");
114
170
  const known = await readKnownIssues(knownIssuesPath);
115
171
  const variables = config.variables ?? {};
116
- const environments = config.environments ?? {};
117
- const plugins = Object.keys(override?.plugins ?? config?.plugins ?? {}).length === 0
172
+ const configuredPlugins = override.plugins ?? config.plugins;
173
+ const plugins = Object.keys(configuredPlugins ?? {}).length === 0
118
174
  ? {
119
175
  awesome: {
120
176
  options: {},
121
177
  },
122
178
  }
123
- : config.plugins;
179
+ : configuredPlugins;
124
180
  const pluginInstances = await resolvePlugins(plugins);
125
181
  return {
126
182
  name,
127
183
  output,
128
184
  open,
129
185
  port,
186
+ hideLabels,
130
187
  knownIssuesPath,
131
188
  known,
189
+ environment,
132
190
  variables,
133
191
  environments,
134
192
  appendHistory,
@@ -167,19 +225,26 @@ export const readConfig = async (cwd = process.cwd(), configPath, override) => {
167
225
  export const getPluginInstance = (config, predicate) => {
168
226
  return config?.plugins?.find(predicate);
169
227
  };
228
+ const isModuleNotFoundError = (err) => {
229
+ return err instanceof Error && "code" in err && err.code === "ERR_MODULE_NOT_FOUND";
230
+ };
170
231
  export const resolvePlugin = async (path) => {
171
232
  if (!path.startsWith("@allurereport/plugin-")) {
172
233
  try {
173
234
  const module = await importWrapper(`@allurereport/plugin-${path}`);
174
235
  return module.default;
175
236
  }
176
- catch (err) { }
237
+ catch (err) {
238
+ if (!isModuleNotFoundError(err)) {
239
+ throw err;
240
+ }
241
+ }
177
242
  }
178
243
  try {
179
244
  const module = await importWrapper(path);
180
245
  return module.default;
181
246
  }
182
- catch (err) {
247
+ catch {
183
248
  throw new Error(`Cannot resolve plugin: ${path}`);
184
249
  }
185
250
  };
package/dist/history.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { AllureHistory, HistoryDataPoint, TestCase, TestResult } from "@allurereport/core-api";
1
+ import { type AllureHistory, type HistoryDataPoint, type TestCase, type TestResult } from "@allurereport/core-api";
2
2
  export declare const createHistory: (reportUuid: string, reportName: string | undefined, testCases: TestCase[], testResults: TestResult[], remoteUrl?: string) => HistoryDataPoint;
3
3
  export declare class AllureLocalHistory implements AllureHistory {
4
4
  #private;
package/dist/history.js CHANGED
@@ -15,8 +15,9 @@ import { mkdir, open } from "node:fs/promises";
15
15
  import path from "node:path";
16
16
  import readline from "node:readline/promises";
17
17
  import { pipeline } from "node:stream/promises";
18
+ import { normalizeHistoryDataPointUrls, } from "@allurereport/core-api";
18
19
  import { isFileNotFoundError } from "./utils/misc.js";
19
- const createHistoryItems = (testResults) => {
20
+ const createHistoryItems = (testResults, remoteUrl) => {
20
21
  return testResults
21
22
  .filter((tr) => tr.historyId)
22
23
  .map(({ id, name, fullName, environment, historyId, status, error: { message, trace } = {}, start, stop, duration, labels, }) => {
@@ -32,7 +33,7 @@ const createHistoryItems = (testResults) => {
32
33
  stop,
33
34
  duration,
34
35
  labels,
35
- url: "",
36
+ url: remoteUrl,
36
37
  historyId: historyId,
37
38
  reportLinks: [],
38
39
  };
@@ -49,7 +50,7 @@ export const createHistory = (reportUuid, reportName = "Allure Report", testCase
49
50
  name: reportName,
50
51
  timestamp: new Date().getTime(),
51
52
  knownTestCaseIds,
52
- testResults: createHistoryItems(testResults),
53
+ testResults: createHistoryItems(testResults, remoteUrl),
53
54
  metrics: {},
54
55
  url: remoteUrl,
55
56
  };
@@ -144,7 +145,7 @@ export class AllureLocalHistory {
144
145
  .createInterface({ input: stream, terminal: false, crlfDelay: Infinity })
145
146
  .on("line", (line) => {
146
147
  if (line && line.trim().length) {
147
- const historyEntry = JSON.parse(line);
148
+ const historyEntry = normalizeHistoryDataPointUrls(JSON.parse(line));
148
149
  historyPoints.push(historyEntry);
149
150
  }
150
151
  });
@@ -157,6 +158,7 @@ export class AllureLocalHistory {
157
158
  }
158
159
  }
159
160
  async appendHistory(data) {
161
+ const normalizedData = normalizeHistoryDataPointUrls(data);
160
162
  const fullPath = path.resolve(this.params.historyPath);
161
163
  const parentDir = path.dirname(fullPath);
162
164
  const { limit } = this.params;
@@ -176,7 +178,7 @@ export class AllureLocalHistory {
176
178
  const src = historyFile.createReadStream({ start, autoClose: false });
177
179
  await pipeline(src, dst, { end: false });
178
180
  }
179
- const sources = [JSON.stringify(data), Buffer.from([0x0a])];
181
+ const sources = [JSON.stringify(normalizedData), Buffer.from([0x0a])];
180
182
  await pipeline(sources, dst);
181
183
  if (historyExists) {
182
184
  await historyFile.truncate(dst.bytesWritten);
@@ -185,7 +187,7 @@ export class AllureLocalHistory {
185
187
  finally {
186
188
  await historyFile.close();
187
189
  if (limit !== 0) {
188
- __classPrivateFieldGet(this, _AllureLocalHistory_cachedHistory, "f").push(data);
190
+ __classPrivateFieldGet(this, _AllureLocalHistory_cachedHistory, "f").push(normalizedData);
189
191
  }
190
192
  if (limit) {
191
193
  __classPrivateFieldGet(this, _AllureLocalHistory_cachedHistory, "f").splice(limit);
package/dist/index.d.ts CHANGED
@@ -4,9 +4,10 @@ export * from "./utils/crypto.js";
4
4
  export * from "./utils/path.js";
5
5
  export * from "./utils/new.js";
6
6
  export * from "./utils/flaky.js";
7
+ export * from "./utils/environment.js";
7
8
  export * from "./history.js";
8
9
  export * from "./known.js";
9
10
  export { resolveConfig, readConfig, getPluginInstance } from "./config.js";
10
11
  export * from "./report.js";
11
12
  export * from "./plugin.js";
12
- export { QualityGateState, qualityGateDefaultRules, maxFailuresRule, minTestsCountRule, successRateRule, convertQualityGateResultsToTestErrors, stringifyQualityGateResults, } from "./qualityGate/index.js";
13
+ export { QualityGateState, qualityGateDefaultRules, maxFailuresRule, minTestsCountRule, successRateRule, maxDurationRule, allTestsContainEnvRule, environmentsTestedRule, convertQualityGateResultsToTestErrors, stringifyQualityGateResults, } from "./qualityGate/index.js";
package/dist/index.js CHANGED
@@ -3,9 +3,10 @@ export * from "./utils/crypto.js";
3
3
  export * from "./utils/path.js";
4
4
  export * from "./utils/new.js";
5
5
  export * from "./utils/flaky.js";
6
+ export * from "./utils/environment.js";
6
7
  export * from "./history.js";
7
8
  export * from "./known.js";
8
9
  export { resolveConfig, readConfig, getPluginInstance } from "./config.js";
9
10
  export * from "./report.js";
10
11
  export * from "./plugin.js";
11
- export { QualityGateState, qualityGateDefaultRules, maxFailuresRule, minTestsCountRule, successRateRule, convertQualityGateResultsToTestErrors, stringifyQualityGateResults, } from "./qualityGate/index.js";
12
+ export { QualityGateState, qualityGateDefaultRules, maxFailuresRule, minTestsCountRule, successRateRule, maxDurationRule, allTestsContainEnvRule, environmentsTestedRule, convertQualityGateResultsToTestErrors, stringifyQualityGateResults, } from "./qualityGate/index.js";
package/dist/plugin.js CHANGED
@@ -13,6 +13,7 @@ var _DefaultPluginState_state, _PluginFiles_parent, _PluginFiles_pluginId, _InMe
13
13
  import { mkdir, writeFile } from "node:fs/promises";
14
14
  import { dirname, resolve } from "node:path";
15
15
  import { join as joinPosix } from "node:path/posix";
16
+ import { resolvePathUnderOutputRoot } from "./utils/safeOutputPath.js";
16
17
  export class DefaultPluginState {
17
18
  constructor(state) {
18
19
  _DefaultPluginState_state.set(this, void 0);
@@ -58,7 +59,7 @@ export class FileSystemReportFiles {
58
59
  constructor(output) {
59
60
  _FileSystemReportFiles_output.set(this, void 0);
60
61
  this.addFile = async (path, data) => {
61
- const targetPath = resolve(__classPrivateFieldGet(this, _FileSystemReportFiles_output, "f"), path);
62
+ const targetPath = resolvePathUnderOutputRoot(__classPrivateFieldGet(this, _FileSystemReportFiles_output, "f"), path);
62
63
  const targetDirPath = dirname(targetPath);
63
64
  await mkdir(targetDirPath, { recursive: true });
64
65
  await writeFile(targetPath, data, { encoding: "utf-8" });
@@ -4,7 +4,6 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
4
4
  return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
5
5
  };
6
6
  var _QualityGateState_state;
7
- import { DEFAULT_ENVIRONMENT } from "@allurereport/core-api";
8
7
  import { gray, red } from "yoctocolors";
9
8
  import { qualityGateDefaultRules } from "./rules.js";
10
9
  export const stringifyQualityGateResults = (results) => {
@@ -77,6 +76,7 @@ export class QualityGate {
77
76
  },
78
77
  expected,
79
78
  knownIssues,
79
+ environment,
80
80
  });
81
81
  if (result.success) {
82
82
  continue;
@@ -89,7 +89,7 @@ export class QualityGate {
89
89
  actual: result.actual,
90
90
  expected,
91
91
  }),
92
- environment: environment || DEFAULT_ENVIRONMENT,
92
+ environment,
93
93
  });
94
94
  if (ruleset.fastFail) {
95
95
  fastFailed = true;
@@ -3,4 +3,6 @@ export declare const maxFailuresRule: QualityGateRule<number>;
3
3
  export declare const minTestsCountRule: QualityGateRule<number>;
4
4
  export declare const successRateRule: QualityGateRule<number>;
5
5
  export declare const maxDurationRule: QualityGateRule<number>;
6
- export declare const qualityGateDefaultRules: QualityGateRule<number>[];
6
+ export declare const allTestsContainEnvRule: QualityGateRule<string>;
7
+ export declare const environmentsTestedRule: QualityGateRule<string[]>;
8
+ export declare const qualityGateDefaultRules: (QualityGateRule<number> | QualityGateRule<string> | QualityGateRule<string[]>)[];
@@ -1,11 +1,11 @@
1
- import { filterSuccessful, filterUnsuccessful } from "@allurereport/core-api";
1
+ import { filterSuccessful, filterUnknownByKnownIssues, filterUnsuccessful } from "@allurereport/core-api";
2
2
  import { bold } from "yoctocolors";
3
3
  export const maxFailuresRule = {
4
4
  rule: "maxFailures",
5
5
  message: ({ actual, expected }) => `The number of failed tests ${bold(String(actual))} exceeds the allowed threshold value ${bold(String(expected))}`,
6
6
  validate: async ({ trs, knownIssues, expected, state }) => {
7
- const knownIssuesHistoryIds = knownIssues.map(({ historyId }) => historyId);
8
- const unknown = trs.filter((tr) => !tr.historyId || !knownIssuesHistoryIds.includes(tr.historyId));
7
+ const knownIssuesHistoryIds = new Set(knownIssues.map(({ historyId }) => historyId));
8
+ const unknown = filterUnknownByKnownIssues(trs, knownIssuesHistoryIds);
9
9
  const failedTrs = unknown.filter(filterUnsuccessful);
10
10
  const actual = failedTrs.length + (state.getResult() ?? 0);
11
11
  state.setResult(actual);
@@ -31,8 +31,8 @@ export const successRateRule = {
31
31
  rule: "successRate",
32
32
  message: ({ actual, expected }) => `Success rate ${bold(String(actual))} is less, than expected ${bold(String(expected))}`,
33
33
  validate: async ({ trs, knownIssues, expected }) => {
34
- const knownIssuesHistoryIds = knownIssues.map(({ historyId }) => historyId);
35
- const unknown = trs.filter((tr) => !tr.historyId || !knownIssuesHistoryIds.includes(tr.historyId));
34
+ const knownIssuesHistoryIds = new Set(knownIssues.map(({ historyId }) => historyId));
35
+ const unknown = filterUnknownByKnownIssues(trs, knownIssuesHistoryIds);
36
36
  const passedTrs = unknown.filter(filterSuccessful);
37
37
  const rate = passedTrs.length === 0 ? 0 : passedTrs.length / unknown.length;
38
38
  return {
@@ -52,4 +52,38 @@ export const maxDurationRule = {
52
52
  };
53
53
  },
54
54
  };
55
- export const qualityGateDefaultRules = [maxFailuresRule, minTestsCountRule, successRateRule, maxDurationRule];
55
+ export const allTestsContainEnvRule = {
56
+ rule: "allTestsContainEnv",
57
+ message: ({ actual, expected }) => `Not all tests contain the required environment, ${bold(`"${expected}"`)}; ${bold(actual.length === 1 ? "one" : String(actual))} ${actual.length === 1 ? "test has" : "tests have"} different or missing environment`,
58
+ validate: async ({ trs, expected }) => {
59
+ const testsWithoutEnv = trs.filter((tr) => (tr.environment ?? "") !== expected);
60
+ const actual = testsWithoutEnv.length;
61
+ return {
62
+ success: actual === 0,
63
+ actual,
64
+ };
65
+ },
66
+ };
67
+ export const environmentsTestedRule = {
68
+ rule: "environmentsTested",
69
+ message: ({ actual, expected }) => `The following environments were not tested: "${actual.join('", "')}"; expected all of: "${expected.join('", "')}"`,
70
+ validate: async ({ trs, expected, state }) => {
71
+ const previouslyTested = new Set(state.getResult() ?? []);
72
+ const batchTested = trs.map((tr) => tr.environment).filter((env) => env != null && env !== "");
73
+ const testedEnvs = new Set([...previouslyTested, ...batchTested]);
74
+ state.setResult([...testedEnvs]);
75
+ const missing = expected.filter((env) => !testedEnvs.has(env));
76
+ return {
77
+ success: missing.length === 0,
78
+ actual: missing,
79
+ };
80
+ },
81
+ };
82
+ export const qualityGateDefaultRules = [
83
+ maxFailuresRule,
84
+ minTestsCountRule,
85
+ successRateRule,
86
+ maxDurationRule,
87
+ allTestsContainEnvRule,
88
+ environmentsTestedRule,
89
+ ];
package/dist/report.js CHANGED
@@ -9,15 +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_reportName, _AllureReport_reportVariables, _AllureReport_ci, _AllureReport_store, _AllureReport_readers, _AllureReport_plugins, _AllureReport_reportFiles, _AllureReport_eventEmitter, _AllureReport_realtimeSubscriber, _AllureReport_realtimeDispatcher, _AllureReport_realTime, _AllureReport_output, _AllureReport_history, _AllureReport_allureServiceClient, _AllureReport_qualityGate, _AllureReport_dump, _AllureReport_categories, _AllureReport_dumpTempDirs, _AllureReport_state, _AllureReport_executionStage, _AllureReport_publish_get, _AllureReport_update, _AllureReport_eachPlugin, _AllureReport_getPluginState;
13
- import { detect } from "@allurereport/ci";
14
- import { normalizeCategoriesConfig } from "@allurereport/core-api";
15
- import { AllureStoreDumpFiles, } from "@allurereport/plugin-api";
16
- import { allure1, allure2, attachments, cucumberjson, junitXml, readXcResultBundle } from "@allurereport/reader";
17
- import { PathResultFile } from "@allurereport/reader-api";
18
- import { AllureRemoteHistory, AllureServiceClient, KnownError, UnknownError } from "@allurereport/service";
19
- import { generateSummary } from "@allurereport/summary";
20
- import ZipReadStream from "node-stream-zip";
12
+ var _AllureReport_instances, _AllureReport_reportName, _AllureReport_reportVariables, _AllureReport_ci, _AllureReport_store, _AllureReport_readers, _AllureReport_plugins, _AllureReport_reportFiles, _AllureReport_eventEmitter, _AllureReport_realtimeSubscriber, _AllureReport_realtimeDispatcher, _AllureReport_realTime, _AllureReport_hideLabels, _AllureReport_output, _AllureReport_history, _AllureReport_allureServiceClient, _AllureReport_qualityGate, _AllureReport_dump, _AllureReport_categories, _AllureReport_environments, _AllureReport_dumpTempDirs, _AllureReport_state, _AllureReport_executionStage, _AllureReport_publish_get, _AllureReport_update, _AllureReport_eachPlugin, _AllureReport_getPluginState;
21
13
  import console from "node:console";
22
14
  import { randomUUID } from "node:crypto";
23
15
  import { EventEmitter } from "node:events";
@@ -26,6 +18,14 @@ import { lstat, mkdtemp, opendir, readdir, realpath, rename, rm, writeFile } fro
26
18
  import { tmpdir } from "node:os";
27
19
  import { basename, dirname, join, resolve } from "node:path";
28
20
  import { promisify } from "node:util";
21
+ import { detect } from "@allurereport/ci";
22
+ import { normalizeCategoriesConfig } from "@allurereport/core-api";
23
+ import { AllureStoreDumpFiles, } from "@allurereport/plugin-api";
24
+ import { allure1, allure2, attachments, cucumberjson, junitXml, readXcResultBundle } from "@allurereport/reader";
25
+ import { PathResultFile } from "@allurereport/reader-api";
26
+ import { AllureRemoteHistory, AllureServiceClient, KnownError, UnknownError } from "@allurereport/service";
27
+ import { generateSummary } from "@allurereport/summary";
28
+ import ZipReadStream from "node-stream-zip";
29
29
  import pLimit from "p-limit";
30
30
  import ProgressBar from "progress";
31
31
  import ZipWriteStream from "zip-stream";
@@ -33,7 +33,9 @@ import { AllureLocalHistory, createHistory } from "./history.js";
33
33
  import { DefaultPluginState, PluginFiles } from "./plugin.js";
34
34
  import { QualityGate } from "./qualityGate/index.js";
35
35
  import { DefaultAllureStore } from "./store/store.js";
36
+ import { environmentIdentityById, environmentIdentityByName } from "./utils/environment.js";
36
37
  import { RealtimeEventsDispatcher, RealtimeSubscriber } from "./utils/event.js";
38
+ import { resolveDumpAttachmentPath, UnsafeDumpPathError } from "./utils/safeDumpPath.js";
37
39
  const { version } = JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf8"));
38
40
  const initRequired = "report is not initialised. Call the start() method first.";
39
41
  export class AllureReport {
@@ -50,12 +52,14 @@ export class AllureReport {
50
52
  _AllureReport_realtimeSubscriber.set(this, void 0);
51
53
  _AllureReport_realtimeDispatcher.set(this, void 0);
52
54
  _AllureReport_realTime.set(this, void 0);
55
+ _AllureReport_hideLabels.set(this, void 0);
53
56
  _AllureReport_output.set(this, void 0);
54
57
  _AllureReport_history.set(this, void 0);
55
58
  _AllureReport_allureServiceClient.set(this, void 0);
56
59
  _AllureReport_qualityGate.set(this, void 0);
57
60
  _AllureReport_dump.set(this, void 0);
58
61
  _AllureReport_categories.set(this, void 0);
62
+ _AllureReport_environments.set(this, void 0);
59
63
  _AllureReport_dumpTempDirs.set(this, []);
60
64
  _AllureReport_state.set(this, void 0);
61
65
  _AllureReport_executionStage.set(this, "init");
@@ -102,11 +106,16 @@ export class AllureReport {
102
106
  };
103
107
  this.validate = async (params) => {
104
108
  const { trs, knownIssues, state, environment } = params;
109
+ const qualityGateEnvironment = environment === undefined
110
+ ? undefined
111
+ : (environmentIdentityById(__classPrivateFieldGet(this, _AllureReport_environments, "f"), environment)?.name ??
112
+ environmentIdentityByName(__classPrivateFieldGet(this, _AllureReport_environments, "f"), environment)?.name ??
113
+ environment);
105
114
  return __classPrivateFieldGet(this, _AllureReport_qualityGate, "f").validate({
106
115
  trs: trs.filter(Boolean),
107
116
  knownIssues,
108
117
  state,
109
- environment,
118
+ environment: qualityGateEnvironment,
110
119
  });
111
120
  };
112
121
  this.start = async () => {
@@ -299,12 +308,18 @@ export class AllureReport {
299
308
  try {
300
309
  for (const [attachmentId] of Object.entries(attachmentsEntries)) {
301
310
  const attachmentContentEntry = await dumpArchive.entryData(attachmentId);
302
- const attachmentFilePath = join(dumpTempDir, attachmentId);
311
+ const attachmentFilePath = resolveDumpAttachmentPath(dumpTempDir, attachmentId);
303
312
  await writeFile(attachmentFilePath, attachmentContentEntry);
304
313
  resultsAttachments[attachmentId] = new PathResultFile(attachmentFilePath, attachmentId);
305
314
  }
306
315
  }
307
316
  catch (err) {
317
+ if (err instanceof UnsafeDumpPathError) {
318
+ 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).`);
319
+ console.error(err.message);
320
+ console.error("Only use dump archives produced by this tool; do not load untrusted or third-party --dump zip files.");
321
+ throw err;
322
+ }
308
323
  console.error(`Can't restore state from "${dump}", continuing without it`);
309
324
  console.error(err);
310
325
  }
@@ -380,6 +395,7 @@ export class AllureReport {
380
395
  if (!summary) {
381
396
  return;
382
397
  }
398
+ summary.pluginId = context.id;
383
399
  summary.pullRequestHref = __classPrivateFieldGet(this, _AllureReport_ci, "f")?.pullRequestUrl;
384
400
  summary.jobHref = __classPrivateFieldGet(this, _AllureReport_ci, "f")?.jobRunUrl;
385
401
  if (context.publish && this.reportUrl && !cancelledPluginsIds.has(context.id)) {
@@ -496,6 +512,7 @@ export class AllureReport {
496
512
  allureVersion: version,
497
513
  reportUuid: this.reportUuid,
498
514
  reportName: __classPrivateFieldGet(this, _AllureReport_reportName, "f"),
515
+ hideLabels: __classPrivateFieldGet(this, _AllureReport_hideLabels, "f"),
499
516
  state: pluginState,
500
517
  reportFiles: pluginFiles,
501
518
  reportUrl: this.reportUrl,
@@ -515,7 +532,7 @@ export class AllureReport {
515
532
  }
516
533
  }
517
534
  });
518
- const { name, readers = [allure1, allure2, cucumberjson, junitXml, attachments], plugins = [], known, reportFiles, realTime, historyPath, historyLimit, defaultLabels = {}, variables = {}, environment, environments, output, qualityGate, dump, categories, allureService: allureServiceConfig, } = opts;
535
+ const { name, readers = [allure1, allure2, cucumberjson, junitXml, attachments], plugins = [], known, reportFiles, realTime, historyPath, historyLimit, defaultLabels = {}, variables = {}, environment, environments, output, hideLabels, qualityGate, dump, categories, allureService: allureServiceConfig, } = opts;
519
536
  __classPrivateFieldSet(this, _AllureReport_allureServiceClient, allureServiceConfig?.accessToken
520
537
  ? new AllureServiceClient(allureServiceConfig)
521
538
  : undefined, "f");
@@ -529,6 +546,8 @@ export class AllureReport {
529
546
  __classPrivateFieldSet(this, _AllureReport_realtimeSubscriber, new RealtimeSubscriber(__classPrivateFieldGet(this, _AllureReport_eventEmitter, "f")), "f");
530
547
  __classPrivateFieldSet(this, _AllureReport_realTime, realTime, "f");
531
548
  __classPrivateFieldSet(this, _AllureReport_dump, dump, "f");
549
+ __classPrivateFieldSet(this, _AllureReport_hideLabels, hideLabels, "f");
550
+ __classPrivateFieldSet(this, _AllureReport_environments, environments ?? {}, "f");
532
551
  if (qualityGate) {
533
552
  __classPrivateFieldSet(this, _AllureReport_qualityGate, new QualityGate(qualityGate), "f");
534
553
  }
@@ -574,7 +593,7 @@ export class AllureReport {
574
593
  return __classPrivateFieldGet(this, _AllureReport_realtimeDispatcher, "f");
575
594
  }
576
595
  }
577
- _AllureReport_reportName = new WeakMap(), _AllureReport_reportVariables = new WeakMap(), _AllureReport_ci = new WeakMap(), _AllureReport_store = new WeakMap(), _AllureReport_readers = new WeakMap(), _AllureReport_plugins = new WeakMap(), _AllureReport_reportFiles = new WeakMap(), _AllureReport_eventEmitter = new WeakMap(), _AllureReport_realtimeSubscriber = new WeakMap(), _AllureReport_realtimeDispatcher = new WeakMap(), _AllureReport_realTime = new WeakMap(), _AllureReport_output = new WeakMap(), _AllureReport_history = new WeakMap(), _AllureReport_allureServiceClient = new WeakMap(), _AllureReport_qualityGate = new WeakMap(), _AllureReport_dump = new WeakMap(), _AllureReport_categories = new WeakMap(), _AllureReport_dumpTempDirs = new WeakMap(), _AllureReport_state = new WeakMap(), _AllureReport_executionStage = new WeakMap(), _AllureReport_update = new WeakMap(), _AllureReport_eachPlugin = new WeakMap(), _AllureReport_instances = new WeakSet(), _AllureReport_publish_get = function _AllureReport_publish_get() {
596
+ _AllureReport_reportName = new WeakMap(), _AllureReport_reportVariables = new WeakMap(), _AllureReport_ci = new WeakMap(), _AllureReport_store = new WeakMap(), _AllureReport_readers = new WeakMap(), _AllureReport_plugins = new WeakMap(), _AllureReport_reportFiles = new WeakMap(), _AllureReport_eventEmitter = new WeakMap(), _AllureReport_realtimeSubscriber = new WeakMap(), _AllureReport_realtimeDispatcher = new WeakMap(), _AllureReport_realTime = new WeakMap(), _AllureReport_hideLabels = new WeakMap(), _AllureReport_output = new WeakMap(), _AllureReport_history = new WeakMap(), _AllureReport_allureServiceClient = new WeakMap(), _AllureReport_qualityGate = new WeakMap(), _AllureReport_dump = new WeakMap(), _AllureReport_categories = new WeakMap(), _AllureReport_environments = new WeakMap(), _AllureReport_dumpTempDirs = new WeakMap(), _AllureReport_state = new WeakMap(), _AllureReport_executionStage = new WeakMap(), _AllureReport_update = new WeakMap(), _AllureReport_eachPlugin = new WeakMap(), _AllureReport_instances = new WeakSet(), _AllureReport_publish_get = function _AllureReport_publish_get() {
578
597
  return __classPrivateFieldGet(this, _AllureReport_plugins, "f").some(({ enabled, options }) => enabled && options.publish);
579
598
  }, _AllureReport_getPluginState = function _AllureReport_getPluginState(init, id) {
580
599
  return init ? new DefaultPluginState({}) : __classPrivateFieldGet(this, _AllureReport_state, "f")?.[id];
@@ -1,7 +1,7 @@
1
+ import { randomUUID } from "node:crypto";
1
2
  import { findByLabelName, notNull } from "@allurereport/core-api";
2
3
  import { md5 } from "@allurereport/plugin-api";
3
4
  import { extension, lookupContentType } from "@allurereport/reader-api";
4
- import { randomUUID } from "node:crypto";
5
5
  const defaultStatus = "unknown";
6
6
  export const __unknown = "#___unknown_value___#";
7
7
  export const testFixtureResultRawToState = (stateData, raw, context) => {
@@ -1,4 +1,4 @@
1
- import { type AllureHistory, type AttachmentLink, type AttachmentLinkLinked, type DefaultLabelsConfig, type EnvironmentsConfig, type HistoryDataPoint, type HistoryTestResult, type KnownTestFailure, type ReportVariables, type Statistic, type TestCase, type TestEnvGroup, type TestError, type TestFixtureResult, type TestResult } from "@allurereport/core-api";
1
+ import { type AllureHistory, type AttachmentLink, type AttachmentLinkLinked, type DefaultLabelsConfig, type EnvironmentIdentity, type EnvironmentsConfig, type HistoryDataPoint, type HistoryTestResult, type KnownTestFailure, type ReportVariables, type Statistic, type TestCase, type TestEnvGroup, type TestError, type TestFixtureResult, type TestResult } from "@allurereport/core-api";
2
2
  import { type AllureStore, type AllureStoreDump, type ExitCode, type QualityGateValidationResult, type RealtimeEventsDispatcher, type RealtimeSubscriber, type ResultFile, type TestResultFilter } from "@allurereport/plugin-api";
3
3
  import type { RawFixtureResult, RawGlobals, RawMetadata, RawTestResult, ReaderContext, ResultsVisitor } from "@allurereport/reader-api";
4
4
  export declare const mapToObject: <K extends string | number | symbol, T = any>(map: Map<K, T>) => Record<K, T>;
@@ -6,6 +6,7 @@ export declare const updateMapWithRecord: <K extends string | number | symbol, T
6
6
  export declare class DefaultAllureStore implements AllureStore, ResultsVisitor {
7
7
  #private;
8
8
  readonly indexTestResultByTestCase: Map<string, TestResult[]>;
9
+ readonly indexTestResultByEnvironmentId: Map<string, TestResult[]>;
9
10
  readonly indexLatestEnvTestResultByHistoryId: Map<string, Map<string, TestResult>>;
10
11
  readonly indexTestResultByHistoryId: Map<string, TestResult[]>;
11
12
  readonly indexAttachmentByTestResult: Map<string, AttachmentLink[]>;
@@ -26,6 +27,7 @@ export declare class DefaultAllureStore implements AllureStore, ResultsVisitor {
26
27
  appendHistory(history: HistoryDataPoint): Promise<void>;
27
28
  qualityGateResults(): Promise<QualityGateValidationResult[]>;
28
29
  qualityGateResultsByEnv(): Promise<Record<string, QualityGateValidationResult[]>>;
30
+ qualityGateResultsByEnvironmentId(): Promise<Record<string, QualityGateValidationResult[]>>;
29
31
  globalExitCode(): Promise<ExitCode | undefined>;
30
32
  allGlobalErrors(): Promise<TestError[]>;
31
33
  allGlobalAttachments(): Promise<AttachmentLinkLinked[]>;
@@ -47,6 +49,7 @@ export declare class DefaultAllureStore implements AllureStore, ResultsVisitor {
47
49
  allFixtures(): Promise<TestFixtureResult[]>;
48
50
  allHistoryDataPoints(): Promise<HistoryDataPoint[]>;
49
51
  allHistoryDataPointsByEnvironment(environment: string): Promise<HistoryDataPoint[]>;
52
+ allHistoryDataPointsByEnvironmentId(environmentId: string): Promise<HistoryDataPoint[]>;
50
53
  allKnownIssues(): Promise<KnownTestFailure[]>;
51
54
  allNewTestResults(filter?: TestResultFilter, history?: HistoryDataPoint[]): Promise<TestResult[]>;
52
55
  testCaseById(tcId: string): Promise<TestCase | undefined>;
@@ -55,8 +58,9 @@ export declare class DefaultAllureStore implements AllureStore, ResultsVisitor {
55
58
  attachmentContentById(attachmentId: string): Promise<ResultFile | undefined>;
56
59
  metadataByKey<T>(key: string): Promise<T | undefined>;
57
60
  testResultsByTcId(tcId: string): Promise<TestResult[]>;
61
+ environmentIdByTrId(trId: string): Promise<string | undefined>;
58
62
  attachmentsByTrId(trId: string): Promise<AttachmentLink[]>;
59
- retriesByTr(tr: TestResult): Promise<TestResult[]>;
63
+ retriesByTr(tr?: TestResult): Promise<TestResult[]>;
60
64
  retriesByTrId(trId: string): Promise<TestResult[]>;
61
65
  historyByTr(tr: TestResult): Promise<HistoryTestResult[] | undefined>;
62
66
  historyByTrId(trId: string): Promise<HistoryTestResult[] | undefined>;
@@ -69,14 +73,21 @@ export declare class DefaultAllureStore implements AllureStore, ResultsVisitor {
69
73
  }>;
70
74
  testsStatistic(filter?: TestResultFilter): Promise<Statistic>;
71
75
  allEnvironments(): Promise<string[]>;
76
+ allEnvironmentIdentities(): Promise<EnvironmentIdentity[]>;
72
77
  testResultsByEnvironment(env: string, options?: {
73
- includeHidden: boolean;
78
+ includeHidden?: boolean;
79
+ }): Promise<TestResult[]>;
80
+ testResultsByEnvironmentId(envId: string, options?: {
81
+ includeHidden?: boolean;
74
82
  }): Promise<TestResult[]>;
75
83
  allTestEnvGroups(): Promise<TestEnvGroup[]>;
76
84
  allVariables(): Promise<ReportVariables>;
77
85
  envVariables(env: string): Promise<{
78
86
  [x: string]: string;
79
87
  }>;
88
+ envVariablesByEnvironmentId(envId: string): Promise<{
89
+ [x: string]: string;
90
+ }>;
80
91
  dumpState(): AllureStoreDump;
81
92
  restoreState(stateDump: AllureStoreDump, attachmentsContents?: Record<string, ResultFile>): Promise<void>;
82
93
  }