allure 3.0.0-beta.16 → 3.0.0-beta.18

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.
Files changed (56) hide show
  1. package/dist/commands/allure2.d.ts +15 -13
  2. package/dist/commands/allure2.js +67 -79
  3. package/dist/commands/awesome.d.ts +18 -15
  4. package/dist/commands/awesome.js +79 -99
  5. package/dist/commands/classic.d.ts +15 -13
  6. package/dist/commands/classic.js +67 -79
  7. package/dist/commands/csv.d.ts +13 -11
  8. package/dist/commands/csv.js +59 -65
  9. package/dist/commands/dashboard.d.ts +15 -13
  10. package/dist/commands/dashboard.js +67 -78
  11. package/dist/commands/generate.d.ts +11 -9
  12. package/dist/commands/generate.js +70 -36
  13. package/dist/commands/history.d.ts +9 -7
  14. package/dist/commands/history.js +31 -28
  15. package/dist/commands/index.d.ts +1 -0
  16. package/dist/commands/index.js +1 -0
  17. package/dist/commands/knownIssue.d.ts +8 -6
  18. package/dist/commands/knownIssue.js +30 -23
  19. package/dist/commands/log.d.ts +12 -9
  20. package/dist/commands/log.js +54 -58
  21. package/dist/commands/login.d.ts +8 -7
  22. package/dist/commands/login.js +39 -36
  23. package/dist/commands/logout.d.ts +8 -7
  24. package/dist/commands/logout.js +39 -36
  25. package/dist/commands/open.d.ts +11 -9
  26. package/dist/commands/open.js +34 -40
  27. package/dist/commands/projects/create.d.ts +9 -7
  28. package/dist/commands/projects/create.js +70 -66
  29. package/dist/commands/projects/delete.d.ts +10 -7
  30. package/dist/commands/projects/delete.js +55 -61
  31. package/dist/commands/projects/list.d.ts +8 -7
  32. package/dist/commands/projects/list.js +62 -62
  33. package/dist/commands/qualityGate.d.ts +14 -7
  34. package/dist/commands/qualityGate.js +131 -45
  35. package/dist/commands/results/index.d.ts +2 -0
  36. package/dist/commands/results/index.js +2 -0
  37. package/dist/commands/results/pack.d.ts +10 -0
  38. package/dist/commands/results/pack.js +111 -0
  39. package/dist/commands/results/unpack.d.ts +9 -0
  40. package/dist/commands/results/unpack.js +79 -0
  41. package/dist/commands/run.d.ts +22 -10
  42. package/dist/commands/run.js +244 -101
  43. package/dist/commands/slack.d.ts +9 -7
  44. package/dist/commands/slack.js +51 -48
  45. package/dist/commands/testplan.d.ts +8 -6
  46. package/dist/commands/testplan.js +36 -29
  47. package/dist/commands/watch.d.ts +12 -10
  48. package/dist/commands/watch.js +103 -99
  49. package/dist/commands/whoami.d.ts +8 -7
  50. package/dist/commands/whoami.js +44 -38
  51. package/dist/index.js +33 -35
  52. package/dist/utils/process.d.ts +7 -1
  53. package/dist/utils/process.js +17 -6
  54. package/package.json +27 -20
  55. package/dist/utils/commands.d.ts +0 -16
  56. package/dist/utils/commands.js +0 -16
