allure 3.14.2 → 3.15.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/README.md CHANGED
@@ -165,7 +165,7 @@ npx allure --version
165
165
 
166
166
  ## Configuration
167
167
 
168
- Allure 3 uses an `allurerc.mjs` or `allurerc.js` configuration file to manage report settings, including the report name, output directory, and plugin options.
168
+ Allure 3 uses an `allurerc.ts`, `allurerc.mts`, `allurerc.cts`, `allurerc.mjs`, or `allurerc.js` configuration file to manage report settings, including the report name, output directory, and plugin options.
169
169
 
170
170
  > [!TIP]
171
171
  > We recommend using the **Awesome** plugin for the best experience.
@@ -193,6 +193,21 @@ export default defineConfig({
193
193
 
194
194
  In this example, the generated report is named *Allure Report Example* and saved to the `./out/allure-report` directory. The **Awesome** plugin is enabled with options to produce a single-file HTML report in English.
195
195
 
196
+ ### TypeScript Configuration File
197
+
198
+ TypeScript configuration files are loaded directly by the Allure CLI, so you don't need to precompile them or install `tsx` or `ts-node`.
199
+
200
+ ```ts
201
+ import type { AllureConfig } from "allure";
202
+
203
+ export default {
204
+ name: "Allure Report Example",
205
+ output: "./out/allure-report",
206
+ } satisfies AllureConfig;
207
+ ```
208
+
209
+ For editor type checking, make sure the `allure` package is available to your project, for example as a local dev dependency. If you run Allure only as a global CLI, you can still use a TypeScript config without importing from `allure`.
210
+
196
211
  ### Configuration Options
197
212
 
198
213
  The configuration file allows you to fine-tune report generation. Key options include:
@@ -217,11 +232,11 @@ For example, setting `"reportLanguage": "fr"` will render the report interface i
217
232
 
218
233
  ### Declarative configuration format
219
234
 
220
- You can also use `allurerc.json` or `allurerc.yaml` files as a declarative way to configure Allure 3.
235
+ You can also use `allurerc.json`, `allurerc.yaml`, or `allurerc.yml` files as a declarative way to configure Allure 3.
221
236
 
222
237
  > [!WARNING]
223
238
  > Declarative formats don't support advanced features such as tests filtering or environments.
224
- > If you need these features, please consider using the `allurerc.mjs` or `allurerc.js` files.
239
+ > If you need these features, please consider using the `allurerc.ts`, `allurerc.mts`, `allurerc.cts`, `allurerc.mjs`, or `allurerc.js` files.
225
240
 
226
241
  ## Official CI/CD Integrations
227
242
 
@@ -34,7 +34,7 @@ export class Allure2Command extends Command {
34
34
  description: "The path to history file",
35
35
  });
36
36
  this.knownIssues = Option.String("--known-issues", {
37
- description: "Path to the known issues file. Updates the file and quarantines failed tests when specified",
37
+ description: "Path to known issues file",
38
38
  });
39
39
  }
40
40
  async execute() {
@@ -40,7 +40,7 @@ export class AwesomeCommand extends Command {
40
40
  description: "The path to history file",
41
41
  });
42
42
  this.knownIssues = Option.String("--known-issues", {
43
- description: "Path to the known issues file. Updates the file and quarantines failed tests when specified",
43
+ description: "Path to known issues file",
44
44
  });
45
45
  this.groupBy = Option.String("--group-by,-g", {
46
46
  description: "Group test results by labels. The labels should be separated by commas",
@@ -34,7 +34,7 @@ export class ClassicCommand extends Command {
34
34
  description: "The path to history file",
35
35
  });
36
36
  this.knownIssues = Option.String("--known-issues", {
37
- description: "Path to the known issues file. Updates the file and quarantines failed tests when specified",
37
+ description: "Path to known issues file",
38
38
  });
39
39
  }
