Skip to content

Commit 362d9ab

Browse files
committed
dashboard: Indicate if a test was rerun
Added code to get rerun information to both fetch scripts. Display the reruns as a superscript in the rowExpansionTemplate with the result/URL. Fixes: #8 Signed-off-by: Anna Finn <[email protected]>
1 parent e7e6cad commit 362d9ab

File tree

3 files changed

+433
-79
lines changed

3 files changed

+433
-79
lines changed

pages/index.js

+202-25
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,8 @@ export default function Home() {
7575
skips : job.skips,
7676
required : job.required,
7777
weather : getWeatherIndex(job),
78+
reruns : job.reruns,
79+
total_reruns : job.reruns.reduce((total, r) => total + r, 0),
7880
}))
7981
);
8082
setLoading(false);
@@ -94,6 +96,8 @@ export default function Home() {
9496
skips : check.skips,
9597
required : check.required,
9698
weather : getWeatherIndex(check),
99+
reruns : check.reruns,
100+
total_reruns : check.reruns.reduce((total, r) => total + r, 0),
97101
}))
98102
);
99103
setLoading(false);
@@ -137,21 +141,63 @@ export default function Home() {
137141
};
138142

139143
const maintainRefs = useRef([]);
144+
const rerunRefs = useRef([]);
140145

