testbeats 2.0.5 → 2.0.6

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "testbeats",
3
- "version": "2.0.5",
3
+ "version": "2.0.6",
4
4
  "description": "Publish test results to Microsoft Teams, Google Chat, Slack and InfluxDB",
5
5
  "main": "src/index.js",
6
6
  "types": "./src/index.d.ts",
@@ -4,6 +4,7 @@ export type IBeatExecutionMetric = {
4
4
  updated_at: string
5
5
  newly_failed: number
6
6
  always_failing: number
7
+ recurring_failures: number
7
8
  recovered: number
8
9
  added: number
9
10
  removed: number
@@ -50,7 +50,7 @@ class BaseExtension {
50
50
 
51
51
  attach() {
52
52
  if (!this.text) {
53
- logger.warn(`⚠️ Extension '${this.extension.name}' has no text. Skipping.`);
53
+ logger.debug(`⚠️ Extension '${this.extension.name}' has no text. Skipping.`);
54
54
  return;
55
55
  }
56
56
 
@@ -69,6 +69,23 @@ class BaseExtension {
69
69
  }
70
70
  }
71
71
 
72
+ /**
73
+ * @param {string[]} texts
74
+ */
75
+ mergeTexts(texts) {
76
+ const _texts = texts.filter(text => !!text);
77
+ switch (this.target.name) {
78
+ case 'teams':
79
+ return _texts.join('\n\n');
80
+ case 'slack':
81
+ return _texts.join('\n');
82
+ case 'chat':
83
+ return _texts.join('<br>');
84
+ default:
85
+ break;
86
+ }
87
+ }
88
+
72
89
  }
73
90
 
74
91
  module.exports = { BaseExtension }
@@ -0,0 +1,81 @@
1
+ const { BaseExtension } = require("./base.extension");
2
+ const { getCIInformation } = require('../helpers/ci');
3
+ const { getMetaDataText } = require("../helpers/metadata.helper");
4
+ const { STATUS, HOOK } = require("../helpers/constants");
5
+
6
+ class CIInfoExtension extends BaseExtension {
7
+
8
+ constructor(target, extension, result, payload, root_payload) {
9
+ super(target, extension, result, payload, root_payload);
10
+ this.#setDefaultOptions();
11
+ this.#setDefaultInputs();
12
+ this.updateExtensionInputs();
13
+
14
+ this.ci = null;
15
+ this.repository_elements = [];
16
+ this.build_elements = [];
17
+ }
18
+
19
+ #setDefaultOptions() {
20
+ this.default_options.hook = HOOK.AFTER_SUMMARY,
21
+ this.default_options.condition = STATUS.PASS_OR_FAIL;
22
+ }
23
+
24
+ #setDefaultInputs() {
25
+ this.default_inputs.title = '';
26
+ this.default_inputs.title_link = '';
27
+ this.default_inputs.show_repository = true;
28
+ this.default_inputs.show_repository_branch = true;
29
+ this.default_inputs.show_build = true;
30
+ }
31
+
32
+ async run() {
33
+ this.ci = getCIInformation();
34
+
35
+ this.setRepositoryElements();
36
+ this.setBuildElements();
37
+
38
+ const repository_text = await getMetaDataText({ elements: this.repository_elements, target: this.target, extension: this.extension, result: this.result, default_condition: this.default_options.condition });
39
+ const build_text = await getMetaDataText({ elements: this.build_elements, target: this.target, extension: this.extension, result: this.result, default_condition: this.default_options.condition });
40
+ this.text = this.mergeTexts([repository_text, build_text]);
41
+ this.attach();
42
+ }
43
+
44
+ setRepositoryElements() {
45
+ if (!this.ci) {
46
+ return;
47
+ }
48
+
49
+ if (this.extension.inputs.show_repository && this.ci.repository_url && this.ci.repository_name) {
50
+ this.repository_elements.push({ label: 'Repository', key: this.ci.repository_name, value: this.ci.repository_url, type: 'hyperlink' });
51
+ }
52
+ if (this.extension.inputs.show_repository_branch && this.ci.repository_ref) {
53
+ if (this.ci.repository_ref.includes('refs/pull')) {
54
+ const pr_url = this.ci.repository_url + this.ci.repository_ref.replace('refs/pull/', '/pull/');
55
+ const pr_name = this.ci.repository_ref.replace('refs/pull/', '').replace('/merge', '');
56
+ this.repository_elements.push({ label: 'Pull Request', key: pr_name, value: pr_url, type: 'hyperlink' });
57
+ } else {
58
+ const branch_url = this.ci.repository_url + this.ci.repository_ref.replace('refs/heads/', '/tree/');
59
+ const branch_name = this.ci.repository_ref.replace('refs/heads/', '');
60
+ this.repository_elements.push({ label: 'Branch', key: branch_name, value: branch_url, type: 'hyperlink' });
61
+ }
62
+ }
63
+ }
64
+
65
+ setBuildElements() {
66
+ if (!this.ci) {
67
+ return;
68
+ }
69
+
70
+ if (this.extension.inputs.show_build && this.ci.build_url) {
71
+ const name = (this.ci.build_name || 'Build') + (this.ci.build_number ? ` #${this.ci.build_number}` : '');
72
+ this.build_elements.push({ label: 'Build', key: name, value: this.ci.build_url, type: 'hyperlink' });
73
+ }
74
+ if (this.extension.inputs.data) {
75
+ this.build_elements = this.build_elements.concat(this.extension.inputs.data);
76
+ }
77
+ }
78
+
79
+ }
80
+
81
+ module.exports = { CIInfoExtension };
@@ -0,0 +1,12 @@
1
+ export type ICIInfo = {
2
+ ci: string
3
+ git: string
4
+ repository_url: string
5
+ repository_name: string
6
+ repository_ref: string
7
+ repository_commit_sha: string
8
+ build_url: string
9
+ build_number: string
10
+ build_name: string
11
+ user: string
12
+ }
@@ -6,9 +6,9 @@ const qc_test_summary = require('./quick-chart-test-summary');
6
6
  const percy_analysis = require('./percy-analysis');
