@testomatio/reporter 0.8.0-beta.9 → 0.8.2-beta.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.
@@ -1,65 +1,68 @@
1
+ const debug = require('debug')('@testomatio/reporter:pipe:github');
2
+ const path = require('path');
1
3
  const chalk = require('chalk');
2
- const { Octokit } = require("@octokit/rest");
4
+ const humanizeDuration = require('humanize-duration');
5
+ const merge = require('lodash.merge');
6
+ const { Octokit } = require('@octokit/rest');
3
7
  const { APP_PREFIX } = require('../constants');
4
8
  const { ansiRegExp, isSameTest } = require('../util');
5
- const merge = require('lodash.merge');
6
-
7
9
 
10
+ /**
11
+ * @typedef {import('../../types').Pipe} Pipe
12
+ * @typedef {import('../../types').TestData} TestData
13
+ * @class GitHubPipe
14
+ * @implements {Pipe}
15
+ */
8
16
  class GitHubPipe {
9
-
10
- isEnabled = false;
11
-
12
17
  constructor(params, store = {}) {
18
+ this.isEnabled = false;
13
19
  this.store = store;
14
- this.tests = []
20
+ this.tests = [];
15
21
  this.token = params.GH_PAT || process.env.GH_PAT;
16
- this.ref = process.env.GITHUB_REF
17
- this.repo = process.env.GITHUB_REPOSITORY
22
+ this.ref = process.env.GITHUB_REF;
23
+ this.repo = process.env.GITHUB_REPOSITORY;
24
+ this.hiddenCommentData = `<!--- testomat.io report ${process.env.GITHUB_WORKFLOW || ''} -->`;
18
25
 
19
- if (process.env.DEBUG) {
20
- console.log(APP_PREFIX, 'GitHub Pipe: ', this.token ? 'TOKEN' : '*no token*', this.ref, this.repo);
21
- }
26
+ debug('GitHub Pipe: ', this.token ? 'TOKEN' : '*no token*', 'Ref:', this.ref, 'Repo:', this.repo);
22
27
 
23
28
  if (!this.token || !this.ref || !this.repo) return;
24
29
  this.isEnabled = true;
25
30
  const matchedIssue = this.ref.match(/refs\/pull\/(\d+)\/merge/);
26
31
  if (!matchedIssue) return;
27
- this.issue = matchedIssue[1]
32
+ this.issue = parseInt(matchedIssue[1], 10);
33
+
28
34
  this.start = new Date();
29
35
 
30
- if (process.env.DEBUG) {
31
- console.log(APP_PREFIX, 'GitHub Pipe: Enabled');
32
- }
36
+ debug('GitHub Pipe: Enabled');
33
37
  }
34
-
35
- async createRun() {}
36
38
 
37
- updateRun() {}
39
+ async createRun() {}
38
40
 
39
41
  addTest(test) {
42
+ debug('Adding test:', test);
40
43
  if (!this.isEnabled) return;
41
44
 
42
- const index = this.tests.findIndex(t => isSameTest(t, test))
45
+ const index = this.tests.findIndex(t => isSameTest(t, test));
43
46
  // update if they were already added
44
47
  if (index >= 0) {
45
48
  this.tests[index] = merge(this.tests[index], test);
46
49
  return;
47
50
  }
48
51
 
49
- this.tests.push(test)
52
+ this.tests.push(test);
50
53
  }
51
54
 
52
55
  async finishRun(runParams) {
53
56
  if (!this.isEnabled) return;
57
+ if (!this.issue) return;
54
58
 
55
59
  if (runParams.tests) runParams.tests.forEach(t => this.addTest(t));
56
-
57
60
 
58
61
  this.octokit = new Octokit({
59
62
  auth: this.token,
60
63
  });
61
64
 
62
- const [owner, repo] = this.repo.split('/');
65
+ const [owner, repo] = (this.repo || '').split('/');
63
66
  if (!(owner || repo)) return;
64
67
 
65
68
  // ... create a comment on GitHub
@@ -67,15 +70,17 @@ class GitHubPipe {
67
70
  const failedCount = this.tests.filter(t => t.status === 'failed').length;
68
71
  const skippedCount = this.tests.filter(t => t.status === 'skipped').length;
69
72
 
70
- let summary = `
71
- ### Run Report
73
+ let summary = `${this.hiddenCommentData}
72
74
 
73
- | | ${statusEmoji(runParams.status)} ${runParams.status.toUpperCase()} ${statusEmoji(runParams.status)} |
75
+ | [![Testomat.io Report](https://avatars.githubusercontent.com/u/59105116?s=36&v=4)](https://testomat.io) | ${
76
+ statusEmoji(runParams.status,)} ${runParams.status.toUpperCase()} ${statusEmoji(runParams.status)} |
74
77
  | --- | --- |
75
78
  | Tests | ✔️ **${this.tests.length}** tests run |
76
- | Summary | ${statusEmoji('failed')} **${failedCount}** failed; ${statusEmoji('passed')} **${passedCount}** passed; **${statusEmoji('skipped')}** ${skippedCount} skipped |
77
- | Duration | 🕐 **${parseFloat(this.tests.reduce((a, t) => a + (t.run_time || 0), 0)).toFixed(2)}**ms |
78
- `
79
+ | Summary | ${statusEmoji('failed')} **${failedCount}** failed; ${statusEmoji(
80
+ 'passed',
81
+ )} **${passedCount}** passed; **${statusEmoji('skipped')}** ${skippedCount} skipped |
82
+ | Duration | 🕐 **${humanizeDuration(parseFloat(this.tests.reduce((a, t) => a + (t.run_time || 0), 0)))}** |
83
+ `;
79
84
  if (this.store.runUrl) {
80
85
  summary += `| Testomat.io Report | 📊 [Run #${this.store.runId}](${this.store.runUrl}) | `;
81
86
  }
@@ -92,71 +97,89 @@ class GitHubPipe {
92
97
  summary += `| Run Attempt | 🌒 \`${process.env.GITHUB_RUN_ATTEMPT}\` | `;
93
98
  }
94
99
  if (process.env.GITHUB_RUN_ID) {
95
- summary += `| Build Log | ✒️ ${process.env.GITHUB_SERVER_URL || 'https://github.com'}/${this.repo}/actions/runs/${process.env.GITHUB_RUN_ID} | `;
100
+ summary += `| Build Log | ✒️ ${process.env.GITHUB_SERVER_URL || 'https://github.com'}/${
101
+ this.repo
102
+ }/actions/runs/${process.env.GITHUB_RUN_ID} | `;
96
103
  }
97
104
 
105
+ const failures = this.tests
106
+ .filter(t => t.status === 'failed')
107
+ .slice(0, 20)
108
+ .map(t => {
109
+ let text = `#### ${statusEmoji('failed')} ${fullName(t)} `;
110
+ text += '\n\n';
111
+ if (t.message)
112
+ text += `> ${t.message
113
+ .replace(/[^\x20-\x7E]/g, '')
114
+ .replace(ansiRegExp(), '')
115
+ .trim()}\n`;
116
+ if (t.stack) text += `\`\`\`diff\n${t.stack.replace(ansiRegExp(), '').trim()}\n\`\`\`\n`;
117
+
118
+ if (t.artifacts && t.artifacts.length && !process.env.TESTOMATIO_PRIVATE_ARTIFACTS) {
119
+ t.artifacts
120
+ .filter(f => !!f)
121
+ .filter(f => f.endsWith('.png'))
122
+ .forEach(f => {
123
+ if (f.endsWith('.png')) {
124
+ text += `![](${f})\n`;
125
+ return text;
126
+ }
127
+ text += `[📄 ${path.basename(f)}](${f})\n`;
128
+ return text;
129
+ });
130
+ }
131
+
132
+ text += '\n---\n';
133
+
134
+ return text;
135
+ });
98
136
 
99
- const failures = this.tests.filter(t => t.status === 'failed').slice(0, 20).map(t => {
100
- let text = `#### ${statusEmoji('failed')} ${fullName(t)} `;
101
- text += "\n\n"
102
- if (t.message) text += "> " + t.message.replace(/[^\x20-\x7E]/g, '').replace(ansiRegExp(), '').trim() + "\n"
103
- if (t.stack) text += "```diff\n" + t.stack.replace(ansiRegExp(), '').trim() + "\n```\n";
104
-
105
- if (t.artifacts && t.artifacts.length && !process.env.TESTOMATIO_PRIVATE_ARTIFACTS) {
106
- t.artifacts.filter(f => f.endsWith('.png')).forEach(f => {
107
- if (f.endsWith('.png')) return text+= `![](${f})\n`
108
- });
109
- }
110
-
111
- text += "\n---\n"
112
-
113
- return text;
114
- })
115
-
116
137
  let body = summary;
117
138
 
118
139
  if (failures.length) {
119
- body += `\n<details>\n<summary><h3>🟥 Failures (${failures.length})</h4></summary>\n${failures.join('\n')} \n</details>\n`;
120
- }
121
-
122
- if (failures.length > 20) {
123
- body += "\n> Notice\n> Only first 20 failures shown*"
140
+ body += `\n<details>\n<summary><h3>🟥 Failures (${failures.length})</h4></summary>\n\n${failures.join('\n')}\n`;
141
+ if (failures.length > 20) {
142
+ body += '\n> Notice\n> Only first 20 failures shown*';
143
+ }
144
+ body += '\n\n</details>';
124
145
  }
125
146
 
126
147
  if (this.tests.length > 0) {
127
- body += "\n### 🐢 Slowest Tests\n\n"
128
- body += this.tests.sort((a, b) => b?.run_time - a?.run_time).slice(0, 5).map(t => {
129
- return `* ${fullName(t)} (${parseFloat(t.run_time).toFixed(2)}ms)`
130
- }).join('\n')
148
+ body += '\n<details>\n<summary><h3>🐢 Slowest Tests</h3></summary>\n\n';
149
+ body += this.tests
150
+ // eslint-disable-next-line no-unsafe-optional-chaining
151
+ .sort((a, b) => b?.run_time - a?.run_time)
152
+ .slice(0, 5)
153
+ .map(t => `* ${fullName(t)} (${humanizeDuration(parseFloat(t.run_time))})`)
154
+ .join('\n');
155
+ body += '\n</details>';
131
156
  }
157
+
132
158
 
159
+ await deletePreviousReport(this.octokit, owner, repo, this.issue, this.hiddenCommentData);
160
+
161
+ // add report as comment
133
162
  try {
163
+ debug('Adding comment\n', body);
134
164
  const resp = await this.octokit.rest.issues.createComment({
135
165
  owner,
136
166
  repo,
137
167
  issue_number: this.issue,
138
168
  body,
139
169
  });
140
-
170
+
141
171
  const url = resp.data?.html_url;
172
+ debug('Comment URL:', url);
142
173
  this.store.githubUrl = url;
143
-
144
- console.log(
145
- APP_PREFIX,
146
- chalk.yellow('GitHub'),
147
- `Report created: ${chalk.magenta(url)}`,
148
- );
174
+
175
+ console.log(APP_PREFIX, chalk.yellow('GitHub'), `Report created: ${chalk.magenta(url)}`);
149
176
  } catch (err) {
150
- console.log(
151
- APP_PREFIX,
152
- chalk.yellow('GitHub'),
153
- `Couldn't create GitHub report ${err}`,
154
- );
177
+ console.log(APP_PREFIX, chalk.yellow('GitHub'), `Couldn't create GitHub report ${err}`);
155
178
  }
156
179
  }
157
180
 
158
181
  toString() {
159
- return 'GitHub Reporter'
182
+ return 'GitHub Reporter';
160
183
  }
161
184
  }
162
185
 
@@ -164,15 +187,56 @@ function statusEmoji(status) {
164
187
  if (status === 'passed') return '🟢';
165
188
  if (status === 'failed') return '🔴';
166
189
  if (status === 'skipped') return '🟡';
167
- return ''
190
+ return '';
168
191
  }
169
192
 
170
193
  function fullName(t) {
171
194
  let line = '';
172
- if (t.suite_title) line = `${t.suite_title}: `;
173
- line += `**${t.title}**`
195
+ if (t.suite_title) line = `${t.suite_title}: `;
196
+ line += `**${t.title}**`;
174
197
  if (t.example) line += ` \`[${Object.values(t.example)}]\``;
175
198
  return line;
176
199
  }
177
200
 
178
- module.exports = GitHubPipe;
201
+ async function deletePreviousReport(octokit, owner, repo, issue, hiddenCommentData) {
202
+ if (process.env.GITHUB_KEEP_OUTDATED_REPORTS) return;
203
+
204
+ // get comments
205
+ let comments = [];
206
+ try {
207
+ const response = await octokit.rest.issues.listComments({
208
+ owner,
209
+ repo,
210
+ issue_number: issue,
211
+ });
212
+ comments = response.data;
213
+ } catch (e) {
214
+ console.error('Error while attempt to retrieve comments on GitHub Pull Request:\n', e);
215
+ }
216
+
217
+ if (!comments.length) return;
218
+
219
+ for (const comment of comments) {
220
+ // if comment was left by the same workflow
221
+ if (comment.body.includes(hiddenCommentData)) {
222
+ try {
223
+ // delete previous comment
224
+ await octokit.rest.issues.deleteComment({
225
+ owner,
226
+ repo,
227
+ issue_number: issue,
228
+ comment_id: comment.id,
229
+ });
230
+ } catch (e) {
231
+ console.warn(`Can't delete previously added comment with testomat.io report. Ignore.`);
232
+ }
233
+
234
+ // pass next env var if need to clear all previous reports;
235
+ // only the last one is removed by default
236
+ if (!process.env.GITHUB_REMOVE_ALL_OUTDATED_REPORTS) break;
237
+ // TODO: in case of many reports should implement pagination
238
+ }
239
+ }
240
+ }
241
+
242
+ module.exports = GitHubPipe;
@@ -0,0 +1,229 @@
1
+ const debug = require('debug')('@testomatio/reporter:pipe:gitlab');
2
+ const { default: axios } = require('axios');
3
+ const chalk = require('chalk');
4
+ const humanizeDuration = require('humanize-duration');
5
+ const merge = require('lodash.merge');
6
+ const path = require('path');
7
+ const { APP_PREFIX } = require('../constants');
8
+ const { ansiRegExp, isSameTest } = require('../util');
9
+
10
+ //! GITLAB_PAT environment variable is required for this functionality to work
11
+ //! and your pipeline trigger should be merge_request
12
+
13
+ /**
14
+ * @class GitLabPipe
15
+ * @typedef {import('../../types').Pipe} Pipe
16
+ * @typedef {import('../../types').TestData} TestData
17
+ */
18
+ class GitLabPipe {
19
+ constructor(params, store = {}) {
20
+ this.isEnabled = false;
21
+ this.ENV = process.env;
22
+ this.store = store;
23
+ this.tests = [];
24
+ // GitLab PAT looks like glpat-nKGdja3jsG4850sGksh7
25
+ this.token = params.GITLAB_PAT || this.ENV.GITLAB_PAT;
26
+ this.hiddenCommentData = `<!--- testomat.io report ${process.env.CI_JOB_NAME || ''} -->`;
27
+
28
+ debug(
29
+ chalk.yellow('GitLab Pipe:'),
30
+ this.token ? 'TOKEN passed' : '*no token*',
31
+ `Project id: ${this.ENV.CI_PROJECT_ID}, MR id: ${this.ENV.CI_MERGE_REQUEST_IID}`,
32
+ );
33
+
34
+ if (!this.ENV.CI_PROJECT_ID || !this.ENV.CI_MERGE_REQUEST_IID) {
35
+ debug(`CI pipeline should be run in Merge Request to have ability to add the report comment.`);
36
+ return;
37
+ }
38
+
39
+ if (!this.token) {
40
+ debug(`Hint: GitLab CI variables are unavailable for unprotected branches by default.`);
41
+ return;
42
+ }
43
+
44
+ this.isEnabled = true;
45
+
46
+ debug('GitLab Pipe: Enabled');
47
+ }
48
+
49
+ async createRun() {}
50
+
51
+ addTest(test) {
52
+ if (!this.isEnabled) return;
53
+
54
+ const index = this.tests.findIndex(t => isSameTest(t, test));
55
+ // update if they were already added
56
+ if (index >= 0) {
57
+ this.tests[index] = merge(this.tests[index], test);
58
+ return;
59
+ }
60
+
61
+ this.tests.push(test);
62
+ }
63
+
64
+ async finishRun(runParams) {
65
+ if (!this.isEnabled) return;
66
+
67
+ if (runParams.tests) runParams.tests.forEach(t => this.addTest(t));
68
+
69
+ // ... create a comment on GitLab
70
+ const passedCount = this.tests.filter(t => t.status === 'passed').length;
71
+ const failedCount = this.tests.filter(t => t.status === 'failed').length;
72
+ const skippedCount = this.tests.filter(t => t.status === 'skipped').length;
73
+
74
+ // constructing the table
75
+ let summary = `${this.hiddenCommentData}
76
+
77
+ | [![Testomat.io Report](https://avatars.githubusercontent.com/u/59105116?s=36&v=4)](https://testomat.io) | ${
78
+ statusEmoji(runParams.status)} ${runParams.status.toUpperCase()} ${statusEmoji(runParams.status)} |
79
+ | --- | --- |
80
+ | Tests | ✔️ **${this.tests.length}** tests run |
81
+ | Summary | ${statusEmoji('failed')} **${failedCount}** failed; ${statusEmoji(
82
+ 'passed',
83
+ )} **${passedCount}** passed; **${statusEmoji('skipped')}** ${skippedCount} skipped |
84
+ | Duration | 🕐 **${humanizeDuration(parseFloat(this.tests.reduce((a, t) => a + (t.run_time || 0), 0)))}** |
85
+ `;
86
+
87
+ if (this.ENV.CI_JOB_NAME && this.ENV.CI_JOB_ID) {
88
+ // eslint-disable-next-line max-len
89
+ summary += `| Job | 👷 [${this.ENV.CI_JOB_ID}](${this.ENV.CI_JOB_URL})<br>Name: **${this.ENV.CI_JOB_NAME}**<br>Stage: **${this.ENV.CI_JOB_STAGE}** | `;
90
+ }
91
+
92
+ const failures = this.tests
93
+ .filter(t => t.status === 'failed')
94
+ .slice(0, 20)
95
+ .map(t => {
96
+ let text = `#### ${statusEmoji('failed')} ${fullName(t)} `;
97
+ text += '\n\n';
98
+ if (t.message)
99
+ text += `> ${t.message
100
+ .replace(/[^\x20-\x7E]/g, '')
101
+ .replace(ansiRegExp(), '')
102
+ .trim()}\n`;
103
+ if (t.stack) text += `\`\`\`diff\n${t.stack.replace(ansiRegExp(), '').trim()}\n\`\`\`\n`;
104
+
105
+ if (t.artifacts && t.artifacts.length && !this.ENV.TESTOMATIO_PRIVATE_ARTIFACTS) {
106
+ t.artifacts
107
+ .filter(f => !!f)
108
+ .filter(f => f.endsWith('.png'))
109
+ .forEach(f => {
110
+ if (f.endsWith('.png')) {
111
+ text += `![](${f})\n`;
112
+ return text;
113
+ }
114
+ text += `[📄 ${path.basename(f)}](${f})\n`;
115
+ return text;
116
+ });
117
+ }
118
+
119
+ text += '\n---\n';
120
+
121
+ return text;
122
+ });
123
+
124
+ let body = summary;
125
+
126
+ if (failures.length) {
127
+ body += `\n<details>\n<summary><h3>🟥 Failures (${failures.length})</h4></summary>\n\n${failures.join('\n')}\n`;
128
+ if (failures.length > 20) {
129
+ body += '\n> Notice\n> Only first 20 failures shown*';
130
+ }
131
+ body += '\n\n</details>';
132
+ }
133
+
134
+ if (this.tests.length > 0) {
135
+ body += '\n<details>\n<summary><h3>🐢 Slowest Tests</h3></summary>\n\n';
136
+ body += this.tests
137
+ // eslint-disable-next-line no-unsafe-optional-chaining
138
+ .sort((a, b) => b?.run_time - a?.run_time)
139
+ .slice(0, 5)
140
+ .map(t => `* ${fullName(t)} (${humanizeDuration(parseFloat(t.run_time))})`)
141
+ .join('\n');
142
+ body += '\n</details>';
143
+ }
144
+
145
+ // eslint-disable-next-line max-len
146
+ const commentsRequestURL = `https://gitlab.com/api/v4/projects/${this.ENV.CI_PROJECT_ID}/merge_requests/${this.ENV.CI_MERGE_REQUEST_IID}/notes`;
147
+
148
+ // delete previous report
149
+ await deletePreviousReport(axios, commentsRequestURL, this.hiddenCommentData, this.token);
150
+
151
+ // add current report
152
+ debug(`Adding comment via url: ${commentsRequestURL}`);
153
+
154
+ try {
155
+ const addCommentResponse = await axios.post(`${commentsRequestURL}?access_token=${this.token}`, { body });
156
+
157
+ const commentID = addCommentResponse.data.id;
158
+ // eslint-disable-next-line max-len
159
+ const commentURL = `${this.ENV.CI_PROJECT_URL}/-/merge_requests/${this.ENV.CI_MERGE_REQUEST_IID}#note_${commentID}`;
160
+
161
+ console.log(APP_PREFIX, chalk.yellow('GitLab'), `Report created: ${chalk.magenta(commentURL)}`);
162
+ } catch (err) {
163
+ console.error(
164
+ APP_PREFIX,
165
+ chalk.yellow('GitLab'),
166
+ `Couldn't create GitLab report\n${err}.
167
+ Request url: ${commentsRequestURL}
168
+ Request data: ${body}`,
169
+ );
170
+ }
171
+ }
172
+
173
+ toString() {
174
+ return 'GitLab Reporter';
175
+ }
176
+
177
+ updateRun() {}
178
+ }
179
+
180
+ function statusEmoji(status) {
181
+ if (status === 'passed') return '🟢';
182
+ if (status === 'failed') return '🔴';
183
+ if (status === 'skipped') return '🟡';
184
+ return '';
185
+ }
186
+
187
+ function fullName(t) {
188
+ let line = '';
189
+ if (t.suite_title) line = `${t.suite_title}: `;
190
+ line += `**${t.title}**`;
191
+ if (t.example) line += ` \`[${Object.values(t.example)}]\``;
192
+ return line;
193
+ }
194
+
195
+ async function deletePreviousReport(axiosInstance, commentsRequestURL, hiddenCommentData, token) {
196
+ if (process.env.GITLAB_KEEP_OUTDATED_REPORTS) return;
197
+
198
+ // get comments
199
+ let comments = [];
200
+
201
+ try {
202
+ const response = await axiosInstance.get(`${commentsRequestURL}?access_token=${token}`);
203
+ comments = response.data;
204
+ } catch (e) {
205
+ console.error('Error while attempt to retrieve comments on GitLab Merge Request:\n', e);
206
+ }
207
+
208
+ if (!comments.length) return;
209
+
210
+ for (const comment of comments) {
211
+ // if comment was left by the same workflow
212
+ if (comment.body.includes(hiddenCommentData)) {
213
+ try {
214
+ // delete previous comment
215
+ const deleteCommentURL = `${commentsRequestURL}/${comment.id}?access_token=${token}`;
216
+ await axiosInstance.delete(deleteCommentURL);
217
+ } catch (e) {
218
+ console.warn(`Can't delete previously added comment with testomat.io report. Ignore.`);
219
+ }
220
+
221
+ // pass next env var if need to clear all previous reports;
222
+ // only the last one is removed by default
223
+ if (!process.env.GITLAB_REMOVE_ALL_OUTDATED_REPORTS) break;
224
+ // TODO: in case of many reports should implement pagination
225
+ }
226
+ }
227
+ }
228
+
229
+ module.exports = GitLabPipe;
package/lib/pipe/index.js CHANGED
@@ -1,48 +1,63 @@
1
1
  const fs = require('fs');
2
2
  const path = require('path');
3
+ const chalk = require('chalk');
3
4
  const { APP_PREFIX } = require('../constants');
4
5
  const TestomatioPipe = require('./testomatio');
5
6
  const GitHubPipe = require('./github');
7
+ const GitLabPipe = require('./gitlab');
8
+ const CsvPipe = require('./csv');
6
9
 
7
- module.exports = function(params, opts) {
10
+ function PipeFactory(params, opts) {
8
11
  const extraPipes = [];
9
12
 
10
13
  // Add extra pipes into package.json file:
11
14
  // "testomatio": {
12
- // "pipes": ["my-module-pipe", "./local/js/file/pipe"]
15
+ // "pipes": ["my-module-pipe", "./local/js/file/pipe"]
13
16
  // }
14
17
 
15
18
  const packageJsonFile = path.join(process.cwd(), 'package.json');
16
19
  if (fs.existsSync(packageJsonFile)) {
17
- const package = fs.readFileSync(packageJsonFile);
18
- const pipeDefs = package?.testomatio?.pipes || [];
19
-
20
+ const packageJson = JSON.parse(fs.readFileSync(packageJsonFile).toString());
21
+ const pipeDefs = packageJson?.testomatio?.pipes || [];
22
+
20
23
  for (const pipeDef of pipeDefs) {
21
- let pipeClass;
24
+ let PipeClass;
22
25
  try {
23
- pipeClass = require(pipeDef);
26
+ PipeClass = require(pipeDef);
24
27
  } catch (err) {
25
28
  console.log(APP_PREFIX, `Can't load module Testomatio pipe module from ${pipeDef}`);
26
29
  continue;
27
30
  }
28
31
 
29
32
  try {
30
- extraPipes.push(new pipeClass(params, opts))
33
+ extraPipes.push(new PipeClass(params, opts));
31
34
  } catch (err) {
32
35
  console.log(APP_PREFIX, `Can't instantiate Testomatio for ${pipeDef}`, err);
33
36
  continue;
34
37
  }
35
38
  }
36
39
  }
37
-
38
40
 
39
41
  const pipes = [
40
42
  new TestomatioPipe(params, opts),
41
- new GitHubPipe(params, opts),
42
- ...extraPipes
43
+ new GitHubPipe(params, opts),
44
+ new GitLabPipe(params, opts),
45
+ new CsvPipe(params, opts),
46
+ ...extraPipes,
43
47
  ];
44
48
 
45
- console.log(APP_PREFIX, pipes.filter(p => p.isEnabled).map(p => p.toString()).join(', ') || "No pipe reporters enabled");
49
+ console.log(
50
+ APP_PREFIX,
51
+ chalk.cyan('Pipes:'),
52
+ chalk.cyan(
53
+ pipes
54
+ .filter(p => p.isEnabled)
55
+ .map(p => p.toString())
56
+ .join(', ') || 'No pipes enabled',
57
+ ),
58
+ );
46
59
 
47
60
  return pipes;
48
61
  }
62
+
63
+ module.exports = PipeFactory;