allure 3.14.3 → 3.16.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.
Files changed (45) hide show
  1. package/README.md +34 -10
  2. package/dist/commands/agent-run.d.ts +1 -0
  3. package/dist/commands/agent-run.js +11 -6
  4. package/dist/commands/agent.d.ts +1 -0
  5. package/dist/commands/agent.js +19 -8
  6. package/dist/commands/allure2.js +10 -10
  7. package/dist/commands/awesome.js +10 -10
  8. package/dist/commands/check.js +1 -1
  9. package/dist/commands/classic.js +10 -10
  10. package/dist/commands/commons/generate.d.ts +1 -1
  11. package/dist/commands/commons/generate.js +7 -3
  12. package/dist/commands/commons/resultsDiscovery.d.ts +5 -0
  13. package/dist/commands/commons/resultsDiscovery.js +17 -0
  14. package/dist/commands/commons/run.d.ts +3 -0
  15. package/dist/commands/commons/run.js +60 -27
  16. package/dist/commands/csv.js +10 -10
  17. package/dist/commands/dashboard.js +9 -9
  18. package/dist/commands/generate.d.ts +1 -0
  19. package/dist/commands/generate.js +7 -3
  20. package/dist/commands/history.js +6 -4
  21. package/dist/commands/index.d.ts +0 -1
  22. package/dist/commands/index.js +0 -1
  23. package/dist/commands/jira/clear.js +1 -1
  24. package/dist/commands/log.js +9 -9
  25. package/dist/commands/open.js +9 -5
  26. package/dist/commands/qualityGate.js +7 -7
  27. package/dist/commands/results/pack.d.ts +1 -0
  28. package/dist/commands/results/pack.js +12 -14
  29. package/dist/commands/run.d.ts +2 -0
  30. package/dist/commands/run.js +24 -8
  31. package/dist/commands/slack.js +9 -9
  32. package/dist/commands/testplan.js +7 -5
  33. package/dist/commands/watch.d.ts +2 -0
  34. package/dist/commands/watch.js +75 -26
  35. package/dist/index.js +1 -2
  36. package/dist/utils/index.d.ts +2 -0
  37. package/dist/utils/index.js +2 -0
  38. package/dist/utils/process.js +1 -0
  39. package/dist/utils/resultsPatterns.d.ts +12 -0
  40. package/dist/utils/resultsPatterns.js +37 -0
  41. package/dist/utils/signals.d.ts +18 -0
  42. package/dist/utils/signals.js +52 -0
  43. package/package.json +22 -22
  44. package/dist/commands/knownIssue.d.ts +0 -8
  45. package/dist/commands/knownIssue.js +0 -59
package/README.md CHANGED
@@ -56,7 +56,15 @@ To hide specific labels use `--hide-labels` option:
56
56
  npx allure run --hide-labels=owner --hide-labels=tag -- npm test
57
57
  ```
58
58
 
59
- To successfully generate a report, ensure that your test setup outputs results into an `allure-results` directory, which is automatically detected by Allure 3. This directory can be placed at any nested level within your project (e.g., `out/tests/allure-results`), provided it retains the correct name.
59
+ To successfully generate a report, ensure that your test setup outputs results into an `allure-results` directory. With `allure run` / `allure agent` / empty `allure watch`, directories named `allure-results` are discovered dynamically (name-based watcher). With one-shot commands such as `allure generate`, an empty CLI and unset `config.resultsDir` default to the `./**/allure-results` glob. Quote globs in the shell so they are not expanded early.
60
+
61
+ You can also set `resultsDir` in the Allure config (`string | string[]`) or pass `--results-dir` on `run` / `agent`:
62
+
63
+ ```bash
64
+ npx allure run --open --results-dir './artifacts/**/allure-results' -- npm test
65
+ ```
66
+
67
+ Repeat `--results-dir` for multiple patterns. CLI overrides `config.resultsDir`.
60
68
 
61
69
  After the tests complete, the report is generated automatically. Existing results from previous runs are ignored, as Allure 3 focuses solely on new data to ensure accurate and up-to-date reporting.
62
70
 
@@ -165,7 +173,7 @@ npx allure --version
165
173
 
166
174
  ## Configuration
167
175
 
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.
176
+ 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
177
 
170
178
  > [!TIP]
171
179
  > We recommend using the **Awesome** plugin for the best experience.
@@ -191,7 +199,22 @@ export default defineConfig({
191
199
  });
192
200
  ```