7
7
  const custom = require('./custom');
8
8
  const metadata = require('./metadata');
9
- const ci_info = require('./ci-info');
10
9
  const { AIFailureSummaryExtension } = require('./ai-failure-summary.extension');
11
10
  const { SmartAnalysisExtension } = require('./smart-analysis.extension');
11
+ const { CIInfoExtension } = require('./ci-info.extension');
12
12
  const { EXTENSION } = require('../helpers/constants');
13
13
  const { checkCondition } = require('../helpers/helper');
14
14
  const logger = require('../utils/logger');
@@ -55,7 +55,7 @@ function getExtensionRunner(extension, options) {
55
55
  case EXTENSION.METADATA:
56
56
  return metadata;
57
57
  case EXTENSION.CI_INFO:
58
- return ci_info;
58
+ return new CIInfoExtension(options.target, extension, options.result, options.payload, options.root_payload);
59
59
  case EXTENSION.AI_FAILURE_SUMMARY:
60
60
  return new AIFailureSummaryExtension(options.target, extension, options.result, options.payload, options.root_payload);
61
61
  case EXTENSION.SMART_ANALYSIS:
@@ -38,14 +38,17 @@ class SmartAnalysisExtension extends BaseExtension {
38
38
  const execution_metrics = data.execution_metrics[0];
39
39
 
40
40
  const smart_analysis = [];
41
- if (execution_metrics.always_failing) {
42
- smart_analysis.push(`🚫 AF: ${execution_metrics.always_failing}`);
43
- }
44
41
  if (execution_metrics.newly_failed) {
45
42
  smart_analysis.push(`⭕ NF: ${execution_metrics.newly_failed}`);
46
43
  }
44
+ if (execution_metrics.always_failing) {
45
+ smart_analysis.push(`🔴 AF: ${execution_metrics.always_failing}`);
46
+ }
47
+ if (execution_metrics.recurring_failures) {
48
+ smart_analysis.push(`🟠 RF: ${execution_metrics.recurring_failures}`);
49
+ }
47
50
  if (execution_metrics.flaky) {
48
- smart_analysis.push(`❄️ FL: ${execution_metrics.flaky}`);
51
+ smart_analysis.push(`🟡 FL: ${execution_metrics.flaky}`);
49
52
  }
50
53
  if (execution_metrics.recovered) {
51
54
  smart_analysis.push(`🟢 RC: ${execution_metrics.recovered}`);
package/src/helpers/ci.js CHANGED
@@ -1,5 +1,8 @@
1
1
  const ENV = process.env;
2
2
 
3
+ /**
4
+ * @returns {import('../extensions/extensions').ICIInfo}
5
+ */
3
6
  function getCIInformation() {
4
7
  if (ENV.GITHUB_ACTIONS) {
5
8
  return getGitHubActionsInformation();
@@ -1,4 +1,17 @@
1
- const { checkCondition } = require('./helper')
1
+ const { checkCondition } = require('./helper');
2
+
3
+ function getMetaDataText(params) {
4
+ switch (params.target.name) {
5
+ case 'teams':
6
+ return getTeamsMetaDataText(params);
7
+ case 'slack':
8
+ return getSlackMetaDataText(params);
9
+ case 'chat':
10
+ return getChatMetaDataText(params);
11
+ default:
12
+ return '';
13
+ }
14
+ }
2
15
 
3
16
  /**
4
17
  * Asynchronously generates metadata text for slack.
@@ -109,6 +122,7 @@ function get_url({ url, target, extension, result}) {
109
122
  }
110
123
 
111
124
  module.exports = {
125
+ getMetaDataText,
112
126
  getSlackMetaDataText,
113
127
  getTeamsMetaDataText,
114
128
  getChatMetaDataText
@@ -1,134 +0,0 @@
1
- const { STATUS, HOOK } = require("../helpers/constants");
2
- const { getCIInformation } = require('../helpers/ci');
3
- const { addTeamsExtension, addSlackExtension, addChatExtension } = require('../helpers/extension.helper');
4
- const { getTeamsMetaDataText, getSlackMetaDataText, getChatMetaDataText } = require('../helpers/metadata.helper');
5
-
6
- /**
7
- *
8
- * @param {object} param0 - the payload object
9
- * @param {import('..').Extension} param0.extension - The result object
10
- *
11
- */
12
- async function run({ target, extension, payload, result }) {
13
- extension.inputs = Object.assign({}, default_inputs, extension.inputs);
14
- if (target.name === 'teams') {
15
- extension.inputs = Object.assign({}, default_inputs_teams, extension.inputs);
16
- const text = await get_text({ target, extension, result });
17
- if (text) {
18
- addTeamsExtension({ payload, extension, text });
19
- }
20
- } else if (target.name === 'slack') {
21
- extension.inputs = Object.assign({}, default_inputs_slack, extension.inputs);
22
- const text = await get_text({ target, extension, result });
23
- if (text) {
24
- addSlackExtension({ payload, extension, text });
25
- }
26
- } else if (target.name === 'chat') {
27
- extension.inputs = Object.assign({}, default_inputs_chat, extension.inputs);
28
- const text = await get_text({ target, extension, result });
29
- if (text) {
30
- addChatExtension({ payload, extension, text });
31
- }
32
- }
33
- }
34
-
35
- /**
36
- *
37
- * @param {import('..').CIInfoInputs} inputs
38
- */
39
- function get_repository_elements(inputs) {
40
- const elements = [];
41
- const ci = getCIInformation();
42
- if (inputs.show_repository && ci && ci.repository_url && ci.repository_name) {
43
- elements.push({ label: 'Repository', key: ci.repository_name, value: ci.repository_url, type: 'hyperlink' });
44
- }
45
- if (inputs.show_repository_branch && ci && ci.repository_ref) {
46
- if (ci.repository_ref.includes('refs/pull')) {
47
- const pr_url = ci.repository_url + ci.repository_ref.replace('refs/pull/', '/pull/');
48
- const pr_name = ci.repository_ref.replace('refs/pull/', '').replace('/merge', '');
49
- elements.push({ label: 'Pull Request', key: pr_name, value: pr_url, type: 'hyperlink' });
50
- } else {
51
- const branch_url = ci.repository_url + ci.repository_ref.replace('refs/heads/', '/tree/');
52
- const branch_name = ci.repository_ref.replace('refs/heads/', '');
53
- elements.push({ label: 'Branch', key: branch_name, value: branch_url, type: 'hyperlink' });
54
- }
55
- }
56
- return elements;
57
- }
58
-
59
- /**
60
- *
61
- * @param {import('..').CIInfoInputs} inputs
62
- */
63
- function get_build_elements(inputs) {
64
- let elements = [];
65
- const ci = getCIInformation();
66
- if (inputs.show_build && ci && ci.build_url) {
67
- const name = (ci.build_name || 'Build') + (ci.build_number ? ` #${ci.build_number}` : '');
68
- elements.push({ label: 'Build', key: name, value: ci.build_url, type: 'hyperlink' });
69
- }
70
- if (inputs.data) {
71
- elements = elements.concat(inputs.data);
72
- }
73
- return elements;
74
- }
75
-
76
- async function get_text({ target, extension, result }) {
77
- const repository_elements = get_repository_elements(extension.inputs);
78
- const build_elements = get_build_elements(extension.inputs);
79
- if (target.name === 'teams') {
80
- const repository_text = await getTeamsMetaDataText({ elements: repository_elements, target, extension, result, default_condition: default_options.condition });
81
- const build_text = await getTeamsMetaDataText({ elements: build_elements, target, extension, result, default_condition: default_options.condition });
82
- if (build_text) {
83
- return `${repository_text ? `${repository_text}\n\n` : '' }${build_text}`;
84
- } else {
85
- return repository_text;
86
- }
87
- } else if (target.name === 'slack') {
88
- const repository_text = await getSlackMetaDataText({ elements: repository_elements, target, extension, result, default_condition: default_options.condition });
89
- const build_text = await getSlackMetaDataText({ elements: build_elements, target, extension, result, default_condition: default_options.condition });
90
- if (build_text) {
91
- return `${repository_text ? `${repository_text}\n` : '' }${build_text}`;
92
- } else {
93
- return repository_text;
94
- }
95
- } else if (target.name === 'chat') {
96
- const repository_text = await getChatMetaDataText({ elements: repository_elements, target, extension, result, default_condition: default_options.condition });
97
- const build_text = await getChatMetaDataText({ elements: build_elements, target, extension, result, default_condition: default_options.condition });
98
- if (build_text) {
99
- return `${repository_text ? `${repository_text}<br>` : '' }${build_text}`;
100
- } else {
101
- return repository_text;
102
- }
103
- }
104
- }
105
-
106
- const default_options = {
107
- hook: HOOK.AFTER_SUMMARY,
108
- condition: STATUS.PASS_OR_FAIL,
109
- }
110
-
111
- const default_inputs = {
112
- title: '',
113
- show_repository: true,
114
- show_repository_branch: true,
115
- show_build: true,
116
- }
117
-
118
- const default_inputs_teams = {
119
-
120
- separator: true
121
- }
122
-
123
- const default_inputs_slack = {
124
- separator: false
125
- }
126
-
127
- const default_inputs_chat = {
128
- separator: true
129
- }
130
-
131
- module.exports = {
132
- run,
133
- default_options
134
- }