allure 3.20.0 → 3.21.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 +25 -1
- package/dist/commands/{agent.js → agents/index.js} +13 -109
- package/dist/commands/agents/lifecycle.d.ts +20 -0
- package/dist/commands/agents/lifecycle.js +91 -0
- package/dist/commands/{agent-run.d.ts → agents/run.d.ts} +1 -13
- package/dist/commands/{agent-run.js → agents/run.js} +12 -67
- package/dist/commands/commons/generate.d.ts +1 -0
- package/dist/commands/commons/generate.js +28 -2
- package/dist/commands/generate.d.ts +2 -0
- package/dist/commands/generate.js +19 -1
- package/dist/commands/index.d.ts +2 -1
- package/dist/commands/index.js +2 -1
- package/dist/commands/migrate.d.ts +6 -0
- package/dist/commands/migrate.js +15 -0
- package/dist/commands/open.d.ts +1 -0
- package/dist/commands/open.js +12 -2
- package/dist/commands/qualityGate.js +11 -1
- package/dist/commands/run.d.ts +4 -0
- package/dist/commands/run.js +27 -5
- package/dist/commands/slack.d.ts +3 -2
- package/dist/commands/slack.js +17 -5
- package/dist/commands/testopsPlan.js +4 -4
- package/dist/commands/watch.d.ts +1 -0
- package/dist/commands/watch.js +10 -1
- package/dist/index.js +30 -9
- package/dist/utils/allure2Hints.d.ts +8 -0
- package/dist/utils/allure2Hints.js +90 -0
- package/dist/utils/cleanOutput.d.ts +9 -0
- package/dist/utils/cleanOutput.js +62 -0
- package/dist/utils/fileSystem.d.ts +4 -1
- package/dist/utils/fileSystem.js +3 -3
- package/dist/utils/serverOptions.d.ts +5 -0
- package/dist/utils/serverOptions.js +4 -0
- package/dist/utils/updateNotifier.d.ts +6 -0
- package/dist/utils/updateNotifier.js +58 -0
- package/dist/utils/verbosity.d.ts +7 -0
- package/dist/utils/verbosity.js +32 -0
- package/package.json +28 -23
- /package/dist/commands/{agent-human-report.d.ts → agents/human-report.d.ts} +0 -0
- /package/dist/commands/{agent-human-report.js → agents/human-report.js} +0 -0
- /package/dist/commands/{agent.d.ts → agents/index.d.ts} +0 -0
package/README.md
CHANGED
|
@@ -73,6 +73,22 @@ Set `ALLURE_LOG_LEVEL=debug` to include details such as selected tests and tempo
|
|
|
73
73
|
the generic `LOG_LEVEL` environment variable. Use `--silent` to hide the nested test process output while keeping
|
|
74
74
|
Allure lifecycle messages visible.
|
|
75
75
|
|
|
76
|
+
### Verbosity flags
|
|
77
|
+
|
|
78
|
+
`-v/--verbose` and `-q/--quiet` are global flags accepted by every command (place them before `--` in `allure run`;
|
|
79
|
+
everything after `--` is passed to your test command untouched).
|
|
80
|
+
|
|
81
|
+
| Flag | Allure log level | `allure run` test process output |
|
|
82
|
+
| --- | --- | --- |
|
|
83
|
+
| _(none)_ | `ALLURE_LOG_LEVEL`, default `info` | printed |
|
|
84
|
+
| `--verbose`, `-v` | `verbose` | printed |
|
|
85
|
+
| `--quiet`, `-q` | `error` (errors only) | hidden, same as `--silent` |
|
|
86
|
+
|
|
87
|
+
- The flags override `ALLURE_LOG_LEVEL`. `--verbose` and `--quiet` cannot be combined.
|
|
88
|
+
- `--quiet` implies `--silent`. Logs are still collected into the report unless `--ignore-logs` is set.
|
|
89
|
+
- `--silent` and `--ignore-logs` keep their meaning and are independent of `--verbose`.
|
|
90
|
+
- A lone `allure -v` still prints the version.
|
|
91
|
+
|
|
76
92
|
### Running Tests In Agent Mode
|
|
77
93
|
|
|
78
94
|
When you need agent-friendly markdown output for review, debugging, or scope validation, use the `agent` command:
|
|
@@ -103,7 +119,7 @@ option writes the agentic output directory.
|
|
|
103
119
|
|
|
104
120
|
`allure agent` and `allure agent inspect` use `--report auto` by default. This writes the agent-readable artifacts and, when the stored visible result count is 1000 or fewer, also writes a single-file Awesome report at `awesome/index.html` inside the agent output directory. Runs above that threshold skip the human report to avoid excessive output, and the status is recorded in `index.md`, `manifest/run.json`, and `manifest/human-report.json`.
|
|
105
121
|
|
|
106
|
-
Use `--report off` for agent-only artifacts, `--report awesome` to force the single-file Awesome report regardless of result count, or `--report config` to force the configured non-agent report plugins inside the agent output directory. Configured presentation or export plugins such as Dashboard or TestOps are otherwise ignored for agent runs.
|
|
122
|
+
Use `--report off` for agent-only artifacts, `--report awesome` to force the single-file Awesome report regardless of result count, or `--report config` to force the configured non-agent report plugins inside the agent output directory. Configured presentation or export plugins such as Dashboard or Allure TestOps are otherwise ignored for agent runs.
|
|
107
123
|
|
|
108
124
|
If you need the human-readable report from the most recent agent run, first run `npx allure agent latest` when the output directory is unknown. Then check `<output>/manifest/human-report.json`; when its status is `generated`, open `<output>/<path>` from that manifest, usually `<output>/awesome/index.html`.
|
|
109
125
|
|
|
@@ -176,6 +192,14 @@ To check your installed version of Allure 3, use:
|
|
|
176
192
|
npx allure --version
|
|
177
193
|
```
|
|
178
194
|
|
|
195
|
+
For direct interactive CLI invocations, Allure checks the npm registry for a newer version alongside the command.
|
|
196
|
+
Each eligible invocation makes one request with a one-second timeout; no update state is stored on disk. Missing
|
|
197
|
+
package metadata and network errors are silently ignored. The check is skipped for `allure agent`, help and version
|
|
198
|
+
output, quiet mode, CI, non-interactive terminals, and invocations through npm or Yarn. Disable it with `--no-update-notifier`
|
|
199
|
+
(for example, `allure --no-update-notifier generate ./allure-results`), or set `NO_UPDATE_NOTIFIER` for the environment.
|
|
200
|
+
Numbered prerelease versions (such as `3.21.0-beta.2`) check their matching npm dist-tag instead of the stable `latest`
|
|
201
|
+
tag. Unrecognized version formats are silently skipped.
|
|
202
|
+
|
|
179
203
|
## Configuration
|
|
180
204
|
|
|
181
205
|
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.
|
|
@@ -1,25 +1,16 @@
|
|
|
1
1
|
import * as console from "node:console";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { tmpdir } from "node:os";
|
|
5
|
-
import { dirname, join, resolve } from "node:path";
|
|
2
|
+
import { mkdir, realpath, writeFile } from "node:fs/promises";
|
|
3
|
+
import { dirname, resolve } from "node:path";
|
|
6
4
|
import process, { exit } from "node:process";
|
|
7
|
-
import { AGENT_FINDING_CATEGORIES, AGENT_FINDING_SEVERITIES, AGENT_TASK_MAP_HELP, AGENT_TEST_STATUSES, AgentExpectationUsageError, assertExplicitAgentOutputDirIsSafe, buildAgentInlineExpectations, buildAgentQueryPayload,
|
|
5
|
+
import { AGENT_FINDING_CATEGORIES, AGENT_FINDING_SEVERITIES, AGENT_TASK_MAP_HELP, AGENT_TEST_STATUSES, AgentExpectationUsageError, assertExplicitAgentOutputDirIsSafe, buildAgentInlineExpectations, buildAgentQueryPayload, createAgentCapabilities, isAgentExpectationUsageError, isAgentTaskMapHelpRequest, isAgentUsageError, loadAgentOutput, normalizeAgentQueryLimit, normalizeAgentQueryView, normalizeAgentRerunPreset, normalizeRepeatedEnumValues, normalizeRepeatedStringValues, parseAgentLabelFilters, readLatestAgentState, resolveAgentSelectionOutputDir, resolveAgentStateDir, selectAgentTestPlan, validateAgentExpectationsFile, } from "@allurereport/plugin-agent";
|
|
8
6
|
import { Command, Option, UsageError } from "clipanion";
|
|
9
|
-
import { parseRunCommand } from "
|
|
7
|
+
import { parseRunCommand } from "../../utils/resultsPatterns.js";
|
|
8
|
+
import { formatAgentCommand, formatAgentInspectCommand, printAgentOutputLinks, writeInvalidAgentExpectationRun, } from "./lifecycle.js";
|
|
10
9
|
export { AGENT_TASK_MAP_HELP, createAgentCapabilities, isAgentTaskMapHelpRequest };
|
|
11
10
|
const readOptionalString = (value) => (typeof value === "string" ? value : undefined);
|
|
12
11
|
const readOptionalBoolean = (value) => value === true;
|
|
13
12
|
const readOptionalStringArray = (value) => (Array.isArray(value) ? value : undefined);
|
|
14
|
-
const formatAgentCommand = (args) => args.join(" ");
|
|
15
13
|
const AGENT_HUMAN_REPORT_MODES = ["auto", "off", "awesome", "config"];
|
|
16
|
-
const formatAgentInspectCommand = (params) => [
|
|
17
|
-
"allure",
|
|
18
|
-
"agent",
|
|
19
|
-
"inspect",
|
|
20
|
-
...(params.dumps ?? []).flatMap((dump) => ["--dump", dump]),
|
|
21
|
-
...(params.resultsDir ?? []),
|
|
22
|
-
].join(" ");
|
|
23
14
|
const buildInlineExpectationsFromOptions = (options) => buildAgentInlineExpectations({
|
|
24
15
|
goal: options.goal,
|
|
25
16
|
taskId: options.taskId,
|
|
@@ -34,53 +25,6 @@ const buildInlineExpectationsFromOptions = (options) => buildAgentInlineExpectat
|
|
|
34
25
|
expectAttachments: options.expectAttachments,
|
|
35
26
|
expectAttachmentFilters: readOptionalStringArray(options.expectAttachmentFilters),
|
|
36
27
|
});
|
|
37
|
-
const printAgentOutputLinks = (outputDir) => {
|
|
38
|
-
for (const line of formatAgentOutputLinks(outputDir)) {
|
|
39
|
-
console.log(line);
|
|
40
|
-
}
|
|
41
|
-
};
|
|
42
|
-
const persistAgentRunState = async (value) => {
|
|
43
|
-
try {
|
|
44
|
-
await writeAgentRunState(value);
|
|
45
|
-
}
|
|
46
|
-
catch (error) {
|
|
47
|
-
console.error(`Could not update agent state in ${resolveAgentStateDir(value.cwd)}: ${error.message}`);
|
|
48
|
-
}
|
|
49
|
-
};
|
|
50
|
-
const logAgentCleanupFailures = (failures) => {
|
|
51
|
-
for (const failure of failures) {
|
|
52
|
-
console.error(`Could not clean stale agent output ${failure.state.outputDir}: ${failure.error.message}`);
|
|
53
|
-
}
|
|
54
|
-
};
|
|
55
|
-
const logAgentOrphanCleanupFailures = (failures) => {
|
|
56
|
-
for (const failure of failures) {
|
|
57
|
-
console.error(`Could not clean stale agent output ${failure.outputDir}: ${failure.error.message}`);
|
|
58
|
-
}
|
|
59
|
-
};
|
|
60
|
-
const cleanupManagedAgentOutputs = async (params) => {
|
|
61
|
-
try {
|
|
62
|
-
const result = await cleanupAgentRunState({
|
|
63
|
-
cwd: params.cwd,
|
|
64
|
-
currentRunId: params.runId,
|
|
65
|
-
keepManagedRuns: params.managedOutput ? 1 : 0,
|
|
66
|
-
});
|
|
67
|
-
logAgentCleanupFailures(result.failed);
|
|
68
|
-
}
|
|
69
|
-
catch (error) {
|
|
70
|
-
console.error(`Could not clean agent state in ${resolveAgentStateDir(params.cwd)}: ${error.message}`);
|
|
71
|
-
}
|
|
72
|
-
try {
|
|
73
|
-
const staleResult = await cleanupStaleAgentRunStates({
|
|
74
|
-
cwd: params.cwd,
|
|
75
|
-
currentRunId: params.runId,
|
|
76
|
-
});
|
|
77
|
-
logAgentCleanupFailures(staleResult.failed);
|
|
78
|
-
logAgentOrphanCleanupFailures(staleResult.orphaned.failed);
|
|
79
|
-
}
|
|
80
|
-
catch (error) {
|
|
81
|
-
console.error(`Could not clean agent state in ${resolveAgentStateDir(params.cwd)}: ${error.message}`);
|
|
82
|
-
}
|
|
83
|
-
};
|
|
84
28
|
const agentEnvironmentOption = () => Option.String("--environment,--env", {
|
|
85
29
|
description: "Force specific environment ID to all tests in the run. Given environment has higher priority than the one defined in the config file (default: empty string)",
|
|
86
30
|
});
|
|
@@ -238,7 +182,7 @@ export class AgentCommand extends Command {
|
|
|
238
182
|
output,
|
|
239
183
|
expectations,
|
|
240
184
|
});
|
|
241
|
-
const { executeAgentMode } = await import("./
|
|
185
|
+
const { executeAgentMode } = await import("./run.js");
|
|
242
186
|
await executeAgentMode({
|
|
243
187
|
configPath,
|
|
244
188
|
cwd: configuredCwd,
|
|
@@ -263,33 +207,13 @@ export class AgentCommand extends Command {
|
|
|
263
207
|
throwCliUsageError(error);
|
|
264
208
|
}
|
|
265
209
|
const expectationError = error;
|
|
266
|
-
const cwd = await realpath(configuredCwd ?? process.cwd());
|
|
267
|
-
const runId = randomUUID();
|
|
268
|
-
const managedOutput = !output;
|
|
269
|
-
const outputDir = output ? resolve(cwd, output) : await mkdtemp(join(tmpdir(), "allure-agent-"));
|
|
270
210
|
const commandString = formatAgentCommand(args);
|
|
271
|
-
|
|
272
|
-
|
|
211
|
+
await writeInvalidAgentExpectationRun({
|
|
212
|
+
configuredCwd,
|
|
213
|
+
output,
|
|
273
214
|
command: commandString,
|
|
274
215
|
error: expectationError,
|
|
275
216
|
});
|
|
276
|
-
const generatedAtMs = Date.parse(generatedAt);
|
|
277
|
-
const generatedAtTimestamp = Number.isFinite(generatedAtMs) ? generatedAtMs : Date.now();
|
|
278
|
-
await persistAgentRunState({
|
|
279
|
-
runId,
|
|
280
|
-
cwd,
|
|
281
|
-
outputDir,
|
|
282
|
-
managedOutput,
|
|
283
|
-
command: commandString,
|
|
284
|
-
startedAt: generatedAtTimestamp,
|
|
285
|
-
finishedAt: generatedAtTimestamp,
|
|
286
|
-
status: "finished",
|
|
287
|
-
exitCode: 1,
|
|
288
|
-
pid: process.pid,
|
|
289
|
-
});
|
|
290
|
-
await cleanupManagedAgentOutputs({ cwd, runId, managedOutput });
|
|
291
|
-
printAgentOutputLinks(outputDir);
|
|
292
|
-
console.error(expectationError.message);
|
|
293
217
|
exit(1);
|
|
294
218
|
}
|
|
295
219
|
}
|
|
@@ -428,7 +352,7 @@ export class AgentInspectCommand extends Command {
|
|
|
428
352
|
output,
|
|
429
353
|
expectations,
|
|
430
354
|
});
|
|
431
|
-
const { executeAgentInspectMode } = await import("./
|
|
355
|
+
const { executeAgentInspectMode } = await import("./run.js");
|
|
432
356
|
await executeAgentInspectMode({
|
|
433
357
|
configPath,
|
|
434
358
|
cwd: configuredCwd,
|
|
@@ -452,33 +376,13 @@ export class AgentInspectCommand extends Command {
|
|
|
452
376
|
throwCliUsageError(error);
|
|
453
377
|
}
|
|
454
378
|
const expectationError = error;
|
|
455
|
-
const cwd = await realpath(configuredCwd ?? process.cwd());
|
|
456
|
-
const runId = randomUUID();
|
|
457
|
-
const managedOutput = !output;
|
|
458
|
-
const outputDir = output ? resolve(cwd, output) : await mkdtemp(join(tmpdir(), "allure-agent-"));
|
|
459
379
|
const commandString = formatAgentInspectCommand({ dumps, resultsDir });
|
|
460
|
-
|
|
461
|
-
|
|
380
|
+
await writeInvalidAgentExpectationRun({
|
|
381
|
+
configuredCwd,
|
|
382
|
+
output,
|
|
462
383
|
command: commandString,
|
|
463
384
|
error: expectationError,
|
|
464
385
|
});
|
|
465
|
-
const generatedAtMs = Date.parse(generatedAt);
|
|
466
|
-
const generatedAtTimestamp = Number.isFinite(generatedAtMs) ? generatedAtMs : Date.now();
|
|
467
|
-
await persistAgentRunState({
|
|
468
|
-
runId,
|
|
469
|
-
cwd,
|
|
470
|
-
outputDir,
|
|
471
|
-
managedOutput,
|
|
472
|
-
command: commandString,
|
|
473
|
-
startedAt: generatedAtTimestamp,
|
|
474
|
-
finishedAt: generatedAtTimestamp,
|
|
475
|
-
status: "finished",
|
|
476
|
-
exitCode: 1,
|
|
477
|
-
pid: process.pid,
|
|
478
|
-
});
|
|
479
|
-
await cleanupManagedAgentOutputs({ cwd, runId, managedOutput });
|
|
480
|
-
printAgentOutputLinks(outputDir);
|
|
481
|
-
console.error(expectationError.message);
|
|
482
386
|
exit(1);
|
|
483
387
|
}
|
|
484
388
|
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { writeAgentRunState, type AgentExpectationUsageError } from "@allurereport/plugin-agent";
|
|
2
|
+
export declare const formatAgentCommand: (args: string[]) => string;
|
|
3
|
+
export declare const formatAgentInspectCommand: (params: {
|
|
4
|
+
dumps?: string[];
|
|
5
|
+
resultsDir?: string[];
|
|
6
|
+
}) => string;
|
|
7
|
+
export declare const resolveAgentOutputDir: (cwd: string, output?: string) => string | Promise<string>;
|
|
8
|
+
export declare const printAgentOutputLinks: (outputDir: string) => void;
|
|
9
|
+
export declare const persistAgentRunState: (value: Parameters<typeof writeAgentRunState>[0]) => Promise<void>;
|
|
10
|
+
export declare const cleanupManagedAgentOutputs: (params: {
|
|
11
|
+
cwd: string;
|
|
12
|
+
runId: string;
|
|
13
|
+
managedOutput: boolean;
|
|
14
|
+
}) => Promise<void>;
|
|
15
|
+
export declare const writeInvalidAgentExpectationRun: (params: {
|
|
16
|
+
configuredCwd?: string;
|
|
17
|
+
output?: string;
|
|
18
|
+
command: string;
|
|
19
|
+
error: AgentExpectationUsageError;
|
|
20
|
+
}) => Promise<void>;
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import * as console from "node:console";
|
|
2
|
+
import { randomUUID } from "node:crypto";
|
|
3
|
+
import { mkdtemp, realpath } from "node:fs/promises";
|
|
4
|
+
import { tmpdir } from "node:os";
|
|
5
|
+
import { join, resolve } from "node:path";
|
|
6
|
+
import process from "node:process";
|
|
7
|
+
import { cleanupAgentRunState, cleanupStaleAgentRunStates, formatAgentOutputLinks, resolveAgentStateDir, writeAgentRunState, writeInvalidAgentExpectationOutput, } from "@allurereport/plugin-agent";
|
|
8
|
+
export const formatAgentCommand = (args) => args.join(" ");
|
|
9
|
+
export const formatAgentInspectCommand = (params) => [
|
|
10
|
+
"allure",
|
|
11
|
+
"agent",
|
|
12
|
+
"inspect",
|
|
13
|
+
...(params.dumps ?? []).flatMap((dump) => ["--dump", dump]),
|
|
14
|
+
...(params.resultsDir ?? []),
|
|
15
|
+
].join(" ");
|
|
16
|
+
export const resolveAgentOutputDir = (cwd, output) => output ? resolve(cwd, output) : mkdtemp(join(tmpdir(), "allure-agent-"));
|
|
17
|
+
export const printAgentOutputLinks = (outputDir) => {
|
|
18
|
+
for (const line of formatAgentOutputLinks(outputDir)) {
|
|
19
|
+
console.log(line);
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
export const persistAgentRunState = async (value) => {
|
|
23
|
+
try {
|
|
24
|
+
await writeAgentRunState(value);
|
|
25
|
+
}
|
|
26
|
+
catch (error) {
|
|
27
|
+
console.error(`Could not update agent state in ${resolveAgentStateDir(value.cwd)}: ${error.message}`);
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
const logAgentCleanupFailures = (failures) => {
|
|
31
|
+
for (const failure of failures) {
|
|
32
|
+
console.error(`Could not clean stale agent output ${failure.state.outputDir}: ${failure.error.message}`);
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
const logAgentOrphanCleanupFailures = (failures) => {
|
|
36
|
+
for (const failure of failures) {
|
|
37
|
+
console.error(`Could not clean stale agent output ${failure.outputDir}: ${failure.error.message}`);
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
export const cleanupManagedAgentOutputs = async (params) => {
|
|
41
|
+
try {
|
|
42
|
+
const result = await cleanupAgentRunState({
|
|
43
|
+
cwd: params.cwd,
|
|
44
|
+
currentRunId: params.runId,
|
|
45
|
+
keepManagedRuns: params.managedOutput ? 1 : 0,
|
|
46
|
+
});
|
|
47
|
+
logAgentCleanupFailures(result.failed);
|
|
48
|
+
}
|
|
49
|
+
catch (error) {
|
|
50
|
+
console.error(`Could not clean agent state in ${resolveAgentStateDir(params.cwd)}: ${error.message}`);
|
|
51
|
+
}
|
|
52
|
+
try {
|
|
53
|
+
const staleResult = await cleanupStaleAgentRunStates({
|
|
54
|
+
cwd: params.cwd,
|
|
55
|
+
currentRunId: params.runId,
|
|
56
|
+
});
|
|
57
|
+
logAgentCleanupFailures(staleResult.failed);
|
|
58
|
+
logAgentOrphanCleanupFailures(staleResult.orphaned.failed);
|
|
59
|
+
}
|
|
60
|
+
catch (error) {
|
|
61
|
+
console.error(`Could not clean agent state in ${resolveAgentStateDir(params.cwd)}: ${error.message}`);
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
export const writeInvalidAgentExpectationRun = async (params) => {
|
|
65
|
+
const cwd = await realpath(params.configuredCwd ?? process.cwd());
|
|
66
|
+
const runId = randomUUID();
|
|
67
|
+
const managedOutput = !params.output;
|
|
68
|
+
const outputDir = await resolveAgentOutputDir(cwd, params.output);
|
|
69
|
+
const { generatedAt } = await writeInvalidAgentExpectationOutput({
|
|
70
|
+
outputDir,
|
|
71
|
+
command: params.command,
|
|
72
|
+
error: params.error,
|
|
73
|
+
});
|
|
74
|
+
const generatedAtMs = Date.parse(generatedAt);
|
|
75
|
+
const generatedAtTimestamp = Number.isFinite(generatedAtMs) ? generatedAtMs : Date.now();
|
|
76
|
+
await persistAgentRunState({
|
|
77
|
+
runId,
|
|
78
|
+
cwd,
|
|
79
|
+
outputDir,
|
|
80
|
+
managedOutput,
|
|
81
|
+
command: params.command,
|
|
82
|
+
startedAt: generatedAtTimestamp,
|
|
83
|
+
finishedAt: generatedAtTimestamp,
|
|
84
|
+
status: "finished",
|
|
85
|
+
exitCode: 1,
|
|
86
|
+
pid: process.pid,
|
|
87
|
+
});
|
|
88
|
+
await cleanupManagedAgentOutputs({ cwd, runId, managedOutput });
|
|
89
|
+
printAgentOutputLinks(outputDir);
|
|
90
|
+
console.error(params.error.message);
|
|
91
|
+
};
|
|
@@ -1,21 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export declare const formatAgentCommand: (args: string[]) => string;
|
|
3
|
-
export declare const formatAgentInspectCommand: (params: {
|
|
4
|
-
dumps?: string[];
|
|
5
|
-
resultsDir?: string[];
|
|
6
|
-
}) => string;
|
|
7
|
-
export declare const printAgentOutputLinks: (outputDir: string) => void;
|
|
1
|
+
import { type AgentExpectationsInput, type AgentHumanReportMode } from "@allurereport/plugin-agent";
|
|
8
2
|
export declare const printAgentRunStart: (outputDir: string, commandString: string) => void;
|
|
9
3
|
export declare const printAgentRunSummary: (outputDir: string, options?: {
|
|
10
4
|
durationMs?: number;
|
|
11
5
|
rerunCommand?: string;
|
|
12
6
|
}) => Promise<void>;
|
|
13
|
-
export declare const persistAgentRunState: (value: Parameters<typeof writeAgentRunState>[0]) => Promise<void>;
|
|
14
|
-
export declare const cleanupManagedAgentOutputs: (params: {
|
|
15
|
-
cwd: string;
|
|
16
|
-
runId: string;
|
|
17
|
-
managedOutput: boolean;
|
|
18
|
-
}) => Promise<void>;
|
|
19
7
|
export type ExecuteAgentModeParams = {
|
|
20
8
|
configPath?: string;
|
|
21
9
|
cwd?: string;
|
|
@@ -1,30 +1,17 @@
|
|
|
1
1
|
import * as console from "node:console";
|
|
2
2
|
import { randomUUID } from "node:crypto";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import { join, resolve } from "node:path";
|
|
3
|
+
import { realpath, rm } from "node:fs/promises";
|
|
4
|
+
import { resolve } from "node:path";
|
|
6
5
|
import process, { exit } from "node:process";
|
|
7
6
|
import { AllureReport, isFileNotFoundError, readConfig } from "@allurereport/core";
|
|
8
|
-
import { createAgentTestPlanContext, AgentUsageError, assertExplicitAgentOutputDirIsSafe,
|
|
9
|
-
import { normalizeCommandEnvironmentOptions, resolveCommandEnvironment } from "
|
|
10
|
-
import { createChildAllureCliEnvironment, getActiveAllureCliCommand } from "
|
|
11
|
-
import { findFilesByGlobs } from "
|
|
12
|
-
import { resolveAndFindResultsDirs, resolveResultsPatterns } from "
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
|
|
16
|
-
export const formatAgentInspectCommand = (params) => [
|
|
17
|
-
"allure",
|
|
18
|
-
"agent",
|
|
19
|
-
"inspect",
|
|
20
|
-
...(params.dumps ?? []).flatMap((dump) => ["--dump", dump]),
|
|
21
|
-
...(params.resultsDir ?? []),
|
|
22
|
-
].join(" ");
|
|
23
|
-
export const printAgentOutputLinks = (outputDir) => {
|
|
24
|
-
for (const line of formatAgentOutputLinks(outputDir)) {
|
|
25
|
-
console.log(line);
|
|
26
|
-
}
|
|
27
|
-
};
|
|
7
|
+
import { createAgentTestPlanContext, AgentUsageError, assertExplicitAgentOutputDirIsSafe, formatAgentRunSummary, isPathInside, loadAgentOutput, normalizeAgentRerunPreset, parseAgentLabelFilters, } from "@allurereport/plugin-agent";
|
|
8
|
+
import { normalizeCommandEnvironmentOptions, resolveCommandEnvironment } from "../../utils/environment.js";
|
|
9
|
+
import { createChildAllureCliEnvironment, getActiveAllureCliCommand } from "../../utils/execution-context.js";
|
|
10
|
+
import { findFilesByGlobs } from "../../utils/fileSystem.js";
|
|
11
|
+
import { resolveAndFindResultsDirs, resolveResultsPatterns } from "../../utils/resultsPatterns.js";
|
|
12
|
+
import { executeAllureRun, executeNestedAllureCommand } from "../commons/run.js";
|
|
13
|
+
import { createAgentHumanReportConfig } from "./human-report.js";
|
|
14
|
+
import { cleanupManagedAgentOutputs, formatAgentCommand, formatAgentInspectCommand, persistAgentRunState, printAgentOutputLinks, resolveAgentOutputDir, } from "./lifecycle.js";
|
|
28
15
|
export const printAgentRunStart = (outputDir, commandString) => {
|
|
29
16
|
console.log(`agent output: ${outputDir}`);
|
|
30
17
|
console.log(commandString);
|
|
@@ -48,48 +35,6 @@ export const printAgentRunSummary = async (outputDir, options = {}) => {
|
|
|
48
35
|
printAgentOutputLinks(outputDir);
|
|
49
36
|
}
|
|
50
37
|
};
|
|
51
|
-
export const persistAgentRunState = async (value) => {
|
|
52
|
-
try {
|
|
53
|
-
await writeAgentRunState(value);
|
|
54
|
-
}
|
|
55
|
-
catch (error) {
|
|
56
|
-
console.error(`Could not update agent state in ${resolveAgentStateDir(value.cwd)}: ${error.message}`);
|
|
57
|
-
}
|
|
58
|
-
};
|
|
59
|
-
const logAgentCleanupFailures = (failures) => {
|
|
60
|
-
for (const failure of failures) {
|
|
61
|
-
console.error(`Could not clean stale agent output ${failure.state.outputDir}: ${failure.error.message}`);
|
|
62
|
-
}
|
|
63
|
-
};
|
|
64
|
-
const logAgentOrphanCleanupFailures = (failures) => {
|
|
65
|
-
for (const failure of failures) {
|
|
66
|
-
console.error(`Could not clean stale agent output ${failure.outputDir}: ${failure.error.message}`);
|
|
67
|
-
}
|
|
68
|
-
};
|
|
69
|
-
export const cleanupManagedAgentOutputs = async (params) => {
|
|
70
|
-
try {
|
|
71
|
-
const result = await cleanupAgentRunState({
|
|
72
|
-
cwd: params.cwd,
|
|
73
|
-
currentRunId: params.runId,
|
|
74
|
-
keepManagedRuns: params.managedOutput ? 1 : 0,
|
|
75
|
-
});
|
|
76
|
-
logAgentCleanupFailures(result.failed);
|
|
77
|
-
}
|
|
78
|
-
catch (error) {
|
|
79
|
-
console.error(`Could not clean agent state in ${resolveAgentStateDir(params.cwd)}: ${error.message}`);
|
|
80
|
-
}
|
|
81
|
-
try {
|
|
82
|
-
const staleResult = await cleanupStaleAgentRunStates({
|
|
83
|
-
cwd: params.cwd,
|
|
84
|
-
currentRunId: params.runId,
|
|
85
|
-
});
|
|
86
|
-
logAgentCleanupFailures(staleResult.failed);
|
|
87
|
-
logAgentOrphanCleanupFailures(staleResult.orphaned.failed);
|
|
88
|
-
}
|
|
89
|
-
catch (error) {
|
|
90
|
-
console.error(`Could not clean agent state in ${resolveAgentStateDir(params.cwd)}: ${error.message}`);
|
|
91
|
-
}
|
|
92
|
-
};
|
|
93
38
|
export const executeAgentMode = async (params) => {
|
|
94
39
|
const { configPath, cwd: configuredCwd, output, expectations, inlineExpectations, environment, environmentName, silent, rerunFrom, rerunLatest, rerunPreset, rerunEnvironments, rerunLabels, reportMode, args, resultsPatterns: cliResultsPatterns = [], } = params;
|
|
95
40
|
const command = args[0];
|
|
@@ -131,7 +76,7 @@ export const executeAgentMode = async (params) => {
|
|
|
131
76
|
}
|
|
132
77
|
const runId = randomUUID();
|
|
133
78
|
const managedOutput = !output;
|
|
134
|
-
const outputDir =
|
|
79
|
+
const outputDir = await resolveAgentOutputDir(cwd, output);
|
|
135
80
|
const expectationsPath = expectations ? resolve(cwd, expectations) : undefined;
|
|
136
81
|
const environmentOptions = {
|
|
137
82
|
environment,
|
|
@@ -256,7 +201,7 @@ export const executeAgentInspectMode = async (params) => {
|
|
|
256
201
|
}
|
|
257
202
|
const runId = randomUUID();
|
|
258
203
|
const managedOutput = !output;
|
|
259
|
-
const outputDir =
|
|
204
|
+
const outputDir = await resolveAgentOutputDir(cwd, output);
|
|
260
205
|
const expectationsPath = expectations ? resolve(cwd, expectations) : undefined;
|
|
261
206
|
const commandString = formatAgentInspectCommand({ dumps: dumpFiles, resultsDir: resultDirectories });
|
|
262
207
|
const hiddenLabels = hideLabels?.length ? hideLabels : undefined;
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { exit } from "node:process";
|
|
1
|
+
import { cwd as processCwd, exit } from "node:process";
|
|
2
2
|
import { createReportContext } from "@allurereport/ci";
|
|
3
3
|
import { AllureReport, filterFailedQualityGateResults, stringifyQualityGateResults } from "@allurereport/core";
|
|
4
4
|
import { KnownError } from "@allurereport/service";
|
|
5
|
-
import { red } from "yoctocolors";
|
|
5
|
+
import { red, yellow } from "yoctocolors";
|
|
6
|
+
import { cleanOutputDirectory, isOutputDirectoryNotEmpty } from "../../utils/cleanOutput.js";
|
|
6
7
|
import { findFilesByGlobs } from "../../utils/fileSystem.js";
|
|
7
8
|
import { logError } from "../../utils/logs.js";
|
|
8
9
|
import { resolveAndFindResultsDirs, resolveResultsPatterns } from "../../utils/resultsPatterns.js";
|
|
@@ -19,6 +20,31 @@ export const generate = async (params) => {
|
|
|
19
20
|
exit(1);
|
|
20
21
|
return;
|
|
21
22
|
}
|
|
23
|
+
if (params.clean) {
|
|
24
|
+
try {
|
|
25
|
+
const globalAttachments = await findFilesByGlobs(params.config.cwd ?? processCwd(), params.config.globalAttachments ?? [], { dot: false, windowsPathsNoEscape: false });
|
|
26
|
+
await cleanOutputDirectory({
|
|
27
|
+
output: params.config.output,
|
|
28
|
+
cwd: params.cwd,
|
|
29
|
+
resultsDirs: resultDirectories,
|
|
30
|
+
inputs: [
|
|
31
|
+
...dumpFiles,
|
|
32
|
+
...globalAttachments,
|
|
33
|
+
params.config.historyPath,
|
|
34
|
+
params.config.resolutions?.knownIssuesPath,
|
|
35
|
+
].filter((path) => !!path),
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
catch (error) {
|
|
39
|
+
console.error(red(error instanceof Error ? error.message : String(error)));
|
|
40
|
+
exit(1);
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
if (!params.clean && params.config.output && (await isOutputDirectoryNotEmpty(params.cwd, params.config.output))) {
|
|
45
|
+
console.warn(yellow(`The output directory "${params.config.output}" is not empty. Files of a previous report may break the layout ` +
|
|
46
|
+
"of the new one. Use the --clean option to remove the directory before generating."));
|
|
47
|
+
}
|
|
22
48
|
try {
|
|
23
49
|
const allureReport = new AllureReport(params.config);
|
|
24
50
|
await allureReport.restoreState(Array.from(dumpFiles));
|
|
@@ -8,8 +8,10 @@ export declare class GenerateCommand extends Command {
|
|
|
8
8
|
cwd: string | undefined;
|
|
9
9
|
reportName: string | undefined;
|
|
10
10
|
dump: string[] | undefined;
|
|
11
|
+
clean: boolean | undefined;
|
|
11
12
|
open: boolean | undefined;
|
|
12
13
|
port: string | undefined;
|
|
14
|
+
host: string | undefined;
|
|
13
15
|
historyLimit: string | undefined;
|
|
14
16
|
historyBaseUrl: string | undefined;
|
|
15
17
|
hideLabels: string[] | undefined;
|
|
@@ -2,6 +2,7 @@ import { cwd as processCwd } from "node:process";
|
|
|
2
2
|
import { readConfig } from "@allurereport/core";
|
|
3
3
|
import { serve } from "@allurereport/static-server";
|
|
4
4
|
import { Command, Option } from "clipanion";
|
|
5
|
+
import { serverOptionsFromConfig } from "../utils/serverOptions.js";
|
|
5
6
|
import { generate } from "./commons/generate.js";
|
|
6
7
|
export class GenerateCommand extends Command {
|
|
7
8
|
constructor() {
|
|
@@ -26,12 +27,19 @@ export class GenerateCommand extends Command {
|
|
|
26
27
|
"Allure loads the matched archives before generating the report. " +
|
|
27
28
|
"This option can be specified multiple times.",
|
|
28
29
|
});
|
|
30
|
+
this.clean = Option.Boolean("--clean", {
|
|
31
|
+
description: "Remove the output directory before generating the report (default: false). " +
|
|
32
|
+
"Refuses to remove the working directory, the home directory, a filesystem root, or the results directories",
|
|
33
|
+
});
|
|
29
34
|
this.open = Option.Boolean("--open", {
|
|
30
35
|
description: "Open the report in the default browser after generation (default: false)",
|
|
31
36
|
});
|
|
32
37
|
this.port = Option.String("--port", {
|
|
33
38
|
description: "The port to serve the reports on. If not set, the server starts on a random port",
|
|
34
39
|
});
|
|
40
|
+
this.host = Option.String("--host", {
|
|
41
|
+
description: "The host (network interface) to serve the reports on, e.g. 127.0.0.1 or 0.0.0.0 (default: all interfaces)",
|
|
42
|
+
});
|
|
35
43
|
this.historyLimit = Option.String("--history-limit", {
|
|
36
44
|
description: "Limits the number of history entries to keep (default: unlimited)",
|
|
37
45
|
});
|
|
@@ -54,6 +62,7 @@ export class GenerateCommand extends Command {
|
|
|
54
62
|
output: this.output,
|
|
55
63
|
open: this.open,
|
|
56
64
|
port: this.port,
|
|
65
|
+
host: this.host,
|
|
57
66
|
hideLabels,
|
|
58
67
|
historyLimit: this.historyLimit !== undefined ? parseInt(this.historyLimit, 10) : undefined,
|
|
59
68
|
...(this.historyBaseUrl !== undefined ? { historyBaseUrl: this.historyBaseUrl } : {}),
|
|
@@ -64,13 +73,14 @@ export class GenerateCommand extends Command {
|
|
|
64
73
|
resultsDir: this.resultsDir,
|
|
65
74
|
cwd,
|
|
66
75
|
config,
|
|
76
|
+
clean: this.clean,
|
|
67
77
|
});
|
|
68
78
|
if (!result) {
|
|
69
79
|
return;
|
|
70
80
|
}
|
|
71
81
|
if (config.open) {
|
|
72
82
|
await serve({
|
|
73
|
-
|
|
83
|
+
...serverOptionsFromConfig(config),
|
|
74
84
|
servePath: config.output,
|
|
75
85
|
open: true,
|
|
76
86
|
});
|
|
@@ -84,11 +94,19 @@ GenerateCommand.usage = Command.Usage({
|
|
|
84
94
|
details: "This command generates a report from the provided Allure Results directories. " +
|
|
85
95
|
"When a quality gate is configured, the command validates the loaded results and finishes writing the report or dump before returning its status.",
|
|
86
96
|
examples: [
|
|
97
|
+
[
|
|
98
|
+
"generate ./allure-results --open --host 0.0.0.0",
|
|
99
|
+
"Generate a report and serve it on all network interfaces after generation",
|
|
100
|
+
],
|
|
87
101
|
["generate ./allure-results", "Generate a report from the ./allure-results directory"],
|
|
88
102
|
[
|
|
89
103
|
"generate ./allure-results --output custom-report",
|
|
90
104
|
"Generate a report from the ./allure-results directory to the custom-report directory",
|
|
91
105
|
],
|
|
106
|
+
[
|
|
107
|
+
"generate ./allure-results --clean",
|
|
108
|
+
"Remove the existing report directory before generating a fresh report from ./allure-results",
|
|
109
|
+
],
|
|
92
110
|
[
|
|
93
111
|
"generate --dump=windows.zip --dump=macos.zip ./allure-results",
|
|
94
112
|
"Generate a report using data from windows.zip and macos.zip archives and using results from the ./allure-results directory",
|
package/dist/commands/index.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ export * from "./history.js";
|
|
|
2
2
|
export * from "./testplan.js";
|
|
3
3
|
export * from "./classic.js";
|
|
4
4
|
export * from "./allure2.js";
|
|
5
|
-
export * from "./
|
|
5
|
+
export * from "./agents/index.js";
|
|
6
6
|
export * from "./awesome.js";
|
|
7
7
|
export * from "./csv.js";
|
|
8
8
|
export * from "./check.js";
|
|
@@ -20,3 +20,4 @@ export * from "./dashboard.js";
|
|
|
20
20
|
export * from "./results/index.js";
|
|
21
21
|
export * from "./jira/index.js";
|
|
22
22
|
export * from "./gitlab/index.js";
|
|
23
|
+
export * from "./migrate.js";
|
package/dist/commands/index.js
CHANGED
|
@@ -2,7 +2,7 @@ export * from "./history.js";
|
|
|
2
2
|
export * from "./testplan.js";
|
|
3
3
|
export * from "./classic.js";
|
|
4
4
|
export * from "./allure2.js";
|
|
5
|
-
export * from "./
|
|
5
|
+
export * from "./agents/index.js";
|
|
6
6
|
export * from "./awesome.js";
|
|
7
7
|
export * from "./csv.js";
|
|
8
8
|
export * from "./check.js";
|
|
@@ -20,3 +20,4 @@ export * from "./dashboard.js";
|
|
|
20
20
|
export * from "./results/index.js";
|
|
21
21
|
export * from "./jira/index.js";
|
|
22
22
|
export * from "./gitlab/index.js";
|
|
23
|
+
export * from "./migrate.js";
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Command } from "clipanion";
|
|
2
|
+
import { renderAllure2CommandMap } from "../utils/allure2Hints.js";
|
|
3
|
+
export class MigrateCommand extends Command {
|
|
4
|
+
async execute() {
|
|
5
|
+
this.context.stdout.write(`${renderAllure2CommandMap()}\n`);
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
MigrateCommand.paths = [["migrate"]];
|
|
9
|
+
MigrateCommand.usage = Command.Usage({
|
|
10
|
+
category: "Reports",
|
|
11
|
+
description: "Shows how Allure 2 commands map to Allure 3",
|
|
12
|
+
details: "This command prints the Allure 3 equivalents of the Allure 2 commands and options " +
|
|
13
|
+
"(serve, generate --clean, --host, --profile, etc.) for users who are moving from Allure 2.",
|
|
14
|
+
examples: [["migrate", "Print the Allure 2 to Allure 3 command mapping"]],
|
|
15
|
+
});
|