Skip to content

Commit 03fbe1c

Browse files
committed
Name the failing test, its error and its job link instead of a dash
1 parent 865a9b7 commit 03fbe1c

2 files changed

Lines changed: 72 additions & 22 deletions

File tree

.github/scripts/ci_triage.py

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,27 @@ def job_unit(name):
272272
return target, (m.group(1) or m.group(2)) if m else "unknown"
273273

274274

275+
HOST_JOB_RE = re.compile(r"^host / (?:Run|Build) / (.+) \((.+)\)$")
276+
277+
278+
def job_urls(run_id):
279+
"""(unit, ref) -> the URL of the job that ran it.
280+
281+
Linking the run only makes a reader hunt through 250 jobs for the red one.
282+
"""
283+
out = {}
284+
for j in all_jobs(run_id):
285+
name, url = j.get("name", ""), j.get("html_url")
286+
m = HOST_JOB_RE.match(name)
287+
if m:
288+
out[(m.group(1), m.group(2))] = url
289+
continue
290+
t, ref = job_unit(name)
291+
if t:
292+
out[(t, ref)] = url
293+
return out
294+
295+
275296
def classify_jobs(run_id, attempt, retry_note):
276297
def by_unit(jobs):
277298
out = defaultdict(list)
@@ -814,6 +835,7 @@ def report(attempt, retry_note):
814835
issues = {store.parse_fp(i.get("body", "")): i for i in open_issues()}
815836
issues.pop(None, None)
816837

838+
urls = job_urls(RUN_ID)
817839
total = len(all_jobs(RUN_ID))
818840
prev = previous_job_count()
819841
close_allowed = not (prev and total < 0.5 * prev)
@@ -870,10 +892,26 @@ def report(attempt, retry_note):
870892
"failing": fail_refs.get(eid, []) if observation != store.PASS else [],
871893
"log": logs.get(eid, "")[-LOG_TAIL_CHARS:],
872894
}
895+
# The real failing target + its error + a link to the job that ran it.
896+
# This used to be a hardcoded "-" profile column and a bare ":x: fail",
897+
# which told a reader nothing they could act on.
873898
rows = [
874-
{"profile": "-", "ref": ref, "status": ":x: fail"}
875-
for ref in fail_refs.get(eid, [])
876-
] or [{"profile": "-", "ref": "all", "status": ":white_check_mark: pass"}]
899+
{
900+
"test": r.get("target") or r.get("stage", "build"),
901+
"ref": r.get("ref", "?"),
902+
"detail": (r.get("detail") or "").strip(),
903+
"url": urls.get((eid, r.get("ref"))),
904+
}
905+
for r in results
906+
if r["id"] == eid and r["status"] == "fail"
907+
]
908+
# cross targets emit no results rows, so fall back to the job itself
909+
if not rows and observation != store.PASS:
910+
rows = [
911+
{"test": eid, "ref": ref, "detail": "job failed",
912+
"url": urls.get((eid, ref))}
913+
for ref in fail_refs.get(eid, ["unknown"])
914+
]
877915
# collected, not read back from `issues`: a dir filed for the first time
878916
# tonight is not in that map, and its card entry would have no link
879917
filed[eid] = apply(eid, observation, issue, verdicts.get(eid), state, rows,

.github/scripts/issue_store.py

Lines changed: 31 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -111,34 +111,46 @@ def render_body(eid, state, ai, failing_rows, run_url, now):
111111
f"<!-- ci-fp: v1|{eid} -->",
112112
f"<!-- ci-state: {json.dumps(marker, sort_keys=True)} -->",
113113
"",
114-
f"**`{eid}`** is failing in the nightly. "
115-
f"{state.get('streak', 1)} consecutive night(s), since {state.get('first', now)}.",
114+
f"**`{eid}`** is failing in the nightly "
115+
f"{state.get('streak', 1)} night(s) running, since {state.get('first', now)}.",
116116
"",
117-
"| profile | wolfSSL ref | status |",
117+
]
118+
119+
if ai:
120+
lines += [
121+
f"### {ai.get('severity', '?')} · {ai.get('category', '?')} · "
122+
f"affects {ai.get('blast', '?')}",
123+
"",
124+
f"- **Symptom** — {scrub(ai.get('symptom', ''))}",
125+
f"- **Likely cause** — {scrub(ai.get('cause', ''))}",
126+
f"- **Next** — {scrub(ai.get('next', ''))}",
127+
"",
128+
]
129+
130+
# "wolfSSL" not "wolfSSL ref": the column answers "which wolfSSL broke it",
131+
# and master-vs-stable is the single most useful fact here -- a stable-only
132+
# break is a released bug, a master-only one is upstream drift.
133+
lines += [
134+
"### What failed",
135+
"",
136+
"| test | wolfSSL | error |",
118137
"|---|---|---|",
119138
]
120139
for row in failing_rows:
121-
lines.append(f"| {row['profile']} | {row['ref']} | {row['status']} |")
140+
test = f"`{row['test']}`"
141+
if row.get("url"):
142+
test = f"[{test}]({row['url']})"
143+
detail = (row.get("detail") or "").replace("|", "\\|")[:120] or "—"
144+
lines.append(f"| {test} | `{row['ref']}` | {detail} |")
122145
lines.append("")
123146

124-
if ai:
147+
if ai and ai.get("upstream"):
125148
lines += [
126-
f"**Severity:** {ai.get('severity', '?')} · "
127-
f"**Category:** {ai.get('category', '?')} · "
128-
f"**Blast radius:** {ai.get('blast', '?')}",
129-
"",
130-
f"**Symptom** — {scrub(ai.get('symptom', ''))}",
131-
f"**Likely cause** — {scrub(ai.get('cause', ''))}",
132-
f"**Next** — {scrub(ai.get('next', ''))}",
149+
"> Fails only against wolfSSL `master` and passes on stable — this "
150+
"is more likely a wolfSSL regression than an example bug. Consider "
151+
"filing against wolfSSL/wolfssl.",
133152
"",
134153
]
135-
if ai.get("upstream"):
136-
lines += [
137-
"> Fails only against wolfSSL `master` and passes on stable — this "
138-
"is more likely a wolfSSL regression than an example bug. Consider "
139-
"filing against wolfSSL/wolfssl.",
140-
"",
141-
]
142154

143155
if state.get("log"):
144156
lines += [

0 commit comments

Comments
 (0)