release 1.13.12: SUMMARY badge rows are not warn/error matches

Classify SUMMARY chrome ([ WARN ] 2, warnings only, bare OK/ERROR
counts without #NNN/tid) as meta so sticky counts and the warn/error
filter only show real checks. Filter context skips blank lines.
This commit is contained in:
Hernâni Marques 2026-07-19 04:17:01 +02:00
parent d47cf43e56
commit 6fdca86f1b
No known key found for this signature in database
GPG key ID: CB5738652768F7E9
3 changed files with 71 additions and 9 deletions

View file

@ -261,31 +261,64 @@ def strip_ansi(s: str) -> str:
return ANSI_RE.sub("", s)
def is_numbered_check_line(line: str) -> bool:
"""True for real suite checks (global #NNN and/or tid like www.merchant-09).
SUMMARY box rows look like `` [ WARN ] 2`` / `` [ WARN ] warnings only``
and must NOT count as warn/error (v1.13.12).
"""
if re.search(r"#\d{3}\b", line):
return True
if TID_RE.search(line):
return True
return False
def classify(line: str) -> str:
u = line.upper()
low = line.lower()
# section / summary headers before badge matching (they contain the word ERROR)
if "SUMMARY" in u or "--- ERRORS" in u or "ERRORS ·" in u or "ERRORS (" in u:
return "meta"
if "numbered checks" in line.lower() or "totals:" in line.lower():
if "numbered checks" in low or "totals:" in low:
return "meta"
# SUMMARY verdict chrome (not a check)
if "warnings only" in low or "all clear" in low or "failed — see" in low or "failed - see" in low:
return "meta"
# host-agent tees converter "wrote … (errors=N …)" into the same log
if line.lstrip().lower().startswith("wrote ") and "errors=" in line.lower():
if line.lstrip().lower().startswith("wrote ") and "errors=" in low:
return "meta"
# git pull / reset noise (commit subjects may contain the word ERROR)
if re.match(r"\s*HEAD is now at\b", line):
return "meta"
if "BLOCKER" in u or "┌ BLOCKER" in u:
# SUMMARY may print " [ BLOCK ] 1" without a check id
if not is_numbered_check_line(line) and re.search(
r"[\[┌]\s*BLOCK(?:ER)?\s*[\]┐]", u
):
return "meta"
return "blocker"
# Only real check badges (not free-text "ERROR" inside commit messages)
# Only real check badges (not free-text "ERROR" inside commit messages,
# and not SUMMARY count rows like " [ ERROR ] 3")
if re.search(r"\s*ERROR\b|\[\s*ERROR\b", u):
if not is_numbered_check_line(line):
return "meta"
return "error"
if re.search(r"\bERROR monpages\b", line, re.I):
return "error"
if re.search(r"\s*WARN\b|\[\s*WARN\b", u):
if not is_numbered_check_line(line):
return "meta"
return "warn"
if re.search(r"\s*INFO\b|\[\s*INFO\b", u):
if not is_numbered_check_line(line):
return "meta"
return "info"
if " OK" in u or "[OK" in u or "┌ OK" in u or u.strip().startswith("OK"):
if re.search(r"\s*OK\b|\[\s*OK\b", u) or (
(" OK" in u or u.strip().startswith("OK")) and is_numbered_check_line(line)
):
if re.search(r"\s*OK\b|\[\s*OK\b", u) and not is_numbered_check_line(line):
return "meta"
return "ok"
if u.strip().startswith("-- ") or u.strip().startswith("=="):
return "section"
@ -394,6 +427,13 @@ def is_summary_error_line(ln: str) -> bool:
return True
if "totals:" in low:
return True
if "warnings only" in low or "all clear" in low:
return True
# SUMMARY count rows without #NNN / tid (e.g. " [ ERROR ] 3")
if re.search(r"[\[\u250c]\s*(ERROR|WARN|OK|INFO|BLOCK)", ln, re.I) and not is_numbered_check_line(
ln
):
return True
# console_to_html "wrote … (errors=N warnings=M level=…)" is teed into the
# host-agent log; "errors=" uppercases to "ERRORS=" and must not count as ERROR.
if low.lstrip().startswith("wrote ") and "errors=" in low:
@ -1419,20 +1459,41 @@ STICKY_JS = """
if (mode === "warn") return el.classList.contains("warn");
return false;
}
function isBlankLine(el) {
var t = (el.textContent || "").replace(/\u00a0/g, " ").trim();
return t.length === 0;
}
// 0 = hide, 1 = match, 2 = context
var keep = new Array(lines.length);
var i, d, j, k;
var i, j, k, n, idx;
for (i = 0; i < lines.length; i++) keep[i] = 0;
for (i = 0; i < lines.length; i++) {
if (!isMatch(lines[i])) continue;
keep[i] = 1;
for (d = 1; d <= FILTER_CTX; d++) {
if (i - d >= 0 && keep[i - d] !== 1) keep[i - d] = 2;
if (i + d < lines.length && keep[i + d] !== 1) keep[i + d] = 2;
// ±FILTER_CTX *non-empty* neighbours (skip blank lines so filter is not full of voids)
n = 0;
idx = i - 1;
while (idx >= 0 && n < FILTER_CTX) {
if (keep[idx] === 1) { idx--; continue; }
if (isBlankLine(lines[idx])) { idx--; continue; }
keep[idx] = 2;
n++;
idx--;
}
n = 0;
idx = i + 1;
while (idx < lines.length && n < FILTER_CTX) {
if (keep[idx] === 1) { idx++; continue; }
if (isBlankLine(lines[idx])) { idx++; continue; }
keep[idx] = 2;
n++;
idx++;
}
}
for (j = 0; j < lines.length; j++) {
if (keep[j] === 2) lines[j].classList.add("filter-ctx");
// never show pure blank lines in filter mode
if (isBlankLine(lines[j]) && keep[j] !== 1) keep[j] = 0;
}
// dashed gap between non-contiguous visible clusters
var prevVisible = -2;