Skip to content

Commit 4a834b5

Browse files
authored
ci: improve JIRA Playwright reporter observability (RocketChat#40145)
1 parent 2356c88 commit 4a834b5

File tree

1 file changed

+44
-24
lines changed

1 file changed

+44
-24
lines changed

apps/meteor/reporters/jira.ts

Lines changed: 44 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import type { Reporter, TestCase, TestResult } from '@playwright/test/reporter';
22
import fetch from 'node-fetch';
33

4+
const LOG = '[JIRA reporter]';
5+
46
class JIRAReporter implements Reporter {
57
private url: string;
68

@@ -42,11 +44,20 @@ class JIRAReporter implements Reporter {
4244
this.pr = options.pr;
4345
}
4446

47+
private static async ensureJiraOk(response: Awaited<ReturnType<typeof fetch>>, context: string): Promise<void> {
48+
if (response.ok) {
49+
return;
50+
}
51+
const text = await response.text();
52+
const preview = text.length > 800 ? `${text.slice(0, 800)}...` : text;
53+
throw new Error(`${LOG} ${context}: HTTP ${response.status} ${response.statusText}. Body: ${preview}`);
54+
}
55+
4556
async onTestEnd(test: TestCase, result: TestResult) {
4657
try {
4758
await this._onTestEnd(test, result);
4859
} catch (error) {
49-
console.error('Error sending test result to JIRA', error);
60+
console.error(`${LOG} Error sending test result to JIRA`, error);
5061
}
5162
}
5263

@@ -77,13 +88,13 @@ class JIRAReporter implements Reporter {
7788
headSha: this.headSha,
7889
};
7990

80-
console.log(`Sending test result to JIRA: ${JSON.stringify(payload)}`);
91+
console.log(`${LOG} preparing notification for flaky/unexpected failure: ${JSON.stringify(payload)}`);
8192

8293
// first search and check if there is an existing issue
8394
// replace all ()[]- with nothing
8495
const search = await fetch(
8596
`${this.url}/rest/api/3/search/jql?${new URLSearchParams({
86-
jql: `project = FLAKY AND summary ~ '${payload.name.replace(/[\(\)\[\]-]/g, '')}'`,
97+
jql: `project = FLAKY AND summary ~ '${payload.name.replace(/[()[\]-]/g, '')}'`,
8798
})}`,
8899
{
89100
method: 'GET',
@@ -94,30 +105,23 @@ class JIRAReporter implements Reporter {
94105
},
95106
);
96107

97-
if (!search.ok) {
98-
throw new Error(
99-
`JIRA: Failed to search for existing issue: ${search.statusText}.` +
100-
`${this.url}/rest/api/3/search/jql?${new URLSearchParams({
101-
jql: `project = FLAKY AND summary ~ '${payload.name}'`,
102-
})}`,
103-
);
104-
}
108+
await JIRAReporter.ensureJiraOk(search, 'search for existing issue');
105109

106-
const { issues } = await search.json();
110+
const { issues } = JSON.parse(await search.text()) as {
111+
issues: { key: string; fields: { summary: string } }[];
112+
};
107113

108-
const existing = issues.find(
109-
(issue: {
110-
fields: {
111-
summary: string;
112-
};
113-
}) => issue.fields.summary === payload.name,
114-
);
114+
console.log(`${LOG} JQL search returned ${issues.length} candidate issue(s) (exact summary match is applied next).`);
115+
116+
const existing = issues.find((issue) => issue.fields.summary === payload.name);
115117

116118
if (existing) {
119+
console.log(`${LOG} exact summary match on ${existing.key}; no new issue will be created (comment / label only).`);
120+
117121
const { location } = test;
118122

119123
if (this.pr === 0) {
120-
await fetch(`${this.url}/rest/api/3/issue/${existing.key}`, {
124+
const labelRes = await fetch(`${this.url}/rest/api/3/issue/${existing.key}`, {
121125
method: 'PUT',
122126
body: JSON.stringify({
123127
update: {
@@ -133,9 +137,11 @@ class JIRAReporter implements Reporter {
133137
'Authorization': `Basic ${this.apiKey}`,
134138
},
135139
});
140+
await JIRAReporter.ensureJiraOk(labelRes, `add label flaky_Develop on ${existing.key}`);
141+
console.log(`${LOG} label update OK for ${existing.key}`);
136142
}
137143

138-
await fetch(`${this.url}/rest/api/3/issue/${existing.key}/comment`, {
144+
const commentRes = await fetch(`${this.url}/rest/api/3/issue/${existing.key}/comment`, {
139145
method: 'POST',
140146
body: JSON.stringify({
141147
body: `Test run ${payload.run} failed
@@ -153,9 +159,13 @@ ${this.run_url}
153159
'Authorization': `Basic ${this.apiKey}`,
154160
},
155161
});
162+
await JIRAReporter.ensureJiraOk(commentRes, `comment on ${existing.key}`);
163+
console.log(`${LOG} comment posted on ${existing.key} for run ${payload.run}.`);
156164
return;
157165
}
158166

167+
console.log(`${LOG} no issue with identical summary; creating new FLAKY issue.`);
168+
159169
const data: {
160170
fields: {
161171
summary: string;
@@ -190,11 +200,19 @@ ${this.run_url}
190200
},
191201
});
192202

193-
const issue = (await responseIssue.json()).key;
203+
await JIRAReporter.ensureJiraOk(responseIssue, 'create issue');
204+
205+
const created = JSON.parse(await responseIssue.text()) as { key?: string };
206+
const issue = created.key;
207+
if (!issue) {
208+
throw new Error(`${LOG} create issue response had no key: ${JSON.stringify(created)}`);
209+
}
210+
211+
console.log(`${LOG} created issue ${issue}.`);
194212

195213
const { location } = test;
196214

197-
await fetch(`${this.url}/rest/api/3/issue/${issue}/comment`, {
215+
const commentRes = await fetch(`${this.url}/rest/api/3/issue/${issue}/comment`, {
198216
method: 'POST',
199217
body: JSON.stringify({
200218
body: `Test run ${payload.run} failed
@@ -203,7 +221,7 @@ PR: ${this.pr}
203221
https://github.com/RocketChat/Rocket.Chat/blob/${payload.headSha}/${location.file.replace(
204222
'/home/runner/work/Rocket.Chat/Rocket.Chat',
205223
'',
206-
)}#L${location.line}:${location.column},
224+
)}#L${location.line}:${location.column}
207225
${this.run_url}
208226
`,
209227
}),
@@ -212,6 +230,8 @@ ${this.run_url}
212230
'Authorization': `Basic ${this.apiKey}`,
213231
},
214232
});
233+
await JIRAReporter.ensureJiraOk(commentRes, `comment on ${issue}`);
234+
console.log(`${LOG} comment posted on ${issue}; done for run ${payload.run}.`);
215235
}
216236
}
217237

0 commit comments

Comments
 (0)