allure 3.7.0 → 3.8.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/README.md CHANGED
@@ -94,7 +94,7 @@ To view a previously generated report locally, the `open` command serves it in y
94
94
  npx allure open <reportDir>
95
95
  ```
96
96
 
97
- If you’ve defined the output directory in your configuration file, specifying `<reportDir>` is optional. By default, Allure 3 looks for a directory named `allure-report`. To open the Awesome report directly, point to the nested directory:
97
+ When `<reportDir>` is omitted, Allure 3 uses the configured output directory, falling back to `allure-report` when no output is configured. To open the Awesome report directly, point to the nested directory:
98
98
 
99
99
  ```bash
100
100
  npx allure open allure-report/awesome
@@ -0,0 +1,15 @@
1
+ import { Command } from "clipanion";
2
+ export declare class CheckCommand extends Command {
3
+ static paths: string[][];
4
+ static usage: import("clipanion").Usage;
5
+ name: string;
6
+ status: string | undefined;
7
+ message: string | undefined;
8
+ tag: string[] | undefined;
9
+ config: string | undefined;
10
+ cwd: string | undefined;
11
+ output: string | undefined;
12
+ dump: string | undefined;
13
+ commandToRun: string[];
14
+ execute(): Promise<void>;
15
+ }
@@ -0,0 +1,166 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { mkdir, realpath, writeFile } from "node:fs/promises";
3
+ import { join } from "node:path";
4
+ import process, { exit } from "node:process";
5
+ import { AllureReport, readConfig } from "@allurereport/core";
6
+ import { Command, Option, UsageError } from "clipanion";
7
+ import { runProcess, terminationOf } from "../utils/index.js";
8
+ const checkStatuses = ["passed", "failed"];
9
+ const parseCheckStatus = (status) => {
10
+ if (status === undefined) {
11
+ return undefined;
12
+ }
13
+ if (checkStatuses.includes(status)) {
14
+ return status;
15
+ }
16
+ throw new UsageError(`Invalid --status value ${JSON.stringify(status)}. Expected one of: passed, failed`);
17
+ };
18
+ const quoteCommandArg = (arg) => {
19
+ if (/^[A-Za-z0-9_/:=.,@%+-]+$/.test(arg)) {
20
+ return arg;
21
+ }
22
+ return `'${arg.replace(/'/g, "'\\''")}'`;
23
+ };
24
+ const resolveCheckCommand = (args) => {
25
+ if (args.length === 1) {
26
+ return {
27
+ command: args[0],
28
+ commandArgs: [],
29
+ commandLine: args[0],
30
+ shell: true,
31
+ };
32
+ }
33
+ return {
34
+ command: args[0],
35
+ commandArgs: args.slice(1),
36
+ commandLine: args.map(quoteCommandArg).join(" "),
37
+ shell: false,
38
+ };
39
+ };
40
+ const buildCheckResult = (name, status, tags, command, message, error) => ({
41
+ name,
42
+ status,
43
+ ...(tags?.length ? { tags } : {}),
44
+ details: {
45
+ command,
46
+ ...(message ? { message } : {}),
47
+ ...(error ? { error } : {}),
48
+ },
49
+ });
50
+ const collectCheckCommandOutput = (checkProcess) => {
51
+ const output = {
52
+ stdout: "",
53
+ stderr: "",
54
+ };
55
+ checkProcess.stdout?.setEncoding("utf8").on?.("data", (data) => {
56
+ output.stdout += data;
57
+ process.stdout.write(data);
58
+ });
59
+ checkProcess.stderr?.setEncoding("utf8").on?.("data", (data) => {
60
+ output.stderr += data;
61
+ process.stderr.write(data);
62
+ });
63
+ return output;
64
+ };
65
+ const writeCheckResultFile = async (output, result) => {
66
+ await mkdir(output, { recursive: true });
67
+ await writeFile(join(output, `${randomUUID()}-check.json`), `${JSON.stringify(result)}\n`, "utf-8");
68
+ };
69
+ const dumpCheckResult = async (config, result, dump) => {
70
+ const allureReport = new AllureReport({
71
+ ...config,
72
+ dump,
73
+ realTime: false,
74
+ plugins: [],
75
+ });
76
+ await allureReport.start();
77
+ await allureReport.store.addCheckResult(result);
78
+ await allureReport.done();
79
+ };
80
+ export class CheckCommand extends Command {
81
+ constructor() {
82
+ super(...arguments);
83
+ this.name = Option.String("--name", {
84
+ description: "The check name",
85
+ required: true,
86
+ });
87
+ this.status = Option.String("--status", {
88
+ description: "The manual check status: passed or failed",
89
+ });
90
+ this.message = Option.String("--message", {
91
+ description: "The manual check message",
92
+ });
93
+ this.tag = Option.Array("--tag", {
94
+ description: "Add a tag to the check result. Repeat the option for multiple tags",
95
+ });
96
+ this.config = Option.String("--config,-c", {
97
+ description: "The path Allure config file",
98
+ });
99
+ this.cwd = Option.String("--cwd", {
100
+ description: "The working directory for the command to run (default: current working directory)",
101
+ });
102
+ this.output = Option.String("--output,-o", {
103
+ description: "The output directory name. Absolute paths are accepted as well",
104
+ });
105
+ this.dump = Option.String("--dump", {
106
+ description: "Write the check result to a dump archive with the provided name instead of output",
107
+ });
108
+ this.commandToRun = Option.Rest();
109
+ }
110
+ async execute() {
111
+ const args = this.commandToRun.filter((arg) => arg !== "--");
112
+ const manualStatus = parseCheckStatus(this.status);
113
+ if (manualStatus && args.length > 0) {
114
+ throw new UsageError("Use either --status for a manual check or a command after --, not both");
115
+ }
116
+ if (!manualStatus && args.length === 0) {
117
+ throw new UsageError("expecting --status or command to be specified after --, e.g. allure check --name Lint -- npm run lint");
118
+ }
119
+ const cwd = await realpath(this.cwd ?? process.cwd());
120
+ let originalExitCode = manualStatus === "failed" ? 1 : 0;
121
+ let status = manualStatus;
122
+ let commandOutput;
123
+ const checkCommand = args.length ? resolveCheckCommand(args) : undefined;
124
+ if (!status) {
125
+ const checkProcess = runProcess({
126
+ command: checkCommand.command,
127
+ commandArgs: checkCommand.commandArgs,
128
+ cwd,
129
+ logs: "pipe",
130
+ shell: checkCommand.shell,
131
+ });
132
+ commandOutput = collectCheckCommandOutput(checkProcess);
133
+ const code = await terminationOf(checkProcess);
134
+ originalExitCode = code ?? 1;
135
+ status = originalExitCode === 0 ? "passed" : "failed";
136
+ }
137
+ const message = (commandOutput ? commandOutput.stdout : this.message)?.trim() ?? "";
138
+ const error = commandOutput?.stderr?.trim() ?? "";
139
+ const result = buildCheckResult(this.name, status, this.tag, checkCommand?.commandLine ?? "", message, error);
140
+ const config = await readConfig(cwd, this.config, {
141
+ output: this.output,
142
+ plugins: {},
143
+ });
144
+ const checkConfig = {
145
+ ...config,
146
+ plugins: [],
147
+ };
148
+ if (this.dump) {
149
+ await dumpCheckResult(checkConfig, result, this.dump);
150
+ }
151
+ else {
152
+ await writeCheckResultFile(checkConfig.output, result);
153
+ }
154
+ exit(status === "passed" ? 0 : originalExitCode || 1);
155
+ }
156
+ }
157
+ CheckCommand.paths = [["check"]];
158
+ CheckCommand.usage = Command.Usage({
159
+ description: "Run a check command or record a manual check result",
160
+ details: "This command records an Allure check result based on a command exit code or an explicit status.",
161
+ examples: [
162
+ ['check --name "Lint" -- npm run lint', "Run npm run lint and record the check result"],
163
+ ['check --name "Manual approval" --status passed --tag release', "Record a manual passed check result"],
164
+ ['check --name "Lint" --dump=checks -- npm run lint', "Store the check result in checks.zip instead of output"],
165
+ ],
166
+ });
@@ -5,6 +5,7 @@ export * from "./allure2.js";
5
5
  export * from "./agent.js";
