in src/pr/FailureReport.js [120:217]
render() {
let items = [];
for (const failure of this.props.failures) {
let failedSteps = [];
if (failure.data.state !== undefined) {
// CircleCI not supported
continue;
} else {
failedSteps = failure.data.checkRuns.nodes.filter(
(x) => x.conclusion === "FAILURE"
);
}
const workflow = failure.data.workflowRun.workflow.name;
let details = null;
for (const step of failedSteps) {
if (step.name.startsWith("test (") && !step.incorrectReport) {
if (!step.artifactUrl) {
details = (
<div>
<Spin text={"Loading test report"} />
</div>
);
} else {
// test failure, try to download report
details = (
<TestReportRenderer
testReportZip={step.artifactUrl}
noSummary={true}
onLoaded={(failures, totals, testInfo) => {
if (failures.length === 0) {
step.incorrectReport = true;
this.setState(this.state);
}
}}
/>
);
}
} else {
// otherwise, open up the log viewer
details = (
<LogViewer
url={`repos/${this.props.user}/${this.props.repo}/actions/jobs/${step.databaseId}/logs`}
/>
);
// details = <p>todo: small log viewer</p>;
}
items.push(
<div
style={{ marginBottom: "10px" }}
key={`fr-${workflow}-${step.name}`}
>
<span style={{ fontWeight: "bold" }}>
{workflow} / {step.name}{" "}
{step.incorrectReport
? help(
"The XML test report for this job had no failures, but the job failed. This usually means something went wrong outside of a Python unittest."
)
: null}
</span>
{details}
</div>
);
}
}
const toggle = () => {
this.setState({ shown: !this.state.shown });
};
let icon = (
<BsFillCaretRightFill style={{ cursor: "pointer" }} onClick={toggle} />
);
if (this.state.shown) {
icon = (
<BsFillCaretDownFill style={{ cursor: "pointer" }} onClick={toggle} />
);
}
if (items.length === 0) {
return null;
}
return (
<Card
style={{
marginBottom: "15px",
boxShadow: "rgb(255 113 113) 0px 0px 9px -3px",
border: "1px solid #ff6060",
}}
>
<Card.Body>
<Card.Title>
GHA Failure Report{" "}
{help("Aggregated information from all failed jobs")} {icon}
</Card.Title>
{this.state.shown ? items : null}
</Card.Body>
</Card>
);
}