193
201
 
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.
202
+ 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.
203
+
204
+ ### TypeScript Configuration File
205
+
206
+ TypeScript configuration files are loaded directly by the Allure CLI, so you don't need to precompile them or install `tsx` or `ts-node`.
207
+
208
+ ```ts
209
+ import type { AllureConfig } from "allure";
210
+
211
+ export default {
212
+ name: "Allure Report Example",
213
+ output: "./out/allure-report",
214
+ } satisfies AllureConfig;
215
+ ```
216
+
217
+ 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`.
195
218
 
196
219
  ### Configuration Options
197
220
 
@@ -199,17 +222,18 @@ The configuration file allows you to fine-tune report generation. Key options in
199
222
 
200
223
  - **`name`**: Specifies the report’s display name.
201
224
  - **`output`**: Defines the directory where the report will be saved.
202
- - **`hideLabels`** *(`(string | RegExp)[]`)*: Hides matching labels by name in report data. Currently, only Allure Awesome report respects the option. Labels with names starting with `_` are hidden by default.
225
+ - **`resultsDir`** _(`string | string[]`)_: Glob patterns or paths used when reading Allure results directories. For one-shot commands, CLI positionals override this value. For `allure run` / `allure agent`, use repeated `--results-dir` (same override priority). When both CLI and `resultsDir` are empty, one-shot commands (`generate`, etc.) use `./**/allure-results`, while live commands (`run`, `agent`, empty `watch`) use name-based discovery of directories named `allure-results`. Quote globs in the shell.
226
+ - **`hideLabels`** _(`(string | RegExp)[]`)_: Hides matching labels by name in report data. Currently, only Allure Awesome report respects the option. Labels with names starting with `_` are hidden by default.
203
227
  - **`plugins`**: Enables and configures plugins, with each supporting various options.
204
228
 
205
229
  ### Awesome Plugin Options
206
230
 
207
231
  The **Awesome** plugin offers several customizable options:
208
232
 
209
- - **`singleFile`** *(boolean)*: If set to `true`, generates the report as a single standalone HTML file.
210
- - **`reportName`** *(string)*: Overrides the default report name.
211
- - **`open`** *(boolean)*: Automatically opens the report after generation if enabled.
212
- - **`reportLanguage`** *(string)*: Sets the UI language of the report. Supported languages include:
233
+ - **`singleFile`** _(boolean)_: If set to `true`, generates the report as a single standalone HTML file.
234
+ - **`reportName`** _(string)_: Overrides the default report name.
235
+ - **`open`** _(boolean)_: Automatically opens the report after generation if enabled.
236
+ - **`reportLanguage`** _(string)_: Sets the UI language of the report. Supported languages include:
213
237
 
214
238
  `az`, `br`, `de`, `en`, `es`, `fr`, `he`, `ja`, `kr`, `nl`, `pl`, `ru`, `sv`, `tr`, `zh`.
215
239
 
@@ -217,11 +241,11 @@ For example, setting `"reportLanguage": "fr"` will render the report interface i
217
241
 
218
242
  ### Declarative configuration format
219
243
 
220
- You can also use `allurerc.json` or `allurerc.yaml` files as a declarative way to configure Allure 3.
244
+ You can also use `allurerc.json`, `allurerc.yaml`, or `allurerc.yml` files as a declarative way to configure Allure 3.
221
245
 
222
246
  > [!WARNING]
223
247
  > 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.
248
+ > If you need these features, please consider using the `allurerc.ts`, `allurerc.mts`, `allurerc.cts`, `allurerc.mjs`, or `allurerc.js` files.
225
249
 
226
250
  ## Official CI/CD Integrations
227
251
 
@@ -32,6 +32,7 @@ export type ExecuteAgentModeParams = {
32
32
  rerunLabels?: string[];
33
33
  reportMode: AgentHumanReportMode;
34
34
  args: string[];
35
+ resultsPatterns?: readonly string[];
35
36
  };
36
37
  export declare const executeAgentMode: (params: ExecuteAgentModeParams) => Promise<void>;
37
38
  export type ExecuteAgentInspectModeParams = {
@@ -8,7 +8,8 @@ import { AllureReport, isFileNotFoundError, readConfig } from "@allurereport/cor
8
8
  import { createAgentTestPlanContext, AgentUsageError, assertExplicitAgentOutputDirIsSafe, formatAgentOutputLinks, formatAgentRunSummary, isPathInside, loadAgentOutput, normalizeAgentRerunPreset, parseAgentLabelFilters, cleanupAgentRunState, cleanupStaleAgentRunStates, resolveAgentStateDir, writeAgentRunState, } from "@allurereport/plugin-agent";
9
9
  import { normalizeCommandEnvironmentOptions, resolveCommandEnvironment } from "../utils/environment.js";
10
10
  import { createChildAllureCliEnvironment, getActiveAllureCliCommand } from "../utils/execution-context.js";
11
- import { findAllureResultDirectories, findFilesByGlobs } from "../utils/fileSystem.js";
11
+ import { findFilesByGlobs } from "../utils/fileSystem.js";
12
+ import { resolveAndFindResultsDirs, resolveResultsPatterns } from "../utils/resultsPatterns.js";
12
13
  import { createAgentHumanReportConfig } from "./agent-human-report.js";
13
14
  import { executeAllureRun, executeNestedAllureCommand } from "./commons/run.js";
14
15
  export const formatAgentCommand = (args) => args.join(" ");
@@ -90,7 +91,7 @@ export const cleanupManagedAgentOutputs = async (params) => {
90
91
  }
91
92
  };
92
93
  export const executeAgentMode = async (params) => {
93
- const { configPath, cwd: configuredCwd, output, expectations, inlineExpectations, environment, environmentName, silent, rerunFrom, rerunLatest, rerunPreset, rerunEnvironments, rerunLabels, reportMode, args, } = params;
94
+ const { configPath, cwd: configuredCwd, output, expectations, inlineExpectations, environment, environmentName, silent, rerunFrom, rerunLatest, rerunPreset, rerunEnvironments, rerunLabels, reportMode, args, resultsPatterns: cliResultsPatterns = [], } = params;
94
95
  const command = args[0];
95
96
  const commandArgs = args.slice(1);
96
97
  const cwd = await realpath(configuredCwd ?? process.cwd());
@@ -197,6 +198,7 @@ export const executeAgentMode = async (params) => {
197
198
  plugins: [...humanReport.plugins, ...(config.plugins ?? [])],
198
199
  });
199
200
  const knownIssues = await allureReport.store.allKnownIssues();
201
+ const resultsPatterns = resolveResultsPatterns(cliResultsPatterns, config.resultsDir);
200
202
  const { globalExitCode } = await executeAllureRun({
201
203
  allureReport,
202
204
  knownIssues,
@@ -210,6 +212,7 @@ export const executeAgentMode = async (params) => {
210
212
  silent: true,
211
213
  ignoreLogs: false,
212
214
  logProcessExit: false,
215
+ resultsPatterns,
213
216
  });
214
217
  await persistAgentRunState({
215
218
  runId,
@@ -240,13 +243,15 @@ export const executeAgentInspectMode = async (params) => {
240
243
  const { configPath, cwd: configuredCwd, output, expectations, inlineExpectations, environment, environmentName, reportName, open, port, historyLimit, hideLabels, dumps = [], reportMode, resultsDir, } = params;
241
244
  const cwd = await realpath(configuredCwd ?? process.cwd());
242
245
  const dumpFiles = dumps.length ? await findFilesByGlobs(cwd, dumps) : [];
243
- const shouldReadResults = resultsDir.length > 0 || dumps.length === 0;
244
- const { resultDirectories = [], patterns = resultsDir } = shouldReadResults
245
- ? await findAllureResultDirectories(cwd, resultsDir)
246
- : {};
247
246
  if (dumps.length > 0 && dumpFiles.length === 0) {
248
247
  throw new AgentUsageError(`No dump files found matching pattern: ${dumps.join(", ")}`);
249
248
  }
249
+ const resultsConfig = await readConfig(cwd, configPath);
250
+ const resolvedPatterns = resolveResultsPatterns(resultsDir, resultsConfig.resultsDir);
251
+ const shouldReadResults = resolvedPatterns.length > 0 || dumpFiles.length === 0;
252
+ const { resultDirectories = [], patterns = resolvedPatterns } = shouldReadResults
253
+ ? await resolveAndFindResultsDirs(cwd, resultsDir, resultsConfig.resultsDir)
254
+ : {};
250
255
  if (resultDirectories.length === 0 && dumpFiles.length === 0) {
251
256
  const inspectedPatterns = [...(patterns ?? []), ...dumps];
252
257
  throw new AgentUsageError(`No test results directories or dump files found matching pattern: ${inspectedPatterns}`);
@@ -35,6 +35,7 @@ export declare class AgentCommand extends Command {
35
35
  rerunPreset: string | undefined;
36
36
  rerunEnvironments: string[] | undefined;
37
37
  rerunLabels: string[] | undefined;
38
+ resultsDir: string[] | undefined;
38
39
  commandToRun: string[];
39
40
  execute(): Promise<void>;
40
41
  }
@@ -6,6 +6,7 @@ import { dirname, join, resolve } from "node:path";
6
6
  import process, { exit } from "node:process";
7
7
  import { AGENT_FINDING_CATEGORIES, AGENT_FINDING_SEVERITIES, AGENT_TASK_MAP_HELP, AGENT_TEST_STATUSES, AgentExpectationUsageError, assertExplicitAgentOutputDirIsSafe, buildAgentInlineExpectations, buildAgentQueryPayload, cleanupAgentRunState, cleanupStaleAgentRunStates, createAgentCapabilities, formatAgentOutputLinks, isAgentExpectationUsageError, isAgentTaskMapHelpRequest, isAgentUsageError, loadAgentOutput, normalizeAgentQueryLimit, normalizeAgentQueryView, normalizeAgentRerunPreset, normalizeRepeatedEnumValues, normalizeRepeatedStringValues, parseAgentLabelFilters, readLatestAgentState, resolveAgentSelectionOutputDir, resolveAgentStateDir, selectAgentTestPlan, validateAgentExpectationsFile, writeAgentRunState, writeInvalidAgentExpectationOutput, } from "@allurereport/plugin-agent";
8
8
  import { Command, Option, UsageError } from "clipanion";
9
+ import { parseRunCommand } from "../utils/resultsPatterns.js";
9
10
  export { AGENT_TASK_MAP_HELP, createAgentCapabilities, isAgentTaskMapHelpRequest };
10
11
  const readOptionalString = (value) => (typeof value === "string" ? value : undefined);
11
12
  const readOptionalBoolean = (value) => value === true;
@@ -125,7 +126,7 @@ export class AgentCommand extends Command {
125
126
  constructor() {
126
127
  super(...arguments);
127
128
  this.config = Option.String("--config,-c", {
128
- description: "The path Allure config file",
129
+ description: "The path to Allure config file",
129
130
  });
130
131
  this.cwd = Option.String("--cwd", {
131
132
  description: "The working directory for the command to run (default: current working directory)",
@@ -195,18 +196,22 @@ export class AgentCommand extends Command {
195
196
  this.rerunLabels = Option.Array("--rerun-label", {
196
197
  description: "Filter rerun selection by exact label name=value. Repeat the option for multiple filters",
197
198
  });
199
+ this.resultsDir = Option.Array("--results-dir", {
200
+ description: "Glob pattern or path for Allure results directories (repeatable). Overrides config.resultsDir. Quote globs in the shell",
201
+ });
198
202
  this.commandToRun = Option.Rest();
199
203
  }
200
204
  async execute() {
201
- const args = this.commandToRun.filter((arg) => arg !== "--");
205
+ const { command, commandArgs } = parseRunCommand(this.commandToRun);
206
+ if (!command) {
207
+ throw new UsageError("expecting command to be specified after --, e.g. allure agent -- npm run test");
208
+ }
209
+ const args = [command, ...commandArgs];
202
210
  const configPath = readOptionalString(this.config);
203
211
  const configuredCwd = readOptionalString(this.cwd);
204
212
  const output = readOptionalString(this.output);
205
213
  const reportMode = normalizeAgentHumanReportMode(readOptionalString(this.report));
206
214
  const expectations = readOptionalString(this.expectations);
207
- if (!args.length) {
208
- throw new UsageError("expecting command to be specified after --, e.g. allure agent -- npm run test");
209
- }
210
215
  try {
211
216
  if (output) {
212
217
  await assertExplicitAgentOutputDirIsSafe(resolve(await realpath(configuredCwd ?? process.cwd()), output));
@@ -250,6 +255,7 @@ export class AgentCommand extends Command {
250
255
  rerunLabels: readOptionalStringArray(this.rerunLabels),
251
256
  reportMode,
252
257
  args,
258
+ resultsPatterns: this.resultsDir ?? [],
253
259
  });
254
260
  }
255
261
  catch (error) {
@@ -291,7 +297,8 @@ export class AgentCommand extends Command {
291
297
  AgentCommand.paths = [["agent"]];
292
298
  AgentCommand.usage = Command.Usage({
293
299
  description: "Run specified command in Allure agent mode",
294
- details: "This command runs the specified command with an agent-mode Allure profile and optional human-readable report output. With the default --report auto mode, runs with 1000 or fewer stored visible logical results also write a single-file Awesome report at <output>/awesome/index.html and record its status in <output>/manifest/human-report.json. If a user asks for the report after a run, use `allure agent latest` to recover the output directory and check the human-report manifest before regenerating anything.",
300
+ details: "This command runs the specified command with an agent-mode Allure profile and optional human-readable report output. With the default --report auto mode, runs with 1000 or fewer stored visible logical results also write a single-file Awesome report at <output>/awesome/index.html and record its status in <output>/manifest/human-report.json. If a user asks for the report after a run, use `allure agent latest` to recover the output directory and check the human-report manifest before regenerating anything. " +
301
+ "Override results discovery with repeated `--results-dir` (CLI overrides `config.resultsDir`). Quote globs in the shell. When neither is set, directories named `allure-results` are discovered dynamically.",
295
302
  examples: [
296
303
  ["agent -- npm test", "Run npm test and capture agent-mode output with the default human report policy"],
297
304
  ["agent --report off -- npm test", "Run npm test and capture only the agent-mode artifacts"],
@@ -299,16 +306,20 @@ AgentCommand.usage = Command.Usage({
299
306
  "agent --expectations ./expected.yaml -- npm test",
300
307
  "Run npm test with agent-mode expectations loaded from ./expected.yaml",
301
308
  ],
309
+ [
310
+ "agent --results-dir './artifacts/**/allure-results' -- npm test",
311
+ "Override results discovery with a quoted glob",
312
+ ],
302
313
  ],
303
314
  });
304
315
  export class AgentInspectCommand extends Command {
305
316
  constructor() {
306
317
  super(...arguments);
307
318
  this.resultsDir = Option.Rest({
308
- name: "Patterns to match test results directories in the current working directory (default: ./**/allure-results)",
319
+ name: "Patterns to match test results directories. Overrides config.resultsDir. Defaults to ./**/allure-results when neither is set.",
309
320
  });
310
321
  this.config = Option.String("--config,-c", {
311
- description: "The path Allure config file",
322
+ description: "The path to Allure config file",
312
323
  });
313
324
  this.cwd = Option.String("--cwd", {
314
325
  description: "The working directory for resolving results and dumps (default: current working directory)",
@@ -5,15 +5,15 @@ import { AllureReport, readConfig } from "@allurereport/core";
5
5
  import Allure2Plugin from "@allurereport/plugin-allure2";
6
6
  import { Command, Option } from "clipanion";
7
7
  import { red } from "yoctocolors";
8
- import { findAllureResultDirectories } from "../utils/fileSystem.js";
8
+ import { resolveAndFindResultsDirs } from "../utils/resultsPatterns.js";
9
9
  export class Allure2Command extends Command {
10
10
  constructor() {
11
11
  super(...arguments);
12
12
  this.resultsDir = Option.Rest({
13
- name: "Patterns to match test results directories in the current working directory (default: ./**/allure-results)",
13
+ name: "Patterns to match test results directories. Overrides config.resultsDir. Defaults to ./**/allure-results when neither is set.",
14
14
  });
15
15
  this.config = Option.String("--config,-c", {
16
- description: "The path Allure config file",
16
+ description: "The path to Allure config file",
17
17
  });
18
18
  this.cwd = Option.String("--cwd", {
19
19
  description: "The working directory for the command to run (default: current working directory)",
@@ -34,17 +34,11 @@ 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() {
41
41
  const cwd = await realpath(this.cwd ?? process.cwd());
42
- const { resultDirectories, patterns } = await findAllureResultDirectories(cwd, this.resultsDir);
43
- if (!resultDirectories.length) {
44
- console.error(red(`No test results directories found matching pattern: ${patterns}`));
45
- exit(1);
46
- return;
47
- }
48
42
  const before = new Date().getTime();
49
43
  const defaultAllure2Options = {
50
44
  singleFile: this.singleFile ?? false,
@@ -56,6 +50,12 @@ export class Allure2Command extends Command {
56
50
  knownIssuesPath: this.knownIssues,
57
51
  historyPath: this.historyPath,
58
52
  });
53
+ const { resultDirectories, patterns } = await resolveAndFindResultsDirs(cwd, this.resultsDir, config.resultsDir);
54
+ if (!resultDirectories.length) {
55
+ console.error(red(`No test results directories found matching pattern: ${patterns}`));
56
+ exit(1);
57
+ return;
58
+ }
59
59
  config.plugins = [
60
60
  {
61
61
  id: "allure2",
@@ -5,15 +5,15 @@ import { AllureReport, readConfig } from "@allurereport/core";
5
5
  import { default as AwesomePlugin } from "@allurereport/plugin-awesome";
6
6
  import { Command, Option } from "clipanion";
7
7
  import { red } from "yoctocolors";
8
- import { findAllureResultDirectories } from "../utils/fileSystem.js";
8
+ import { resolveAndFindResultsDirs } from "../utils/resultsPatterns.js";
9
9
  export class AwesomeCommand extends Command {
10
10
  constructor() {
11
11
  super(...arguments);
12
12
  this.resultsDir = Option.Rest({
13
- name: "Patterns to match test results directories in the current working directory (default: ./**/allure-results)",
13
+ name: "Patterns to match test results directories. Overrides config.resultsDir. Defaults to ./**/allure-results when neither is set.",
14
14
  });
15
15
  this.config = Option.String("--config,-c", {
16
- description: "The path Allure config file",
16
+ description: "The path to Allure config file",
17
17
  });
18
18
  this.cwd = Option.String("--cwd", {
19
19
  description: "The working directory for the command to run (default: current working directory)",
@@ -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",
@@ -51,12 +51,6 @@ export class AwesomeCommand extends Command {
51
51
  }
52
52
  async execute() {
53
53
  const cwd = await realpath(this.cwd ?? process.cwd());
54
- const { resultDirectories, patterns } = await findAllureResultDirectories(cwd, this.resultsDir);
55
- if (!resultDirectories.length) {
56
- console.error(red(`No test results directories found matching pattern: ${patterns}`));
57
- exit(1);
58
- return;
59
- }
60
54
  const before = new Date().getTime();
61
55
  const hideLabels = this.hideLabels?.length ? this.hideLabels : undefined;
62
56
  const config = await readConfig(cwd, this.config, {
@@ -66,6 +60,12 @@ export class AwesomeCommand extends Command {
66
60
  historyPath: this.historyPath,
67
61
  hideLabels,
68
62
  });
63
+ const { resultDirectories, patterns } = await resolveAndFindResultsDirs(cwd, this.resultsDir, config.resultsDir);
64
+ if (!resultDirectories.length) {
65
+ console.error(red(`No test results directories found matching pattern: ${patterns}`));
66
+ exit(1);
67
+ return;
68
+ }
69
69
  const defaultAwesomeOptions = {
70
70
  singleFile: this.singleFile ?? false,
71
71
  logo: this.logo,
@@ -95,7 +95,7 @@ export class CheckCommand extends Command {
95
95
  description: "Add a tag to the check result. Repeat the option for multiple tags",
96
96
  });
97
97
  this.config = Option.String("--config,-c", {
98
- description: "The path Allure config file",
98
+ description: "The path to Allure config file",
99
99
  });
100
100
  this.cwd = Option.String("--cwd", {
101
101
  description: "The working directory for the command to run (default: current working directory)",
@@ -5,15 +5,15 @@ import { AllureReport, readConfig } from "@allurereport/core";
5
5
  import ClassicPlugin from "@allurereport/plugin-classic";
6
6
  import { Command, Option } from "clipanion";
7
7
  import { red } from "yoctocolors";
8
- import { findAllureResultDirectories } from "../utils/fileSystem.js";
8
+ import { resolveAndFindResultsDirs } from "../utils/resultsPatterns.js";
9
9
  export class ClassicCommand extends Command {
10
10
  constructor() {
11
11
  super(...arguments);
12
12
  this.resultsDir = Option.Rest({
13
- name: "Patterns to match test results directories in the current working directory (default: ./**/allure-results)",
13
+ name: "Patterns to match test results directories. Overrides config.resultsDir. Defaults to ./**/allure-results when neither is set.",
14
14
  });
15
15
  this.config = Option.String("--config,-c", {
16
- description: "The path Allure config file",
16
+ description: "The path to Allure config file",
17
17
  });
18
18
  this.cwd = Option.String("--cwd", {
19
19
  description: "The working directory for the command to run (default: current working directory)",
@@ -34,17 +34,11 @@ 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() {
41
41
  const cwd = await realpath(this.cwd ?? process.cwd());
42
- const { resultDirectories, patterns } = await findAllureResultDirectories(cwd, this.resultsDir);
43
- if (!resultDirectories.length) {
44
- console.error(red(`No test results directories found matching pattern: ${patterns}`));
45
- exit(1);
46
- return;
47
- }
48
42
  const before = new Date().getTime();
49
43
  const defaultClassicOptions = {
50
44
  singleFile: this.singleFile ?? false,
@@ -56,6 +50,12 @@ export class ClassicCommand extends Command {
56
50
  knownIssuesPath: this.knownIssues,
57
51
  historyPath: this.historyPath,
58
52
  });
53
+ const { resultDirectories, patterns } = await resolveAndFindResultsDirs(cwd, this.resultsDir, config.resultsDir);
54
+ if (!resultDirectories.length) {
55
+ console.error(red(`No test results directories found matching pattern: ${patterns}`));
56
+ exit(1);
57
+ return;
58
+ }
59
59
  config.plugins = [
60
60
  {
61
61
  id: "classic",
@@ -2,6 +2,6 @@ import type { FullConfig } from "@allurereport/core";
2
2
  export declare const generate: (params: {
3
3
  cwd: string;
4
4
  config: FullConfig;
5
- resultsDir: string[];
5
+ resultsDir?: string[];
6
6
  dump?: string[];
7
7
  }) => Promise<void>;
@@ -2,12 +2,16 @@ import { exit } from "node:process";
2
2
  import { AllureReport } from "@allurereport/core";
3
3
  import { KnownError } from "@allurereport/service";
4
4
  import { red } from "yoctocolors";
5
- import { findAllureResultDirectories, findFilesByGlobs } from "../../utils/fileSystem.js";
5
+ import { findFilesByGlobs } from "../../utils/fileSystem.js";
6
6
  import { logError } from "../../utils/logs.js";
7
+ import { resolveAndFindResultsDirs, resolveResultsPatterns } from "../../utils/resultsPatterns.js";
7
8
  export const generate = async (params) => {
8
9
  const dumpFiles = params?.dump?.length ? await findFilesByGlobs(params.cwd, params.dump) : [];
9
- const { resultDirectories = [], patterns = params.resultsDir } = !!params?.resultsDir || dumpFiles.length === 0
10
- ? await findAllureResultDirectories(params.cwd, params.resultsDir)
10
+ const cliPatterns = params.resultsDir ?? [];
11
+ const resolvedPatterns = resolveResultsPatterns(cliPatterns, params.config.resultsDir);
12
+ const shouldReadResults = resolvedPatterns.length > 0 || dumpFiles.length === 0;
13
+ const { resultDirectories = [], patterns = resolvedPatterns } = shouldReadResults
14
+ ? await resolveAndFindResultsDirs(params.cwd, cliPatterns, params.config.resultsDir)
11
15
  : {};
12
16
  if (resultDirectories.length === 0 && dumpFiles.length === 0) {
13
17
  console.error(red(`No test results directories found matching pattern: ${patterns}`));
@@ -0,0 +1,5 @@
1
+ import type { Watcher } from "@allurereport/directory-watcher";
2
+ export declare const allureResultsDirectoriesGlobWatcher: (cwd: string, patterns: readonly string[], update: (newAllureResults: Set<string>, deletedAllureResults: Set<string>) => Promise<void>, options?: {
3
+ indexDelay?: number;
4
+ abortController?: AbortController;
5
+ }) => Watcher;
@@ -0,0 +1,17 @@
1
+ import { difference, watch } from "@allurereport/directory-watcher";
2
+ import { findDirectoriesByGlobs } from "../../utils/fileSystem.js";
3
+ export const allureResultsDirectoriesGlobWatcher = (cwd, patterns, update, options = {}) => {
4
+ const { abortController = new AbortController(), indexDelay = 600 } = options;
5
+ let previousAllureResults = new Set();
6
+ const callback = async () => {
7
+ if (abortController.signal.aborted) {
8
+ return;
9
+ }
10
+ const matched = await findDirectoriesByGlobs(cwd, patterns);
11
+ const currentAllureResults = new Set(matched);
12
+ const [added, deleted] = difference(previousAllureResults, currentAllureResults);
13
+ await update(added, deleted);
14
+ previousAllureResults = currentAllureResults;
15
+ };
16
+ return watch(callback, callback, callback, { indexDelay, abortController });
17
+ };
@@ -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: {
@@ -27,6 +28,7 @@ export declare const runTests: (params: {
27
28
  silent?: boolean;
28
29
  logs?: RunLogsMode;
29
30
  logProcessExit?: boolean;
31
+ resultsPatterns?: readonly string[];
30
32
  }) => Promise<TestProcessResult | null>;
31
33
  export declare const executeAllureRun: (params: {
32
34
  allureReport: AllureReport;
@@ -42,6 +44,7 @@ export declare const executeAllureRun: (params: {
42
44
  ignoreLogs?: boolean;
43
45
  maxRerun?: number;
44
46
  logProcessExit?: boolean;
47
+ resultsPatterns?: readonly string[];
45
48
  }) => Promise<{
46
49
  globalExitCode: ExitCode;
47
50
  testProcessResult: TestProcessResult | null;