@testomatio/reporter 1.4.11-beta-bitbucket-pipe β†’ 1.4.13-beta-bitbucket-pipe

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -11,7 +11,7 @@ Testomat.io Reporter (this npm package) supports:
11
11
  - πŸ„ Integarion with all popular [JavaScript/TypeScript frameworks](./docs/frameworks.md)
12
12
  - πŸ—„οΈ Screenshots, videos, traces [uploaded into S3 bucket](./docs/artifacts.md)
13
13
  - πŸ”Ž [Stack traces](./docs/stacktrace.md) and error messages
14
- - πŸ™ [GitHub](./docs/pipes/github.md) & [GitLab](./docs/pipes/gitlab.md) integration
14
+ - πŸ™ [GitHub](./docs/pipes/github.md), [GitLab](./docs/pipes/gitlab.md) & [Bitbucket](./docs/pipes/bitbucket.md) integration
15
15
  - πŸš… Realtime reports
16
16
  - πŸ—ƒοΈ Other test frameworks supported via [JUNit XML](./docs/junit.md)
17
17
  - πŸšΆβ€β™€οΈ Steps _(work in progress)_
@@ -128,6 +128,7 @@ Bring this reporter on CI and never lose test results again!
128
128
  - [Gitlab](./docs/pipes/gitlab.md)
129
129
  - [CSV](./docs/pipes/csv.md)
130
130
  - [HTML report](./docs/pipes/html.md)
131
+ - [Bitbucket](./docs/pipes/bitbucket.md)
131
132
  - πŸ““ [JUnit](./docs/junit.md)
132
133
  - πŸ—„οΈ [Artifacts](./docs/artifacts.md)
133
134
  - πŸ”‚ [Workflows](./docs/workflows.md)
@@ -8,7 +8,7 @@ const { APP_PREFIX, testomatLogoURL } = require('../constants');
8
8
  const { ansiRegExp, isSameTest } = require('../utils/utils');
9
9
  const { statusEmoji, fullName } = require('../utils/pipe_utils');
10
10
 
11
- //! BITBUCKET_PAT environment variable is required for this functionality to work
11
+ //! BITBUCKET_ACCESS_TOKEN environment variable is required for this functionality to work
12
12
  //! and your pipeline trigger should be a pull request
13
13
 
