allure 3.20.1 → 3.22.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 +64 -3
- 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/ghWorkflow.d.ts +11 -0
- package/dist/commands/ghWorkflow.js +77 -0
- package/dist/commands/index.d.ts +4 -1
- package/dist/commands/index.js +4 -1
- package/dist/commands/jira/clear.js +3 -3
- package/dist/commands/migrate.d.ts +6 -0
- package/dist/commands/migrate.js +15 -0
- package/dist/commands/open.d.ts +3 -10
- package/dist/commands/open.js +20 -99
- 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/serve.d.ts +19 -0
- package/dist/commands/serve.js +168 -0
- 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 +32 -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/ghWorkflow.d.ts +10 -0
- package/dist/utils/ghWorkflow.js +75 -0
- 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 +35 -28
- /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
|
|
|
@@ -123,6 +139,23 @@ npx allure agent query --latest tests --status failed
|
|
|
123
139
|
npx allure agent query --from ./agent-output findings --severity high
|
|
124
140
|
```
|
|
125
141
|
|
|
142
|
+
### Generating GitHub Actions Jobs
|
|
143
|
+
|
|
144
|
+
Print GitHub Actions jobs that run your tests once per environment and build a single Allure report from all of them:
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
npx allure gh-workflow --env foo --env bar --env baz -- npm test
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
Paste the output under `jobs:` in a workflow file and fill in the `TODO` steps (runtime setup and dependencies). The output has two jobs:
|
|
151
|
+
|
|
152
|
+
- `test` runs `allure run --environment=<id> --dump=allure-results-<id> -- <test command>` for every environment in a matrix and uploads `allure-results-<id>.zip` as an artifact;
|
|
153
|
+
- `report` downloads all `allure-results-*` artifacts and runs `allure generate --dump="allure-results-*/*.zip"`.
|
|
154
|
+
|
|
155
|
+
The environment id, the dump file, the artifact name and the download pattern have to agree with each other; the command keeps them consistent.
|
|
156
|
+
|
|
157
|
+
Environments come from `--env` (repeatable, no config needed). Without `--env`, the ids declared under `environments` in your Allure config are used (integer-like ids come first, as JavaScript orders object keys). Pass the test command after `--` (default: `npm test`); `--config` is also added to the generated `allure` commands. The versions of the GitHub actions in the output are examples, pin the ones you use. Errors are written to stderr with a non-zero exit code, while command-line syntax errors are reported by the CLI parser on stdout.
|
|
158
|
+
|
|
126
159
|
### Generating Reports Manually
|
|
127
160
|
|
|
128
161
|
If you already have test results and wish to generate a report manually, use the `generate` command:
|
|
@@ -149,6 +182,26 @@ npx allure open allure-report/awesome
|
|
|
149
182
|
|
|
150
183
|
If the provided directory doesn't contain previously generated report, it will be treated as a source of results, and a new report will be generated on the fly and opened in the browser.
|
|
151
184
|
|
|
185
|
+
To stop serving the report, press CTRL+C.
|
|
186
|
+
|
|
187
|
+
#### Serving a report without opening
|
|
188
|
+
|
|
189
|
+
Use the `serve` command to start a local report server without opening a browser:
|
|
190
|
+
|
|
191
|
+
```bash
|
|
192
|
+
npx allure serve <reportDir>
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
Like `open`, this command uses the configured output directory when `<reportDir>` is omitted and generates a report on the fly when given test results. Open the URL printed in the console to view the report.
|
|
196
|
+
|
|
197
|
+
Use `--host` and `--port` to control the interfaces and port to listen:
|
|
198
|
+
|
|
199
|
+
```bash
|
|
200
|
+
npx allure serve --port 8080 --host 127.0.0.1
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
Press CTRL+C to stop serving.
|
|
204
|
+
|
|
152
205
|
### Real-time Report Monitoring
|
|
153
206
|
|
|
154
207
|
When you need to monitor test execution live, the `watch` command provides dynamic report updates. It continuously monitors the specified results directory for changes and refreshes the report automatically:
|
|
@@ -176,12 +229,20 @@ To check your installed version of Allure 3, use:
|
|
|
176
229
|
npx allure --version
|
|
177
230
|
```
|
|
178
231
|
|
|
232
|
+
For direct interactive CLI invocations, Allure checks the npm registry for a newer version alongside the command.
|
|
233
|
+
Each eligible invocation makes one request with a one-second timeout; no update state is stored on disk. Missing
|
|
234
|
+
package metadata and network errors are silently ignored. The check is skipped for `allure agent`, help and version
|
|
235
|
+
output, quiet mode, CI, non-interactive terminals, and invocations through npm or Yarn. Disable it with `--no-update-notifier`
|
|
236
|
+
(for example, `allure --no-update-notifier generate ./allure-results`), or set `NO_UPDATE_NOTIFIER` for the environment.
|
|
237
|
+
Numbered prerelease versions (such as `3.21.0-beta.2`) check their matching npm dist-tag instead of the stable `latest`
|
|
238
|
+
tag. Unrecognized version formats are silently skipped.
|
|
239
|
+
|
|
179
240
|
## Configuration
|
|
180
241
|
|
|
181
242
|
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.
|
|
182
243
|
|
|
183
244
|
> [!TIP]
|
|
184
|
-
> We recommend using the **Awesome** plugin for the best experience.
|
|
245
|
+
> We recommend using the **Awesome** plugin for the best experience.
|
|
185
246
|
> Support for Classic and Allure 2-style reports is currently experimental.
|
|
186
247
|
|
|
187
248
|
### Example Configuration File
|
|
@@ -248,7 +309,7 @@ For example, setting `"reportLanguage": "fr"` will render the report interface i
|
|
|
248
309
|
|
|
249
310
|
You can also use `allurerc.json`, `allurerc.yaml`, or `allurerc.yml` files as a declarative way to configure Allure 3.
|
|
250
311
|
|
|
251
|
-
> [!WARNING]
|
|
312
|
+
> [!WARNING]
|
|
252
313
|
> Declarative formats don't support advanced features such as tests filtering or environments.
|
|
253
314
|
> If you need these features, please consider using the `allurerc.ts`, `allurerc.mts`, `allurerc.cts`, `allurerc.mjs`, or `allurerc.js` files.
|
|
254
315
|
|
|
@@ -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;
|