6
6
  export * from "./awesome.js";
7
7
  export * from "./csv.js";
8
+ export * from "./check.js";
8
9
  export * from "./history.js";
9
10
  export * from "./knownIssue.js";
10
11
  export * from "./run.js";
@@ -5,6 +5,7 @@ export * from "./allure2.js";
5
5
  export * from "./agent.js";
6
6
  export * from "./awesome.js";
7
7
  export * from "./csv.js";
8
+ export * from "./check.js";
8
9
  export * from "./history.js";
9
10
  export * from "./knownIssue.js";
10
11
  export * from "./run.js";
@@ -12,7 +12,7 @@ export class OpenCommand extends Command {
12
12
  constructor() {
13
13
  super(...arguments);
14
14
  this.resultsDir = Option.String({
15
- name: "A report to open or a pattern to match test results directories in the current working directory (default: ./allure-results)",
15
+ name: "A report to open or a pattern to match test results directories in the current working directory (default: configured output)",
16
16
  required: false,
17
17
  });
18
18
  this.config = Option.String("--config,-c", {
@@ -31,7 +31,10 @@ export class OpenCommand extends Command {
31
31
  async execute() {
32
32
  const cwd = this.cwd ?? processCwd();
33
33
  const hideLabels = this.hideLabels?.length ? this.hideLabels : undefined;
34
- const targetFullPath = join(cwd, this.resultsDir ?? "allure-report");
34
+ const config = await readConfig(cwd, this.config, {
35
+ port: this.port,
36
+ });
37
+ const targetFullPath = this.resultsDir ? join(cwd, this.resultsDir) : config.output;
35
38
  const summaryFiles = existsSync(targetFullPath)
36
39
  ? await glob(join(targetFullPath, "**", "summary.json"), {
37
40
  mark: true,
@@ -43,9 +46,6 @@ export class OpenCommand extends Command {
43
46
  })
44
47
  : [];
45
48
  if (summaryFiles.length > 0) {
46
- const config = await readConfig(cwd, this.config, {
47
- port: this.port,
48
- });
49
49
  await serve({
50
50
  port: config.port ? parseInt(config.port, 10) : undefined,
51
51
  servePath: targetFullPath,
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { readFileSync } from "node:fs";
2
2
  import { argv } from "node:process";
3
3
  import { Builtins, Cli } from "clipanion";
4
- import { AgentCommand, AgentLatestCommand, AgentSelectCommand, AgentStateDirCommand, Allure2Command, AwesomeCommand, ClassicCommand, CsvCommand, DashboardCommand, GenerateCommand, HistoryCommand, JiraClearCommand, KnownIssueCommand, LogCommand, OpenCommand, QualityGateCommand, ResultsPackCommand, ResultsUnpackCommand, RunCommand, SlackCommand, TestPlanCommand, WatchCommand, } from "./commands/index.js";
4
+ import { AgentCommand, AgentLatestCommand, AgentSelectCommand, AgentStateDirCommand, Allure2Command, AwesomeCommand, CheckCommand, ClassicCommand, CsvCommand, DashboardCommand, GenerateCommand, HistoryCommand, JiraClearCommand, KnownIssueCommand, LogCommand, OpenCommand, QualityGateCommand, ResultsPackCommand, ResultsUnpackCommand, RunCommand, SlackCommand, TestPlanCommand, WatchCommand, } 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({
@@ -15,6 +15,7 @@ cli.register(AgentLatestCommand);
15
15
  cli.register(AgentSelectCommand);
16
16
  cli.register(AgentStateDirCommand);
17
17
  cli.register(AgentCommand);
18
+ cli.register(CheckCommand);
18
19
  cli.register(ClassicCommand);
19
20
  cli.register(CsvCommand);
20
21
  cli.register(DashboardCommand);
@@ -13,6 +13,7 @@ export declare const runProcess: (params: {
13
13
  cwd: string | undefined;
14
14
  environmentVariables?: Record<string, string>;
15
15
  logs?: "pipe" | "inherit" | "ignore";
16
+ shell?: boolean;
16
17
  }) => ChildProcess;
17
18
  export declare const terminationOf: (testProcess: ChildProcess) => Promise<number | null>;
18
19
  export declare const stopProcessTree: (pid: number, { signal }?: StopProcessTreeOpts) => Promise<ProcessBrief[]>;
@@ -5,7 +5,7 @@ import { invokeStdoutCliTool } from "@allurereport/reader-api";
5
5
  const IS_WIN = platform === "win32";
6
6
  const PS_OUTPUT_PATTERN = /(?<ppid>\d+)\s+(?<pid>\d+)\s+(?<comm>.*)/;
7
7
  export const runProcess = (params) => {
8
- const { command, commandArgs, cwd, environmentVariables = {}, logs = "inherit" } = params;
8
+ const { command, commandArgs, cwd, environmentVariables = {}, logs = "inherit", shell = IS_WIN } = params;
9
9
  const env = {
10
10
  ...process.env,
11
11
  ...environmentVariables,
@@ -24,7 +24,7 @@ export const runProcess = (params) => {
24
24
  env,
25
25
  cwd,
26
26
  stdio: logs,
27
- shell: IS_WIN,
27
+ shell,
28
28
  });
29
29
  };
30
30
  export const terminationOf = (testProcess) => new Promise((resolve) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "allure",
3
- "version": "3.7.0",
3
+ "version": "3.8.1",
4
4
  "description": "Allure Commandline Tool",
5
5
  "keywords": [
6
6
  "allure",
@@ -32,29 +32,29 @@
32
32
  "lint:fix": "oxlint --import-plugin --fix src test features stories"
33
33
  },
34
34
  "dependencies": {
35
- "@allurereport/charts-api": "3.7.0",
36
- "@allurereport/ci": "3.7.0",
37
- "@allurereport/core": "3.7.0",
38
- "@allurereport/core-api": "3.7.0",
39
- "@allurereport/directory-watcher": "3.7.0",
40
- "@allurereport/plugin-agent": "3.7.0",
41
- "@allurereport/plugin-allure2": "3.7.0",
42
- "@allurereport/plugin-api": "3.7.0",
43
- "@allurereport/plugin-awesome": "3.7.0",
44
- "@allurereport/plugin-classic": "3.7.0",
45
- "@allurereport/plugin-csv": "3.7.0",
46
- "@allurereport/plugin-dashboard": "3.7.0",
47
- "@allurereport/plugin-jira": "3.7.0",
48
- "@allurereport/plugin-log": "3.7.0",
49
- "@allurereport/plugin-progress": "3.7.0",
50
- "@allurereport/plugin-server-reload": "3.7.0",
51
- "@allurereport/plugin-slack": "3.7.0",
52
- "@allurereport/reader-api": "3.7.0",
53
- "@allurereport/service": "3.7.0",
54
- "@allurereport/static-server": "3.7.0",
35
+ "@allurereport/charts-api": "3.8.1",
36
+ "@allurereport/ci": "3.8.1",
37
+ "@allurereport/core": "3.8.1",
38
+ "@allurereport/core-api": "3.8.1",
39
+ "@allurereport/directory-watcher": "3.8.1",
40
+ "@allurereport/plugin-agent": "3.8.1",
41
+ "@allurereport/plugin-allure2": "3.8.1",
42
+ "@allurereport/plugin-api": "3.8.1",
43
+ "@allurereport/plugin-awesome": "3.8.1",
44
+ "@allurereport/plugin-classic": "3.8.1",
45
+ "@allurereport/plugin-csv": "3.8.1",
46
+ "@allurereport/plugin-dashboard": "3.8.1",
47
+ "@allurereport/plugin-jira": "3.8.1",
48
+ "@allurereport/plugin-log": "3.8.1",
49
+ "@allurereport/plugin-progress": "3.8.1",
50
+ "@allurereport/plugin-server-reload": "3.8.1",
51
+ "@allurereport/plugin-slack": "3.8.1",
52
+ "@allurereport/reader-api": "3.8.1",
53
+ "@allurereport/service": "3.8.1",
54
+ "@allurereport/static-server": "3.8.1",
55
55
  "adm-zip": "^0.5.16",
56
56
  "clipanion": "^4.0.0-rc.4",
57
- "glob": "^11.1.0",
57
+ "glob": "^13.0.6",
58
58
  "lodash.omit": "^4.18.0",
59
59
  "prompts": "^2.4.2",
60
60
  "typanion": "^3.14.0",