141146
const rowExpansionTemplate = (data) => {
142147
const job = (display === "nightly"
143148
? jobs
144149
: checks).find((job) => job.name === data.name);
145150

151+
if (!job) return (
152+
<div className="p-3 bg-gray-100">
153+
No data available for this job.
154+
</div>
155+
);
156+
146157
// Prepare run data
147-
const runs = [];
148-
for (let i = 0; i < job.runs; i++) {
149-
runs.push({
150-
run_num: job.run_nums[i],
151-
result: job.results[i],
152-
url: job.urls[i],
153-
});
154-
}
158+
const getRunStatusIcon = (runs) => {
159+
if (Array.isArray(runs)) {
160+
const allPass = runs.every(run => run === "Pass");
161+
const allFail = runs.every(run => run === "Fail");
162+
163+
if (allPass) {return "✅";}
164+
if (allFail) {return "❌";}
165+
} else if (runs === "Pass") {
166+
return "✅";
167+
} else if (runs === "Fail") {
168+
return "❌";
169+
}
170+
return "⚠️"; // return a warning if a mix of results
171+
};
172+
173+
const runEntries = job.run_nums.map((run_num, idx) => ({
174+
run_num,
175+
result: job.results[idx],
176+
reruns: job.reruns[idx],
177+
rerun_result: job.rerun_results[idx],
178+
url: job.urls[idx],
179+
attempt_urls: job.attempt_urls[idx],
180+
}));
181+
182+
// Find maintainers for the given job
183+
const maintainerData = MaintainerMapping.mappings
184+
.filter(({ regex }) => new RegExp(regex).test(job.name))
185+
.flatMap((match) =>
186+
match.owners.map((owner) => ({
187+
...owner,
188+
group: match.group,
189+
}))
190+
);
191+
192+
// Group maintainers by their group name
193+
const groupedMaintainers = maintainerData.reduce((acc, owner) => {
194+
if (!acc[owner.group]) {
195+
acc[owner.group] = [];
196+
}
197+
acc[owner.group].push(owner);
198+
return acc;
199+
}, {});
200+
155201

156202
// Find maintainers for the given job
157203
const maintainerData = MaintainerMapping.mappings
@@ -177,25 +223,154 @@ export default function Home() {
177223
<div key={`${job.name}-runs`} className="p-3 bg-gray-100">
178224
{/* Display last 10 runs */}
179225
<div className="flex flex-wrap gap-4">
180-
{runs.length > 0 ? (
181-
runs.map((run) => {
182-
const emoji =
183-
run.result === "Pass"
184-
? "✅"
185-
: run.result === "Fail"
186-
? "❌"
187-
: "⚠️";
188-
return (
189-
<span key={`${job.name}-runs-${run.run_num}`}>
190-
<a href={run.url} target="_blank" rel="noopener noreferrer">
191-
{emoji} {run.run_num}
226+
{runEntries.map(({
227+
run_num,
228+
result,
229+
url,
230+
reruns,
231+
rerun_result,
232+
attempt_urls
233+
}, idx) => {
234+
const allResults = rerun_result
235+
? [result, ...rerun_result]
236+
: [result];
237+
238+
const runStatuses = allResults.map((result, idx) =>
239+
`${allResults.length - idx}. ${result === 'Pass'
240+
? '✅ Success'
241+
: result === 'Fail'
242+
? '❌ Fail'
243+
: '⚠️ Warning'}`);
244+
245+
// IDs can't have a '/'...
246+
const sanitizedJobName = job.name.replace(/[^a-zA-Z0-9-_]/g, '');
247+
248+
const badgeReruns = `reruns-${sanitizedJobName}-${run_num}`;
249+
250+
rerunRefs.current[badgeReruns] = rerunRefs.current[badgeReruns]
251+
|| React.createRef();
252+
253+
return (
254+
<div key={run_num} className="flex">
255+
<div key={idx} className="flex items-center">
256+
{/* <a href={url} target="_blank" rel="noopener noreferrer"> */}
257+
<a href={attempt_urls[0]} target="_blank" rel="noopener noreferrer">
258+
{getRunStatusIcon(allResults)} {run_num}
192259
</a>
193-
&nbsp;&nbsp;&nbsp;&nbsp;
194-
</span>
195-
);
196-
})
260+
</div>
261+
{reruns > 0 &&(
262+
<span className="p-overlay-badge">
263+
<sup className="text-xs font-bold align-super ml-1"
264+
onMouseEnter={(e) =>
265+
rerunRefs.current[badgeReruns].current.toggle(e)}>
266+
{reruns+1}
267+
</sup>
268+
<OverlayPanel ref={rerunRefs.current[badgeReruns]} dismissable
269+
onMouseLeave={(e) =>
270+
rerunRefs.current[badgeReruns].current.toggle(e)}>
271+
<ul className="bg-white border rounded shadow-lg p-2">
272+
{runStatuses.map((status, index) => (
273+
<li key={index} className="p-2 hover:bg-gray-200">
274+
<a
275+
href={attempt_urls[index] || `${url}/attempts/${index}`}
276+
target="_blank"
277+
rel="noopener noreferrer">
278+
{status}
279+
</a>
280+
</li>
281+
))}
282+
</ul>
283+
</OverlayPanel>
284+
</span>
285+
)}
286+
</div>
287+
);
288+
})}
289+
</div>
290+
{/* Display Maintainers, if there's any */}
291+
<div className="mt-4 p-2 bg-gray-300 w-full">
292+
{Object.keys(groupedMaintainers).length > 0 ? (
293+
<div className="grid grid-cols-2 p-2 gap-6">
294+
{Object.entries(groupedMaintainers).map(
295+
([group, owners], groupIndex) => (
296+
<div key={groupIndex} className="flex flex-col max-w-xs">
297+
{/* List the group name */}
298+
<strong className="pl-2">{group}:</strong>
299+
<div>
300+
{/* List all maintainers for the group */}
301+
{owners.map((owner, ownerIndex) => {
302+
const badgeMaintain = `maintain-${owner.github}`;
303+
maintainRefs.current[badgeMaintain] =
304+
maintainRefs.current[badgeMaintain] || React.createRef();
305+
306+
return (
307+
// Create the OverlayPanel with contact information.
308+
<span key={ownerIndex}>
309+
<span
310+
onMouseEnter={(e) =>
311+
maintainRefs.current[badgeMaintain].current.toggle(e)
312+
}
313+
>
314+
<a
315+
href={`https://github.com/${owner.github}`}
316+
target="_blank"
317+
rel="noopener noreferrer"
318+
className="text-blue-500 underline pl-2 whitespace-nowrap"
319+
>
320+
{owner.fullname}
321+
</a>
322+
{ownerIndex < owners.length - 1 && ", "}
323+
</span>
324+
<OverlayPanel
325+
ref={maintainRefs.current[badgeMaintain]}
326+
dismissable
327+
onMouseLeave={(e) =>
328+
maintainRefs.current[badgeMaintain].current.toggle(e)
329+
}
330+
>
331+
<ul className="bg-white border rounded shadow-lg p-2">
332+
<li className="p-2 hover:bg-gray-200">
333+
<span className="font-bold mr-4">Email:</span>{" "}
334+
{owner.email}
335+
</li>
336+
<a
337+
href={`https://github.com/${owner.github}`}
338+
target="_blank"
339+
rel="noopener noreferrer"
340+
>
341+
<li className="p-2 hover:bg-gray-200 flex justify-between">
342+
<span className="font-bold mr-4">
343+
GitHub:
344+
</span>
345+
<span className="text-right">
346+
{owner.github}
347+
</span>
348+
</li>
349+
</a>
350+
<a
351+
href={`${owner.slackurl}`}
352+
target="_blank"
353+
rel="noopener noreferrer"
354+
>
355+
<li className="p-2 hover:bg-gray-200 flex justify-between">
356+
<span className="font-bold mr-4">Slack:</span>
357+
<span className="text-right">
358+
@{owner.slack}
359+
</span>
360+
</li>
361+
</a>
362+
</ul>
363+
</OverlayPanel>
364+
</span>
365+
);
366+
})}
367+
</div>
368+
</div>
369+
)
370+
)}
371+
</div>
197372
) : (
198-
<div>No Nightly Runs associated with this job</div>
373+
<div>No Maintainer Information Available</div>
199374
)}
200375
</div>
201376
{/* Display Maintainers, if there's any */}
@@ -315,6 +490,7 @@ export default function Home() {
315490
header = "Runs"
316491
className="whitespace-nowrap px-2"
317492
sortable />
493+
<Column field = "total_reruns" header = "Reruns" sortable/>
318494
<Column field = "fails" header = "Fails" sortable/>
319495
<Column field = "skips" header = "Skips" sortable/>
320496
<Column
@@ -351,6 +527,7 @@ export default function Home() {
351527
header = "Runs"
352528
className="whitespace-nowrap px-2"
353529
sortable />
530+
<Column field = "total_reruns" header = "Reruns" sortable/>
354531
<Column field = "fails" header = "Fails" sortable/>
355532
<Column field = "skips" header = "Skips" sortable/>
356533
<Column

0 commit comments

Comments
 (0)