allure 3.0.0-beta.17 → 3.0.0-beta.19
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/dist/commands/generate.d.ts +2 -1
- package/dist/commands/generate.js +58 -7
- package/dist/commands/index.d.ts +1 -0
- package/dist/commands/index.js +1 -0
- package/dist/commands/projects/create.js +2 -2
- package/dist/commands/projects/delete.js +2 -2
- package/dist/commands/projects/list.js +1 -1
- package/dist/commands/qualityGate.d.ts +6 -1
- package/dist/commands/qualityGate.js +102 -25
- package/dist/commands/results/index.d.ts +2 -0
- package/dist/commands/results/index.js +2 -0
- package/dist/commands/results/pack.d.ts +10 -0
- package/dist/commands/results/pack.js +106 -0
- package/dist/commands/results/unpack.d.ts +9 -0
- package/dist/commands/results/unpack.js +79 -0
- package/dist/commands/run.d.ts +11 -0
- package/dist/commands/run.js +203 -39
- package/dist/index.d.ts +1 -1
- package/dist/index.js +4 -2
- package/dist/utils/process.d.ts +7 -1
- package/dist/utils/process.js +17 -6
- package/package.json +25 -19
|
@@ -2,10 +2,11 @@ import { Command } from "clipanion";
|
|
|
2
2
|
export declare class GenerateCommand extends Command {
|
|
3
3
|
static paths: string[][];
|
|
4
4
|
static usage: import("clipanion").Usage;
|
|
5
|
-
resultsDir: string;
|
|
5
|
+
resultsDir: string | undefined;
|
|
6
6
|
config: string | undefined;
|
|
7
7
|
output: string | undefined;
|
|
8
8
|
cwd: string | undefined;
|
|
9
9
|
reportName: string | undefined;
|
|
10
|
+
stage: string[] | undefined;
|
|
10
11
|
execute(): Promise<void>;
|
|
11
12
|
}
|
|
@@ -1,13 +1,19 @@
|
|
|
1
1
|
import { AllureReport, readConfig } from "@allurereport/core";
|
|
2
2
|
import { KnownError } from "@allurereport/service";
|
|
3
3
|
import { Command, Option } from "clipanion";
|
|
4
|
-
import
|
|
4
|
+
import { glob } from "glob";
|
|
5
|
+
import * as console from "node:console";
|
|
6
|
+
import { sep } from "node:path";
|
|
7
|
+
import { exit, cwd as processCwd } from "node:process";
|
|
5
8
|
import { red } from "yoctocolors";
|
|
6
9
|
import { logError } from "../utils/logs.js";
|
|
7
10
|
export class GenerateCommand extends Command {
|
|
8
11
|
constructor() {
|
|
9
12
|
super(...arguments);
|
|
10
|
-
this.resultsDir = Option.String({
|
|
13
|
+
this.resultsDir = Option.String({
|
|
14
|
+
required: false,
|
|
15
|
+
name: "Pattern to match test results directories in the current working directory (default: ./**/allure-results)",
|
|
16
|
+
});
|
|
11
17
|
this.config = Option.String("--config,-c", {
|
|
12
18
|
description: "The path Allure config file",
|
|
13
19
|
});
|
|
@@ -18,28 +24,65 @@ export class GenerateCommand extends Command {
|
|
|
18
24
|
description: "The working directory for the command to run (default: current working directory)",
|
|
19
25
|
});
|
|
20
26
|
this.reportName = Option.String("--report-name,--name", {
|
|
21
|
-
description: "The report name",
|
|
27
|
+
description: "The report name (default: Allure Report)",
|
|
28
|
+
});
|
|
29
|
+
this.stage = Option.Array("--stage", {
|
|
30
|
+
description: "Stages archives to restore state from (default: empty string)",
|
|
22
31
|
});
|
|
23
32
|
}
|
|
24
33
|
async execute() {
|
|
25
|
-
const
|
|
34
|
+
const cwd = this.cwd ?? processCwd();
|
|
35
|
+
const resultsDir = (this.resultsDir ?? "./**/allure-results").replace(/[\\/]$/, "");
|
|
36
|
+
const config = await readConfig(cwd, this.config, {
|
|
26
37
|
name: this.reportName,
|
|
27
38
|
output: this.output ?? "allure-report",
|
|
28
39
|
});
|
|
40
|
+
const stageDumpFiles = [];
|
|
41
|
+
const resultsDirectories = [];
|
|
42
|
+
if (this.stage?.length) {
|
|
43
|
+
for (const stage of this.stage) {
|
|
44
|
+
const matchedFiles = await glob(stage, {
|
|
45
|
+
nodir: true,
|
|
46
|
+
dot: true,
|
|
47
|
+
absolute: true,
|
|
48
|
+
windowsPathsNoEscape: true,
|
|
49
|
+
cwd,
|
|
50
|
+
});
|
|
51
|
+
stageDumpFiles.push(...matchedFiles);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
if (!!this.resultsDir || stageDumpFiles.length === 0) {
|
|
55
|
+
const matchedDirs = (await glob(resultsDir, {
|
|
56
|
+
mark: true,
|
|
57
|
+
nodir: false,
|
|
58
|
+
absolute: true,
|
|
59
|
+
dot: true,
|
|
60
|
+
windowsPathsNoEscape: true,
|
|
61
|
+
cwd,
|
|
62
|
+
})).filter((p) => p.endsWith(sep));
|
|
63
|
+
resultsDirectories.push(...matchedDirs);
|
|
64
|
+
}
|
|
65
|
+
if (resultsDirectories.length === 0 && stageDumpFiles.length === 0) {
|
|
66
|
+
console.log(red(`No test results directories found matching pattern: ${resultsDir}`));
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
29
69
|
try {
|
|
30
70
|
const allureReport = new AllureReport(config);
|
|
71
|
+
await allureReport.restoreState(Array.from(stageDumpFiles));
|
|
31
72
|
await allureReport.start();
|
|
32
|
-
|
|
73
|
+
for (const dir of resultsDirectories) {
|
|
74
|
+
await allureReport.readDirectory(dir);
|
|
75
|
+
}
|
|
33
76
|
await allureReport.done();
|
|
34
77
|
}
|
|
35
78
|
catch (error) {
|
|
36
79
|
if (error instanceof KnownError) {
|
|
37
80
|
console.error(red(error.message));
|
|
38
|
-
|
|
81
|
+
exit(1);
|
|
39
82
|
return;
|
|
40
83
|
}
|
|
41
84
|
await logError("Failed to generate report due to unexpected error", error);
|
|
42
|
-
|
|
85
|
+
exit(1);
|
|
43
86
|
}
|
|
44
87
|
}
|
|
45
88
|
}
|
|
@@ -53,5 +96,13 @@ GenerateCommand.usage = Command.Usage({
|
|
|
53
96
|
"generate ./allure-results --output custom-report",
|
|
54
97
|
"Generate a report from the ./allure-results directory to the custom-report directory",
|
|
55
98
|
],
|
|
99
|
+
[
|
|
100
|
+
"generate --stage=windows.zip --stage=macos.zip ./allure-results",
|
|
101
|
+
"Generate a report using data from windows.zip and macos.zip archives and using results from the ./allure-results directory",
|
|
102
|
+
],
|
|
103
|
+
[
|
|
104
|
+
"generate --stage=allure-*.zip",
|
|
105
|
+
"Generate a report using data from any stage archive that matches the given pattern only (ignoring results directories)",
|
|
106
|
+
],
|
|
56
107
|
],
|
|
57
108
|
});
|
package/dist/commands/index.d.ts
CHANGED
package/dist/commands/index.js
CHANGED
|
@@ -77,7 +77,7 @@ ProjectsCreateCommand.usage = Command.Usage({
|
|
|
77
77
|
description: "Creates a new project",
|
|
78
78
|
details: "This command creates a new project in the Allure Service.",
|
|
79
79
|
examples: [
|
|
80
|
-
["project
|
|
81
|
-
["project
|
|
80
|
+
["project create my-project", "Create a new project named 'my-project'"],
|
|
81
|
+
["project create", "Create a new project with a name from git repo or prompt for a name"],
|
|
82
82
|
],
|
|
83
83
|
});
|
|
@@ -62,7 +62,7 @@ ProjectsDeleteCommand.usage = Command.Usage({
|
|
|
62
62
|
description: "Deletes a project",
|
|
63
63
|
details: "This command deletes a project from the Allure Service.",
|
|
64
64
|
examples: [
|
|
65
|
-
["project
|
|
66
|
-
["project
|
|
65
|
+
["project delete my-project", "Delete the project named 'my-project' (with confirmation)"],
|
|
66
|
+
["project delete my-project --force", "Delete the project named 'my-project' without confirmation"],
|
|
67
67
|
],
|
|
68
68
|
});
|
|
@@ -71,5 +71,5 @@ ProjectsListCommand.usage = Command.Usage({
|
|
|
71
71
|
category: "Allure Service Projects",
|
|
72
72
|
description: "Shows list of all available projects for current user",
|
|
73
73
|
details: "This command lists all available projects for the current user and allows selecting one to get configuration information.",
|
|
74
|
-
examples: [["projects", "List all available projects"]],
|
|
74
|
+
examples: [["projects list", "List all available projects"]],
|
|
75
75
|
});
|
|
@@ -2,8 +2,13 @@ import { Command } from "clipanion";
|
|
|
2
2
|
export declare class QualityGateCommand extends Command {
|
|
3
3
|
static paths: string[][];
|
|
4
4
|
static usage: import("clipanion").Usage;
|
|
5
|
-
resultsDir: string;
|
|
5
|
+
resultsDir: string | undefined;
|
|
6
6
|
config: string | undefined;
|
|
7
|
+
fastFail: boolean | undefined;
|
|
8
|
+
maxFailures: number | undefined;
|
|
9
|
+
minTestsCount: number | undefined;
|
|
10
|
+
successRate: number | undefined;
|
|
11
|
+
knownIssues: string | undefined;
|
|
7
12
|
cwd: string | undefined;
|
|
8
13
|
execute(): Promise<void>;
|
|
9
14
|
}
|
|
@@ -1,45 +1,122 @@
|
|
|
1
|
-
import { AllureReport, readConfig } from "@allurereport/core";
|
|
1
|
+
import { AllureReport, QualityGateState, readConfig, stringifyQualityGateResults } from "@allurereport/core";
|
|
2
2
|
import { Command, Option } from "clipanion";
|
|
3
|
+
import { glob } from "glob";
|
|
3
4
|
import * as console from "node:console";
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
5
|
+
import { realpath } from "node:fs/promises";
|
|
6
|
+
import { sep } from "node:path";
|
|
7
|
+
import { exit, cwd as processCwd } from "node:process";
|
|
8
|
+
import * as typanion from "typanion";
|
|
9
|
+
import { red } from "yoctocolors";
|
|
6
10
|
export class QualityGateCommand extends Command {
|
|
7
11
|
constructor() {
|
|
8
12
|
super(...arguments);
|
|
9
|
-
this.resultsDir = Option.String({
|
|
13
|
+
this.resultsDir = Option.String({
|
|
14
|
+
required: false,
|
|
15
|
+
name: "Pattern to match test results directories in the current working directory (default: ./**/allure-results)",
|
|
16
|
+
});
|
|
10
17
|
this.config = Option.String("--config,-c", {
|
|
11
18
|
description: "The path Allure config file",
|
|
12
19
|
});
|
|
20
|
+
this.fastFail = Option.Boolean("--fast-fail", {
|
|
21
|
+
description: "Force the command to fail if there are any rule failures",
|
|
22
|
+
});
|
|
23
|
+
this.maxFailures = Option.String("--max-failures", {
|
|
24
|
+
description: "The maximum number of rule failures to allow before failing the command",
|
|
25
|
+
validator: typanion.isNumber(),
|
|
26
|
+
});
|
|
27
|
+
this.minTestsCount = Option.String("--min-tests-count", {
|
|
28
|
+
description: "The minimum number of tests to run before validating the quality gate",
|
|
29
|
+
validator: typanion.isNumber(),
|
|
30
|
+
});
|
|
31
|
+
this.successRate = Option.String("--success-rate", {
|
|
32
|
+
description: "The minimum success rate to allow before failing the command",
|
|
33
|
+
validator: typanion.isNumber(),
|
|
34
|
+
});
|
|
35
|
+
this.knownIssues = Option.String("--known-issues", {
|
|
36
|
+
description: "Path to the known issues file. Updates the file and quarantines failed tests when specified",
|
|
37
|
+
});
|
|
13
38
|
this.cwd = Option.String("--cwd", {
|
|
14
39
|
description: "The working directory for the command to run (default: current working directory)",
|
|
15
40
|
});
|
|
16
41
|
}
|
|
17
42
|
async execute() {
|
|
18
|
-
const
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
await
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
43
|
+
const cwd = await realpath(this.cwd ?? processCwd());
|
|
44
|
+
const resultsDir = (this.resultsDir ?? "./**/allure-results").replace(/[\\/]$/, "");
|
|
45
|
+
const { maxFailures, minTestsCount, successRate, fastFail, knownIssues: knownIssuesPath } = this;
|
|
46
|
+
const config = await readConfig(cwd, this.config, {
|
|
47
|
+
knownIssuesPath,
|
|
48
|
+
});
|
|
49
|
+
const rules = {};
|
|
50
|
+
if (maxFailures !== undefined) {
|
|
51
|
+
rules.maxFailures = maxFailures;
|
|
52
|
+
}
|
|
53
|
+
if (minTestsCount !== undefined) {
|
|
54
|
+
rules.minTestsCount = minTestsCount;
|
|
55
|
+
}
|
|
56
|
+
if (successRate !== undefined) {
|
|
57
|
+
rules.successRate = successRate;
|
|
58
|
+
}
|
|
59
|
+
if (fastFail) {
|
|
60
|
+
rules.fastFail = fastFail;
|
|
61
|
+
}
|
|
62
|
+
config.plugins = [];
|
|
63
|
+
if (Object.keys(rules).length > 0) {
|
|
64
|
+
config.qualityGate = {
|
|
65
|
+
rules: [rules],
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
const allureReport = new AllureReport(config);
|
|
69
|
+
if (!allureReport.hasQualityGate) {
|
|
70
|
+
console.error(red("Quality gate is not configured!"));
|
|
71
|
+
console.error(red("Add qualityGate to the config or consult help to know, how to use the command with command-line arguments"));
|
|
72
|
+
exit(-1);
|
|
25
73
|
return;
|
|
26
74
|
}
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
75
|
+
const resultsDirectories = (await glob(resultsDir, {
|
|
76
|
+
mark: true,
|
|
77
|
+
nodir: false,
|
|
78
|
+
absolute: true,
|
|
79
|
+
dot: true,
|
|
80
|
+
windowsPathsNoEscape: true,
|
|
81
|
+
cwd,
|
|
82
|
+
})).filter((p) => p.endsWith(sep));
|
|
83
|
+
if (resultsDirectories.length === 0) {
|
|
84
|
+
console.error("No Allure results directories found");
|
|
85
|
+
exit(0);
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
const knownIssues = await allureReport.store.allKnownIssues();
|
|
89
|
+
const state = new QualityGateState();
|
|
90
|
+
allureReport.realtimeSubscriber.onTestResults(async (trsIds) => {
|
|
91
|
+
const trs = await Promise.all(trsIds.map((id) => allureReport.store.testResultById(id)));
|
|
92
|
+
const notHiddenTrs = trs.filter((tr) => !tr.hidden);
|
|
93
|
+
const { results, fastFailed } = await allureReport.validate({
|
|
94
|
+
trs: notHiddenTrs,
|
|
95
|
+
knownIssues,
|
|
96
|
+
state,
|
|
97
|
+
});
|
|
98
|
+
if (!fastFailed) {
|
|
99
|
+
return;
|
|
38
100
|
}
|
|
39
|
-
console.error(
|
|
101
|
+
console.error(stringifyQualityGateResults(results));
|
|
102
|
+
exit(1);
|
|
103
|
+
});
|
|
104
|
+
await allureReport.start();
|
|
105
|
+
for (const dir of resultsDirectories) {
|
|
106
|
+
await allureReport.readDirectory(dir);
|
|
107
|
+
}
|
|
108
|
+
await allureReport.done();
|
|
109
|
+
const allTrs = await allureReport.store.allTestResults({ includeHidden: false });
|
|
110
|
+
const validationResults = await allureReport.validate({
|
|
111
|
+
trs: allTrs,
|
|
112
|
+
knownIssues,
|
|
113
|
+
});
|
|
114
|
+
if (validationResults.results.length === 0) {
|
|
115
|
+
exit(0);
|
|
116
|
+
return;
|
|
40
117
|
}
|
|
41
|
-
console.error(
|
|
42
|
-
exit(
|
|
118
|
+
console.error(stringifyQualityGateResults(validationResults.results));
|
|
119
|
+
exit(1);
|
|
43
120
|
}
|
|
44
121
|
}
|
|
45
122
|
QualityGateCommand.paths = [["quality-gate"]];
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Command } from "clipanion";
|
|
2
|
+
export declare class ResultsPackCommand extends Command {
|
|
3
|
+
#private;
|
|
4
|
+
static paths: string[][];
|
|
5
|
+
static usage: import("clipanion").Usage;
|
|
6
|
+
resultsDir: string | undefined;
|
|
7
|
+
name: string | undefined;
|
|
8
|
+
cwd: string | undefined;
|
|
9
|
+
execute(): Promise<void>;
|
|
10
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
|
2
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
|
3
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
4
|
+
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
5
|
+
};
|
|
6
|
+
var _ResultsPackCommand_instances, _ResultsPackCommand_formatSize;
|
|
7
|
+
import AdmZip from "adm-zip";
|
|
8
|
+
import { Command, Option } from "clipanion";
|
|
9
|
+
import { glob } from "glob";
|
|
10
|
+
import * as console from "node:console";
|
|
11
|
+
import * as fs from "node:fs/promises";
|
|
12
|
+
import { realpath } from "node:fs/promises";
|
|
13
|
+
import { basename, join, resolve, sep } from "node:path";
|
|
14
|
+
import { green, red } from "yoctocolors";
|
|
15
|
+
export class ResultsPackCommand extends Command {
|
|
16
|
+
constructor() {
|
|
17
|
+
super(...arguments);
|
|
18
|
+
_ResultsPackCommand_instances.add(this);
|
|
19
|
+
this.resultsDir = Option.String({
|
|
20
|
+
required: false,
|
|
21
|
+
name: "Pattern to match test results directories in the current working directory (default: ./**/allure-results)",
|
|
22
|
+
});
|
|
23
|
+
this.name = Option.String("--name", {
|
|
24
|
+
description: "The archive name (default: allure-results.zip)",
|
|
25
|
+
});
|
|
26
|
+
this.cwd = Option.String("--cwd", {
|
|
27
|
+
description: "The working directory for the command to run (default: current working directory)",
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
async execute() {
|
|
31
|
+
const cwd = await realpath(this.cwd ?? process.cwd());
|
|
32
|
+
const resultsDir = (this.resultsDir ?? "./**/allure-results").replace(/[\\/]$/, "");
|
|
33
|
+
const archiveName = this.name ?? "allure-results.zip";
|
|
34
|
+
const resultsDirectories = (await glob(resultsDir, {
|
|
35
|
+
mark: true,
|
|
36
|
+
nodir: false,
|
|
37
|
+
dot: true,
|
|
38
|
+
absolute: true,
|
|
39
|
+
windowsPathsNoEscape: true,
|
|
40
|
+
cwd,
|
|
41
|
+
})).filter((p) => p.endsWith(sep));
|
|
42
|
+
const resultsFiles = new Set();
|
|
43
|
+
if (resultsDirectories.length === 0) {
|
|
44
|
+
console.log(red(`No test results directories found matching pattern: ${resultsDir}`));
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
for (const dir of resultsDirectories) {
|
|
48
|
+
const files = await fs.readdir(dir);
|
|
49
|
+
if (files.length === 0) {
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
for (const file of files) {
|
|
53
|
+
resultsFiles.add(resolve(dir, file));
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
const outputPath = join(cwd, archiveName);
|
|
57
|
+
const zip = new AdmZip();
|
|
58
|
+
for (const file of resultsFiles) {
|
|
59
|
+
try {
|
|
60
|
+
const stats = await fs.stat(file);
|
|
61
|
+
if (stats.isFile()) {
|
|
62
|
+
zip.addLocalFile(file, "", basename(file));
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
console.log(red(`Error adding file ${file} to archive: ${error.message}`));
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
try {
|
|
70
|
+
zip.writeZip(outputPath);
|
|
71
|
+
const stats = await fs.stat(outputPath);
|
|
72
|
+
console.log(green(`Archive created successfully: ${outputPath}`));
|
|
73
|
+
console.log(green(`Total size: ${__classPrivateFieldGet(this, _ResultsPackCommand_instances, "m", _ResultsPackCommand_formatSize).call(this, stats.size)}. ${resultsFiles.size} results files have been collected`));
|
|
74
|
+
}
|
|
75
|
+
catch (err) {
|
|
76
|
+
console.log(red(`Error creating archive: ${err.message}`));
|
|
77
|
+
throw err;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
_ResultsPackCommand_instances = new WeakSet(), _ResultsPackCommand_formatSize = function _ResultsPackCommand_formatSize(bytes) {
|
|
82
|
+
const units = ["bytes", "KB", "MB", "GB"];
|
|
83
|
+
let size = bytes;
|
|
84
|
+
let unitIndex = 0;
|
|
85
|
+
while (size >= 1024 && unitIndex < units.length - 1) {
|
|
86
|
+
size /= 1024;
|
|
87
|
+
unitIndex++;
|
|
88
|
+
}
|
|
89
|
+
if (bytes === 0) {
|
|
90
|
+
return "0 bytes";
|
|
91
|
+
}
|
|
92
|
+
return unitIndex === 0 ? `${Math.round(size)} ${units[unitIndex]}` : `${size.toFixed(2)} ${units[unitIndex]}`;
|
|
93
|
+
};
|
|
94
|
+
ResultsPackCommand.paths = [["results", "pack"]];
|
|
95
|
+
ResultsPackCommand.usage = Command.Usage({
|
|
96
|
+
description: "Creates .zip archive with test results",
|
|
97
|
+
category: "Allure Test Results",
|
|
98
|
+
details: "This command creates .zip archive with all test results which can be collected in the project",
|
|
99
|
+
examples: [
|
|
100
|
+
["results pack", "Creates .zip archive with test results in directories matched to ./**/allure-results pattern"],
|
|
101
|
+
[
|
|
102
|
+
"results pack ./**/foo/**/my-results --name results.zip",
|
|
103
|
+
"Creates results.zip archive with test results in directories matched to ./**/foo/**/my-results pattern",
|
|
104
|
+
],
|
|
105
|
+
],
|
|
106
|
+
});
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Command } from "clipanion";
|
|
2
|
+
export declare class ResultsUnpackCommand extends Command {
|
|
3
|
+
static paths: string[][];
|
|
4
|
+
static usage: import("clipanion").Usage;
|
|
5
|
+
output: string;
|
|
6
|
+
archives: string[];
|
|
7
|
+
cwd: string | undefined;
|
|
8
|
+
execute(): Promise<void>;
|
|
9
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import AdmZip from "adm-zip";
|
|
2
|
+
import { Command, Option } from "clipanion";
|
|
3
|
+
import * as console from "node:console";
|
|
4
|
+
import * as fs from "node:fs/promises";
|
|
5
|
+
import { realpath } from "node:fs/promises";
|
|
6
|
+
import { basename, resolve } from "node:path";
|
|
7
|
+
import { green, red } from "yoctocolors";
|
|
8
|
+
export class ResultsUnpackCommand extends Command {
|
|
9
|
+
constructor() {
|
|
10
|
+
super(...arguments);
|
|
11
|
+
this.output = Option.String("--output", "./allure-results", {
|
|
12
|
+
description: "Output directory where the archives should be unarchived to (default: ./allure-results)",
|
|
13
|
+
});
|
|
14
|
+
this.archives = Option.Rest({
|
|
15
|
+
name: "List of test results archives to extract separated by spaces. If no archives are provided, the command will extract allure-results.zip archive",
|
|
16
|
+
});
|
|
17
|
+
this.cwd = Option.String("--cwd", {
|
|
18
|
+
description: "The working directory for the command to run (default: current working directory)",
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
async execute() {
|
|
22
|
+
const cwd = await realpath(this.cwd ?? process.cwd());
|
|
23
|
+
const outputDir = resolve(cwd, this.output);
|
|
24
|
+
const archives = this.archives.length > 0 ? this.archives : ["allure-results.zip"];
|
|
25
|
+
try {
|
|
26
|
+
await fs.mkdir(outputDir, { recursive: true });
|
|
27
|
+
}
|
|
28
|
+
catch (ignored) { }
|
|
29
|
+
let successCount = 0;
|
|
30
|
+
let failCount = 0;
|
|
31
|
+
for (const archivePath of archives) {
|
|
32
|
+
const resolvedPath = resolve(cwd, archivePath);
|
|
33
|
+
try {
|
|
34
|
+
await fs.access(resolvedPath);
|
|
35
|
+
console.log(`Extracting ${resolvedPath} to ${outputDir}`);
|
|
36
|
+
try {
|
|
37
|
+
const zip = new AdmZip(resolvedPath);
|
|
38
|
+
zip.extractAllTo(outputDir, true);
|
|
39
|
+
console.log(green(`Successfully extracted ${basename(resolvedPath)}`));
|
|
40
|
+
successCount++;
|
|
41
|
+
}
|
|
42
|
+
catch (err) {
|
|
43
|
+
console.log(red(`Error extracting ${basename(resolvedPath)}: ${err.message}`));
|
|
44
|
+
failCount++;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
catch (error) {
|
|
48
|
+
console.log(red(`Error accessing archive ${resolvedPath}: ${error.message}`));
|
|
49
|
+
failCount++;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
console.log(green(`Extraction complete. Successfully extracted ${successCount} archive(s).`));
|
|
53
|
+
if (failCount > 0) {
|
|
54
|
+
console.log(red(`Failed to extract ${failCount} archive(s).`));
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
ResultsUnpackCommand.paths = [["results", "unpack"]];
|
|
60
|
+
ResultsUnpackCommand.usage = Command.Usage({
|
|
61
|
+
description: "Extracts test results from .zip archives",
|
|
62
|
+
category: "Allure Test Results",
|
|
63
|
+
details: "This command extracts test results from .zip archives to the specified output directory",
|
|
64
|
+
examples: [
|
|
65
|
+
["results unpack", "Extract test results from allure-results.zip to the default directory (./allure-results)"],
|
|
66
|
+
[
|
|
67
|
+
"results unpack results.zip",
|
|
68
|
+
"Extract test results from results.zip to the default directory (./allure-results)",
|
|
69
|
+
],
|
|
70
|
+
[
|
|
71
|
+
"results unpack results1.zip results2.zip results3.zip",
|
|
72
|
+
"Extract test results from multiple archives to the default directory",
|
|
73
|
+
],
|
|
74
|
+
[
|
|
75
|
+
"results unpack --output ./mydir results1.zip results2.zip results3.zip",
|
|
76
|
+
"Extract test results from multiple archives to the specified directory (./mydir)",
|
|
77
|
+
],
|
|
78
|
+
],
|
|
79
|
+
});
|
package/dist/commands/run.d.ts
CHANGED
|
@@ -1,4 +1,11 @@
|
|
|
1
|
+
import type { QualityGateValidationResult } from "@allurereport/plugin-api";
|
|
1
2
|
import { Command } from "clipanion";
|
|
3
|
+
export type TestProcessResult = {
|
|
4
|
+
code: number | null;
|
|
5
|
+
stdout: string;
|
|
6
|
+
stderr: string;
|
|
7
|
+
qualityGateResults: QualityGateValidationResult[];
|
|
8
|
+
};
|
|
2
9
|
export declare class RunCommand extends Command {
|
|
3
10
|
static paths: string[][];
|
|
4
11
|
static usage: import("clipanion").Usage;
|
|
@@ -8,6 +15,10 @@ export declare class RunCommand extends Command {
|
|
|
8
15
|
reportName: string | undefined;
|
|
9
16
|
rerun: string | undefined;
|
|
10
17
|
silent: boolean | undefined;
|
|
18
|
+
ignoreLogs: boolean | undefined;
|
|
19
|
+
stage: string | undefined;
|
|
20
|
+
environment: string | undefined;
|
|
11
21
|
commandToRun: string[];
|
|
22
|
+
get logs(): "pipe" | "inherit" | "ignore";
|
|
12
23
|
execute(): Promise<void>;
|
|
13
24
|
}
|
package/dist/commands/run.js
CHANGED
|
@@ -1,19 +1,21 @@
|
|
|
1
|
-
import { AllureReport, isFileNotFoundError, readConfig } from "@allurereport/core";
|
|
1
|
+
import { AllureReport, QualityGateState, isFileNotFoundError, readConfig, stringifyQualityGateResults, } from "@allurereport/core";
|
|
2
2
|
import { createTestPlan } from "@allurereport/core-api";
|
|
3
3
|
import { allureResultsDirectoriesWatcher, delayedFileProcessingWatcher, newFilesInDirectoryWatcher, } from "@allurereport/directory-watcher";
|
|
4
4
|
import Awesome from "@allurereport/plugin-awesome";
|
|
5
|
-
import { PathResultFile } from "@allurereport/reader-api";
|
|
5
|
+
import { BufferResultFile, PathResultFile } from "@allurereport/reader-api";
|
|
6
6
|
import { KnownError } from "@allurereport/service";
|
|
7
7
|
import { Command, Option } from "clipanion";
|
|
8
8
|
import * as console from "node:console";
|
|
9
9
|
import { mkdtemp, realpath, rm, writeFile } from "node:fs/promises";
|
|
10
10
|
import { tmpdir } from "node:os";
|
|
11
11
|
import { join, resolve } from "node:path";
|
|
12
|
-
import process from "node:process";
|
|
12
|
+
import process, { exit } from "node:process";
|
|
13
|
+
import terminate from "terminate/promise";
|
|
13
14
|
import { red } from "yoctocolors";
|
|
14
15
|
import { logTests, runProcess, terminationOf } from "../utils/index.js";
|
|
15
16
|
import { logError } from "../utils/logs.js";
|
|
16
|
-
const runTests = async (
|
|
17
|
+
const runTests = async (params) => {
|
|
18
|
+
const { allureReport, knownIssues, cwd, command, commandArgs, logs, environment, withQualityGate, silent } = params;
|
|
17
19
|
let testProcessStarted = false;
|
|
18
20
|
const allureResultsWatchers = new Map();
|
|
19
21
|
const processWatcher = delayedFileProcessingWatcher(async (path) => {
|
|
@@ -47,17 +49,83 @@ const runTests = async (allureReport, cwd, command, commandArgs, environment, si
|
|
|
47
49
|
await allureResultsWatch.initialScan();
|
|
48
50
|
testProcessStarted = true;
|
|
49
51
|
const beforeProcess = Date.now();
|
|
50
|
-
const testProcess = runProcess(
|
|
52
|
+
const testProcess = runProcess({
|
|
53
|
+
command,
|
|
54
|
+
commandArgs,
|
|
55
|
+
cwd,
|
|
56
|
+
environment,
|
|
57
|
+
logs,
|
|
58
|
+
});
|
|
59
|
+
const qualityGateState = new QualityGateState();
|
|
60
|
+
let qualityGateUnsub;
|
|
61
|
+
let qualityGateResults = [];
|
|
62
|
+
let testProcessStdout = "";
|
|
63
|
+
let testProcessStderr = "";
|
|
64
|
+
if (withQualityGate) {
|
|
65
|
+
qualityGateUnsub = allureReport.realtimeSubscriber.onTestResults(async (testResults) => {
|
|
66
|
+
const trs = await Promise.all(testResults.map((tr) => allureReport.store.testResultById(tr)));
|
|
67
|
+
const filteredTrs = trs.filter((tr) => tr !== undefined);
|
|
68
|
+
if (!filteredTrs.length) {
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
const { results, fastFailed } = await allureReport.validate({
|
|
72
|
+
trs: filteredTrs,
|
|
73
|
+
state: qualityGateState,
|
|
74
|
+
knownIssues,
|
|
75
|
+
});
|
|
76
|
+
if (!fastFailed) {
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
allureReport.realtimeDispatcher.sendQualityGateResults(results);
|
|
80
|
+
qualityGateResults = results;
|
|
81
|
+
try {
|
|
82
|
+
await terminate(testProcess.pid, "SIGTERM");
|
|
83
|
+
}
|
|
84
|
+
catch (err) {
|
|
85
|
+
if (err.message.includes("kill ESRCH")) {
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
throw err;
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
if (logs === "pipe") {
|
|
93
|
+
testProcess.stdout?.setEncoding("utf8").on?.("data", (data) => {
|
|
94
|
+
testProcessStdout += data;
|
|
95
|
+
if (silent) {
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
process.stdout.write(data);
|
|
99
|
+
});
|
|
100
|
+
testProcess.stderr?.setEncoding("utf8").on?.("data", async (data) => {
|
|
101
|
+
testProcessStderr += data;
|
|
102
|
+
if (silent) {
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
process.stderr.write(data);
|
|
106
|
+
});
|
|
107
|
+
}
|
|
51
108
|
const code = await terminationOf(testProcess);
|
|
52
109
|
const afterProcess = Date.now();
|
|
53
|
-
|
|
110
|
+
if (code !== null) {
|
|
111
|
+
console.log(`process finished with code ${code} (${afterProcess - beforeProcess}ms)`);
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
console.log(`process terminated (${afterProcess - beforeProcess}ms)`);
|
|
115
|
+
}
|
|
54
116
|
await allureResultsWatch.abort();
|
|
55
117
|
for (const [ar, watcher] of allureResultsWatchers) {
|
|
56
118
|
await watcher.abort();
|
|
57
119
|
allureResultsWatchers.delete(ar);
|
|
58
120
|
}
|
|
59
121
|
await processWatcher.abort();
|
|
60
|
-
|
|
122
|
+
qualityGateUnsub?.();
|
|
123
|
+
return {
|
|
124
|
+
code,
|
|
125
|
+
stdout: testProcessStdout,
|
|
126
|
+
stderr: testProcessStderr,
|
|
127
|
+
qualityGateResults,
|
|
128
|
+
};
|
|
61
129
|
};
|
|
62
130
|
export class RunCommand extends Command {
|
|
63
131
|
constructor() {
|
|
@@ -80,7 +148,22 @@ export class RunCommand extends Command {
|
|
|
80
148
|
this.silent = Option.Boolean("--silent", {
|
|
81
149
|
description: "Don't pipe the process output logs to console (default: 0)",
|
|
82
150
|
});
|
|
83
|
-
this.
|
|
151
|
+
this.ignoreLogs = Option.Boolean("--ignore-logs", {
|
|
152
|
+
description: "Prevent logs attaching to the report (default: false)",
|
|
153
|
+
});
|
|
154
|
+
this.stage = Option.String("--stage", {
|
|
155
|
+
description: "Runs tests in stage mode to collect results to a stage archive with the provided name (default: empty string)",
|
|
156
|
+
});
|
|
157
|
+
this.environment = Option.String("--environment", {
|
|
158
|
+
description: "Force specific environment to all tests in the run. Given environment has higher priority than the one defined in the config file (default: empty string)",
|
|
159
|
+
});
|
|
160
|
+
this.commandToRun = Option.Rest();
|
|
161
|
+
}
|
|
162
|
+
get logs() {
|
|
163
|
+
if (this.silent) {
|
|
164
|
+
return this.ignoreLogs ? "ignore" : "pipe";
|
|
165
|
+
}
|
|
166
|
+
return this.ignoreLogs ? "inherit" : "pipe";
|
|
84
167
|
}
|
|
85
168
|
async execute() {
|
|
86
169
|
const args = this.commandToRun.filter((arg) => arg !== "--");
|
|
@@ -97,8 +180,14 @@ export class RunCommand extends Command {
|
|
|
97
180
|
const cwd = await realpath(this.cwd ?? process.cwd());
|
|
98
181
|
console.log(`${command} ${commandArgs.join(" ")}`);
|
|
99
182
|
const maxRerun = this.rerun ? parseInt(this.rerun, 10) : 0;
|
|
100
|
-
const silent = this.silent ?? false;
|
|
101
183
|
const config = await readConfig(cwd, this.config, { output: this.output, name: this.reportName });
|
|
184
|
+
const withQualityGate = !!config.qualityGate;
|
|
185
|
+
const withRerun = !!this.rerun;
|
|
186
|
+
if (withQualityGate && withRerun) {
|
|
187
|
+
console.error(red("At this moment, quality gate and rerun can't be used at the same time!"));
|
|
188
|
+
console.error(red("Consider using --rerun=0 or disable quality gate in the config to run tests"));
|
|
189
|
+
exit(-1);
|
|
190
|
+
}
|
|
102
191
|
try {
|
|
103
192
|
await rm(config.output, { recursive: true });
|
|
104
193
|
}
|
|
@@ -107,27 +196,46 @@ export class RunCommand extends Command {
|
|
|
107
196
|
console.error("could not clean output directory", e);
|
|
108
197
|
}
|
|
109
198
|
}
|
|
199
|
+
const allureReport = new AllureReport({
|
|
200
|
+
...config,
|
|
201
|
+
environment: this.environment,
|
|
202
|
+
stage: this.stage,
|
|
203
|
+
realTime: false,
|
|
204
|
+
plugins: [
|
|
205
|
+
...(config.plugins?.length
|
|
206
|
+
? config.plugins
|
|
207
|
+
: [
|
|
208
|
+
{
|
|
209
|
+
id: "awesome",
|
|
210
|
+
enabled: true,
|
|
211
|
+
options: {},
|
|
212
|
+
plugin: new Awesome({
|
|
213
|
+
reportName: config.name,
|
|
214
|
+
}),
|
|
215
|
+
},
|
|
216
|
+
]),
|
|
217
|
+
],
|
|
218
|
+
});
|
|
219
|
+
const knownIssues = await allureReport.store.allKnownIssues();
|
|
220
|
+
await allureReport.start();
|
|
221
|
+
const globalExitCode = {
|
|
222
|
+
original: 0,
|
|
223
|
+
actual: undefined,
|
|
224
|
+
};
|
|
225
|
+
let qualityGateResults;
|
|
226
|
+
let testProcessResult = null;
|
|
110
227
|
try {
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
options: {},
|
|
122
|
-
plugin: new Awesome({
|
|
123
|
-
reportName: config.name,
|
|
124
|
-
}),
|
|
125
|
-
},
|
|
126
|
-
]),
|
|
127
|
-
],
|
|
228
|
+
testProcessResult = await runTests({
|
|
229
|
+
logs: this.logs,
|
|
230
|
+
silent: this.silent,
|
|
231
|
+
allureReport,
|
|
232
|
+
knownIssues,
|
|
233
|
+
cwd,
|
|
234
|
+
command,
|
|
235
|
+
commandArgs,
|
|
236
|
+
environment: {},
|
|
237
|
+
withQualityGate,
|
|
128
238
|
});
|
|
129
|
-
await allureReport.start();
|
|
130
|
-
let code = await runTests(allureReport, cwd, command, commandArgs, {}, silent);
|
|
131
239
|
for (let rerun = 0; rerun < maxRerun; rerun++) {
|
|
132
240
|
const failed = await allureReport.store.failedTestResults();
|
|
133
241
|
if (failed.length === 0) {
|
|
@@ -140,26 +248,78 @@ export class RunCommand extends Command {
|
|
|
140
248
|
const tmpDir = await mkdtemp(join(tmpdir(), "allure-run-"));
|
|
141
249
|
const testPlanPath = resolve(tmpDir, `${rerun}-testplan.json`);
|
|
142
250
|
await writeFile(testPlanPath, JSON.stringify(testPlan));
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
251
|
+
testProcessResult = await runTests({
|
|
252
|
+
silent: this.silent,
|
|
253
|
+
logs: this.logs,
|
|
254
|
+
allureReport,
|
|
255
|
+
knownIssues,
|
|
256
|
+
cwd,
|
|
257
|
+
command,
|
|
258
|
+
commandArgs,
|
|
259
|
+
environment: {
|
|
260
|
+
ALLURE_TESTPLAN_PATH: testPlanPath,
|
|
261
|
+
ALLURE_RERUN: `${rerun}`,
|
|
262
|
+
},
|
|
263
|
+
withQualityGate,
|
|
264
|
+
});
|
|
147
265
|
await rm(tmpDir, { recursive: true });
|
|
148
266
|
logTests(await allureReport.store.allTestResults());
|
|
149
267
|
}
|
|
150
|
-
await allureReport.
|
|
151
|
-
|
|
152
|
-
|
|
268
|
+
const trs = await allureReport.store.allTestResults({ includeHidden: false });
|
|
269
|
+
qualityGateResults = testProcessResult?.qualityGateResults ?? [];
|
|
270
|
+
if (withQualityGate && !qualityGateResults?.length) {
|
|
271
|
+
const { results } = await allureReport.validate({
|
|
272
|
+
trs,
|
|
273
|
+
knownIssues,
|
|
274
|
+
});
|
|
275
|
+
qualityGateResults = results;
|
|
276
|
+
}
|
|
277
|
+
if (qualityGateResults?.length) {
|
|
278
|
+
const qualityGateMessage = stringifyQualityGateResults(qualityGateResults);
|
|
279
|
+
console.error(qualityGateMessage);
|
|
280
|
+
allureReport.realtimeDispatcher.sendQualityGateResults(qualityGateResults);
|
|
281
|
+
}
|
|
282
|
+
globalExitCode.original = testProcessResult?.code ?? -1;
|
|
283
|
+
if (withQualityGate) {
|
|
284
|
+
globalExitCode.actual = qualityGateResults.length > 0 ? 1 : 0;
|
|
285
|
+
}
|
|
153
286
|
}
|
|
154
287
|
catch (error) {
|
|
288
|
+
globalExitCode.actual = 1;
|
|
155
289
|
if (error instanceof KnownError) {
|
|
156
290
|
console.error(red(error.message));
|
|
157
|
-
|
|
158
|
-
|
|
291
|
+
allureReport.realtimeDispatcher.sendGlobalError({
|
|
292
|
+
message: error.message,
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
else {
|
|
296
|
+
await logError("Failed to run tests using Allure due to unexpected error", error);
|
|
297
|
+
allureReport.realtimeDispatcher.sendGlobalError({
|
|
298
|
+
message: error.message,
|
|
299
|
+
trace: error.stack,
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
const processFailed = Math.abs(globalExitCode.actual ?? globalExitCode.original) !== 0;
|
|
304
|
+
if (!this.ignoreLogs && testProcessResult?.stdout) {
|
|
305
|
+
const stdoutResultFile = new BufferResultFile(Buffer.from(testProcessResult.stdout, "utf8"), "stdout.txt");
|
|
306
|
+
stdoutResultFile.contentType = "text/plain";
|
|
307
|
+
allureReport.realtimeDispatcher.sendGlobalAttachment(stdoutResultFile);
|
|
308
|
+
}
|
|
309
|
+
if (!this.ignoreLogs && testProcessResult?.stderr) {
|
|
310
|
+
const stderrResultFile = new BufferResultFile(Buffer.from(testProcessResult.stderr, "utf8"), "stderr.txt");
|
|
311
|
+
stderrResultFile.contentType = "text/plain";
|
|
312
|
+
allureReport.realtimeDispatcher.sendGlobalAttachment(stderrResultFile);
|
|
313
|
+
if (processFailed) {
|
|
314
|
+
allureReport.realtimeDispatcher.sendGlobalError({
|
|
315
|
+
message: "Test process has failed",
|
|
316
|
+
trace: testProcessResult.stderr,
|
|
317
|
+
});
|
|
159
318
|
}
|
|
160
|
-
await logError("Failed to run tests using Allure due to unexpected error", error);
|
|
161
|
-
process.exit(1);
|
|
162
319
|
}
|
|
320
|
+
allureReport.realtimeDispatcher.sendGlobalExitCode(globalExitCode);
|
|
321
|
+
await allureReport.done();
|
|
322
|
+
exit(globalExitCode.actual ?? globalExitCode.original);
|
|
163
323
|
}
|
|
164
324
|
}
|
|
165
325
|
RunCommand.paths = [["run"]];
|
|
@@ -169,5 +329,9 @@ RunCommand.usage = Command.Usage({
|
|
|
169
329
|
examples: [
|
|
170
330
|
["run -- npm run test", "Run npm run test and collect Allure results"],
|
|
171
331
|
["run --rerun 3 -- npm run test", "Run npm run test and rerun failed tests up to 3 times"],
|
|
332
|
+
[
|
|
333
|
+
"run --stage=my-stage -- npm run test",
|
|
334
|
+
"Run npm run test and pack inner report state into my-stage.zip archive to restore the state in the next run",
|
|
335
|
+
],
|
|
172
336
|
],
|
|
173
337
|
});
|
package/dist/index.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { defineConfig } from "@allurereport/plugin-api";
|
|
1
|
+
export { defineConfig, defaultChartsConfig } from "@allurereport/plugin-api";
|
package/dist/index.js
CHANGED
|
@@ -2,7 +2,7 @@ import { Builtins, Cli } from "clipanion";
|
|
|
2
2
|
import console from "node:console";
|
|
3
3
|
import { readFileSync } from "node:fs";
|
|
4
4
|
import { argv, cwd } from "node:process";
|
|
5
|
-
import { Allure2Command, AwesomeCommand, ClassicCommand, CsvCommand, DashboardCommand, GenerateCommand, HistoryCommand, KnownIssueCommand, LogCommand, LoginCommand, LogoutCommand, OpenCommand, ProjectsCreateCommand, ProjectsDeleteCommand, ProjectsListCommand, QualityGateCommand, RunCommand, SlackCommand, TestPlanCommand, WatchCommand, WhoamiCommand, } from "./commands/index.js";
|
|
5
|
+
import { Allure2Command, AwesomeCommand, ClassicCommand, CsvCommand, DashboardCommand, GenerateCommand, HistoryCommand, KnownIssueCommand, LogCommand, LoginCommand, LogoutCommand, OpenCommand, ProjectsCreateCommand, ProjectsDeleteCommand, ProjectsListCommand, QualityGateCommand, ResultsPackCommand, ResultsUnpackCommand, RunCommand, SlackCommand, TestPlanCommand, WatchCommand, WhoamiCommand, } from "./commands/index.js";
|
|
6
6
|
const [node, app, ...args] = argv;
|
|
7
7
|
const pkg = JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf8"));
|
|
8
8
|
const cli = new Cli({
|
|
@@ -31,7 +31,9 @@ cli.register(WhoamiCommand);
|
|
|
31
31
|
cli.register(ProjectsCreateCommand);
|
|
32
32
|
cli.register(ProjectsDeleteCommand);
|
|
33
33
|
cli.register(ProjectsListCommand);
|
|
34
|
+
cli.register(ResultsPackCommand);
|
|
35
|
+
cli.register(ResultsUnpackCommand);
|
|
34
36
|
cli.register(Builtins.HelpCommand);
|
|
35
37
|
cli.runExit(args);
|
|
36
38
|
console.log(cwd());
|
|
37
|
-
export { defineConfig } from "@allurereport/plugin-api";
|
|
39
|
+
export { defineConfig, defaultChartsConfig } from "@allurereport/plugin-api";
|
package/dist/utils/process.d.ts
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
1
|
import type { ChildProcess } from "node:child_process";
|
|
2
|
-
export declare const runProcess: (
|
|
2
|
+
export declare const runProcess: (params: {
|
|
3
|
+
command: string;
|
|
4
|
+
commandArgs: string[];
|
|
5
|
+
cwd: string | undefined;
|
|
6
|
+
environment?: Record<string, string>;
|
|
7
|
+
logs?: "pipe" | "inherit" | "ignore";
|
|
8
|
+
}) => ChildProcess;
|
|
3
9
|
export declare const terminationOf: (testProcess: ChildProcess) => Promise<number | null>;
|
package/dist/utils/process.js
CHANGED
|
@@ -1,12 +1,23 @@
|
|
|
1
1
|
import { spawn } from "node:child_process";
|
|
2
|
-
export const runProcess = (
|
|
2
|
+
export const runProcess = (params) => {
|
|
3
|
+
const { command, commandArgs, cwd, environment = {}, logs = "inherit" } = params;
|
|
4
|
+
const env = {
|
|
5
|
+
...process.env,
|
|
6
|
+
...environment,
|
|
7
|
+
};
|
|
8
|
+
if (logs === "pipe") {
|
|
9
|
+
Object.assign(env, {
|
|
10
|
+
FORCE_COLOR: "1",
|
|
11
|
+
CLICOLOR_FORCE: "1",
|
|
12
|
+
COLOR: "1",
|
|
13
|
+
COLORTERM: "truecolor",
|
|
14
|
+
TERM: "xterm-256color",
|
|
15
|
+
});
|
|
16
|
+
}
|
|
3
17
|
return spawn(command, commandArgs, {
|
|
4
|
-
env
|
|
5
|
-
...process.env,
|
|
6
|
-
...environment,
|
|
7
|
-
},
|
|
18
|
+
env,
|
|
8
19
|
cwd,
|
|
9
|
-
stdio:
|
|
20
|
+
stdio: logs,
|
|
10
21
|
shell: true,
|
|
11
22
|
});
|
|
12
23
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "allure",
|
|
3
|
-
"version": "3.0.0-beta.
|
|
3
|
+
"version": "3.0.0-beta.19",
|
|
4
4
|
"description": "Allure Commandline Tool",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"allure",
|
|
@@ -12,7 +12,8 @@
|
|
|
12
12
|
"author": "Qameta Software",
|
|
13
13
|
"type": "module",
|
|
14
14
|
"exports": {
|
|
15
|
-
".": "./dist/index.js"
|
|
15
|
+
".": "./dist/index.js",
|
|
16
|
+
"./qualityGate": "./dist/qualityGate.js"
|
|
16
17
|
},
|
|
17
18
|
"main": "./dist/index.js",
|
|
18
19
|
"module": "./dist/index.js",
|
|
@@ -30,29 +31,34 @@
|
|
|
30
31
|
"test": "vitest run"
|
|
31
32
|
},
|
|
32
33
|
"dependencies": {
|
|
33
|
-
"@allurereport/core": "3.0.0-beta.
|
|
34
|
-
"@allurereport/core-api": "3.0.0-beta.
|
|
35
|
-
"@allurereport/directory-watcher": "3.0.0-beta.
|
|
36
|
-
"@allurereport/plugin-allure2": "3.0.0-beta.
|
|
37
|
-
"@allurereport/plugin-api": "3.0.0-beta.
|
|
38
|
-
"@allurereport/plugin-awesome": "3.0.0-beta.
|
|
39
|
-
"@allurereport/plugin-classic": "3.0.0-beta.
|
|
40
|
-
"@allurereport/plugin-csv": "3.0.0-beta.
|
|
41
|
-
"@allurereport/plugin-dashboard": "3.0.0-beta.
|
|
42
|
-
"@allurereport/plugin-log": "3.0.0-beta.
|
|
43
|
-
"@allurereport/plugin-progress": "3.0.0-beta.
|
|
44
|
-
"@allurereport/plugin-server-reload": "3.0.0-beta.
|
|
45
|
-
"@allurereport/plugin-slack": "3.0.0-beta.
|
|
46
|
-
"@allurereport/reader-api": "3.0.0-beta.
|
|
47
|
-
"@allurereport/service": "3.0.0-beta.
|
|
48
|
-
"@allurereport/static-server": "3.0.0-beta.
|
|
34
|
+
"@allurereport/core": "3.0.0-beta.19",
|
|
35
|
+
"@allurereport/core-api": "3.0.0-beta.19",
|
|
36
|
+
"@allurereport/directory-watcher": "3.0.0-beta.19",
|
|
37
|
+
"@allurereport/plugin-allure2": "3.0.0-beta.19",
|
|
38
|
+
"@allurereport/plugin-api": "3.0.0-beta.19",
|
|
39
|
+
"@allurereport/plugin-awesome": "3.0.0-beta.19",
|
|
40
|
+
"@allurereport/plugin-classic": "3.0.0-beta.19",
|
|
41
|
+
"@allurereport/plugin-csv": "3.0.0-beta.19",
|
|
42
|
+
"@allurereport/plugin-dashboard": "3.0.0-beta.19",
|
|
43
|
+
"@allurereport/plugin-log": "3.0.0-beta.19",
|
|
44
|
+
"@allurereport/plugin-progress": "3.0.0-beta.19",
|
|
45
|
+
"@allurereport/plugin-server-reload": "3.0.0-beta.19",
|
|
46
|
+
"@allurereport/plugin-slack": "3.0.0-beta.19",
|
|
47
|
+
"@allurereport/reader-api": "3.0.0-beta.19",
|
|
48
|
+
"@allurereport/service": "3.0.0-beta.19",
|
|
49
|
+
"@allurereport/static-server": "3.0.0-beta.19",
|
|
50
|
+
"adm-zip": "^0.5.16",
|
|
49
51
|
"clipanion": "^4.0.0-rc.4",
|
|
52
|
+
"glob": "^11.0.3",
|
|
50
53
|
"lodash.omit": "^4.5.0",
|
|
51
54
|
"prompts": "^2.4.2",
|
|
55
|
+
"terminate": "^2.8.0",
|
|
56
|
+
"typanion": "^3.14.0",
|
|
52
57
|
"yoctocolors": "^2.1.1"
|
|
53
58
|
},
|
|
54
59
|
"devDependencies": {
|
|
55
60
|
"@stylistic/eslint-plugin": "^2.6.1",
|
|
61
|
+
"@types/adm-zip": "^0",
|
|
56
62
|
"@types/eslint": "^8.56.11",
|
|
57
63
|
"@types/lodash.omit": "^4.5.9",
|
|
58
64
|
"@types/node": "^20.17.9",
|
|
@@ -61,7 +67,7 @@
|
|
|
61
67
|
"@typescript-eslint/parser": "^8.0.0",
|
|
62
68
|
"@vitest/runner": "^2.1.9",
|
|
63
69
|
"@vitest/snapshot": "^2.1.9",
|
|
64
|
-
"allure-vitest": "^3.3.
|
|
70
|
+
"allure-vitest": "^3.3.3",
|
|
65
71
|
"eslint": "^8.57.0",
|
|
66
72
|
"eslint-config-prettier": "^9.1.0",
|
|
67
73
|
"eslint-plugin-import": "^2.29.1",
|