@@ -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
+ });
@@ -1,10 +1,22 @@
1
- export type RunCommandOptions = {
2
- config?: string;
3
- cwd?: string;
4
- output?: string;
5
- reportName?: string;
6
- rerun?: number;
7
- silent?: boolean;
8
- } & Record<"--", string[]>;
9
- export declare const RunCommandAction: (options: RunCommandOptions) => Promise<void>;
10
- export declare const RunCommand: (cli: import("cac").CAC) => void;
1
+ import type { QualityGateValidationResult } from "@allurereport/plugin-api";
2
+ import { Command } from "clipanion";
3
+ export type TestProcessResult = {
4
+ code: number | null;
5
+ stdout: string;
6
+ stderr: string;
7
+ qualityGateResults: QualityGateValidationResult[];
8
+ };
9
+ export declare class RunCommand extends Command {
10
+ static paths: string[][];
11
+ static usage: import("clipanion").Usage;
12
+ config: string | undefined;
13
+ cwd: string | undefined;
14
+ output: string | undefined;
15
+ reportName: string | undefined;
16
+ rerun: string | undefined;
17
+ silent: boolean | undefined;
18
+ ignoreLogs: boolean | undefined;
19
+ commandToRun: string[];
20
+ get logs(): "pipe" | "ignore" | "inherit";
21
+ execute(): Promise<void>;
22
+ }
@@ -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
+ import { Command, Option } from "clipanion";
7
8
  import * as console from "node:console";
8
9
  import { mkdtemp, realpath, rm, writeFile } from "node:fs/promises";
9
10
  import { tmpdir } from "node:os";
10
11
  import { join, resolve } from "node:path";
11
- import process from "node:process";
12
+ import process, { exit } from "node:process";
13
+ import terminate from "terminate/promise";
12
14
  import { red } from "yoctocolors";
13
- import { createCommand } from "../utils/commands.js";
14
15
  import { logTests, runProcess, terminationOf } from "../utils/index.js";
15
16
  import { logError } from "../utils/logs.js";
16
- const runTests = async (allureReport, cwd, command, commandArgs, environment, silent) => {
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,43 +49,147 @@ 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(command, commandArgs, cwd, environment, silent);
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
- console.log(`process finished with code ${code ?? 0} (${afterProcess - beforeProcess})ms`);
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
- return code;
122
+ qualityGateUnsub?.();
123
+ return {
124
+ code,
125
+ stdout: testProcessStdout,
126
+ stderr: testProcessStderr,
127
+ qualityGateResults,
128
+ };
61
129
  };
