Skip to content

Commit 5397098

Browse files
authored
Merge pull request #60 from test-results-reporter/58-extension-percy
58 extension percy
2 parents 1ddf5ba + b4ae01d commit 5397098

21 files changed

+615
-33
lines changed

assets/cucumber.png

-192 KB
Loading

assets/teams.png

-79.3 KB
Loading

package-lock.json

+38-13
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+3-2
Original file line numberDiff line numberDiff line change
@@ -42,16 +42,17 @@
4242
},
4343
"homepage": "https://test-results-reporter.github.io",
4444
"dependencies": {
45+
"async-retry": "^1.3.3",
4546
"dotenv": "^14.3.0",
4647
"phin-retry": "^1.0.3",
4748
"pretty-ms": "^7.0.0",
4849
"rosters": "0.0.1",
4950
"sade": "^1.7.4",
50-
"test-results-parser": "^0.0.11"
51+
"test-results-parser": "^0.1.0"
5152
},
5253
"devDependencies": {
5354
"mocha": "^10.0.0",
5455
"nyc": "^15.1.0",
55-
"pactum": "^3.1.8"
56+
"pactum": "^3.1.10"
5657
}
5758
}

src/extensions/index.js

+3
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ const mentions = require('./mentions');
33
const rp_analysis = require('./report-portal-analysis');
44
const rp_history = require('./report-portal-history');
55
const qc_test_summary = require('./quick-chart-test-summary');
6+
const percy_analysis = require('./percy-analysis');
67
const { EXTENSION } = require('../helpers/constants');
78
const { checkCondition } = require('../helpers/helper');
89

@@ -34,6 +35,8 @@ function getExtensionRunner(extension) {
3435
return rp_history;
3536
case EXTENSION.QUICK_CHART_TEST_SUMMARY:
3637
return qc_test_summary;
38+
case EXTENSION.PERCY_ANALYSIS:
39+
return percy_analysis;
3740
default:
3841
return require(extension.name);
3942
}

src/extensions/mentions.js

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
const { getOnCallPerson } = require('rosters');
22
const { addExtension } = require('../helpers/teams');
33
const { addTextBlock } = require('../helpers/slack');
4+
const { HOOK, STATUS } = require('../helpers/constants');
45

