@testomatio/reporter 2.0.1-beta.5-timestamp → 2.0.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.
- package/README.md +1 -0
- package/lib/adapter/codecept.d.ts +2 -0
- package/lib/adapter/codecept.js +293 -335
- package/lib/adapter/cucumber/current.d.ts +14 -0
- package/lib/adapter/cucumber/current.js +195 -203
- package/lib/adapter/cucumber/legacy.d.ts +0 -0
- package/lib/adapter/cucumber/legacy.js +130 -155
- package/lib/adapter/cucumber.d.ts +2 -0
- package/lib/adapter/cucumber.js +5 -16
- package/lib/adapter/cypress-plugin/index.d.ts +2 -0
- package/lib/adapter/cypress-plugin/index.js +91 -105
- package/lib/adapter/jasmine.d.ts +11 -0
- package/lib/adapter/jasmine.js +54 -53
- package/lib/adapter/jest.d.ts +13 -0
- package/lib/adapter/jest.js +97 -99
- package/lib/adapter/mocha.d.ts +2 -0
- package/lib/adapter/mocha.js +112 -141
- package/lib/adapter/nightwatch.d.ts +4 -0
- package/lib/adapter/nightwatch.js +80 -0
- package/lib/adapter/playwright.d.ts +14 -0
- package/lib/adapter/playwright.js +199 -231
- package/lib/adapter/vitest.d.ts +35 -0
- package/lib/adapter/vitest.js +150 -149
- package/lib/adapter/webdriver.d.ts +24 -0
- package/lib/adapter/webdriver.js +144 -121
- package/lib/bin/cli.d.ts +2 -0
- package/lib/bin/cli.js +229 -211
- package/lib/bin/reportXml.d.ts +2 -0
- package/lib/bin/reportXml.js +51 -52
- package/lib/bin/startTest.d.ts +2 -0
- package/lib/bin/startTest.js +83 -95
- package/lib/bin/uploadArtifacts.d.ts +2 -0
- package/lib/bin/uploadArtifacts.js +56 -61
- package/lib/client.d.ts +76 -0
- package/lib/client.js +429 -465
- package/lib/config.d.ts +1 -0
- package/lib/config.js +18 -23
- package/lib/constants.d.ts +25 -0
- package/lib/constants.js +50 -44
- package/lib/data-storage.d.ts +34 -0
- package/lib/data-storage.js +216 -188
- package/lib/junit-adapter/adapter.d.ts +9 -0
- package/lib/junit-adapter/adapter.js +17 -20
- package/lib/junit-adapter/csharp.d.ts +5 -0
- package/lib/junit-adapter/csharp.js +28 -14
- package/lib/junit-adapter/index.d.ts +3 -0
- package/lib/junit-adapter/index.js +27 -25
- package/lib/junit-adapter/java.d.ts +5 -0
- package/lib/junit-adapter/java.js +41 -53
- package/lib/junit-adapter/javascript.d.ts +4 -0
- package/lib/junit-adapter/javascript.js +30 -27
- package/lib/junit-adapter/python.d.ts +5 -0
- package/lib/junit-adapter/python.js +38 -37
- package/lib/junit-adapter/ruby.d.ts +4 -0
- package/lib/junit-adapter/ruby.js +11 -8
- package/lib/output.d.ts +11 -0
- package/lib/output.js +44 -52
- package/lib/package.json +3 -0
- package/lib/pipe/bitbucket.d.ts +25 -0
- package/lib/pipe/bitbucket.js +223 -230
- package/lib/pipe/csv.d.ts +47 -0
- package/lib/pipe/csv.js +113 -126
- package/lib/pipe/debug.d.ts +29 -0
- package/lib/pipe/debug.js +125 -99
- package/lib/pipe/github.d.ts +30 -0
- package/lib/pipe/github.js +218 -213
- package/lib/pipe/gitlab.d.ts +25 -0
- package/lib/pipe/gitlab.js +183 -206
- package/lib/pipe/html.d.ts +35 -0
- package/lib/pipe/html.js +258 -321
- package/lib/pipe/index.d.ts +1 -0
- package/lib/pipe/index.js +94 -66
- package/lib/pipe/testomatio.d.ts +71 -0
- package/lib/pipe/testomatio.js +429 -474
- package/lib/replay.d.ts +31 -0
- package/lib/replay.js +255 -0
- package/lib/reporter-functions.d.ts +34 -0
- package/lib/reporter-functions.js +28 -26
- package/lib/reporter.d.ts +232 -0
- package/lib/reporter.js +34 -29
- package/lib/services/artifacts.d.ts +33 -0
- package/lib/services/artifacts.js +55 -51
- package/lib/services/index.d.ts +9 -0
- package/lib/services/index.js +14 -12
- package/lib/services/key-values.d.ts +27 -0
- package/lib/services/key-values.js +56 -53
- package/lib/services/logger.d.ts +64 -0
- package/lib/services/logger.js +226 -245
- package/lib/template/testomatio.hbs +1026 -1366
- package/lib/uploader.d.ts +60 -0
- package/lib/uploader.js +295 -364
- package/lib/utils/pipe_utils.d.ts +41 -0
- package/lib/utils/pipe_utils.js +89 -85
- package/lib/utils/utils.d.ts +54 -0
- package/lib/utils/utils.js +398 -307
- package/lib/xmlReader.d.ts +92 -0
- package/lib/xmlReader.js +525 -532
- package/package.json +64 -21
- package/src/adapter/codecept.js +373 -0
- package/src/adapter/cucumber/current.js +228 -0
- package/src/adapter/cucumber/legacy.js +158 -0
- package/src/adapter/cucumber.js +4 -0
- package/src/adapter/cypress-plugin/index.js +110 -0
- package/src/adapter/jasmine.js +60 -0
- package/src/adapter/jest.js +107 -0
- package/src/adapter/mocha.cjs +2 -0
- package/src/adapter/mocha.js +156 -0
- package/src/adapter/nightwatch.js +88 -0
- package/src/adapter/playwright.js +254 -0
- package/src/adapter/vitest.js +183 -0
- package/src/adapter/webdriver.js +142 -0
- package/src/bin/cli.js +348 -0
- package/src/bin/reportXml.js +77 -0
- package/src/bin/startTest.js +124 -0
- package/src/bin/uploadArtifacts.js +91 -0
- package/src/client.js +515 -0
- package/src/config.js +30 -0
- package/src/constants.js +53 -0
- package/src/data-storage.js +204 -0
- package/src/junit-adapter/adapter.js +23 -0
- package/src/junit-adapter/csharp.js +28 -0
- package/src/junit-adapter/index.js +28 -0
- package/src/junit-adapter/java.js +58 -0
- package/src/junit-adapter/javascript.js +31 -0
- package/src/junit-adapter/python.js +42 -0
- package/src/junit-adapter/ruby.js +10 -0
- package/src/output.js +57 -0
- package/src/pipe/bitbucket.js +252 -0
- package/src/pipe/csv.js +140 -0
- package/src/pipe/debug.js +125 -0
- package/src/pipe/github.js +232 -0
- package/src/pipe/gitlab.js +247 -0
- package/src/pipe/html.js +373 -0
- package/src/pipe/index.js +71 -0
- package/src/pipe/testomatio.js +504 -0
- package/src/replay.js +262 -0
- package/src/reporter-functions.js +55 -0
- package/src/reporter.cjs_decprecated +21 -0
- package/src/reporter.js +33 -0
- package/src/services/artifacts.js +59 -0
- package/src/services/index.js +13 -0
- package/src/services/key-values.js +59 -0
- package/src/services/logger.js +315 -0
- package/src/template/emptyData.svg +23 -0
- package/src/template/testomatio.hbs +1081 -0
- package/src/uploader.js +376 -0
- package/src/utils/pipe_utils.js +119 -0
- package/src/utils/utils.js +416 -0
- package/src/xmlReader.js +614 -0
package/lib/pipe/bitbucket.js
CHANGED
|
@@ -1,254 +1,247 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.BitbucketPipe = void 0;
|
|
40
|
+
const constants_js_1 = require("../constants.js");
|
|
41
|
+
const utils_js_1 = require("../utils/utils.js");
|
|
42
|
+
const pipe_utils_js_1 = require("../utils/pipe_utils.js");
|
|
43
|
+
const gaxios_1 = require("gaxios");
|
|
44
|
+
const picocolors_1 = __importDefault(require("picocolors"));
|
|
45
|
+
const humanize_duration_1 = __importDefault(require("humanize-duration"));
|
|
46
|
+
const lodash_merge_1 = __importDefault(require("lodash.merge"));
|
|
47
|
+
const path_1 = __importDefault(require("path"));
|
|
48
|
+
const debug_1 = __importDefault(require("debug"));
|
|
49
|
+
const debug = (0, debug_1.default)('@testomatio/reporter:pipe:bitbucket');
|
|
11
50
|
//! BITBUCKET_ACCESS_TOKEN environment variable is required for this functionality to work
|
|
12
51
|
//! and your pipeline trigger should be a pull request
|
|
13
|
-
|
|
14
52
|
/**
|
|
15
53
|
* @class BitbucketPipe
|
|
16
|
-
* @typedef {import('../../types').Pipe} Pipe
|
|
17
|
-
* @typedef {import('../../types').TestData} TestData
|
|
54
|
+
* @typedef {import('../../types/types.js').Pipe} Pipe
|
|
55
|
+
* @typedef {import('../../types/types.js').TestData} TestData
|
|
18
56
|
*/
|
|
19
57
|
class BitbucketPipe {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
58
|
+
constructor(params, store = {}) {
|
|
59
|
+
this.isEnabled = false;
|
|
60
|
+
this.ENV = process.env;
|
|
61
|
+
this.store = store;
|
|
62
|
+
this.tests = [];
|
|
63
|
+
// Bitbucket PAT looks like bbpat-*****
|
|
64
|
+
this.token = params.BITBUCKET_ACCESS_TOKEN || process.env.BITBUCKET_ACCESS_TOKEN || this.ENV.BITBUCKET_ACCESS_TOKEN;
|
|
65
|
+
this.hiddenCommentData = `Testomat.io report: ${process.env.BITBUCKET_BRANCH || ''}`;
|
|
66
|
+
debug(picocolors_1.default.yellow('Bitbucket Pipe:'), this.token ? 'TOKEN passed' : '*no token*', `Project key: ${this.ENV.BITBUCKET_PROJECT_KEY}, Pull request ID: ${this.ENV.BITBUCKET_PR_ID}`);
|
|
67
|
+
if (!this.token) {
|
|
68
|
+
debug(`Hint: Bitbucket CI variables are unavailable for unprotected branches by default.`);
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
this.isEnabled = true;
|
|
72
|
+
this.client = new gaxios_1.Gaxios({
|
|
73
|
+
baseURL: 'https://api.bitbucket.org/2.0',
|
|
74
|
+
headers: {
|
|
75
|
+
'Content-Type': 'application/json',
|
|
76
|
+
'Authorization': `Bearer ${this.token}`
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
debug('Bitbucket Pipe: Enabled');
|
|
38
80
|
}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
debug('Bitbucket Pipe: Enabled');
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
async cleanLog(log) {
|
|
46
|
-
const stripAnsi = (await import('strip-ansi')).default;
|
|
47
|
-
return stripAnsi(log);
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
// Prepare the run (if needed)
|
|
51
|
-
async prepareRun() {}
|
|
52
|
-
|
|
53
|
-
// Create a new run (if needed)
|
|
54
|
-
async createRun() {}
|
|
55
|
-
|
|
56
|
-
addTest(test) {
|
|
57
|
-
if (!this.isEnabled) return;
|
|
58
|
-
|
|
59
|
-
const index = this.tests.findIndex(t => isSameTest(t, test));
|
|
60
|
-
// Update if they were already added
|
|
61
|
-
if (index >= 0) {
|
|
62
|
-
this.tests[index] = merge(this.tests[index], test);
|
|
63
|
-
return;
|
|
81
|
+
async cleanLog(log) {
|
|
82
|
+
const stripAnsi = (await Promise.resolve().then(() => __importStar(require('strip-ansi')))).default;
|
|
83
|
+
return stripAnsi(log);
|
|
64
84
|
}
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
85
|
+
// Prepare the run (if needed)
|
|
86
|
+
async prepareRun() { }
|
|
87
|
+
// Create a new run (if needed)
|
|
88
|
+
async createRun() { }
|
|
89
|
+
addTest(test) {
|
|
90
|
+
if (!this.isEnabled)
|
|
91
|
+
return;
|
|
92
|
+
const index = this.tests.findIndex(t => (0, utils_js_1.isSameTest)(t, test));
|
|
93
|
+
// Update if they were already added
|
|
94
|
+
if (index >= 0) {
|
|
95
|
+
this.tests[index] = (0, lodash_merge_1.default)(this.tests[index], test);
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
this.tests.push(test);
|
|
78
99
|
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
100
|
+
async finishRun(runParams) {
|
|
101
|
+
if (!this.isEnabled)
|
|
102
|
+
return;
|
|
103
|
+
if (runParams.tests)
|
|
104
|
+
runParams.tests.forEach(t => this.addTest(t));
|
|
105
|
+
// Clean up the logs from ANSI codes
|
|
106
|
+
for (let i = 0; i < this.tests.length; i++) {
|
|
107
|
+
this.tests[i].message = await this.cleanLog(this.tests[i].message || '');
|
|
108
|
+
this.tests[i].stack = await this.cleanLog(this.tests[i].stack || '');
|
|
109
|
+
}
|
|
110
|
+
// Create a comment on Bitbucket
|
|
111
|
+
const passedCount = this.tests.filter(t => t.status === 'passed').length;
|
|
112
|
+
const failedCount = this.tests.filter(t => t.status === 'failed').length;
|
|
113
|
+
const skippedCount = this.tests.filter(t => t.status === 'skipped').length;
|
|
114
|
+
// Constructing the table
|
|
115
|
+
let summary = `${this.hiddenCommentData}
|
|
87
116
|
|
|
88
|
-
|  | ${statusEmoji(
|
|
89
|
-
runParams.status,
|
|
90
|
-
)} ${runParams.status.toUpperCase()} ${statusEmoji(runParams.status)} |
|
|
117
|
+
|  | ${(0, pipe_utils_js_1.statusEmoji)(runParams.status)} ${runParams.status.toUpperCase()} ${(0, pipe_utils_js_1.statusEmoji)(runParams.status)} |
|
|
91
118
|
| --- | --- |
|
|
92
119
|
| **Tests** | ✔️ **${this.tests.length}** tests run |
|
|
93
|
-
| **Summary** | ${statusEmoji('failed')} **${failedCount}** failed; ${statusEmoji(
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
parseInt(
|
|
98
|
-
this.tests.reduce((a, t) => a + (t.run_time || 0), 0),
|
|
99
|
-
10,
|
|
100
|
-
),
|
|
101
|
-
{
|
|
102
|
-
maxDecimalPoints: 0,
|
|
103
|
-
},
|
|
104
|
-
)}** |
|
|
120
|
+
| **Summary** | ${(0, pipe_utils_js_1.statusEmoji)('failed')} **${failedCount}** failed; ${(0, pipe_utils_js_1.statusEmoji)('passed')} **${passedCount}** passed; **${(0, pipe_utils_js_1.statusEmoji)('skipped')}** ${skippedCount} skipped |
|
|
121
|
+
| **Duration** | 🕐 **${(0, humanize_duration_1.default)(parseInt(this.tests.reduce((a, t) => a + (t.run_time || 0), 0), 10), {
|
|
122
|
+
maxDecimalPoints: 0,
|
|
123
|
+
})}** |
|
|
105
124
|
`;
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
.
|
|
125
|
+
if (this.ENV.BITBUCKET_BRANCH && this.ENV.BITBUCKET_COMMIT) {
|
|
126
|
+
// eslint-disable-next-line max-len
|
|
127
|
+
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}** |`;
|
|
128
|
+
}
|
|
129
|
+
const failures = this.tests
|
|
130
|
+
.filter(t => t.status === 'failed')
|
|
131
|
+
.slice(0, 20)
|
|
132
|
+
.map(t => {
|
|
133
|
+
let text = `${(0, pipe_utils_js_1.statusEmoji)('failed')} ${(0, pipe_utils_js_1.fullName)(t)}\n`;
|
|
134
|
+
if (t.message) {
|
|
135
|
+
text += `> ${t.message
|
|
136
|
+
.replace(/[^\x20-\x7E]/g, '')
|
|
137
|
+
.replace((0, utils_js_1.ansiRegExp)(), '')
|
|
138
|
+
.trim()}\n`;
|
|
139
|
+
}
|
|
140
|
+
if (t.stack) {
|
|
141
|
+
text += `\n\`\`\`diff\n${t.stack
|
|
142
|
+
.replace((0, utils_js_1.ansiRegExp)(), '')
|
|
143
|
+
.replace(/^[\s\S]*################\[ Failure \]################/g, '################[ Failure ]################')
|
|
144
|
+
.trim()}\n\`\`\`\n`;
|
|
145
|
+
}
|
|
146
|
+
if (t.artifacts && t.artifacts.length && !this.ENV.TESTOMATIO_PRIVATE_ARTIFACTS) {
|
|
147
|
+
t.artifacts
|
|
148
|
+
.filter(f => !!f)
|
|
149
|
+
.forEach(f => {
|
|
150
|
+
if (f.endsWith('.png')) {
|
|
151
|
+
text += `\n`;
|
|
152
|
+
}
|
|
153
|
+
else {
|
|
154
|
+
text += `[📄 ${path_1.default.basename(f)}](${f})\n`;
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
text += `\n---\n`;
|
|
159
|
+
return text;
|
|
160
|
+
});
|
|
161
|
+
let body = summary;
|
|
162
|
+
if (failures.length) {
|
|
163
|
+
body += `\n🟥 **Failures (${failures.length})**\n\n* ${failures.join('\n* ')}\n`;
|
|
164
|
+
if (failures.length > 10) {
|
|
165
|
+
body += `\n> Notice: Only the first 10 failures are shown.`;
|
|
166
|
+
}
|
|
122
167
|
}
|
|
123
|
-
if (
|
|
124
|
-
|
|
125
|
-
.
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
.trim()}\n\`\`\`\n`;
|
|
168
|
+
if (this.tests.length > 0) {
|
|
169
|
+
body += `\n\n**🐢 Slowest Tests**\n\n`;
|
|
170
|
+
body += this.tests
|
|
171
|
+
.sort((a, b) => b.run_time - a.run_time)
|
|
172
|
+
.slice(0, 5)
|
|
173
|
+
.map(t => `* **${(0, pipe_utils_js_1.fullName)(t)}** (${(0, humanize_duration_1.default)(parseFloat(t.run_time))})`)
|
|
174
|
+
.join('\n');
|
|
131
175
|
}
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
176
|
+
// Construct Bitbucket API URL for comments
|
|
177
|
+
// eslint-disable-next-line max-len
|
|
178
|
+
const commentsRequestURL = `/repositories/${this.ENV.BITBUCKET_WORKSPACE}/${this.ENV.BITBUCKET_REPO_SLUG}/pullrequests/${this.ENV.BITBUCKET_PR_ID}/comments`;
|
|
179
|
+
// Delete previous report
|
|
180
|
+
await deletePreviousReport(this.client, commentsRequestURL, this.hiddenCommentData);
|
|
181
|
+
// Add current report
|
|
182
|
+
debug(`Adding comment via URL: ${commentsRequestURL}`);
|
|
183
|
+
debug(`Final Bitbucket API call body: ${body}`);
|
|
184
|
+
try {
|
|
185
|
+
const addCommentResponse = await this.client.request({
|
|
186
|
+
method: 'POST',
|
|
187
|
+
url: commentsRequestURL,
|
|
188
|
+
data: { content: { raw: body } }
|
|
141
189
|
});
|
|
190
|
+
const commentID = addCommentResponse.data.id;
|
|
191
|
+
// eslint-disable-next-line max-len
|
|
192
|
+
const commentURL = `https://bitbucket.org/${this.ENV.BITBUCKET_WORKSPACE}/${this.ENV.BITBUCKET_REPO_SLUG}/pull-requests/${this.ENV.BITBUCKET_PR_ID}#comment-${commentID}`;
|
|
193
|
+
console.log(constants_js_1.APP_PREFIX, picocolors_1.default.yellow('Bitbucket'), `Report created: ${picocolors_1.default.magenta(commentURL)}`);
|
|
142
194
|
}
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
});
|
|
146
|
-
|
|
147
|
-
let body = summary;
|
|
148
|
-
|
|
149
|
-
if (failures.length) {
|
|
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.`;
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
if (this.tests.length > 0) {
|
|
157
|
-
body += `\n\n**🐢 Slowest Tests**\n\n`;
|
|
158
|
-
body += this.tests
|
|
159
|
-
.sort((a, b) => b.run_time - a.run_time)
|
|
160
|
-
.slice(0, 5)
|
|
161
|
-
.map(t => `* **${fullName(t)}** (${humanizeDuration(parseFloat(t.run_time))})`)
|
|
162
|
-
.join('\n');
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
// Construct Bitbucket API URL for comments
|
|
166
|
-
// eslint-disable-next-line max-len
|
|
167
|
-
const commentsRequestURL = `https://api.bitbucket.org/2.0/repositories/${this.ENV.BITBUCKET_WORKSPACE}/${this.ENV.BITBUCKET_REPO_SLUG}/pullrequests/${this.ENV.BITBUCKET_PR_ID}/comments`;
|
|
168
|
-
|
|
169
|
-
// Delete previous report
|
|
170
|
-
await deletePreviousReport(axios, commentsRequestURL, this.hiddenCommentData, this.token);
|
|
171
|
-
|
|
172
|
-
// Add current report
|
|
173
|
-
debug(`Adding comment via URL: ${commentsRequestURL}`);
|
|
174
|
-
debug(`Final Bitbucket API call body: ${body}`);
|
|
175
|
-
|
|
176
|
-
try {
|
|
177
|
-
const addCommentResponse = await axios.post(
|
|
178
|
-
commentsRequestURL,
|
|
179
|
-
{ content: { raw: body } },
|
|
180
|
-
{
|
|
181
|
-
headers: {
|
|
182
|
-
Authorization: `Bearer ${this.token}`,
|
|
183
|
-
'Content-Type': 'application/json',
|
|
184
|
-
},
|
|
185
|
-
},
|
|
186
|
-
);
|
|
187
|
-
|
|
188
|
-
const commentID = addCommentResponse.data.id;
|
|
189
|
-
// eslint-disable-next-line max-len
|
|
190
|
-
const commentURL = `https://bitbucket.org/${this.ENV.BITBUCKET_WORKSPACE}/${this.ENV.BITBUCKET_REPO_SLUG}/pull-requests/${this.ENV.BITBUCKET_PR_ID}#comment-${commentID}`;
|
|
191
|
-
|
|
192
|
-
console.log(APP_PREFIX, chalk.yellow('Bitbucket'), `Report created: ${chalk.magenta(commentURL)}`);
|
|
193
|
-
} catch (err) {
|
|
194
|
-
console.error(
|
|
195
|
-
APP_PREFIX,
|
|
196
|
-
chalk.yellow('Bitbucket'),
|
|
197
|
-
`Couldn't create Bitbucket report\n${err}.
|
|
195
|
+
catch (err) {
|
|
196
|
+
console.error(constants_js_1.APP_PREFIX, picocolors_1.default.yellow('Bitbucket'), `Couldn't create Bitbucket report\n${err}.
|
|
198
197
|
Request URL: ${commentsRequestURL}
|
|
199
|
-
Request data: ${body}
|
|
200
|
-
|
|
198
|
+
Request data: ${body}`);
|
|
199
|
+
}
|
|
201
200
|
}
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
updateRun() {}
|
|
201
|
+
toString() {
|
|
202
|
+
return 'Bitbucket Reporter';
|
|
203
|
+
}
|
|
204
|
+
updateRun() { }
|
|
209
205
|
}
|
|
210
|
-
|
|
211
|
-
async function deletePreviousReport(
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
Authorization: `Bearer ${token}`,
|
|
221
|
-
'Content-Type': 'application/json',
|
|
222
|
-
},
|
|
223
|
-
});
|
|
224
|
-
comments = response.data.values;
|
|
225
|
-
} catch (e) {
|
|
226
|
-
console.error('Error while attempting to retrieve comments on Bitbucket Pull Request:\n', e);
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
if (!comments.length) return;
|
|
230
|
-
|
|
231
|
-
for (const comment of comments) {
|
|
232
|
-
// If comment was left by the same workflow
|
|
233
|
-
if (comment.content.raw.includes(hiddenCommentData)) {
|
|
234
|
-
try {
|
|
235
|
-
// Delete previous comment
|
|
236
|
-
const deleteCommentURL = `${commentsRequestURL}/${comment.id}`;
|
|
237
|
-
await axiosInstance.delete(deleteCommentURL, {
|
|
238
|
-
headers: {
|
|
239
|
-
Authorization: `Bearer ${token}`,
|
|
240
|
-
'Content-Type': 'application/json',
|
|
241
|
-
},
|
|
206
|
+
exports.BitbucketPipe = BitbucketPipe;
|
|
207
|
+
async function deletePreviousReport(client, commentsRequestURL, hiddenCommentData) {
|
|
208
|
+
if (process.env.BITBUCKET_KEEP_OUTDATED_REPORTS)
|
|
209
|
+
return;
|
|
210
|
+
// Get comments
|
|
211
|
+
let comments = [];
|
|
212
|
+
try {
|
|
213
|
+
const response = await client.request({
|
|
214
|
+
method: 'GET',
|
|
215
|
+
url: commentsRequestURL
|
|
242
216
|
});
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
217
|
+
comments = response.data.values;
|
|
218
|
+
}
|
|
219
|
+
catch (e) {
|
|
220
|
+
console.error('Error while attempting to retrieve comments on Bitbucket Pull Request:\n', e);
|
|
221
|
+
}
|
|
222
|
+
if (!comments.length)
|
|
223
|
+
return;
|
|
224
|
+
for (const comment of comments) {
|
|
225
|
+
// If comment was left by the same workflow
|
|
226
|
+
if (comment.content.raw.includes(hiddenCommentData)) {
|
|
227
|
+
try {
|
|
228
|
+
// Delete previous comment
|
|
229
|
+
const deleteCommentURL = `${commentsRequestURL}/${comment.id}`;
|
|
230
|
+
await client.request({
|
|
231
|
+
method: 'DELETE',
|
|
232
|
+
url: deleteCommentURL
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
catch (e) {
|
|
236
|
+
console.warn(`Can't delete previously added comment with testomat.io report. Ignored.`);
|
|
237
|
+
}
|
|
238
|
+
// Pass next env var if need to clear all previous reports;
|
|
239
|
+
// only the last one is removed by default
|
|
240
|
+
if (!process.env.BITBUCKET_REMOVE_ALL_OUTDATED_REPORTS)
|
|
241
|
+
break;
|
|
242
|
+
// TODO: in case of many reports should implement pagination
|
|
243
|
+
}
|
|
250
244
|
}
|
|
251
|
-
}
|
|
252
245
|
}
|
|
253
246
|
|
|
254
|
-
module.exports = BitbucketPipe;
|
|
247
|
+
module.exports.BitbucketPipe = BitbucketPipe;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
export default CsvPipe;
|
|
2
|
+
export type Pipe = import("../../types/types.js").Pipe;
|
|
3
|
+
export type TestData = import("../../types/types.js").TestData;
|
|
4
|
+
/**
|
|
5
|
+
* @typedef {import('../../types/types.js').Pipe} Pipe
|
|
6
|
+
* @typedef {import('../../types/types.js').TestData} TestData
|
|
7
|
+
* @class CsvPipe
|
|
8
|
+
* @implements {Pipe}
|
|
9
|
+
*/
|
|
10
|
+
declare class CsvPipe implements Pipe {
|
|
11
|
+
constructor(params: any, store: any);
|
|
12
|
+
store: any;
|
|
13
|
+
title: any;
|
|
14
|
+
results: any[];
|
|
15
|
+
outputDir: string;
|
|
16
|
+
defaultReportName: string;
|
|
17
|
+
csvFilename: string;
|
|
18
|
+
isEnabled: boolean;
|
|
19
|
+
outputFile: string;
|
|
20
|
+
prepareRun(): Promise<void>;
|
|
21
|
+
createRun(): Promise<void>;
|
|
22
|
+
updateRun(): void;
|
|
23
|
+
/**
|
|
24
|
+
* Create a folder that will contain the exported files
|
|
25
|
+
*/
|
|
26
|
+
checkExportDir(): void;
|
|
27
|
+
/**
|
|
28
|
+
* Save data to the csv file.
|
|
29
|
+
* @param {Object} data - data that will be added to the CSV file.
|
|
30
|
+
* Example: [{suite_title: "Suite #1", test: "Test-case-1", message: "Test msg"}]
|
|
31
|
+
* @param {Object} headers - csv file headers. Example: [{ id: 'suite_title', title: 'Suite_title' }]
|
|
32
|
+
*/
|
|
33
|
+
saveToCsv(data: any, headers: any): Promise<void>;
|
|
34
|
+
/**
|
|
35
|
+
* Add test data to the result array for saving. As a result of this function, we get a result object to save.
|
|
36
|
+
* @param {Object} test - object which includes each test entry.
|
|
37
|
+
*/
|
|
38
|
+
addTest(test: any): void;
|
|
39
|
+
/**
|
|
40
|
+
* @param {{ tests?: TestData[] }} runParams
|
|
41
|
+
* @returns {Promise<void>}
|
|
42
|
+
*/
|
|
43
|
+
finishRun(runParams: {
|
|
44
|
+
tests?: TestData[];
|
|
45
|
+
}): Promise<void>;
|
|
46
|
+
toString(): string;
|
|
47
|
+
}
|