allure 3.15.0 → 3.16.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 +16 -7
- package/dist/commands/agent-run.d.ts +1 -0
- package/dist/commands/agent-run.js +11 -8
- package/dist/commands/agent.d.ts +1 -0
- package/dist/commands/agent.js +19 -8
- package/dist/commands/allure2.js +10 -10
- package/dist/commands/awesome.js +10 -10
- package/dist/commands/check.js +1 -1
- package/dist/commands/classic.js +10 -10
- package/dist/commands/commons/generate.d.ts +1 -1
- package/dist/commands/commons/generate.js +7 -3
- package/dist/commands/commons/resultsDiscovery.d.ts +5 -0
- package/dist/commands/commons/resultsDiscovery.js +17 -0
- package/dist/commands/commons/run.d.ts +2 -3
- package/dist/commands/commons/run.js +37 -26
- package/dist/commands/csv.js +10 -10
- package/dist/commands/dashboard.js +9 -9
- package/dist/commands/generate.js +5 -4
- package/dist/commands/history.js +6 -4
- package/dist/commands/index.d.ts +1 -0
- package/dist/commands/index.js +1 -0
- package/dist/commands/jira/clear.js +1 -1
- package/dist/commands/log.js +9 -9
- package/dist/commands/open.js +9 -5
- package/dist/commands/qualityGate.js +5 -8
- package/dist/commands/results/pack.d.ts +1 -0
- package/dist/commands/results/pack.js +12 -14
- package/dist/commands/run.d.ts +1 -0
- package/dist/commands/run.js +20 -10
- package/dist/commands/slack.js +9 -9
- package/dist/commands/testopsPlan.d.ts +7 -0
- package/dist/commands/testopsPlan.js +65 -0
- package/dist/commands/testplan.js +7 -5
- package/dist/commands/watch.d.ts +1 -0
- package/dist/commands/watch.js +71 -25
- package/dist/index.js +2 -1
- package/dist/utils/index.d.ts +2 -0
- package/dist/utils/index.js +2 -0
- package/dist/utils/process.js +1 -0
- package/dist/utils/resultsPatterns.d.ts +12 -0
- package/dist/utils/resultsPatterns.js +37 -0
- package/dist/utils/signals.d.ts +18 -0
- package/dist/utils/signals.js +52 -0
- package/package.json +21 -21
|
@@ -5,15 +5,15 @@ import { AllureReport, readConfig } from "@allurereport/core";
|
|
|
5
5
|
import DashboardPlugin from "@allurereport/plugin-dashboard";
|
|
6
6
|
import { Command, Option } from "clipanion";
|
|
7
7
|
import { red } from "yoctocolors";
|
|
8
|
-
import {
|
|
8
|
+
import { resolveAndFindResultsDirs } from "../utils/resultsPatterns.js";
|
|
9
9
|
export class DashboardCommand extends Command {
|
|
10
10
|
constructor() {
|
|
11
11
|
super(...arguments);
|
|
12
12
|
this.resultsDir = Option.Rest({
|
|
13
|
-
name: "Patterns to match test results directories
|
|
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)",
|
|
@@ -39,12 +39,6 @@ export class DashboardCommand extends Command {
|
|
|
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 defaultDashboardOptions = {
|
|
50
44
|
singleFile: this.singleFile ?? false,
|
|
@@ -56,6 +50,12 @@ export class DashboardCommand extends Command {
|
|
|
56
50
|
output: this.output,
|
|
57
51
|
name: this.reportName,
|
|
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: "dashboard",
|
|
@@ -7,10 +7,10 @@ export class GenerateCommand extends Command {
|
|
|
7
7
|
constructor() {
|
|
8
8
|
super(...arguments);
|
|
9
9
|
this.resultsDir = Option.Rest({
|
|
10
|
-
name: "Patterns to match test results directories
|
|
10
|
+
name: "Patterns to match test results directories. Overrides config.resultsDir. Defaults to ./**/allure-results when neither is set.",
|
|
11
11
|
});
|
|
12
12
|
this.config = Option.String("--config,-c", {
|
|
13
|
-
description: "The path Allure config file",
|
|
13
|
+
description: "The path to Allure config file",
|
|
14
14
|
});
|
|
15
15
|
this.output = Option.String("--output,-o", {
|
|
16
16
|
description: "The output directory name. Absolute paths are accepted as well (default: allure-report)",
|
|
@@ -39,7 +39,8 @@ export class GenerateCommand extends Command {
|
|
|
39
39
|
description: "Hide labels by exact name in generated reports. Repeat the option for multiple labels",
|
|
40
40
|
});
|
|
41
41
|
this.knownIssues = Option.String("--known-issues", {
|
|
42
|
-
description: "Path to known issues file"
|
|
42
|
+
description: "Path to known issues file. " +
|
|
43
|
+
"Allure loads the file and updates it every time with the actual resolutions data of type `issue`",
|
|
43
44
|
});
|
|
44
45
|
}
|
|
45
46
|
async execute() {
|
|
@@ -52,7 +53,7 @@ export class GenerateCommand extends Command {
|
|
|
52
53
|
port: this.port,
|
|
53
54
|
hideLabels,
|
|
54
55
|
historyLimit: this.historyLimit !== undefined ? parseInt(this.historyLimit, 10) : undefined,
|
|
55
|
-
knownIssuesPath: this.knownIssues,
|
|
56
|
+
resolutions: { knownIssuesPath: this.knownIssues },
|
|
56
57
|
});
|
|
57
58
|
await generate({
|
|
58
59
|
dump: this.dump,
|
package/dist/commands/history.js
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import * as console from "node:console";
|
|
2
2
|
import process, { exit } from "node:process";
|
|
3
|
-
import { AllureReport, resolveConfig } from "@allurereport/core";
|
|
3
|
+
import { AllureReport, readRawConfig, resolveConfig } from "@allurereport/core";
|
|
4
4
|
import { Command, Option } from "clipanion";
|
|
5
5
|
import { red } from "yoctocolors";
|
|
6
|
-
import {
|
|
6
|
+
import { resolveAndFindResultsDirs } from "../utils/resultsPatterns.js";
|
|
7
7
|
export class HistoryCommand extends Command {
|
|
8
8
|
constructor() {
|
|
9
9
|
super(...arguments);
|
|
10
10
|
this.resultsDir = Option.Rest({
|
|
11
|
-
name: "Patterns to match test results directories
|
|
11
|
+
name: "Patterns to match test results directories. Overrides config.resultsDir. Defaults to ./**/allure-results when neither is set.",
|
|
12
12
|
});
|
|
13
13
|
this.historyPath = Option.String("--history-path,-h", {
|
|
14
14
|
description: "The path to history file",
|
|
@@ -21,7 +21,9 @@ export class HistoryCommand extends Command {
|
|
|
21
21
|
});
|
|
22
22
|
}
|
|
23
23
|
async execute() {
|
|
24
|
-
const
|
|
24
|
+
const cwd = process.cwd();
|
|
25
|
+
const rawConfig = await readRawConfig(cwd);
|
|
26
|
+
const { resultDirectories, patterns } = await resolveAndFindResultsDirs(cwd, this.resultsDir, rawConfig.resultsDir);
|
|
25
27
|
if (!resultDirectories.length) {
|
|
26
28
|
console.error(red(`No test results directories found matching pattern: ${patterns}`));
|
|
27
29
|
exit(1);
|
package/dist/commands/index.d.ts
CHANGED
package/dist/commands/index.js
CHANGED
|
@@ -8,7 +8,7 @@ class BaseJiraCommand extends Command {
|
|
|
8
8
|
constructor() {
|
|
9
9
|
super(...arguments);
|
|
10
10
|
this.config = Option.String("--config,-c", {
|
|
11
|
-
description: "The path Allure config file",
|
|
11
|
+
description: "The path to Allure config file",
|
|
12
12
|
});
|
|
13
13
|
this.cwd = Option.String("--cwd", {
|
|
14
14
|
description: "The working directory for the command to run (default: current working directory)",
|
package/dist/commands/log.js
CHANGED
|
@@ -5,15 +5,15 @@ import { AllureReport, readConfig } from "@allurereport/core";
|
|
|
5
5
|
import LogPlugin from "@allurereport/plugin-log";
|
|
6
6
|
import { Command, Option } from "clipanion";
|
|
7
7
|
import { red } from "yoctocolors";
|
|
8
|
-
import {
|
|
8
|
+
import { resolveAndFindResultsDirs } from "../utils/resultsPatterns.js";
|
|
9
9
|
export class LogCommand extends Command {
|
|
10
10
|
constructor() {
|
|
11
11
|
super(...arguments);
|
|
12
12
|
this.resultsDir = Option.Rest({
|
|
13
|
-
name: "Patterns to match test results directories
|
|
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)",
|
|
@@ -30,12 +30,6 @@ export class LogCommand extends Command {
|
|
|
30
30
|
}
|
|
31
31
|
async execute() {
|
|
32
32
|
const cwd = await realpath(this.cwd ?? process.cwd());
|
|
33
|
-
const { resultDirectories, patterns } = await findAllureResultDirectories(cwd, this.resultsDir);
|
|
34
|
-
if (!resultDirectories.length) {
|
|
35
|
-
console.error(red(`No test results directories found matching pattern: ${patterns}`));
|
|
36
|
-
exit(1);
|
|
37
|
-
return;
|
|
38
|
-
}
|
|
39
33
|
const before = new Date().getTime();
|
|
40
34
|
const defaultLogOptions = {
|
|
41
35
|
allSteps: this.allSteps ?? false,
|
|
@@ -43,6 +37,12 @@ export class LogCommand extends Command {
|
|
|
43
37
|
groupBy: this.groupBy ?? "suite",
|
|
44
38
|
};
|
|
45
39
|
const config = await readConfig(cwd, this.config);
|
|
40
|
+
const { resultDirectories, patterns } = await resolveAndFindResultsDirs(cwd, this.resultsDir, config.resultsDir);
|
|
41
|
+
if (!resultDirectories.length) {
|
|
42
|
+
console.error(red(`No test results directories found matching pattern: ${patterns}`));
|
|
43
|
+
exit(1);
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
46
|
config.plugins = [
|
|
47
47
|
{
|
|
48
48
|
id: "log",
|
package/dist/commands/open.js
CHANGED
|
@@ -8,15 +8,17 @@ import { serve } from "@allurereport/static-server";
|
|
|
8
8
|
import { Command, Option } from "clipanion";
|
|
9
9
|
import { red } from "yoctocolors";
|
|
10
10
|
import { findFilesByGlobs } from "./../utils/fileSystem.js";
|
|
11
|
+
import { resolveResultsPatterns } from "./../utils/resultsPatterns.js";
|
|
12
|
+
import { notifySignals, waitForAbort } from "./../utils/signals.js";
|
|
11
13
|
import { generate } from "./commons/generate.js";
|
|
12
14
|
export class OpenCommand extends Command {
|
|
13
15
|
constructor() {
|
|
14
16
|
super(...arguments);
|
|
15
17
|
this.resultsDir = Option.Rest({
|
|
16
|
-
name: "A report to open or
|
|
18
|
+
name: "A report path to open, or results patterns. Overrides config.resultsDir. Empty Rest serves the configured output.",
|
|
17
19
|
});
|
|
18
20
|
this.config = Option.String("--config,-c", {
|
|
19
|
-
description: "The path Allure config file",
|
|
21
|
+
description: "The path to Allure config file",
|
|
20
22
|
});
|
|
21
23
|
this.port = Option.String("--port", {
|
|
22
24
|
description: "The port to serve the reports on. If not set, the server starts on a random port",
|
|
@@ -35,6 +37,7 @@ export class OpenCommand extends Command {
|
|
|
35
37
|
port: this.port,
|
|
36
38
|
});
|
|
37
39
|
const servePath = this.resolveReportPath(cwd, this.resultsDir, config.output);
|
|
40
|
+
const resolvedPatterns = resolveResultsPatterns(this.resultsDir, config.resultsDir);
|
|
38
41
|
if (await this.reportExists(servePath)) {
|
|
39
42
|
await serve({
|
|
40
43
|
port: config.port ? parseInt(config.port, 10) : undefined,
|
|
@@ -42,7 +45,7 @@ export class OpenCommand extends Command {
|
|
|
42
45
|
open: true,
|
|
43
46
|
});
|
|
44
47
|
}
|
|
45
|
-
else if (
|
|
48
|
+
else if (resolvedPatterns.length) {
|
|
46
49
|
const tmpDir = await mkdtemp(join(tmpdir(), "allure-report-"));
|
|
47
50
|
const config = await readConfig(cwd, this.config, {
|
|
48
51
|
port: this.port,
|
|
@@ -54,12 +57,13 @@ export class OpenCommand extends Command {
|
|
|
54
57
|
cwd,
|
|
55
58
|
config,
|
|
56
59
|
});
|
|
57
|
-
|
|
60
|
+
const notifier = notifySignals(["SIGINT", "SIGTERM"]);
|
|
61
|
+
void waitForAbort(notifier.signal).then(async () => {
|
|
58
62
|
try {
|
|
59
63
|
await rm(config.output, { recursive: true });
|
|
60
64
|
}
|
|
61
65
|
catch { }
|
|
62
|
-
process.exit(0);
|
|
66
|
+
process.exit(notifier.info()?.code ?? 0);
|
|
63
67
|
});
|
|
64
68
|
await serve({
|
|
65
69
|
port: config.port ? parseInt(config.port, 10) : undefined,
|
|
@@ -6,15 +6,15 @@ import { Command, Option } from "clipanion";
|
|
|
6
6
|
import * as typanion from "typanion";
|
|
7
7
|
import { red } from "yoctocolors";
|
|
8
8
|
import { environmentNameOption, environmentOption, normalizeCommandEnvironmentOptions, resolveCommandEnvironment, } from "../utils/environment.js";
|
|
9
|
-
import {
|
|
9
|
+
import { resolveAndFindResultsDirs } from "../utils/resultsPatterns.js";
|
|
10
10
|
export class QualityGateCommand extends Command {
|
|
11
11
|
constructor() {
|
|
12
12
|
super(...arguments);
|
|
13
13
|
this.resultsDir = Option.Rest({
|
|
14
|
-
name: "Patterns to match test results directories
|
|
14
|
+
name: "Patterns to match test results directories. Overrides config.resultsDir. Defaults to ./**/allure-results when neither is set.",
|
|
15
15
|
});
|
|
16
16
|
this.config = Option.String("--config,-c", {
|
|
17
|
-
description: "The path Allure config file",
|
|
17
|
+
description: "The path to Allure config file",
|
|
18
18
|
});
|
|
19
19
|
this.fastFail = Option.Boolean("--fast-fail", {
|
|
20
20
|
description: "Force the command to fail if there are any rule failures",
|
|
@@ -49,7 +49,7 @@ export class QualityGateCommand extends Command {
|
|
|
49
49
|
const cwd = await realpath(this.cwd ?? processCwd());
|
|
50
50
|
const { maxFailures, minTestsCount, successRate, fastFail } = this;
|
|
51
51
|
const config = await readConfig(cwd, this.config, {
|
|
52
|
-
knownIssuesPath: this.knownIssues,
|
|
52
|
+
resolutions: { knownIssuesPath: this.knownIssues },
|
|
53
53
|
});
|
|
54
54
|
const resolvedEnvironment = resolveCommandEnvironment(config, environmentOptions);
|
|
55
55
|
const rules = {};
|
|
@@ -81,13 +81,12 @@ export class QualityGateCommand extends Command {
|
|
|
81
81
|
exit(-1);
|
|
82
82
|
return;
|
|
83
83
|
}
|
|
84
|
-
const { resultDirectories, patterns } = await
|
|
84
|
+
const { resultDirectories, patterns } = await resolveAndFindResultsDirs(cwd, this.resultsDir, config.resultsDir);
|
|
85
85
|
if (!resultDirectories.length) {
|
|
86
86
|
console.error(red(`No test results directories found matching pattern: ${patterns}`));
|
|
87
87
|
exit(1);
|
|
88
88
|
return;
|
|
89
89
|
}
|
|
90
|
-
const knownIssues = await allureReport.store.allKnownIssues();
|
|
91
90
|
const state = new QualityGateState();
|
|
92
91
|
allureReport.realtimeSubscriber.onTestResults(async (trsIds) => {
|
|
93
92
|
const trs = await Promise.all(trsIds.map((id) => allureReport.store.testResultById(id)));
|
|
@@ -95,7 +94,6 @@ export class QualityGateCommand extends Command {
|
|
|
95
94
|
const { results, fastFailed } = await allureReport.validate({
|
|
96
95
|
trs: nonRetryTrs,
|
|
97
96
|
environment: resolvedEnvironment?.id,
|
|
98
|
-
knownIssues,
|
|
99
97
|
state,
|
|
100
98
|
});
|
|
101
99
|
if (!fastFailed) {
|
|
@@ -112,7 +110,6 @@ export class QualityGateCommand extends Command {
|
|
|
112
110
|
const allTrs = await allureReport.store.allTestResults({ includeRetries: false });
|
|
113
111
|
const validationResults = await allureReport.validate({
|
|
114
112
|
trs: allTrs,
|
|
115
|
-
knownIssues,
|
|
116
113
|
environment: resolvedEnvironment?.id,
|
|
117
114
|
});
|
|
118
115
|
if (validationResults.results.length === 0) {
|
|
@@ -9,44 +9,42 @@ import * as fs from "node:fs/promises";
|
|
|
9
9
|
import { realpath } from "node:fs/promises";
|
|
10
10
|
import { basename, join, resolve } from "node:path";
|
|
11
11
|
import { exit } from "node:process";
|
|
12
|
+
import { readRawConfig } from "@allurereport/core";
|
|
12
13
|
import AdmZip from "adm-zip";
|
|
13
14
|
import { Command, Option } from "clipanion";
|
|
14
|
-
import { glob } from "glob";
|
|
15
15
|
import { green, red } from "yoctocolors";
|
|
16
|
+
import { resolveAndFindResultsDirs } from "../../utils/resultsPatterns.js";
|
|
16
17
|
export class ResultsPackCommand extends Command {
|
|
17
18
|
constructor() {
|
|
18
19
|
super(...arguments);
|
|
19
20
|
_ResultsPackCommand_instances.add(this);
|
|
20
21
|
this.resultsDir = Option.String({
|
|
21
22
|
required: false,
|
|
22
|
-
name: "Pattern to match test results directories
|
|
23
|
+
name: "Pattern to match test results directories. Overrides config.resultsDir. Defaults to ./**/allure-results when neither is set.",
|
|
23
24
|
});
|
|
24
25
|
this.name = Option.String("--name", {
|
|
25
26
|
description: "The archive name (default: allure-results.zip)",
|
|
26
27
|
});
|
|
28
|
+
this.config = Option.String("--config,-c", {
|
|
29
|
+
description: "The path to Allure config file",
|
|
30
|
+
});
|
|
27
31
|
this.cwd = Option.String("--cwd", {
|
|
28
32
|
description: "The working directory for the command to run (default: current working directory)",
|
|
29
33
|
});
|
|
30
34
|
}
|
|
31
35
|
async execute() {
|
|
32
36
|
const cwd = await realpath(this.cwd ?? process.cwd());
|
|
33
|
-
const
|
|
37
|
+
const rawConfig = await readRawConfig(cwd, this.config);
|
|
38
|
+
const cliPatterns = this.resultsDir ? [this.resultsDir] : [];
|
|
39
|
+
const { resultDirectories, patterns } = await resolveAndFindResultsDirs(cwd, cliPatterns, rawConfig.resultsDir);
|
|
34
40
|
const archiveName = this.name ?? "allure-results.zip";
|
|
35
|
-
const resultsDirectories = (await glob(resultsDir, {
|
|
36
|
-
mark: true,
|
|
37
|
-
nodir: false,
|
|
38
|
-
dot: true,
|
|
39
|
-
absolute: true,
|
|
40
|
-
windowsPathsNoEscape: true,
|
|
41
|
-
cwd,
|
|
42
|
-
})).filter((p) => /(\/|\\)$/.test(p));
|
|
43
41
|
const resultsFiles = new Set();
|
|
44
|
-
if (
|
|
45
|
-
console.error(red(`No test results directories found matching pattern: ${
|
|
42
|
+
if (resultDirectories.length === 0) {
|
|
43
|
+
console.error(red(`No test results directories found matching pattern: ${patterns}`));
|
|
46
44
|
exit(1);
|
|
47
45
|
return;
|
|
48
46
|
}
|
|
49
|
-
for (const dir of
|
|
47
|
+
for (const dir of resultDirectories) {
|
|
50
48
|
const files = await fs.readdir(dir);
|
|
51
49
|
if (files.length === 0) {
|
|
52
50
|
continue;
|
package/dist/commands/run.d.ts
CHANGED
|
@@ -17,6 +17,7 @@ export declare class RunCommand extends Command {
|
|
|
17
17
|
historyLimit: string | undefined;
|
|
18
18
|
hideLabels: string[] | undefined;
|
|
19
19
|
knownIssues: string | undefined;
|
|
20
|
+
resultsDir: string[] | undefined;
|
|
20
21
|
commandToRun: string[];
|
|
21
22
|
get logs(): "pipe" | "inherit" | "ignore";
|
|
22
23
|
execute(): Promise<void>;
|
package/dist/commands/run.js
CHANGED
|
@@ -7,12 +7,14 @@ import { serve } from "@allurereport/static-server";
|
|
|
7
7
|
import { Command, Option, UsageError } from "clipanion";
|
|
8
8
|
import { environmentNameOption, environmentOption, normalizeCommandEnvironmentOptions, resolveCommandEnvironment, } from "../utils/environment.js";
|
|
9
9
|
import { createChildAllureCliEnvironment, getActiveAllureCliCommand } from "../utils/execution-context.js";
|
|
10
|
+
import { parseRunCommand, resolveResultsPatterns } from "../utils/resultsPatterns.js";
|
|
10
11
|
import { executeAllureRun, executeNestedAllureCommand } from "./commons/run.js";
|
|
12
|
+
const missingRunCommandUsageError = () => new UsageError("expecting command to be specified after --, e.g. allure run -- npm run test");
|
|
11
13
|
export class RunCommand extends Command {
|
|
12
14
|
constructor() {
|
|
13
15
|
super(...arguments);
|
|
14
16
|
this.config = Option.String("--config,-c", {
|
|
15
|
-
description: "The path Allure config file",
|
|
17
|
+
description: "The path to Allure config file",
|
|
16
18
|
});
|
|
17
19
|
this.cwd = Option.String("--cwd", {
|
|
18
20
|
description: "The working directory for the command to run (default: current working directory)",
|
|
@@ -52,6 +54,9 @@ export class RunCommand extends Command {
|
|
|
52
54
|
this.knownIssues = Option.String("--known-issues", {
|
|
53
55
|
description: "Path to known issues file",
|
|
54
56
|
});
|
|
57
|
+
this.resultsDir = Option.Array("--results-dir", {
|
|
58
|
+
description: "Glob pattern or path for Allure results directories (repeatable). Overrides config.resultsDir. Quote globs in the shell",
|
|
59
|
+
});
|
|
55
60
|
this.commandToRun = Option.Rest();
|
|
56
61
|
}
|
|
57
62
|
get logs() {
|
|
@@ -61,17 +66,15 @@ export class RunCommand extends Command {
|
|
|
61
66
|
return this.ignoreLogs ? "inherit" : "pipe";
|
|
62
67
|
}
|
|
63
68
|
async execute() {
|
|
64
|
-
const
|
|
65
|
-
if (!
|
|
66
|
-
throw
|
|
69
|
+
const { command, commandArgs } = parseRunCommand(this.commandToRun);
|
|
70
|
+
if (!command) {
|
|
71
|
+
throw missingRunCommandUsageError();
|
|
67
72
|
}
|
|
68
73
|
const before = new Date().getTime();
|
|
69
74
|
process.on("exit", (exitCode) => {
|
|
70
75
|
const after = new Date().getTime();
|
|
71
76
|
console.log(`exit code ${exitCode} (${after - before}ms)`);
|
|
72
77
|
});
|
|
73
|
-
const command = args[0];
|
|
74
|
-
const commandArgs = args.slice(1);
|
|
75
78
|
const cwd = await realpath(this.cwd ?? process.cwd());
|
|
76
79
|
const hideLabels = this.hideLabels?.length ? this.hideLabels : undefined;
|
|
77
80
|
console.log(`${command} ${commandArgs.join(" ")}`);
|
|
@@ -98,8 +101,9 @@ export class RunCommand extends Command {
|
|
|
98
101
|
port: this.port,
|
|
99
102
|
hideLabels,
|
|
100
103
|
historyLimit: this.historyLimit !== undefined ? parseInt(this.historyLimit, 10) : undefined,
|
|
101
|
-
knownIssuesPath: this.knownIssues,
|
|
104
|
+
resolutions: { knownIssuesPath: this.knownIssues },
|
|
102
105
|
});
|
|
106
|
+
const resultsPatterns = resolveResultsPatterns(this.resultsDir ?? [], config.resultsDir);
|
|
103
107
|
const resolvedEnvironment = resolveCommandEnvironment(config, environmentOptions);
|
|
104
108
|
const withRerun = maxRerun > 0;
|
|
105
109
|
const withQualityGate = !!config.qualityGate && !withRerun;
|
|
@@ -135,10 +139,8 @@ export class RunCommand extends Command {
|
|
|
135
139
|
]),
|
|
136
140
|
],
|
|
137
141
|
});
|
|
138
|
-
const knownIssues = await allureReport.store.allKnownIssues();
|
|
139
142
|
const { globalExitCode } = await executeAllureRun({
|
|
140
143
|
allureReport,
|
|
141
|
-
knownIssues,
|
|
142
144
|
cwd,
|
|
143
145
|
command,
|
|
144
146
|
commandArgs,
|
|
@@ -149,6 +151,7 @@ export class RunCommand extends Command {
|
|
|
149
151
|
silent: this.silent,
|
|
150
152
|
ignoreLogs: this.ignoreLogs,
|
|
151
153
|
maxRerun,
|
|
154
|
+
resultsPatterns,
|
|
152
155
|
});
|
|
153
156
|
if (config.open) {
|
|
154
157
|
await serve({
|
|
@@ -165,7 +168,10 @@ export class RunCommand extends Command {
|
|
|
165
168
|
RunCommand.paths = [["run"]];
|
|
166
169
|
RunCommand.usage = Command.Usage({
|
|
167
170
|
description: "Run specified command",
|
|
168
|
-
details: "This command runs the specified command and collects Allure results."
|
|
171
|
+
details: "This command runs the specified command and collects Allure results. " +
|
|
172
|
+
"Override results discovery with repeated `--results-dir` (CLI overrides `config.resultsDir`). " +
|
|
173
|
+
"When neither is set, directories named `allure-results` are discovered dynamically. " +
|
|
174
|
+
"Quote globs in the shell so they are not expanded early.",
|
|
169
175
|
examples: [
|
|
170
176
|
["run -- npm run test", "Run npm run test and collect Allure results"],
|
|
171
177
|
["run --rerun 3 -- npm run test", "Run npm run test and rerun failed tests up to 3 times"],
|
|
@@ -173,5 +179,9 @@ RunCommand.usage = Command.Usage({
|
|
|
173
179
|
"run --dump=my-dump -- npm run test",
|
|
174
180
|
"Run npm run test and pack inner report state into my-dump.zip archive to restore the state in the next run",
|
|
175
181
|
],
|
|
182
|
+
[
|
|
183
|
+
"run --results-dir './artifacts/**/allure-results' -- npm test",
|
|
184
|
+
"Override results discovery with a quoted glob",
|
|
185
|
+
],
|
|
176
186
|
],
|
|
177
187
|
});
|
package/dist/commands/slack.js
CHANGED
|
@@ -5,15 +5,15 @@ import { AllureReport, readConfig } from "@allurereport/core";
|
|
|
5
5
|
import SlackPlugin from "@allurereport/plugin-slack";
|
|
6
6
|
import { Command, Option } from "clipanion";
|
|
7
7
|
import { red } from "yoctocolors";
|
|
8
|
-
import {
|
|
8
|
+
import { resolveAndFindResultsDirs } from "../utils/resultsPatterns.js";
|
|
9
9
|
export class SlackCommand extends Command {
|
|
10
10
|
constructor() {
|
|
11
11
|
super(...arguments);
|
|
12
12
|
this.resultsDir = Option.Rest({
|
|
13
|
-
name: "Patterns to match test results directories
|
|
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)",
|
|
@@ -29,18 +29,18 @@ export class SlackCommand extends Command {
|
|
|
29
29
|
}
|
|
30
30
|
async execute() {
|
|
31
31
|
const cwd = await realpath(this.cwd ?? process.cwd());
|
|
32
|
-
const { resultDirectories, patterns } = await findAllureResultDirectories(cwd, this.resultsDir);
|
|
33
|
-
if (!resultDirectories.length) {
|
|
34
|
-
console.error(red(`No test results directories found matching pattern: ${patterns}`));
|
|
35
|
-
exit(1);
|
|
36
|
-
return;
|
|
37
|
-
}
|
|
38
32
|
const before = new Date().getTime();
|
|
39
33
|
const defaultSlackOptions = {
|
|
40
34
|
token: this.token,
|
|
41
35
|
channel: this.channel,
|
|
42
36
|
};
|
|
43
37
|
const config = await readConfig(cwd, this.config);
|
|
38
|
+
const { resultDirectories, patterns } = await resolveAndFindResultsDirs(cwd, this.resultsDir, config.resultsDir);
|
|
39
|
+
if (!resultDirectories.length) {
|
|
40
|
+
console.error(red(`No test results directories found matching pattern: ${patterns}`));
|
|
41
|
+
exit(1);
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
44
|
config.plugins = [
|
|
45
45
|
{
|
|
46
46
|
id: "slack",
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import * as console from "node:console";
|
|
2
|
+
import { rm, writeFile } from "node:fs/promises";
|
|
3
|
+
import { resolve } from "node:path";
|
|
4
|
+
import { env, exit } from "node:process";
|
|
5
|
+
import { applyAllureCiEnv } from "@allurereport/ci";
|
|
6
|
+
import { createServiceHttpClient } from "@allurereport/service";
|
|
7
|
+
import { Command, Option } from "clipanion";
|
|
8
|
+
import { red } from "yoctocolors";
|
|
9
|
+
export class TestOpsPlanCommand extends Command {
|
|
10
|
+
constructor() {
|
|
11
|
+
super(...arguments);
|
|
12
|
+
this.output = Option.String("--output,-o", {
|
|
13
|
+
description: "The output file name. Absolute paths are accepted as well (default: ./testplan.json)",
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
async execute() {
|
|
17
|
+
applyAllureCiEnv();
|
|
18
|
+
const jobRunId = Number(env.ALLURE_JOB_RUN_ID);
|
|
19
|
+
if (!Number.isInteger(jobRunId) || jobRunId <= 0) {
|
|
20
|
+
console.log("ALLURE_JOB_RUN_ID isn't set, skipping test plan generation");
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
const endpoint = env.ALLURE_ENDPOINT;
|
|
24
|
+
const accessToken = env.ALLURE_TOKEN;
|
|
25
|
+
if (!endpoint || !accessToken) {
|
|
26
|
+
console.error(red("ALLURE_ENDPOINT and ALLURE_TOKEN are required to fetch a test plan from TestOps"));
|
|
27
|
+
exit(1);
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
const client = createServiceHttpClient(endpoint, { apiToken: accessToken });
|
|
31
|
+
const output = resolve(this.output ?? "./testplan.json");
|
|
32
|
+
let tests;
|
|
33
|
+
try {
|
|
34
|
+
tests = await client.get(`/api/rs/jobrun/${jobRunId}/plan`, {
|
|
35
|
+
params: { expected: "true" },
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
catch (error) {
|
|
39
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
40
|
+
await rm(output, { force: true });
|
|
41
|
+
console.error(red(`Could not fetch the test plan for job run ${jobRunId}, continuing without one: ${message}`));
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
const testPlan = {
|
|
45
|
+
version: "1.0",
|
|
46
|
+
tests: (tests ?? []).map(({ id, selector }) => ({
|
|
47
|
+
...(id !== undefined ? { id: String(id) } : {}),
|
|
48
|
+
...(selector !== undefined ? { selector } : {}),
|
|
49
|
+
})),
|
|
50
|
+
};
|
|
51
|
+
await writeFile(output, JSON.stringify(testPlan), "utf-8");
|
|
52
|
+
console.log(`test plan for job run ${jobRunId} written to ${output} (${testPlan.tests.length} test(s))`);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
TestOpsPlanCommand.paths = [["testops-plan"]];
|
|
56
|
+
TestOpsPlanCommand.usage = Command.Usage({
|
|
57
|
+
description: "Fetches a testplan.json for the current TestOps job run",
|
|
58
|
+
details: "Reads ALLURE_JOB_RUN_ID and, when it's set, downloads the test cases selected for that job run " +
|
|
59
|
+
"from TestOps and writes them as a testplan.json compatible with ALLURE_TESTPLAN_PATH. " +
|
|
60
|
+
"Does nothing when ALLURE_JOB_RUN_ID isn't set, which covers every run TestOps didn't trigger itself.",
|
|
61
|
+
examples: [
|
|
62
|
+
["testops-plan", "Write ./testplan.json from the current job run, if any"],
|
|
63
|
+
["testops-plan --output custom-testplan.json", "Write to a custom path instead"],
|
|
64
|
+
],
|
|
65
|
+
});
|
|
@@ -1,22 +1,24 @@
|
|
|
1
1
|
import * as console from "node:console";
|
|
2
2
|
import { basename, dirname, resolve } from "node:path";
|
|
3
|
-
import { exit } from "node:process";
|
|
4
|
-
import { AllureReport, resolveConfig } from "@allurereport/core";
|
|
3
|
+
import { cwd as processCwd, exit } from "node:process";
|
|
4
|
+
import { AllureReport, readRawConfig, resolveConfig } from "@allurereport/core";
|
|
5
5
|
import { Command, Option } from "clipanion";
|
|
6
6
|
import { red } from "yoctocolors";
|
|
7
|
-
import {
|
|
7
|
+
import { resolveAndFindResultsDirs } from "../utils/resultsPatterns.js";
|
|
8
8
|
export class TestPlanCommand extends Command {
|
|
9
9
|
constructor() {
|
|
10
10
|
super(...arguments);
|
|
11
11
|
this.resultsDir = Option.Rest({
|
|
12
|
-
name: "Patterns to match test results directories
|
|
12
|
+
name: "Patterns to match test results directories. Overrides config.resultsDir. Defaults to ./**/allure-results when neither is set.",
|
|
13
13
|
});
|
|
14
14
|
this.output = Option.String("--output,-o", {
|
|
15
15
|
description: "The output file name. Absolute paths are accepted as well",
|
|
16
16
|
});
|
|
17
17
|
}
|
|
18
18
|
async execute() {
|
|
19
|
-
const
|
|
19
|
+
const cwd = processCwd();
|
|
20
|
+
const rawConfig = await readRawConfig(cwd);
|
|
21
|
+
const { resultDirectories, patterns } = await resolveAndFindResultsDirs(cwd, this.resultsDir, rawConfig.resultsDir);
|
|
20
22
|
if (!resultDirectories.length) {
|
|
21
23
|
console.error(red(`No test results directories found matching pattern: ${patterns}`));
|
|
22
24
|
exit(1);
|