testbeats 2.0.0
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/LICENSE +21 -0
- package/README.md +60 -0
- package/package.json +65 -0
- package/src/beats/index.js +74 -0
- package/src/cli.js +23 -0
- package/src/commands/publish.js +54 -0
- package/src/extensions/ci-info.js +134 -0
- package/src/extensions/custom.js +29 -0
- package/src/extensions/hyperlinks.js +60 -0
- package/src/extensions/index.js +63 -0
- package/src/extensions/mentions.js +112 -0
- package/src/extensions/metadata.js +89 -0
- package/src/extensions/percy-analysis.js +203 -0
- package/src/extensions/quick-chart-test-summary.js +82 -0
- package/src/extensions/report-portal-analysis.js +95 -0
- package/src/extensions/report-portal-history.js +105 -0
- package/src/helpers/ci.js +62 -0
- package/src/helpers/constants.js +45 -0
- package/src/helpers/extension.helper.js +107 -0
- package/src/helpers/helper.js +102 -0
- package/src/helpers/metadata.helper.js +115 -0
- package/src/helpers/percy.js +60 -0
- package/src/helpers/performance.js +141 -0
- package/src/helpers/report-portal.js +47 -0
- package/src/index.d.ts +243 -0
- package/src/index.js +14 -0
- package/src/targets/chat.js +242 -0
- package/src/targets/custom.js +28 -0
- package/src/targets/delay.js +19 -0
- package/src/targets/index.js +39 -0
- package/src/targets/influx.js +208 -0
- package/src/targets/slack.js +266 -0
- package/src/targets/teams.js +304 -0
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
const { getOnCallPerson } = require('rosters');
|
|
2
|
+
const { addSlackExtension, addTeamsExtension } = require('../helpers/extension.helper');
|
|
3
|
+
const { HOOK, STATUS } = require('../helpers/constants');
|
|
4
|
+
|
|
5
|
+
function run({ target, extension, payload, root_payload }) {
|
|
6
|
+
if (target.name === 'teams') {
|
|
7
|
+
extension.inputs = Object.assign({}, default_inputs_teams, extension.inputs);
|
|
8
|
+
attachForTeam({ extension, payload });
|
|
9
|
+
} else if (target.name === 'slack') {
|
|
10
|
+
extension.inputs = Object.assign({}, default_inputs_slack, extension.inputs);
|
|
11
|
+
attachForSlack({ extension, payload });
|
|
12
|
+
} else if (target.name === 'chat') {
|
|
13
|
+
extension.inputs = Object.assign({}, default_inputs_chat, extension.inputs);
|
|
14
|
+
attachForChat({ extension, root_payload });
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function attachForTeam({ extension, payload }) {
|
|
19
|
+
const users = getUsers(extension);
|
|
20
|
+
if (users.length > 0) {
|
|
21
|
+
setPayloadWithMSTeamsEntities(payload);
|
|
22
|
+
const users_ats = users.map(user => `<at>${user.name}</at>`);
|
|
23
|
+
addTeamsExtension({ payload, extension, text: users_ats.join(' | ')});
|
|
24
|
+
for (const user of users) {
|
|
25
|
+
payload.msteams.entities.push({
|
|
26
|
+
"type": "mention",
|
|
27
|
+
"text": `<at>${user.name}</at>`,
|
|
28
|
+
"mentioned": {
|
|
29
|
+
"id": user.teams_upn,
|
|
30
|
+
"name": user.name
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function formatSlackMentions({slack_uid, slack_gid}) {
|
|
38
|
+
if (slack_gid && slack_uid) {
|
|
39
|
+
throw new Error(`Error in slack extension configuration. Either slack user or group Id is allowed`);
|
|
40
|
+
}
|
|
41
|
+
if (slack_uid) {
|
|
42
|
+
return `<@${slack_uid}>`
|
|
43
|
+
}
|
|
44
|
+
const tagPrefix = ["here", "everyone", "channel"].includes(slack_gid.toLowerCase()) ? "" : "subteam^";
|
|
45
|
+
return `<!${tagPrefix}${slack_gid}>`
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function attachForSlack({ extension, payload }) {
|
|
49
|
+
const users = getUsers(extension);
|
|
50
|
+
const user_ids = users.map(formatSlackMentions);
|
|
51
|
+
if (users.length > 0) {
|
|
52
|
+
addSlackExtension({ payload, extension, text: user_ids.join(' | ') });
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function attachForChat({ extension, root_payload }) {
|
|
57
|
+
const users = getUsers(extension);
|
|
58
|
+
const user_ids = users.map(user => `<users/${user.chat_uid}>`);
|
|
59
|
+
if (users.length > 0) {
|
|
60
|
+
root_payload.text = user_ids.join(' | ');
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function getUsers(extension) {
|
|
65
|
+
const users = [];
|
|
66
|
+
if (extension.inputs.users) {
|
|
67
|
+
users.push(...extension.inputs.users);
|
|
68
|
+
}
|
|
69
|
+
if (extension.inputs.schedule) {
|
|
70
|
+
const user = getOnCallPerson(extension.inputs.schedule);
|
|
71
|
+
if (user) {
|
|
72
|
+
users.push(user);
|
|
73
|
+
} else {
|
|
74
|
+
// TODO: warn message for no on-call person
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return users;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function setPayloadWithMSTeamsEntities(payload) {
|
|
81
|
+
if (!payload.msteams) {
|
|
82
|
+
payload.msteams = {};
|
|
83
|
+
}
|
|
84
|
+
if (!payload.msteams.entities) {
|
|
85
|
+
payload.msteams.entities = [];
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const default_options = {
|
|
90
|
+
hook: HOOK.END,
|
|
91
|
+
condition: STATUS.FAIL
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const default_inputs_teams = {
|
|
95
|
+
title: '',
|
|
96
|
+
separator: true
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const default_inputs_slack = {
|
|
100
|
+
title: '',
|
|
101
|
+
separator: false
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const default_inputs_chat = {
|
|
105
|
+
title: '',
|
|
106
|
+
separator: true
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
module.exports = {
|
|
110
|
+
run,
|
|
111
|
+
default_options
|
|
112
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
const { HOOK, STATUS } = require('../helpers/constants');
|
|
2
|
+
const { addChatExtension, addSlackExtension, addTeamsExtension } = require('../helpers/extension.helper');
|
|
3
|
+
const { getTeamsMetaDataText, getSlackMetaDataText, getChatMetaDataText } = require('../helpers/metadata.helper');
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @param {object} param0
|
|
7
|
+
* @param {import('..').Target} param0.target
|
|
8
|
+
* @param {import('..').MetadataExtension} param0.extension
|
|
9
|
+
*/
|
|
10
|
+
async function run({ target, extension, result, payload, root_payload }) {
|
|
11
|
+
if (target.name === 'teams') {
|
|
12
|
+
extension.inputs = Object.assign({}, default_inputs_teams, extension.inputs);
|
|
13
|
+
await attachForTeams({ target, extension, payload, result });
|
|
14
|
+
} else if (target.name === 'slack') {
|
|
15
|
+
extension.inputs = Object.assign({}, default_inputs_slack, extension.inputs);
|
|
16
|
+
await attachForSlack({ target, extension, payload, result });
|
|
17
|
+
} else if (target.name === 'chat') {
|
|
18
|
+
extension.inputs = Object.assign({}, default_inputs_chat, extension.inputs);
|
|
19
|
+
await attachForChat({ target, extension, payload, result });
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* @param {object} param0
|
|
25
|
+
* @param {import('..').MetadataExtension} param0.extension
|
|
26
|
+
*/
|
|
27
|
+
async function attachForTeams({ target, extension, payload, result }) {
|
|
28
|
+
const text = await getTeamsMetaDataText({
|
|
29
|
+
elements: extension.inputs.data,
|
|
30
|
+
target,
|
|
31
|
+
extension,
|
|
32
|
+
result,
|
|
33
|
+
default_condition: default_options.condition
|
|
34
|
+
});
|
|
35
|
+
if (text) {
|
|
36
|
+
addTeamsExtension({ payload, extension, text });
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
async function attachForSlack({ target, extension, payload, result }) {
|
|
41
|
+
const text = await getSlackMetaDataText({
|
|
42
|
+
elements: extension.inputs.data,
|
|
43
|
+
target,
|
|
44
|
+
extension,
|
|
45
|
+
result,
|
|
46
|
+
default_condition: default_options.condition
|
|
47
|
+
});
|
|
48
|
+
if (text) {
|
|
49
|
+
addSlackExtension({ payload, extension, text });
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
async function attachForChat({ target, extension, payload, result }) {
|
|
54
|
+
const text = await getChatMetaDataText({
|
|
55
|
+
elements: extension.inputs.data,
|
|
56
|
+
target,
|
|
57
|
+
extension,
|
|
58
|
+
result,
|
|
59
|
+
default_condition: default_options.condition
|
|
60
|
+
});
|
|
61
|
+
if (text) {
|
|
62
|
+
addChatExtension({ payload, extension, text });
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const default_options = {
|
|
67
|
+
hook: HOOK.END,
|
|
68
|
+
condition: STATUS.PASS_OR_FAIL
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const default_inputs_teams = {
|
|
72
|
+
title: '',
|
|
73
|
+
separator: true
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const default_inputs_slack = {
|
|
77
|
+
title: '',
|
|
78
|
+
separator: false
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const default_inputs_chat = {
|
|
82
|
+
title: '',
|
|
83
|
+
separator: true
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
module.exports = {
|
|
87
|
+
run,
|
|
88
|
+
default_options
|
|
89
|
+
}
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
const retry = require('async-retry');
|
|
2
|
+
const { getProjectByName, getLastBuild, getBuild, getRemovedSnapshots } = require('../helpers/percy');
|
|
3
|
+
const { HOOK, STATUS, URLS } = require('../helpers/constants');
|
|
4
|
+
const { addChatExtension, addSlackExtension, addTeamsExtension } = require('../helpers/extension.helper');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
*
|
|
8
|
+
* @param {object} param0
|
|
9
|
+
* @param {import('../index').PercyAnalysisExtension} param0.extension
|
|
10
|
+
*/
|
|
11
|
+
async function run({ extension, payload, target }) {
|
|
12
|
+
extension.inputs = Object.assign({}, default_inputs, extension.inputs);
|
|
13
|
+
await initialize(extension);
|
|
14
|
+
if (target.name === 'teams') {
|
|
15
|
+
extension.inputs = Object.assign({}, default_inputs_teams, extension.inputs);
|
|
16
|
+
attachForTeams({ payload, extension });
|
|
17
|
+
} else if (target.name === 'slack') {
|
|
18
|
+
extension.inputs = Object.assign({}, default_inputs_slack, extension.inputs);
|
|
19
|
+
attachForSlack({ payload, extension });
|
|
20
|
+
} else if (target.name === 'chat') {
|
|
21
|
+
extension.inputs = Object.assign({}, default_inputs_chat, extension.inputs);
|
|
22
|
+
attachForChat({ payload, extension });
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* @param {import('../index').PercyAnalysisExtension} extension
|
|
28
|
+
*/
|
|
29
|
+
async function initialize(extension) {
|
|
30
|
+
const { inputs } = extension;
|
|
31
|
+
if (!inputs.build_id) {
|
|
32
|
+
await setBuildByLastRun(extension);
|
|
33
|
+
} else {
|
|
34
|
+
await setBuild(extension);
|
|
35
|
+
}
|
|
36
|
+
await setRemovedSnapshots(extension);
|
|
37
|
+
if (!inputs.title_link && inputs.title_link_to_build) {
|
|
38
|
+
inputs.title_link = `https://percy.io/${inputs.organization_uid}/${inputs.project_name}/builds/${inputs.build_id}`;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* @param {import('../index').PercyAnalysisExtension} extension
|
|
44
|
+
*/
|
|
45
|
+
async function setBuildByLastRun(extension) {
|
|
46
|
+
const { inputs, outputs } = extension;
|
|
47
|
+
if (!inputs.project_id) {
|
|
48
|
+
await setProjectId(extension)
|
|
49
|
+
}
|
|
50
|
+
const response = await getLastFinishedBuild(extension);
|
|
51
|
+
inputs.build_id = response.data[0].id;
|
|
52
|
+
outputs.build = response.data[0];
|
|
53
|
+
if (!outputs.project) {
|
|
54
|
+
outputs.project = response.included.find(_item => _item.type === 'projects');
|
|
55
|
+
}
|
|
56
|
+
if (!inputs.project_name) {
|
|
57
|
+
inputs.project_name = outputs.project.attributes.name;
|
|
58
|
+
}
|
|
59
|
+
if (!inputs.organization_uid) {
|
|
60
|
+
inputs.organization_uid = getOrganizationUID(outputs.project.attributes['full-slug']);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* @param {import('../index').PercyAnalysisExtension} extension
|
|
66
|
+
*/
|
|
67
|
+
function getLastFinishedBuild(extension) {
|
|
68
|
+
const { inputs } = extension;
|
|
69
|
+
const minTimeout = 5000;
|
|
70
|
+
|
|
71
|
+
return retry(async () => {
|
|
72
|
+
let response;
|
|
73
|
+
try {
|
|
74
|
+
response = await getLastBuild(inputs);
|
|
75
|
+
} catch (error) {
|
|
76
|
+
throw new Error(`Error occurred while fetching the last build: ${error}`);
|
|
77
|
+
}
|
|
78
|
+
if (!response.data || !response.data[0] || !response.data[0].attributes) {
|
|
79
|
+
throw new Error(`Invalid response data: ${JSON.stringify(response)}`);
|
|
80
|
+
}
|
|
81
|
+
const state = response.data[0].attributes.state;
|
|
82
|
+
if (state !== "finished" && state !== "failed") {
|
|
83
|
+
throw new Error(`build is still '${state}'`);
|
|
84
|
+
}
|
|
85
|
+
return response;
|
|
86
|
+
}, { retries: inputs.retries, minTimeout });
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* @param {import('../index').PercyAnalysisExtension} extension
|
|
91
|
+
*/
|
|
92
|
+
async function setProjectId(extension) {
|
|
93
|
+
const { inputs, outputs } = extension;
|
|
94
|
+
if (!inputs.project_name) {
|
|
95
|
+
throw "mandatory inputs 'build_id' or 'project_id' or 'project_name' are not provided for percy-analysis extension"
|
|
96
|
+
}
|
|
97
|
+
const response = await getProjectByName(inputs);
|
|
98
|
+
inputs.project_id = response.data.id;
|
|
99
|
+
outputs.project = response.data;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* @param {import('../index').PercyAnalysisExtension} extension
|
|
104
|
+
*/
|
|
105
|
+
async function setBuild(extension) {
|
|
106
|
+
const { inputs, outputs } = extension;
|
|
107
|
+
const response = await getBuild(inputs);
|
|
108
|
+
outputs.build = response.data;
|
|
109
|
+
outputs.project = response.included.find(_item => _item.type === 'projects');
|
|
110
|
+
if (!inputs.project_id) {
|
|
111
|
+
inputs.project_id = outputs.project.id;
|
|
112
|
+
}
|
|
113
|
+
if (!inputs.project_name) {
|
|
114
|
+
inputs.project_name = outputs.project.attributes.name;
|
|
115
|
+
}
|
|
116
|
+
if (!inputs.organization_uid) {
|
|
117
|
+
inputs.organization_uid = getOrganizationUID(outputs.project.attributes['full-slug']);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function getOrganizationUID(slug) {
|
|
122
|
+
return slug.split('/')[0];
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* @param {import('../index').PercyAnalysisExtension} extension
|
|
127
|
+
*/
|
|
128
|
+
async function setRemovedSnapshots(extension) {
|
|
129
|
+
const response = await getRemovedSnapshots(extension.inputs);
|
|
130
|
+
extension.outputs.removed_snapshots = response.data;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function attachForTeams({ payload, extension }) {
|
|
134
|
+
const text = getAnalysisSummary(extension.outputs).join(' | ');
|
|
135
|
+
addTeamsExtension({ payload, extension, text });
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function attachForSlack({ payload, extension }) {
|
|
139
|
+
const text = getAnalysisSummary(extension.outputs, '*', '*').join(' | ');
|
|
140
|
+
addSlackExtension({ payload, extension, text });
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function attachForChat({ payload, extension }) {
|
|
144
|
+
const text = getAnalysisSummary(extension.outputs, '<b>', '</b>').join(' | ');
|
|
145
|
+
addChatExtension({ payload, extension, text });
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function getAnalysisSummary(outputs, bold_start = '**', bold_end = '**') {
|
|
149
|
+
const { build, removed_snapshots } = outputs;
|
|
150
|
+
const results = [];
|
|
151
|
+
const total = build.attributes['total-snapshots'];
|
|
152
|
+
const un_reviewed = build.attributes['total-snapshots-unreviewed'];
|
|
153
|
+
const approved = total - un_reviewed;
|
|
154
|
+
if (approved) {
|
|
155
|
+
results.push(`${bold_start}✔ AP - ${approved}${bold_end}`);
|
|
156
|
+
} else {
|
|
157
|
+
results.push(`✔ AP - ${approved || 0}`);
|
|
158
|
+
}
|
|
159
|
+
if (un_reviewed) {
|
|
160
|
+
results.push(`${bold_start}🔎 UR - ${un_reviewed}${bold_end}`);
|
|
161
|
+
} else {
|
|
162
|
+
results.push(`🔎 UR - ${un_reviewed || 0}`);
|
|
163
|
+
}
|
|
164
|
+
if (removed_snapshots && removed_snapshots.length) {
|
|
165
|
+
results.push(`${bold_start}🗑 RM - ${removed_snapshots.length}${bold_end}`);
|
|
166
|
+
} else {
|
|
167
|
+
results.push(`🗑 RM - 0`);
|
|
168
|
+
}
|
|
169
|
+
return results;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
const default_options = {
|
|
173
|
+
hook: HOOK.END,
|
|
174
|
+
condition: STATUS.PASS_OR_FAIL
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
const default_inputs = {
|
|
178
|
+
title: 'Percy Analysis',
|
|
179
|
+
url: URLS.PERCY,
|
|
180
|
+
title_link_to_build: true,
|
|
181
|
+
retries: 10,
|
|
182
|
+
build_id: '',
|
|
183
|
+
project_id: '',
|
|
184
|
+
project_name: '',
|
|
185
|
+
organization_uid: ''
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
const default_inputs_teams = {
|
|
189
|
+
separator: true
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
const default_inputs_slack = {
|
|
193
|
+
separator: false
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
const default_inputs_chat = {
|
|
197
|
+
separator: true
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
module.exports = {
|
|
201
|
+
run,
|
|
202
|
+
default_options
|
|
203
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
const { getPercentage } = require('../helpers/helper');
|
|
2
|
+
const { HOOK, STATUS, URLS } = require('../helpers/constants');
|
|
3
|
+
|
|
4
|
+
function getUrl(extension, result) {
|
|
5
|
+
const percentage = getPercentage(result.passed, result.total);
|
|
6
|
+
const chart = {
|
|
7
|
+
type: 'radialGauge',
|
|
8
|
+
data: {
|
|
9
|
+
datasets: [{
|
|
10
|
+
data: [percentage],
|
|
11
|
+
backgroundColor: 'green',
|
|
12
|
+
}]
|
|
13
|
+
},
|
|
14
|
+
options: {
|
|
15
|
+
trackColor: '#FF0000',
|
|
16
|
+
roundedCorners: false,
|
|
17
|
+
centerPercentage: 80,
|
|
18
|
+
centerArea: {
|
|
19
|
+
fontSize: 74,
|
|
20
|
+
text: `${percentage}%`,
|
|
21
|
+
},
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
return `${extension.inputs.url}/chart?c=${encodeURIComponent(JSON.stringify(chart))}`;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function attachForTeams({ extension, result, payload }) {
|
|
28
|
+
const main_column = {
|
|
29
|
+
"type": "Column",
|
|
30
|
+
"items": [payload.body[0], payload.body[1]],
|
|
31
|
+
"width": "stretch"
|
|
32
|
+
}
|
|
33
|
+
const image_column = {
|
|
34
|
+
"type": "Column",
|
|
35
|
+
"items": [
|
|
36
|
+
{
|
|
37
|
+
"type": "Image",
|
|
38
|
+
"url": getUrl(extension, result),
|
|
39
|
+
"altText": "overall-results-summary",
|
|
40
|
+
"size": "large"
|
|
41
|
+
}
|
|
42
|
+
],
|
|
43
|
+
"width": "auto"
|
|
44
|
+
}
|
|
45
|
+
const column_set = {
|
|
46
|
+
"type": "ColumnSet",
|
|
47
|
+
"columns": [
|
|
48
|
+
main_column,
|
|
49
|
+
image_column
|
|
50
|
+
]
|
|
51
|
+
}
|
|
52
|
+
payload.body = [column_set];
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function attachForSlack({ extension, result, payload }) {
|
|
56
|
+
payload.blocks[0]["accessory"] = {
|
|
57
|
+
"type": "image",
|
|
58
|
+
"alt_text": "overall-results-summary",
|
|
59
|
+
"image_url": getUrl(extension, result)
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function run(params) {
|
|
64
|
+
const { extension, target } = params;
|
|
65
|
+
params.extension.inputs = extension.inputs || {};
|
|
66
|
+
params.extension.inputs["url"] = (extension.inputs.url && extension.inputs.url.trim()) || URLS.QUICK_CHART;
|
|
67
|
+
if (target.name === 'teams') {
|
|
68
|
+
attachForTeams(params);
|
|
69
|
+
} else if (target.name === 'slack') {
|
|
70
|
+
attachForSlack(params);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const default_options = {
|
|
75
|
+
hook: HOOK.AFTER_SUMMARY,
|
|
76
|
+
condition: STATUS.PASS_OR_FAIL
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
module.exports = {
|
|
80
|
+
run,
|
|
81
|
+
default_options
|
|
82
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
const { getLaunchDetails, getLastLaunchByName } = require('../helpers/report-portal');
|
|
2
|
+
const { addChatExtension, addSlackExtension, addTeamsExtension } = require('../helpers/extension.helper');
|
|
3
|
+
const { HOOK, STATUS } = require('../helpers/constants');
|
|
4
|
+
|
|
5
|
+
function getReportPortalDefectsSummary(defects, bold_start = '**', bold_end = '**') {
|
|
6
|
+
const results = [];
|
|
7
|
+
if (defects.product_bug) {
|
|
8
|
+
results.push(`${bold_start}🔴 PB - ${defects.product_bug.total}${bold_end}`);
|
|
9
|
+
} else {
|
|
10
|
+
results.push(`🔴 PB - 0`);
|
|
11
|
+
}
|
|
12
|
+
if (defects.automation_bug) {
|
|
13
|
+
results.push(`${bold_start}🟡 AB - ${defects.automation_bug.total}${bold_end}`);
|
|
14
|
+
} else {
|
|
15
|
+
results.push(`🟡 AB - 0`);
|
|
16
|
+
}
|
|
17
|
+
if (defects.system_issue) {
|
|
18
|
+
results.push(`${bold_start}🔵 SI - ${defects.system_issue.total}${bold_end}`);
|
|
19
|
+
} else {
|
|
20
|
+
results.push(`🔵 SI - 0`);
|
|
21
|
+
}
|
|
22
|
+
if (defects.no_defect) {
|
|
23
|
+
results.push(`${bold_start}◯ ND - ${defects.no_defect.total}${bold_end}`);
|
|
24
|
+
} else {
|
|
25
|
+
results.push(`◯ ND - 0`);
|
|
26
|
+
}
|
|
27
|
+
if (defects.to_investigate) {
|
|
28
|
+
results.push(`${bold_start}🟠 TI - ${defects.to_investigate.total}${bold_end}`);
|
|
29
|
+
} else {
|
|
30
|
+
results.push(`🟠 TI - 0`);
|
|
31
|
+
}
|
|
32
|
+
return results;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
async function _getLaunchDetails(options) {
|
|
36
|
+
if (!options.launch_id && options.launch_name) {
|
|
37
|
+
return getLastLaunchByName(options);
|
|
38
|
+
}
|
|
39
|
+
return getLaunchDetails(options);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
async function initialize(extension) {
|
|
43
|
+
extension.inputs = Object.assign({}, default_inputs, extension.inputs);
|
|
44
|
+
extension.outputs.launch = await _getLaunchDetails(extension.inputs);
|
|
45
|
+
if (!extension.inputs.title_link && extension.inputs.title_link_to_launch) {
|
|
46
|
+
extension.inputs.title_link = `${extension.inputs.url}/ui/#${extension.inputs.project}/launches/all/${extension.outputs.launch.uuid}`;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
async function run({ extension, payload, target }) {
|
|
51
|
+
await initialize(extension);
|
|
52
|
+
const { statistics } = extension.outputs.launch;
|
|
53
|
+
if (statistics && statistics.defects) {
|
|
54
|
+
if (target.name === 'teams') {
|
|
55
|
+
extension.inputs = Object.assign({}, default_inputs_teams, extension.inputs);
|
|
56
|
+
const analyses = getReportPortalDefectsSummary(statistics.defects);
|
|
57
|
+
addTeamsExtension({ payload, extension, text: analyses.join(' | ') });
|
|
58
|
+
} else if (target.name === 'slack') {
|
|
59
|
+
extension.inputs = Object.assign({}, default_inputs_slack, extension.inputs);
|
|
60
|
+
const analyses = getReportPortalDefectsSummary(statistics.defects, '*', '*');
|
|
61
|
+
addSlackExtension({ payload, extension, text: analyses.join(' | ') });
|
|
62
|
+
} else if (target.name === 'chat') {
|
|
63
|
+
extension.inputs = Object.assign({}, default_inputs_chat, extension.inputs);
|
|
64
|
+
const analyses = getReportPortalDefectsSummary(statistics.defects, '<b>', '</b>');
|
|
65
|
+
addChatExtension({ payload, extension, text: analyses.join(' | ') });
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const default_options = {
|
|
71
|
+
hook: HOOK.END,
|
|
72
|
+
condition: STATUS.FAIL
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const default_inputs = {
|
|
76
|
+
title: 'Report Portal Analysis',
|
|
77
|
+
title_link_to_launch: true,
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const default_inputs_teams = {
|
|
81
|
+
separator: true
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const default_inputs_slack = {
|
|
85
|
+
separator: false
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const default_inputs_chat = {
|
|
89
|
+
separator: true
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
module.exports = {
|
|
93
|
+
run,
|
|
94
|
+
default_options
|
|
95
|
+
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
const { getSuiteHistory, getLastLaunchByName, getLaunchDetails } = require('../helpers/report-portal');
|
|
2
|
+
const { addChatExtension, addSlackExtension, addTeamsExtension } = require('../helpers/extension.helper');
|
|
3
|
+
const { HOOK, STATUS } = require('../helpers/constants');
|
|
4
|
+
|
|
5
|
+
async function getLaunchHistory(extension) {
|
|
6
|
+
const { inputs, outputs } = extension;
|
|
7
|
+
if (!inputs.launch_id && inputs.launch_name) {
|
|
8
|
+
const launch = await getLastLaunchByName(inputs);
|
|
9
|
+
outputs.launch = launch;
|
|
10
|
+
inputs.launch_id = launch.id;
|
|
11
|
+
}
|
|
12
|
+
if (typeof inputs.launch_id === 'string') {
|
|
13
|
+
const launch = await getLaunchDetails(inputs);
|
|
14
|
+
outputs.launch = launch;
|
|
15
|
+
inputs.launch_id = launch.id;
|
|
16
|
+
}
|
|
17
|
+
const response = await getSuiteHistory(inputs);
|
|
18
|
+
if (response.content.length > 0) {
|
|
19
|
+
outputs.history = response.content[0].resources;
|
|
20
|
+
return response.content[0].resources;
|
|
21
|
+
}
|
|
22
|
+
return [];
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function getSymbols({ target, extension, launches }) {
|
|
26
|
+
const symbols = [];
|
|
27
|
+
for (let i = 0; i < launches.length; i++) {
|
|
28
|
+
const launch = launches[i];
|
|
29
|
+
const launch_url = `${extension.inputs.url}/ui/#${extension.inputs.project}/launches/all/${launch[extension.inputs.link_history_via]}`;
|
|
30
|
+
let current_symbol = '⚠️';
|
|
31
|
+
if (launch.status === 'PASSED') {
|
|
32
|
+
current_symbol = '✅';
|
|
33
|
+
} else if (launch.status === 'FAILED') {
|
|
34
|
+
current_symbol = '❌';
|
|
35
|
+
}
|
|
36
|
+
if (target.name === 'teams') {
|
|
37
|
+
symbols.push(`[${current_symbol}](${launch_url})`);
|
|
38
|
+
} else if (target.name === 'slack') {
|
|
39
|
+
symbols.push(`<${launch_url}|${current_symbol}>`);
|
|
40
|
+
} else if (target.name === 'chat') {
|
|
41
|
+
symbols.push(`<a href="${launch_url}">${current_symbol}</a>`);
|
|
42
|
+
} else {
|
|
43
|
+
symbols.push(current_symbol);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return symbols;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function setTitle(extension, symbols) {
|
|
50
|
+
if (extension.inputs.title === 'Last Runs') {
|
|
51
|
+
extension.inputs.title = `Last ${symbols.length} Runs`
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
async function run({ extension, target, payload }) {
|
|
56
|
+
try {
|
|
57
|
+
extension.inputs = Object.assign({}, default_inputs, extension.inputs);
|
|
58
|
+
const launches = await getLaunchHistory(extension);
|
|
59
|
+
const symbols = getSymbols({ target, extension, launches });
|
|
60
|
+
if (symbols.length > 0) {
|
|
61
|
+
setTitle(extension, symbols);
|
|
62
|
+
if (target.name === 'teams') {
|
|
63
|
+
extension.inputs = Object.assign({}, default_inputs_teams, extension.inputs);
|
|
64
|
+
addTeamsExtension({ payload, extension, text: symbols.join(' ') });
|
|
65
|
+
} else if (target.name === 'slack') {
|
|
66
|
+
extension.inputs = Object.assign({}, default_inputs_slack, extension.inputs);
|
|
67
|
+
addSlackExtension({ payload, extension, text: symbols.join(' ') });
|
|
68
|
+
} else if (target.name === 'chat') {
|
|
69
|
+
extension.inputs = Object.assign({}, default_inputs_chat, extension.inputs);
|
|
70
|
+
addChatExtension({ payload, extension, text: symbols.join(' ') });
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
} catch (error) {
|
|
74
|
+
console.log('Failed to get report portal history');
|
|
75
|
+
console.log(error);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const default_inputs = {
|
|
80
|
+
history_depth: 5,
|
|
81
|
+
title: 'Last Runs',
|
|
82
|
+
link_history_via: 'uuid'
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const default_inputs_teams = {
|
|
86
|
+
separator: true
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const default_inputs_chat = {
|
|
90
|
+
separator: true
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const default_inputs_slack = {
|
|
94
|
+
separator: false
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const default_options = {
|
|
98
|
+
hook: HOOK.END,
|
|
99
|
+
condition: STATUS.FAIL
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
module.exports = {
|
|
103
|
+
run,
|
|
104
|
+
default_options
|
|
105
|
+
}
|