k6-perf-reporter 1.7.0 → 1.7.2

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/cli.js CHANGED
@@ -6,6 +6,45 @@ const config_1 = require("./config");
6
6
  const data_collector_1 = require("./data-collector");
7
7
  const datasources_1 = require("./datasources");
8
8
  const reporters_1 = require("./reporters");
9
+ const logger_1 = require("./logger");
10
+ const VALID_REPORTERS = ["cli", "json", "markdown", "slack"];
11
+ function defaultOutputPath(name, runId) {
12
+ const extensions = {
13
+ json: "json",
14
+ markdown: "md",
15
+ };
16
+ const ext = extensions[name];
17
+ return ext ? `report-${runId}.${ext}` : undefined;
18
+ }
19
+ async function runReporter(name, report, options, configInstance) {
20
+ const output = options.output || defaultOutputPath(name, report.runId);
21
+ logger_1.logger.info(`runReporter: starting reporter=${name}${output ? `, output=${output}` : ""}`);
22
+ switch (name) {
23
+ case "json":
24
+ new reporters_1.JsonReporter().report(report, output);
25
+ logger_1.logger.info(`runReporter: json report generated`);
26
+ break;
27
+ case "markdown":
28
+ new reporters_1.MarkdownReporter().report(report, output);
29
+ logger_1.logger.info(`runReporter: markdown report generated`);
30
+ break;
31
+ case "slack": {
32
+ const slackConfig = configInstance.getSlackConfig();
33
+ if (!slackConfig) {
34
+ throw new Error("Slack token not configured. Set SLACK_TOKEN environment variable or configure in config file.");
35
+ }
36
+ const slackReporter = new reporters_1.SlackReporter(slackConfig.token, slackConfig.channel);
37
+ await slackReporter.report(report);
38
+ logger_1.logger.info(`runReporter: slack report sent to channel=${slackConfig.channel}`);
39
+ console.log("Report sent to Slack");
40
+ break;
41
+ }
42
+ case "cli":
43
+ new reporters_1.CliReporter().report(report);
44
+ logger_1.logger.info(`runReporter: cli report printed`);
45
+ break;
46
+ }
47
+ }
9
48
  function main() {
10
49
  commander_1.program
11
50
  .name("k6-reporter")
@@ -20,36 +59,33 @@ function main() {
20
59
  .option("-c, --config <path>", "Path to config file", ".config.json")
21
60
  .option("-d, --datasource <type>", "Data source: 'influxdb' or 'prometheus'")
22
61
  .option("-f, --format <format>", "Output format: 'json', 'cli', 'markdown', or 'slack'", "cli")
23
- .option("-o, --output <path>", "Output file path (for json format)")
62
+ .option("-r, --report <reporters>", "Run one or more reporters (comma-separated): cli, json, markdown, slack")
63
+ .option("-o, --output <path>", "Output file path (for json and markdown formats)")
24
64
  .option("--no-cache", "Disable cache, always fetch fresh data")
25
65
  .action(async (options) => {
26
66
  try {
67
+ if (options.report && options.format !== "cli") {
68
+ throw new Error("Cannot use --report and --format together. Use --report for multiple reporters.");
69
+ }
27
70
  const configInstance = config_1.Config.getInstance(options.config);
28
71
  const dsType = (options.datasource || configInstance.getDataSourceType());
29
72
  const dataSource = (0, datasources_1.createDataSource)(dsType, configInstance);
30
73
  const cacheTtl = options.cache ? configInstance.getCacheConfig().ttl : 0;
31
74
  const collector = new data_collector_1.DataCollector(dataSource, cacheTtl);
32
75
  const report = await collector.collect(options.runId, options.startTime || "-1h", options.endTime || "now()");
33
- if (options.format === "json") {
34
- const jsonReporter = new reporters_1.JsonReporter();
35
- jsonReporter.report(report, options.output);
36
- }
37
- else if (options.format === "markdown") {
38
- const markdownReporter = new reporters_1.MarkdownReporter();
39
- markdownReporter.report(report, options.output);
40
- }
41
- else if (options.format === "slack") {
42
- const slackConfig = configInstance.getSlackConfig();
43
- if (!slackConfig) {
44
- throw new Error("Slack token not configured. Set SLACK_TOKEN environment variable or configure in config file.");
76
+ if (options.report) {
77
+ const reporters = options.report.split(",").map((r) => r.trim());
78
+ logger_1.logger.info(`generate: using --report with reporters=[${reporters.join(", ")}]`);
79
+ const invalid = reporters.filter((r) => !VALID_REPORTERS.includes(r));
80
+ if (invalid.length > 0) {
81
+ throw new Error(`Invalid reporter(s): ${invalid.join(", ")}. Valid options: ${VALID_REPORTERS.join(", ")}`);
82
+ }
83
+ for (const name of reporters) {
84
+ await runReporter(name, report, options, configInstance);
45
85
  }
46
- const slackReporter = new reporters_1.SlackReporter(slackConfig.token, slackConfig.channel);
47
- await slackReporter.report(report);
48
- console.log("Report sent to Slack");
49
86
  }
50
87
  else {
51
- const cliReporter = new reporters_1.CliReporter();
52
- cliReporter.report(report);
88
+ await runReporter(options.format, report, options, configInstance);
53
89
  }
54
90
  }
55
91
  catch (error) {
@@ -81,6 +117,7 @@ OPTIONS:
81
117
  -c, --config Path to config file (default: .config.json)
82
118
  -d, --datasource Data source: 'influxdb' or 'prometheus' (default: influxdb)
83
119
  -f, --format Output format: 'json', 'cli', 'markdown', or 'slack' (default: cli)
120
+ -r, --report Run one or more reporters (comma-separated): cli, json, markdown, slack
84
121
  -o, --output Output file path (for json and markdown formats)
85
122
  --no-cache Disable cache, always fetch fresh data
86
123
  -h, --help Show command help
@@ -115,6 +152,12 @@ EXAMPLES:
115
152
  9. Get help for generate command:
116
153
  k6-reporter generate --help
117
154
 
155
+ 10. Run multiple reporters at once:
156
+ k6-reporter generate --run-id 123456790121 --report cli,slack
157
+
158
+ 11. Generate Markdown and JSON reports together:
159
+ k6-reporter generate --run-id 123456790121 --report markdown,json -o report
160
+
118
161
  TIME FORMAT:
119
162
 
120
163
  Relative times (from now):
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "k6-perf-reporter",
3
- "version": "1.7.0",
3
+ "version": "1.7.2",
4
4
  "description": "Reporting tool for k6 performance tests with InfluxDB 2 integration",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.js",
@@ -12,8 +12,7 @@
12
12
  "build": "tsc",
13
13
  "start": "node dist/index.js",
14
14
  "report": "tsx src/cli.ts",
15
- "report:example": "tsx src/cli.ts generate --run-id '965375' -st '-24h'",
16
- "report:example:json": "LOG_LEVEL=info tsx src/cli.ts generate --run-id '977442' -st '-24h' --format slack",
15
+ "report:example": "LOG_LEVEL=info tsx src/cli.ts generate --run-id '980231' -st '-24h' --report slack,markdown",
17
16
  "lint": "eslint src",
18
17
  "type-check": "tsc --noEmit"
19
18
  },
package/src/cli.ts CHANGED
@@ -5,6 +5,55 @@ import { Config, DataSourceType } from "./config";
5
5
  import { DataCollector } from "./data-collector";
6
6
  import { createDataSource } from "./datasources";
7
7
  import { JsonReporter, CliReporter, SlackReporter, MarkdownReporter } from "./reporters";
8
+ import { logger } from "./logger";
9
+ import { ReporterResponse } from "./types";
10
+
11
+ const VALID_REPORTERS = ["cli", "json", "markdown", "slack"] as const;
12
+ type ReporterName = (typeof VALID_REPORTERS)[number];
13
+
14
+ function defaultOutputPath(name: ReporterName, runId: string): string | undefined {
15
+ const extensions: Partial<Record<ReporterName, string>> = {
16
+ json: "json",
17
+ markdown: "md",
18
+ };
19
+ const ext = extensions[name];
20
+ return ext ? `report-${runId}.${ext}` : undefined;
21
+ }
22
+
23
+ async function runReporter(
24
+ name: ReporterName,
25
+ report: ReporterResponse,
26
+ options: { output?: string },
27
+ configInstance: Config
28
+ ): Promise<void> {
29
+ const output = options.output || defaultOutputPath(name, report.runId);
30
+ logger.info(`runReporter: starting reporter=${name}${output ? `, output=${output}` : ""}`);
31
+ switch (name) {
32
+ case "json":
33
+ new JsonReporter().report(report, output);
34
+ logger.info(`runReporter: json report generated`);
35
+ break;
36
+ case "markdown":
37
+ new MarkdownReporter().report(report, output);
38
+ logger.info(`runReporter: markdown report generated`);
39
+ break;
40
+ case "slack": {
41
+ const slackConfig = configInstance.getSlackConfig();
42
+ if (!slackConfig) {
43
+ throw new Error("Slack token not configured. Set SLACK_TOKEN environment variable or configure in config file.");
44
+ }
45
+ const slackReporter = new SlackReporter(slackConfig.token, slackConfig.channel);
46
+ await slackReporter.report(report);
47
+ logger.info(`runReporter: slack report sent to channel=${slackConfig.channel}`);
48
+ console.log("Report sent to Slack");
49
+ break;
50
+ }
51
+ case "cli":
52
+ new CliReporter().report(report);
53
+ logger.info(`runReporter: cli report printed`);
54
+ break;
55
+ }
56
+ }
8
57
 
9
58
  function main(): void {
10
59
  program
@@ -21,10 +70,15 @@ function main(): void {
21
70
  .option("-c, --config <path>", "Path to config file", ".config.json")
22
71
  .option("-d, --datasource <type>", "Data source: 'influxdb' or 'prometheus'")
23
72
  .option("-f, --format <format>", "Output format: 'json', 'cli', 'markdown', or 'slack'", "cli")
24
- .option("-o, --output <path>", "Output file path (for json format)")
73
+ .option("-r, --report <reporters>", "Run one or more reporters (comma-separated): cli, json, markdown, slack")
74
+ .option("-o, --output <path>", "Output file path (for json and markdown formats)")
25
75
  .option("--no-cache", "Disable cache, always fetch fresh data")
26
76
  .action(async (options) => {
27
77
  try {
78
+ if (options.report && options.format !== "cli") {
79
+ throw new Error("Cannot use --report and --format together. Use --report for multiple reporters.");
80
+ }
81
+
28
82
  const configInstance = Config.getInstance(options.config);
29
83
  const dsType = (options.datasource || configInstance.getDataSourceType()) as DataSourceType;
30
84
  const dataSource = createDataSource(dsType, configInstance);
@@ -36,23 +90,18 @@ function main(): void {
36
90
  options.endTime || "now()"
37
91
  );
38
92
 
39
- if (options.format === "json") {
40
- const jsonReporter = new JsonReporter();
41
- jsonReporter.report(report, options.output);
42
- } else if (options.format === "markdown") {
43
- const markdownReporter = new MarkdownReporter();
44
- markdownReporter.report(report, options.output);
45
- } else if (options.format === "slack") {
46
- const slackConfig = configInstance.getSlackConfig();
47
- if (!slackConfig) {
48
- throw new Error("Slack token not configured. Set SLACK_TOKEN environment variable or configure in config file.");
93
+ if (options.report) {
94
+ const reporters = options.report.split(",").map((r: string) => r.trim());
95
+ logger.info(`generate: using --report with reporters=[${reporters.join(", ")}]`);
96
+ const invalid = reporters.filter((r: string) => !VALID_REPORTERS.includes(r as ReporterName));
97
+ if (invalid.length > 0) {
98
+ throw new Error(`Invalid reporter(s): ${invalid.join(", ")}. Valid options: ${VALID_REPORTERS.join(", ")}`);
99
+ }
100
+ for (const name of reporters) {
101
+ await runReporter(name as ReporterName, report, options, configInstance);
49
102
  }
50
- const slackReporter = new SlackReporter(slackConfig.token, slackConfig.channel);
51
- await slackReporter.report(report);
52
- console.log("Report sent to Slack");
53
103
  } else {
54
- const cliReporter = new CliReporter();
55
- cliReporter.report(report);
104
+ await runReporter(options.format as ReporterName, report, options, configInstance);
56
105
  }
57
106
  } catch (error) {
58
107
  console.error("Error:", error instanceof Error ? error.message : error);
@@ -84,6 +133,7 @@ OPTIONS:
84
133
  -c, --config Path to config file (default: .config.json)
85
134
  -d, --datasource Data source: 'influxdb' or 'prometheus' (default: influxdb)
86
135
  -f, --format Output format: 'json', 'cli', 'markdown', or 'slack' (default: cli)
136
+ -r, --report Run one or more reporters (comma-separated): cli, json, markdown, slack
87
137
  -o, --output Output file path (for json and markdown formats)
88
138
  --no-cache Disable cache, always fetch fresh data
89
139
  -h, --help Show command help
@@ -118,6 +168,12 @@ EXAMPLES:
118
168
  9. Get help for generate command:
119
169
  k6-reporter generate --help
120
170
 
171
+ 10. Run multiple reporters at once:
172
+ k6-reporter generate --run-id 123456790121 --report cli,slack
173
+
174
+ 11. Generate Markdown and JSON reports together:
175
+ k6-reporter generate --run-id 123456790121 --report markdown,json -o report
176
+
121
177
  TIME FORMAT:
122
178
 
123
179
  Relative times (from now):