40
40
  async execute() {
@@ -6,6 +6,7 @@ export type TestProcessResult = {
6
6
  stdout: string;
7
7
  stderr: string;
8
8
  qualityGateResults: QualityGateValidationResult[];
9
+ fastFailed: boolean;
9
10
  };
10
11
  export type RunLogsMode = "pipe" | "inherit" | "ignore";
11
12
  export declare const executeNestedAllureCommand: (params: {
@@ -7,6 +7,7 @@ import process from "node:process";
7
7
  import { QualityGateState, stringifyQualityGateResults } from "@allurereport/core";
8
8
  import { createTestPlan } from "@allurereport/core-api";
9
9
  import { allureResultsDirectoriesWatcher, delayedFileProcessingWatcher, newFilesInDirectoryWatcher, } from "@allurereport/directory-watcher";
10
+ import { formatProcessLogAttachmentName } from "@allurereport/plugin-agent";
10
11
  import { BufferResultFile, PathResultFile } from "@allurereport/reader-api";
11
12
  import { KnownError } from "@allurereport/service";
12
13
  import { red } from "yoctocolors";
@@ -68,10 +69,14 @@ export const runTests = async (params) => {
68
69
  const qualityGateState = new QualityGateState();
69
70
  let qualityGateUnsub;
70
71
  let qualityGateResults = [];
72
+ let fastFailTriggered = false;
71
73
  let testProcessStdout = "";
72
74
  let testProcessStderr = "";
73
75
  if (withQualityGate) {
74
76
  qualityGateUnsub = allureReport.realtimeSubscriber.onTestResults(async (testResults) => {
77
+ if (fastFailTriggered) {
78
+ return;
79
+ }
75
80
  const trs = await Promise.all(testResults.map((tr) => allureReport.store.testResultById(tr)));
76
81
  const filteredTrs = trs.filter((tr) => tr !== undefined);
77
82
  if (!filteredTrs.length) {
@@ -86,8 +91,10 @@ export const runTests = async (params) => {
86
91
  if (!fastFailed) {
87
92
  return;
88
93
  }
89
- allureReport.realtimeDispatcher.sendQualityGateResults(results);
94
+ qualityGateUnsub?.();
95
+ fastFailTriggered = true;
90
96
  qualityGateResults = results;
97
+ qualityGateUnsub = undefined;
91
98
  try {
92
99
  await stopProcessTree(testProcess.pid);
93
100
  }
@@ -137,6 +144,7 @@ export const runTests = async (params) => {
137
144
  stdout: testProcessStdout,
138
145
  stderr: testProcessStderr,
139
146
  qualityGateResults,
147
+ fastFailed: fastFailTriggered,
140
148
  };
141
149
  };
142
150
  export const executeAllureRun = async (params) => {
@@ -162,8 +170,13 @@ export const executeAllureRun = async (params) => {
162
170
  withQualityGate,
163
171
  logProcessExit,
164
172
  });
165
- for (let rerun = 0; rerun < maxRerun; rerun++) {
166
- const failed = await allureReport.store.failedTestResults();
173
+ const allFailuresAfterInitialRun = await allureReport.store.failedTestResults();
174
+ const blockingFailuresAfterInitialRun = await allureReport.store.blockingFailedTestResults();
175
+ if (allFailuresAfterInitialRun.length > 0 && blockingFailuresAfterInitialRun.length === 0 && testProcessResult) {
176
+ globalExitCode.actual = 0;
177
+ }
178
+ for (let rerun = 0; rerun < maxRerun && testProcessResult && !testProcessResult.fastFailed; rerun++) {
179
+ const failed = await allureReport.store.blockingFailedTestResults();
167
180
  if (failed.length === 0) {
168
181
  console.log("no failed tests is detected.");
169
182
  break;
@@ -194,6 +207,11 @@ export const executeAllureRun = async (params) => {
194
207
  await rm(tmpDir, { recursive: true });
195
208
  logTests(await allureReport.store.allTestResults());
196
209
  }
210
+ const allFailuresAfterReruns = await allureReport.store.failedTestResults();
211
+ const blockingFailuresAfterReruns = await allureReport.store.blockingFailedTestResults();
212
+ if (allFailuresAfterReruns.length > 0 && blockingFailuresAfterReruns.length === 0 && testProcessResult) {
213
+ globalExitCode.actual = 0;
214
+ }
197
215
  const trs = await allureReport.store.allTestResults({ includeRetries: false });
198
216
  qualityGateResults = testProcessResult?.qualityGateResults ?? [];
199
217
  if (withQualityGate && !qualityGateResults.length) {
@@ -235,13 +253,13 @@ export const executeAllureRun = async (params) => {
235
253
  const fileName = randomUUID();
236
254
  const stdoutResultFile = new BufferResultFile(Buffer.from(testProcessResult.stdout, "utf8"), `${fileName}`);
237
255
  stdoutResultFile.contentType = "text/plain";
238
- allureReport.realtimeDispatcher.sendGlobalAttachment(stdoutResultFile, "stdout.txt");
256
+ allureReport.realtimeDispatcher.sendGlobalAttachment(stdoutResultFile, formatProcessLogAttachmentName([command, ...commandArgs].join(" "), "stdout"));
239
257
  }
240
258
  if (!ignoreLogs && testProcessResult?.stderr) {
241
259
  const fileName = randomUUID();
242
260
  const stderrResultFile = new BufferResultFile(Buffer.from(testProcessResult.stderr, "utf8"), fileName);
243
261
  stderrResultFile.contentType = "text/plain";
244
- allureReport.realtimeDispatcher.sendGlobalAttachment(stderrResultFile, "stderr.txt");
262
+ allureReport.realtimeDispatcher.sendGlobalAttachment(stderrResultFile, formatProcessLogAttachmentName([command, ...commandArgs].join(" "), "stderr"));
245
263
  if (processFailed) {
246
264
  allureReport.realtimeDispatcher.sendGlobalError({
247
265
  message: "Test process has failed",
@@ -29,7 +29,7 @@ export class CsvCommand extends Command {
29
29
  description: "The csv separator",
30
30
  });
31
31
  this.knownIssues = Option.String("--known-issues", {
32
- description: "Path to the known issues file. Updates the file and quarantines failed tests when specified",
32
+ description: "Path to known issues file",
33
33
  });
34
34
  }
35
35
  async execute() {
@@ -12,5 +12,6 @@ export declare class GenerateCommand extends Command {
12
12
  port: string | undefined;
13
13
  historyLimit: string | undefined;
14
14
  hideLabels: string[] | undefined;
15
+ knownIssues: string | undefined;
15
16
  execute(): Promise<void>;
16
17
  }
@@ -38,6 +38,9 @@ export class GenerateCommand extends Command {
38
38
  this.hideLabels = Option.Array("--hide-labels", {
39
39
  description: "Hide labels by exact name in generated reports. Repeat the option for multiple labels",
40
40
  });
41
+ this.knownIssues = Option.String("--known-issues", {
42
+ description: "Path to known issues file",
43
+ });
41
44
  }
42
45
  async execute() {
43
46
  const cwd = this.cwd ?? processCwd();
@@ -48,7 +51,8 @@ export class GenerateCommand extends Command {
48
51
  open: this.open,
49
52
  port: this.port,
50
53
  hideLabels,
51
- historyLimit: this.historyLimit ? parseInt(this.historyLimit, 10) : undefined,
54
+ historyLimit: this.historyLimit !== undefined ? parseInt(this.historyLimit, 10) : undefined,
55
+ knownIssuesPath: this.knownIssues,
52
56
  });
53
57
  await generate({
54
58
  dump: this.dump,
@@ -7,7 +7,6 @@ export * from "./awesome.js";
7
7
  export * from "./csv.js";
8
8
  export * from "./check.js";
9
9
  export * from "./history.js";
10
- export * from "./knownIssue.js";
11
10
  export * from "./run.js";
12
11
  export * from "./slack.js";
13
12
  export * from "./testplan.js";
@@ -7,7 +7,6 @@ export * from "./awesome.js";
7
7
  export * from "./csv.js";
8
8
  export * from "./check.js";
9
9
  export * from "./history.js";
10
- export * from "./knownIssue.js";
11
10
  export * from "./run.js";
12
11
  export * from "./slack.js";
13
12
  export * from "./testplan.js";
@@ -32,7 +32,7 @@ export class QualityGateCommand extends Command {
32
32
  validator: typanion.isNumber(),
33
33
  });
34
34
  this.knownIssues = Option.String("--known-issues", {
35
- description: "Path to the known issues file. Updates the file and quarantines failed tests when specified",
35
+ description: "Path to known issues file",
36
36
  });
37
37
  this.environment = environmentOption();
38
38
  this.environmentName = environmentNameOption();
@@ -47,9 +47,9 @@ export class QualityGateCommand extends Command {
47
47
  };
48
48
  normalizeCommandEnvironmentOptions(environmentOptions);
49
49
  const cwd = await realpath(this.cwd ?? processCwd());
50
- const { maxFailures, minTestsCount, successRate, fastFail, knownIssues: knownIssuesPath } = this;
50
+ const { maxFailures, minTestsCount, successRate, fastFail } = this;
51
51
  const config = await readConfig(cwd, this.config, {
52
- knownIssuesPath,
52
+ knownIssuesPath: this.knownIssues,
53
53
  });
54
54
  const resolvedEnvironment = resolveCommandEnvironment(config, environmentOptions);
55
55
  const rules = {};
@@ -16,6 +16,7 @@ export declare class RunCommand extends Command {
16
16
  environmentName: string | undefined;
17
17
  historyLimit: string | undefined;
18
18
  hideLabels: string[] | undefined;
19
+ knownIssues: string | undefined;
19
20
  commandToRun: string[];
20
21
  get logs(): "pipe" | "inherit" | "ignore";
21
22
  execute(): Promise<void>;
@@ -49,6 +49,9 @@ export class RunCommand extends Command {
49
49
  this.hideLabels = Option.Array("--hide-labels", {
50
50
  description: "Hide labels by exact name in generated reports. Repeat the option for multiple labels",
51
51
  });
52
+ this.knownIssues = Option.String("--known-issues", {
53
+ description: "Path to known issues file",
54
+ });
52
55
  this.commandToRun = Option.Rest();
53
56
  }
54
57
  get logs() {
@@ -94,7 +97,8 @@ export class RunCommand extends Command {
94
97
  open: this.open,
95
98
  port: this.port,
96
99
  hideLabels,
97
- historyLimit: this.historyLimit ? parseInt(this.historyLimit, 10) : undefined,
100
+ historyLimit: this.historyLimit !== undefined ? parseInt(this.historyLimit, 10) : undefined,
101
+ knownIssuesPath: this.knownIssues,
98
102
  });
99
103
  const resolvedEnvironment = resolveCommandEnvironment(config, environmentOptions);
100
104
  const withRerun = maxRerun > 0;
@@ -9,5 +9,6 @@ export declare class WatchCommand extends Command {
9
9
  reportName: string | undefined;
10
10
  open: boolean | undefined;
11
11
  port: string | undefined;
12
+ preserve: boolean | undefined;
12
13
  execute(): Promise<void>;
13
14
  }
@@ -37,6 +37,9 @@ export class WatchCommand extends Command {
37
37
  this.port = Option.String("--port", {
38
38
  description: "The port to serve the reports on (default: random port)",
39
39
  });
40
+ this.preserve = Option.Boolean("--preserve", {
41
+ description: "Don't clear terminal output on the data refresh",
42
+ });
40
43
  }
41
44
  async execute() {
42
45
  const cwd = await realpath(this.cwd ?? process.cwd());
@@ -93,7 +96,7 @@ export class WatchCommand extends Command {
93
96
  id: "watch log",
94
97
  enabled: true,
95
98
  options: {},
96
- plugin: new ProgressPlugin(),
99
+ plugin: new ProgressPlugin({ preserve: this.preserve }),
97
100
  },
98
101
  {
99
102
  id: "server reload",
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { readFileSync } from "node:fs";
2
2
  import process, { argv } from "node:process";
3
3
  import { Builtins, Cli } from "clipanion";
4
- import { AgentCommand, AGENT_TASK_MAP_HELP, AgentCapabilitiesCommand, AgentInspectCommand, AgentLatestCommand, AgentQueryCommand, AgentSelectCommand, AgentStateDirCommand, Allure2Command, AwesomeCommand, CheckCommand, ClassicCommand, CsvCommand, DashboardCommand, GenerateCommand, HistoryCommand, JiraClearCommand, KnownIssueCommand, LogCommand, OpenCommand, QualityGateCommand, ResultsPackCommand, ResultsUnpackCommand, RunCommand, SlackCommand, TestPlanCommand, WatchCommand, isAgentTaskMapHelpRequest, } from "./commands/index.js";
4
+ import { AgentCommand, AGENT_TASK_MAP_HELP, AgentCapabilitiesCommand, AgentInspectCommand, AgentLatestCommand, AgentQueryCommand, AgentSelectCommand, AgentStateDirCommand, Allure2Command, AwesomeCommand, CheckCommand, ClassicCommand, CsvCommand, DashboardCommand, GenerateCommand, HistoryCommand, JiraClearCommand, LogCommand, OpenCommand, QualityGateCommand, ResultsPackCommand, ResultsUnpackCommand, RunCommand, SlackCommand, TestPlanCommand, WatchCommand, isAgentTaskMapHelpRequest, } from "./commands/index.js";
5
5
  const [node, app, ...args] = argv;
6
6
  const pkg = JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf8"));
7
7
  const cli = new Cli({
@@ -25,7 +25,6 @@ cli.register(DashboardCommand);
25
25
  cli.register(GenerateCommand);
26
26
  cli.register(HistoryCommand);
27
27
  cli.register(JiraClearCommand);
28
- cli.register(KnownIssueCommand);
29
28
  cli.register(LogCommand);
30
29
  cli.register(OpenCommand);
31
30
  cli.register(QualityGateCommand);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "allure",
3
- "version": "3.14.2",
3
+ "version": "3.15.0",
4
4
  "description": "Allure Commandline Tool",
5
5
  "keywords": [
6
6
  "allure",
@@ -32,33 +32,33 @@
32
32
  "lint:fix": "oxlint --import-plugin --fix src test features stories"
33
33
  },
34
34
  "dependencies": {
35
- "@allurereport/charts-api": "3.14.2",
36
- "@allurereport/ci": "3.14.2",
37
- "@allurereport/core": "3.14.2",
38
- "@allurereport/core-api": "3.14.2",
39
- "@allurereport/directory-watcher": "3.14.2",
40
- "@allurereport/plugin-agent": "3.14.2",
41
- "@allurereport/plugin-allure2": "3.14.2",
42
- "@allurereport/plugin-api": "3.14.2",
43
- "@allurereport/plugin-awesome": "3.14.2",
44
- "@allurereport/plugin-classic": "3.14.2",
45
- "@allurereport/plugin-csv": "3.14.2",
46
- "@allurereport/plugin-dashboard": "3.14.2",
47
- "@allurereport/plugin-jira": "3.14.2",
48
- "@allurereport/plugin-log": "3.14.2",
49
- "@allurereport/plugin-progress": "3.14.2",
50
- "@allurereport/plugin-server-reload": "3.14.2",
51
- "@allurereport/plugin-slack": "3.14.2",
52
- "@allurereport/reader-api": "3.14.2",
53
- "@allurereport/service": "3.14.2",
54
- "@allurereport/static-server": "3.14.2",
55
- "adm-zip": "^0.5.16",
35
+ "@allurereport/charts-api": "3.15.0",
36
+ "@allurereport/ci": "3.15.0",
37
+ "@allurereport/core": "3.15.0",
38
+ "@allurereport/core-api": "3.15.0",
39
+ "@allurereport/directory-watcher": "3.15.0",
40
+ "@allurereport/plugin-agent": "3.15.0",
41
+ "@allurereport/plugin-allure2": "3.15.0",
42
+ "@allurereport/plugin-api": "3.15.0",
43
+ "@allurereport/plugin-awesome": "3.15.0",
44
+ "@allurereport/plugin-classic": "3.15.0",
45
+ "@allurereport/plugin-csv": "3.15.0",
46
+ "@allurereport/plugin-dashboard": "3.15.0",
47
+ "@allurereport/plugin-jira": "3.15.0",
48
+ "@allurereport/plugin-log": "3.15.0",
49
+ "@allurereport/plugin-progress": "3.15.0",
50
+ "@allurereport/plugin-server-reload": "3.15.0",
51
+ "@allurereport/plugin-slack": "3.15.0",
52
+ "@allurereport/reader-api": "3.15.0",
53
+ "@allurereport/service": "3.15.0",
54
+ "@allurereport/static-server": "3.15.0",
55
+ "adm-zip": "^0.6.0",
56
56
  "clipanion": "^4.0.0-rc.4",
57
57
  "glob": "^13.0.6",
58
58
  "lodash.omit": "^4.18.0",
59
59
  "prompts": "^2.4.2",
60
60
  "typanion": "^3.14.0",
61
- "yoctocolors": "^2.1.1"
61
+ "yoctocolors": "^2.1.2"
62
62
  },
63
63
  "devDependencies": {
64
64
  "@types/adm-zip": "^0",
@@ -1,8 +0,0 @@
1
- import { Command } from "clipanion";
2
- export declare class KnownIssueCommand extends Command {
3
- static paths: string[][];
4
- static usage: import("clipanion").Usage;
5
- resultsDir: string[];
6
- output: string | undefined;
7
- execute(): Promise<void>;
8
- }
@@ -1,59 +0,0 @@
1
- import * as console from "node:console";
2
- import { resolve } from "node:path";
3
- import process, { exit } from "node:process";
4
- import { AllureReport, resolveConfig, writeKnownIssues } from "@allurereport/core";
5
- import { Command, Option } from "clipanion";
6
- import { red } from "yoctocolors";
7
- import { findAllureResultDirectories } from "../utils/fileSystem.js";
8
- export class KnownIssueCommand extends Command {
9
- constructor() {
10
- super(...arguments);
11
- this.resultsDir = Option.Rest({
12
- name: "Patterns to match test results directories in the current working directory (default: ./**/allure-results)",
13
- });
14
- this.output = Option.String("--output,-o", {
15
- description: "The output file name. Absolute paths are accepted as well",
16
- });
17
- }
18
- async execute() {
19
- const { resultDirectories, patterns } = await findAllureResultDirectories(process.cwd(), this.resultsDir);
20
- if (!resultDirectories.length) {
21
- console.error(red(`No test results directories found matching pattern: ${patterns}`));
22
- exit(1);
23
- return;
24
- }
25
- const outputPath = this.output ?? "known-issues.json";
26
- const config = await resolveConfig({
27
- plugins: {},
28
- });
29
- const allureReport = new AllureReport(config);
30
- await allureReport.start();
31
- for (const directory of resultDirectories) {
32
- await allureReport.readDirectory(directory);
33
- }
34
- await allureReport.done();
35
- const targetPath = resolve(outputPath);
36
- await writeKnownIssues(allureReport.store, outputPath);
37
- console.log(`writing known-issues.json to ${targetPath}`);
38
- }
39
- }
40
- KnownIssueCommand.paths = [["known-issue"]];
41
- KnownIssueCommand.usage = Command.Usage({
42
- description: "Generates a known issue list",
43
- details: "This command generates a known issue list from the provided Allure Results directory.",
44
- examples: [
45
- ["known-issue ./allure-results", "Generate a known issue list from the ./allure-results directory"],
46
- [
47
- "known-issue ./allure-results --output custom-issues.json",
48
- "Generate a known issue list from the ./allure-results directory to the custom-issues.json file",
49
- ],
50
- [
51
- "known-issue ./packages/*/allure-results",
52
- "Generate a known issue list from all Allure result directories matching the pattern",
53
- ],
54
- [
55
- "known-issue ./packages/foo/allure-results ./packages/bar/allure-results",
56
- "Generate a known issue list from two Allure result directories",
57
- ],
58
- ],
59
- });