56
function run({ target, extension, payload, root_payload }) {
67
if (target.name === 'teams') {
@@ -76,8 +77,8 @@ function setPayloadWithMSTeamsEntities(payload) {
7677
}
7778

7879
const default_options = {
79-
hook: 'end',
80-
condition: 'fail'
80+
hook: HOOK.END,
81+
condition: STATUS.FAIL
8182
}
8283

8384
const default_inputs_teams = {

src/extensions/percy-analysis.js

+162
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
const retry = require('async-retry');
2+
const { getProjectByName, getLastBuild, getBuild } = require('../helpers/percy');
3+
const { HOOK, STATUS, URLS } = require('../helpers/constants');
4+
const { addExtension } = require('../helpers/teams');
5+
const { addTextBlock } = require('../helpers/slack');
6+
const { addTextSection } = require('../helpers/chat');
7+
8+
async function run({ extension, payload, target }) {
9+
extension.inputs = Object.assign({}, default_inputs, extension.inputs);
10+
await initialize(extension.inputs);
11+
if (target.name === 'teams') {
12+
extension.inputs = Object.assign({}, default_inputs_teams, extension.inputs);
13+
attachForTeams({ payload, extension });
14+
} else if (target.name === 'slack') {
15+
extension.inputs = Object.assign({}, default_inputs_slack, extension.inputs);
16+
attachForSlack({ payload, extension });
17+
} else if (target.name === 'chat') {
18+
extension.inputs = Object.assign({}, default_inputs_chat, extension.inputs);
19+
attachForChat({ payload, extension });
20+
}
21+
}
22+
23+
/**
24+
* @param {import('../index').PercyAnalysisInputs} inputs
25+
*/
26+
async function initialize(inputs) {
27+
if (!inputs.build_id) {
28+
await setBuildByLastRun(inputs);
29+
} else {
30+
await setBuild(inputs);
31+
}
32+
if (!inputs.title_link && inputs.title_link_to_build) {
33+
inputs.title_link = `https://percy.io/${inputs.organization_uid}/${inputs.project_name}/builds/${inputs.build_id}`;
34+
}
35+
}
36+
37+
/**
38+
* @param {import('../index').PercyAnalysisInputs} inputs
39+
*/
40+
async function setBuildByLastRun(inputs) {
41+
if (!inputs.project_id) {
42+
await setProjectId(inputs)
43+
}
44+
const response = await getLastFinishedBuild(inputs);
45+
inputs.build_id = response.data[0].id;
46+
inputs._build = response.data[0];
47+
if (!inputs._project) {
48+
inputs._project = response.included.find(_item => _item.type === 'projects');
49+
}
50+
if (!inputs.project_name) {
51+
inputs.project_name = inputs._project.attributes.name;
52+
}
53+
if (!inputs.organization_uid) {
54+
inputs.organization_uid = getOrganizationUID(inputs._project.attributes['full-slug']);
55+
}
56+
}
57+
58+
/**
59+
* @param {import('../index').PercyAnalysisInputs} inputs
60+
*/
61+
function getLastFinishedBuild(inputs) {
62+
return retry(async () => {
63+
const response = await getLastBuild(inputs);
64+
if (response.data[0].attributes.state !== "finished") {
65+
throw `build is still '${response.data[0].attributes.state}'`;
66+
}
67+
return response;
68+
}, { retries: 10, minTimeout: 5000 });
69+
}
70+
71+
/**
72+
* @param {import('../index').PercyAnalysisInputs} inputs
73+
*/
74+
async function setProjectId(inputs) {
75+
if (!inputs.project_name) {
76+
throw "mandatory inputs 'build_id' or 'project_id' or 'project_name' are not provided"
77+
}
78+
const response = await getProjectByName(inputs);
79+
inputs.project_id = response.data.id;
80+
inputs._project = response.data;
81+
}
82+
83+
/**
84+
* @param {import('../index').PercyAnalysisInputs} inputs
85+
*/
86+
async function setBuild(inputs) {
87+
const response = await getBuild(inputs);
88+
inputs._build = response.data;
89+
inputs._project = response.included.find(_item => _item.type === 'projects');
90+
if (!inputs.project_id) {
91+
inputs.project_id = inputs._project.id;
92+
}
93+
if (!inputs.project_name) {
94+
inputs.project_name = inputs._project.attributes.name;
95+
}
96+
if (!inputs.organization_uid) {
97+
inputs.organization_uid = getOrganizationUID(inputs._project.attributes['full-slug']);
98+
}
99+
}
100+
101+
function getOrganizationUID(slug) {
102+
return slug.split('/')[0];
103+
}
104+
105+
function attachForTeams({ payload, extension }) {
106+
const text = getResults(extension.inputs._build).join(' | ');
107+
addExtension({ payload, extension, text });
108+
}
109+
110+
function attachForSlack({ payload, extension }) {
111+
const text = getResults(extension.inputs._build).join(' | ');
112+
addTextBlock({ payload, extension, text });
113+
}
114+
115+
function attachForChat({ payload, extension }) {
116+
const text = getResults(extension.inputs._build).join(' | ');
117+
addTextSection({ payload, extension, text });
118+
}
119+
120+
function getResults(build) {
121+
const results = [];
122+
const total = build.attributes['total-snapshots'];
123+
const un_reviewed = build.attributes['total-snapshots-unreviewed'];
124+
const approved = total - un_reviewed;
125+
results.push(`✅ AP - ${approved}`);
126+
if (un_reviewed > 0) {
127+
results.push(`🔎 UR - ${un_reviewed}`)
128+
}
129+
return results;
130+
}
131+
132+
const default_options = {
133+
hook: HOOK.END,
134+
condition: STATUS.PASS_OR_FAIL
135+
}
136+
137+
const default_inputs = {
138+
title: 'Percy Analysis',
139+
url: URLS.PERCY,
140+
title_link_to_build: true,
141+
build_id: '',
142+
project_id: '',
143+
project_name: '',
144+
organization_uid: ''
145+
}
146+
147+
const default_inputs_teams = {
148+
separator: true
149+
}
150+
151+
const default_inputs_slack = {
152+
separator: false
153+
}
154+
155+
const default_inputs_chat = {
156+
separator: true
157+
}
158+
159+
module.exports = {
160+
run,
161+
default_options
162+
}

src/extensions/quick-chart-test-summary.js

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
const { getPercentage } = require('../helpers/helper');
2-
const constants = require('../lib/constants');
2+
const { HOOK, STATUS, URLS } = require('../helpers/constants');
33

44
function getUrl(extension, result) {
55
const percentage = getPercentage(result.passed, result.total);
@@ -63,7 +63,7 @@ function attachForSlack({ extension, result, payload }) {
6363
function run(params) {
6464
const { extension, target } = params;
6565
params.extension.inputs = extension.inputs || {};
66-
params.extension.inputs["url"] = (extension.inputs.url && extension.inputs.url.trim()) || constants.QUICK_CHART_URL;
66+
params.extension.inputs["url"] = (extension.inputs.url && extension.inputs.url.trim()) || URLS.QUICK_CHART;
6767
if (target.name === 'teams') {
6868
attachForTeams(params);
6969
} else if (target.name === 'slack') {
@@ -72,8 +72,8 @@ function run(params) {
7272
}
7373

7474
const default_options = {
75-
hook: 'post-main',
76-
condition: 'passOrFail'
75+
hook: HOOK.POST_MAIN,
76+
condition: STATUS.PASS_OR_FAIL
7777
}
7878

7979
module.exports = {

src/extensions/report-portal-analysis.js

+3-2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ const { getLaunchDetails, getLastLaunchByName } = require('../helpers/report-por
22
const { addExtension } = require('../helpers/teams');
33
const { addTextBlock } = require('../helpers/slack');
44
const { addTextSection } = require('../helpers/chat');
5+
const { HOOK, STATUS } = require('../helpers/constants');
56

67
function getReportPortalDefectsSummary(defects, bold_start = '**', bold_end= '**') {
78
const results = [];
@@ -77,8 +78,8 @@ async function run({ extension, payload, target }) {
7778
}
7879

7980
const default_options = {
80-
hook: 'end',
81-
condition: 'fail'
81+
hook: HOOK.END,
82+
condition: STATUS.FAIL
8283
}
8384

8485
const default_inputs_teams = {

0 commit comments

Comments
 (0)