14
14
  /**
@@ -23,8 +23,8 @@ class BitbucketPipe {
23
23
  this.store = store;
24
24
  this.tests = [];
25
25
  // Bitbucket PAT looks like bbpat-*****
26
- this.token = params.BITBUCKET_PAT || process.env.BITBUCKET_PAT || this.ENV.BITBUCKET_PAT;
27
- this.hiddenCommentData = `<!--- testomat.io report ${process.env.BITBUCKET_STEP_NAME || ''} -->`;
26
+ this.token = params.BITBUCKET_ACCESS_TOKEN || process.env.BITBUCKET_ACCESS_TOKEN || this.ENV.BITBUCKET_ACCESS_TOKEN;
27
+ this.hiddenCommentData = `Testomat.io report: ${process.env.BITBUCKET_BRANCH || ''}`;
28
28
 
29
29
  debug(
30
30
  chalk.yellow('Bitbucket Pipe:'),
@@ -32,11 +32,6 @@ class BitbucketPipe {
32
32
  `Project key: ${this.ENV.BITBUCKET_PROJECT_KEY}, Pull request ID: ${this.ENV.BITBUCKET_PR_ID}`,
33
33
  );
34
34
 
35
- if (!this.ENV.BITBUCKET_PROJECT_KEY || !this.ENV.BITBUCKET_PR_ID) {
36
- debug(`CI pipeline should be run in a Pull Request to have the ability to add the report comment.`);
37
- return;
38
- }
39
-
40
35
  if (!this.token) {
41
36
  debug(`Hint: Bitbucket CI variables are unavailable for unprotected branches by default.`);
42
37
  return;
@@ -47,6 +42,11 @@ class BitbucketPipe {
47
42
  debug('Bitbucket Pipe: Enabled');
48
43
  }
49
44
 
45
+ async cleanLog(log) {
46
+ const stripAnsi = (await import('strip-ansi')).default;
47
+ return stripAnsi(log);
48
+ }
49
+
50
50
  // Prepare the run (if needed)
51
51
  async prepareRun() {}
52
52
 
@@ -71,6 +71,12 @@ class BitbucketPipe {
71
71
 
72
72
  if (runParams.tests) runParams.tests.forEach(t => this.addTest(t));
73
73
 
74
+ // Clean up the logs from ANSI codes
75
+ for (let i = 0; i < this.tests.length; i++) {
76
+ this.tests[i].message = await this.cleanLog(this.tests[i].message || '');
77
+ this.tests[i].stack = await this.cleanLog(this.tests[i].stack || '');
78
+ }
79
+
74
80
  // Create a comment on Bitbucket
75
81
  const passedCount = this.tests.filter(t => t.status === 'passed').length;
76
82
  const failedCount = this.tests.filter(t => t.status === 'failed').length;
@@ -79,15 +85,15 @@ class BitbucketPipe {
79
85
  // Constructing the table
80
86
  let summary = `${this.hiddenCommentData}
81
87
 
82
- | [![Testomat.io Report](${testomatLogoURL})](https://testomat.io) | ${statusEmoji(
88
+ | ![Testomat.io Report](${testomatLogoURL}) | ${statusEmoji(
83
89
  runParams.status,
84
90
  )} ${runParams.status.toUpperCase()} ${statusEmoji(runParams.status)} |
85
91
  | --- | --- |
86
- | Tests | βœ”οΈ **${this.tests.length}** tests run |
87
- | Summary | ${statusEmoji('failed')} **${failedCount}** failed; ${statusEmoji(
92
+ | **Tests** | βœ”οΈ **${this.tests.length}** tests run |
93
+ | **Summary** | ${statusEmoji('failed')} **${failedCount}** failed; ${statusEmoji(
88
94
  'passed',
89
95
  )} **${passedCount}** passed; **${statusEmoji('skipped')}** ${skippedCount} skipped |
90
- | Duration | πŸ• **${humanizeDuration(
96
+ | **Duration** | πŸ• **${humanizeDuration(
91
97
  parseInt(
92
98
  this.tests.reduce((a, t) => a + (t.run_time || 0), 0),
93
99
  10,
@@ -98,61 +104,62 @@ class BitbucketPipe {
98
104
  )}** |
99
105
  `;
100
106
 
101
- if (this.ENV.BITBUCKET_STEP_NAME && this.ENV.BITBUCKET_STEP_UUID) {
107
+ if (this.ENV.BITBUCKET_BRANCH && this.ENV.BITBUCKET_COMMIT) {
102
108
  // eslint-disable-next-line max-len
103
- summary += `| Job | πŸ‘· [${this.ENV.BITBUCKET_STEP_UUID}](${this.ENV.BITBUCKET_PIPELINE_STEP_URL})<br>Name: **${this.ENV.BITBUCKET_STEP_NAME}** | `;
109
+ summary += `| **Job** | πŸ‘· [#${this.ENV.BITBUCKET_BUILD_NUMBER}](https://bitbucket.org/${this.ENV.BITBUCKET_REPO_FULL_NAME}/pipelines/results/${this.ENV.BITBUCKET_BUILD_NUMBER}") by commit: **${this.ENV.BITBUCKET_COMMIT}** |`;
104
110
  }
105
111
 
106
112
  const failures = this.tests
107
113
  .filter(t => t.status === 'failed')
108
114
  .slice(0, 20)
109
115
  .map(t => {
110
- let text = `#### ${statusEmoji('failed')} ${fullName(t)} `;
111
- text += '\n\n';
112
- if (t.message)
116
+ let text = `${statusEmoji('failed')} ${fullName(t)}\n`;
117
+ if (t.message) {
113
118
  text += `> ${t.message
114
119
  .replace(/[^\x20-\x7E]/g, '')
115
120
  .replace(ansiRegExp(), '')
116
121
  .trim()}\n`;
117
- if (t.stack) text += `\`\`\`diff\n${t.stack.replace(ansiRegExp(), '').trim()}\n\`\`\`\n`;
118
-
122
+ }
123
+ if (t.stack) {
124
+ text += `\n\`\`\`diff\n${t.stack
125
+ .replace(ansiRegExp(), '')
126
+ .replace(
127
+ /^[\s\S]*################\[ Failure \]################/g,
128
+ '################[ Failure ]################',
129
+ )
130
+ .trim()}\n\`\`\`\n`;
131
+ }
119
132
  if (t.artifacts && t.artifacts.length && !this.ENV.TESTOMATIO_PRIVATE_ARTIFACTS) {
120
133
  t.artifacts
121
134
  .filter(f => !!f)
122
- .filter(f => f.endsWith('.png'))
123
135
  .forEach(f => {
124
136
  if (f.endsWith('.png')) {
125
- text += `![](${f})\n`;
126
- return text;
137
+ text += `![Image](${f})\n`;
138
+ } else {
139
+ text += `[πŸ“„ ${path.basename(f)}](${f})\n`;
127
140
  }
128
- text += `[πŸ“„ ${path.basename(f)}](${f})\n`;
129
- return text;
130
141
  });
131
142
  }
132
-
133
- text += '\n---\n';
134
-
143
+ text += `\n---\n`;
135
144
  return text;
136
145
  });
137
146
 
138
147
  let body = summary;
139
148
 
140
149
  if (failures.length) {
141
- body += `\n<details>\n<summary><h3>πŸŸ₯ Failures (${failures.length})</h3></summary>\n\n${failures.join('\n')}\n`;
142
- if (failures.length > 20) {
143
- body += '\n> Notice\n> Only first 20 failures shown*';
150
+ body += `\nπŸŸ₯ **Failures (${failures.length})**\n\n* ${failures.join('\n* ')}\n`;
151
+ if (failures.length > 10) {
152
+ body += `\n> Notice: Only the first 10 failures are shown.`;
144
153
  }
145
- body += '\n\n</details>';
146
154
  }
147
155
 
148
156
  if (this.tests.length > 0) {
149
- body += '\n<details>\n<summary><h3>🐒 Slowest Tests</h3></summary>\n\n';
157
+ body += `\n\n**🐒 Slowest Tests**\n\n`;
150
158
  body += this.tests
151
159
  .sort((a, b) => b.run_time - a.run_time)
152
160
  .slice(0, 5)
153
- .map(t => `* ${fullName(t)} (${humanizeDuration(parseFloat(t.run_time))})`)
161
+ .map(t => `* **${fullName(t)}** (${humanizeDuration(parseFloat(t.run_time))})`)
154
162
  .join('\n');
155
- body += '\n</details>';
156
163
  }
157
164
 
158
165
  // Construct Bitbucket API URL for comments
@@ -164,6 +171,7 @@ class BitbucketPipe {
164
171
 
165
172
  // Add current report
166
173
  debug(`Adding comment via URL: ${commentsRequestURL}`);
174
+ debug(`Final Bitbucket API call body: ${body}`);
167
175
 
168
176
  try {
169
177
  const addCommentResponse = await axios.post(
@@ -179,7 +187,7 @@ class BitbucketPipe {
179
187
 
180
188
  const commentID = addCommentResponse.data.id;
181
189
  // eslint-disable-next-line max-len
182
- const commentURL = `${this.ENV.BITBUCKET_REPO_URL}/pull-requests/${this.ENV.BITBUCKET_PR_ID}#comment-${commentID}`;
190
+ const commentURL = `https://bitbucket.org/${this.ENV.BITBUCKET_WORKSPACE}/${this.ENV.BITBUCKET_REPO_SLUG}/pull-requests/${this.ENV.BITBUCKET_PR_ID}#comment-${commentID}`;
183
191
 
184
192
  console.log(APP_PREFIX, chalk.yellow('Bitbucket'), `Report created: ${chalk.magenta(commentURL)}`);
185
193
  } catch (err) {
@@ -235,7 +243,6 @@ async function deletePreviousReport(axiosInstance, commentsRequestURL, hiddenCom
235
243
  } catch (e) {
236
244
  console.warn(`Can't delete previously added comment with testomat.io report. Ignored.`);
237
245
  }
238
-
239
246
  // Pass next env var if need to clear all previous reports;
240
247
  // only the last one is removed by default
241
248
  if (!process.env.BITBUCKET_REMOVE_ALL_OUTDATED_REPORTS) break;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@testomatio/reporter",
3
- "version": "1.4.11-beta-bitbucket-pipe",
3
+ "version": "1.4.13-beta-bitbucket-pipe",
4
4
  "description": "Testomatio Reporter Client",
5
5
  "main": "./lib/reporter.js",
6
6
  "typings": "typings/index.d.ts",
@@ -33,6 +33,7 @@
33
33
  "lodash.merge": "^4.6.2",
34
34
  "minimatch": "^9.0.3",
35
35
  "promise-retry": "^2.0.1",
36
+ "strip-ansi": "^7.1.0",
36
37
  "uuid": "^9.0.0"
37
38
  },
38
39
  "files": [