62
- export const RunCommandAction = async (options) => {
63
- const args = options["--"];
64
- if (!args || !args.length) {
65
- throw new Error("expecting command to be specified after --, e.g. allure run -- npm run test");
66
- }
67
- const before = new Date().getTime();
68
- process.on("exit", (exitCode) => {
69
- const after = new Date().getTime();
70
- console.log(`exit code ${exitCode} (${after - before}ms)`);
71
- });
72
- const command = args[0];
73
- const commandArgs = args.slice(1);
74
- const cwd = await realpath(options.cwd ?? process.cwd());
75
- console.log(`${command} ${commandArgs.join(" ")}`);
76
- const { config: configPath, output, reportName, rerun: maxRerun = 0, silent = false } = options;
77
- const config = await readConfig(cwd, configPath, { output, name: reportName });
78
- try {
79
- await rm(config.output, { recursive: true });
130
+ export class RunCommand extends Command {
131
+ constructor() {
132
+ super(...arguments);
133
+ this.config = Option.String("--config,-c", {
134
+ description: "The path Allure config file",
135
+ });
136
+ this.cwd = Option.String("--cwd", {
137
+ description: "The working directory for the command to run (default: current working directory)",
138
+ });
139
+ this.output = Option.String("--output,-o", {
140
+ description: "The output file name, allure.csv by default. Accepts absolute paths (default: ./allure-report)",
141
+ });
142
+ this.reportName = Option.String("--report-name,--name", {
143
+ description: "The report name (default: Allure Report)",
144
+ });
145
+ this.rerun = Option.String("--rerun", {
146
+ description: "The number of reruns for failed tests (default: 0)",
147
+ });
148
+ this.silent = Option.Boolean("--silent", {
149
+ description: "Don't pipe the process output logs to console (default: 0)",
150
+ });
151
+ this.ignoreLogs = Option.Boolean("--ignore-logs", {
152
+ description: "Prevent logs attaching to the report (default: false)",
153
+ });
154
+ this.commandToRun = Option.Rest();
80
155
  }
81
- catch (e) {
82
- if (!isFileNotFoundError(e)) {
83
- console.error("could not clean output directory", e);
156
+ get logs() {
157
+ if (this.silent) {
158
+ return this.ignoreLogs ? "ignore" : "pipe";
84
159
  }
160
+ return this.ignoreLogs ? "inherit" : "pipe";
85
161
  }
86
- try {
162
+ async execute() {
163
+ const args = this.commandToRun.filter((arg) => arg !== "--");
164
+ if (!args || !args.length) {
165
+ throw new Error("expecting command to be specified after --, e.g. allure run -- npm run test");
166
+ }
167
+ const before = new Date().getTime();
168
+ process.on("exit", (exitCode) => {
169
+ const after = new Date().getTime();
170
+ console.log(`exit code ${exitCode} (${after - before}ms)`);
171
+ });
172
+ const command = args[0];
173
+ const commandArgs = args.slice(1);
174
+ const cwd = await realpath(this.cwd ?? process.cwd());
175
+ console.log(`${command} ${commandArgs.join(" ")}`);
176
+ const maxRerun = this.rerun ? parseInt(this.rerun, 10) : 0;
177
+ const config = await readConfig(cwd, this.config, { output: this.output, name: this.reportName });
178
+ const withQualityGate = !!config.qualityGate;
179
+ const withRerun = !!this.rerun;
180
+ if (withQualityGate && withRerun) {
181
+ console.error(red("At this moment, quality gate and rerun can't be used at the same time!"));
182
+ console.error(red("Consider using --rerun=0 or disable quality gate in the config to run tests"));
183
+ exit(-1);
184
+ }
185
+ try {
186
+ await rm(config.output, { recursive: true });
187
+ }
188
+ catch (e) {
189
+ if (!isFileNotFoundError(e)) {
190
+ console.error("could not clean output directory", e);
191
+ }
192
+ }
87
193
  const allureReport = new AllureReport({
88
194
  ...config,
89
195
  realTime: false,
@@ -102,81 +208,118 @@ export const RunCommandAction = async (options) => {
102
208
  ]),
103
209
  ],
104
210
  });
211
+ const knownIssues = await allureReport.store.allKnownIssues();
105
212
  await allureReport.start();
106
- let code = await runTests(allureReport, cwd, command, commandArgs, {}, silent);
107
- for (let rerun = 0; rerun < maxRerun; rerun++) {
108
- const failed = await allureReport.store.failedTestResults();
109
- if (failed.length === 0) {
110
- console.log("no failed tests is detected.");
111
- break;
112
- }
113
- const testPlan = createTestPlan(failed);
114
- console.log(`rerun number ${rerun} of ${testPlan.tests.length} tests:`);
115
- logTests(failed);
116
- const tmpDir = await mkdtemp(join(tmpdir(), "allure-run-"));
117
- const testPlanPath = resolve(tmpDir, `${rerun}-testplan.json`);
118
- await writeFile(testPlanPath, JSON.stringify(testPlan));
119
- code = await runTests(allureReport, cwd, command, commandArgs, {
120
- ALLURE_TESTPLAN_PATH: testPlanPath,
121
- ALLURE_RERUN: `${rerun}`,
122
- }, silent);
123
- await rm(tmpDir, { recursive: true });
124
- logTests(await allureReport.store.allTestResults());
213
+ const globalExitCode = {
214
+ original: 0,
215
+ actual: undefined,
216
+ };
217
+ let qualityGateResults;
218
+ let testProcessResult = null;
219
+ try {
220
+ testProcessResult = await runTests({
221
+ logs: this.logs,
222
+ silent: this.silent,
223
+ allureReport,
224
+ knownIssues,
225
+ cwd,
226
+ command,
227
+ commandArgs,
228
+ environment: {},
229
+ withQualityGate,
230
+ });
231
+ for (let rerun = 0; rerun < maxRerun; rerun++) {
232
+ const failed = await allureReport.store.failedTestResults();
233
+ if (failed.length === 0) {
234
+ console.log("no failed tests is detected.");
235
+ break;
236
+ }
237
+ const testPlan = createTestPlan(failed);
238
+ console.log(`rerun number ${rerun} of ${testPlan.tests.length} tests:`);
239
+ logTests(failed);
240
+ const tmpDir = await mkdtemp(join(tmpdir(), "allure-run-"));
241
+ const testPlanPath = resolve(tmpDir, `${rerun}-testplan.json`);
242
+ await writeFile(testPlanPath, JSON.stringify(testPlan));
243
+ testProcessResult = await runTests({
244
+ silent: this.silent,
245
+ logs: this.logs,
246
+ allureReport,
247
+ knownIssues,
248
+ cwd,
249
+ command,
250
+ commandArgs,
251
+ environment: {
252
+ ALLURE_TESTPLAN_PATH: testPlanPath,
253
+ ALLURE_RERUN: `${rerun}`,
254
+ },
255
+ withQualityGate,
256
+ });
257
+ await rm(tmpDir, { recursive: true });
258
+ logTests(await allureReport.store.allTestResults());
259
+ }
260
+ const trs = await allureReport.store.allTestResults({ includeHidden: false });
261
+ qualityGateResults = testProcessResult?.qualityGateResults ?? [];
262
+ if (withQualityGate && !qualityGateResults?.length) {
263
+ const { results } = await allureReport.validate({
264
+ trs,
265
+ knownIssues,
266
+ });
267
+ qualityGateResults = results;
268
+ }
269
+ if (qualityGateResults?.length) {
270
+ const qualityGateMessage = stringifyQualityGateResults(qualityGateResults);
271
+ console.error(qualityGateMessage);
272
+ allureReport.realtimeDispatcher.sendQualityGateResults(qualityGateResults);
273
+ }
274
+ globalExitCode.original = testProcessResult?.code ?? -1;
275
+ if (withQualityGate) {
276
+ globalExitCode.actual = qualityGateResults.length > 0 ? 1 : 0;
277
+ }
125
278
  }
126
- await allureReport.done();
127
- await allureReport.validate();
128
- process.exit(code ?? allureReport.exitCode);
129
- }
130
- catch (error) {
131
- if (error instanceof KnownError) {
132
- console.error(red(error.message));
133
- process.exit(1);
134
- return;
279
+ catch (error) {
280
+ globalExitCode.actual = 1;
281
+ if (error instanceof KnownError) {
282
+ console.error(red(error.message));
283
+ allureReport.realtimeDispatcher.sendGlobalError({
284
+ message: error.message,
285
+ });
286
+ }
287
+ else {
288
+ await logError("Failed to run tests using Allure due to unexpected error", error);
289
+ allureReport.realtimeDispatcher.sendGlobalError({
290
+ message: error.message,
291
+ trace: error.stack,
292
+ });
293
+ }
135
294
  }
136
- await logError("Failed to run tests using Allure due to unexpected error", error);
137
- process.exit(1);
295
+ const processFailed = Math.abs(globalExitCode.actual ?? globalExitCode.original) !== 0;
296
+ if (!this.ignoreLogs && testProcessResult?.stdout) {
297
+ const stdoutResultFile = new BufferResultFile(Buffer.from(testProcessResult.stdout, "utf8"), "stdout.txt");
298
+ stdoutResultFile.contentType = "text/plain";
299
+ allureReport.realtimeDispatcher.sendGlobalAttachment(stdoutResultFile);
300
+ }
301
+ if (!this.ignoreLogs && testProcessResult?.stderr) {
302
+ const stderrResultFile = new BufferResultFile(Buffer.from(testProcessResult.stderr, "utf8"), "stderr.txt");
303
+ stderrResultFile.contentType = "text/plain";
304
+ allureReport.realtimeDispatcher.sendGlobalAttachment(stderrResultFile);
305
+ if (processFailed) {
306
+ allureReport.realtimeDispatcher.sendGlobalError({
307
+ message: "Test process has failed",
308
+ trace: testProcessResult.stderr,
309
+ });
310
+ }
311
+ }
312
+ allureReport.realtimeDispatcher.sendGlobalExitCode(globalExitCode);
313
+ await allureReport.done();
314
+ exit(globalExitCode.actual ?? globalExitCode.original);
138
315
  }
139
- };
140
- export const RunCommand = createCommand({
141
- name: "run",
316
+ }
317
+ RunCommand.paths = [["run"]];
318
+ RunCommand.usage = Command.Usage({
142
319
  description: "Run specified command",
143
- options: [
144
- [
145
- "--config, -c <file>",
146
- {
147
- description: "The path Allure config file",
148
- },
149
- ],
150
- [
151
- "--cwd <cwd>",
152
- {
153
- description: "The working directory for the command to run (Default: current working directory)",
154
- },
155
- ],
156
- [
157
- "--output, -o <file>",
158
- {
159
- description: "The output file name, allure.csv by default. Accepts absolute paths (Default: ./allure-report)",
160
- },
161
- ],
162
- [
163
- "--report-name, --name <string>",
164
- {
165
- description: "The report name (Default: Allure Report)",
166
- },
167
- ],
168
- [
169
- "--rerun <number>",
170
- {
171
- description: "The number of reruns for failed tests (Default: 0)",
172
- },
173
- ],
174
- [
175
- "--silent",
176
- {
177
- description: "Don't pipe the process output logs to console (Default: 0)",
178
- },
179
- ],
320
+ details: "This command runs the specified command and collects Allure results.",
321
+ examples: [
322
+ ["run -- npm run test", "Run npm run test and collect Allure results"],
323
+ ["run --rerun 3 -- npm run test", "Run npm run test and rerun failed tests up to 3 times"],
180
324
  ],
181
- action: RunCommandAction,
182
325
  });
@@ -1,9 +1,11 @@
1
- type CommandOptions = {
2
- cwd?: string;
3
- config?: string;
1
+ import { Command } from "clipanion";
2
+ export declare class SlackCommand extends Command {
3
+ static paths: string[][];
4
+ static usage: import("clipanion").Usage;
5
+ resultsDir: string;
6
+ config: string | undefined;
7
+ cwd: string | undefined;
4
8
  token: string;
5
9
  channel: string;
6
- };
7
- export declare const SlackCommandAction: (resultsDir: string, options: CommandOptions) => Promise<void>;
8
- export declare const SlackCommand: (cli: import("cac").CAC) => void;
9
- export {};
10
+ execute(): Promise<void>;
11
+ }
@@ -1,58 +1,61 @@
1
- import { AllureReport, enforcePlugin, readConfig } from "@allurereport/core";
1
+ import { AllureReport, readConfig } from "@allurereport/core";
2
2
  import SlackPlugin from "@allurereport/plugin-slack";
3
+ import { Command, Option } from "clipanion";
3
4
  import * as console from "node:console";
4
5
  import { realpath } from "node:fs/promises";
5
6
  import process from "node:process";
6
- import { createCommand } from "../utils/commands.js";
7
- export const SlackCommandAction = async (resultsDir, options) => {
8
- const cwd = await realpath(options.cwd ?? process.cwd());
9
- const before = new Date().getTime();
10
- const { config: configPath, token, channel } = options;
11
- const defaultSlackOptions = {
12
- token,
13
- channel,
14
- };
15
- const config = enforcePlugin(await readConfig(cwd, configPath), {
16
- id: "slack",
17
- enabled: true,
18
- options: defaultSlackOptions,
19
- plugin: new SlackPlugin(defaultSlackOptions),
20
- });
21
- const allureReport = new AllureReport(config);
22
- await allureReport.start();
23
- await allureReport.readDirectory(resultsDir);
24
- await allureReport.done();
25
- const after = new Date().getTime();
26
- console.log(`the report successfully generated (${after - before}ms)`);
27
- };
28
- export const SlackCommand = createCommand({
29
- name: "slack <resultsDir>",
30
- description: "Posts test results into Slack Channel",
31
- options: [
32
- [
33
- "--config, -c <file>",
34
- {
35
- description: "The path Allure config file",
36
- },
37
- ],
38
- [
39
- "--cwd <cwd>",
40
- {
41
- description: "The working directory for the command to run (Default: current working directory)",
42
- },
43
- ],
44
- [
45
- "--token, -t <token>",
7
+ export class SlackCommand extends Command {
8
+ constructor() {
9
+ super(...arguments);
10
+ this.resultsDir = Option.String({ required: true, name: "The directory with Allure results" });
11
+ this.config = Option.String("--config,-c", {
12
+ description: "The path Allure config file",
13
+ });
14
+ this.cwd = Option.String("--cwd", {
15
+ description: "The working directory for the command to run (default: current working directory)",
16
+ });
17
+ this.token = Option.String("--token,-t", {
18
+ description: "Slack Bot User OAuth Token",
19
+ required: true,
20
+ });
21
+ this.channel = Option.String("--channel", {
22
+ description: "Slack channelId",
23
+ required: true,
24
+ });
25
+ }
26
+ async execute() {
27
+ const cwd = await realpath(this.cwd ?? process.cwd());
28
+ const before = new Date().getTime();
29
+ const defaultSlackOptions = {
30
+ token: this.token,
31
+ channel: this.channel,
32
+ };
33
+ const config = await readConfig(cwd, this.config);
34
+ config.plugins = [
46
35
  {
47
- description: "Slack Bot User OAuth Token",
36
+ id: "slack",
37
+ enabled: true,
38
+ options: defaultSlackOptions,
39
+ plugin: new SlackPlugin(defaultSlackOptions),
48
40
  },
49
- ],
41
+ ];
42
+ const allureReport = new AllureReport(config);
43
+ await allureReport.start();
44
+ await allureReport.readDirectory(this.resultsDir);
45
+ await allureReport.done();
46
+ const after = new Date().getTime();
47
+ console.log(`the report successfully generated (${after - before}ms)`);
48
+ }
49
+ }
50
+ SlackCommand.paths = [["slack"]];
51
+ SlackCommand.usage = Command.Usage({
52
+ category: "Reports",
53
+ description: "Posts test results into Slack Channel",
54
+ details: "This command posts test results from the provided Allure Results directory to a Slack channel.",
55
+ examples: [
50
56
  [
51
- "--channel, -c <channel>",
52
- {
53
- description: "Slack channelId",
54
- },
57
+ "slack ./allure-results --token xoxb-token --channel C12345",
58
+ "Post test results from the ./allure-results directory to the specified Slack channel",
55
59
  ],
56
60
  ],
57
- action: SlackCommandAction,
58
61
  });
@@ -1,6 +1,8 @@
1
- type CommandOptions = {
2
- output?: string;
3
- };
4
- export declare const TestPlanCommandAction: (resultsDir: string, options: CommandOptions) => Promise<void>;
5
- export declare const TestPlanCommand: (cli: import("cac").CAC) => void;
6
- export {};
1
+ import { Command } from "clipanion";
2
+ export declare class TestPlanCommand extends Command {
3
+ static paths: string[][];
4
+ static usage: import("clipanion").Usage;
5
+ resultsDir: string;
6
+ output: string | undefined;
7
+ execute(): Promise<void>;
8
+ }