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:
parent
d47cf43e56
commit
6fdca86f1b
3 changed files with 71 additions and 9 deletions
2
VERSION
2
VERSION
|
|
@ -1 +1 @@
|
||||||
1.13.11
|
1.13.12
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ Git tags: `vMAJOR.FEATURE.FIX` (e.g. `v1.8.0`). File `VERSION` omits the `v` pre
|
||||||
|
|
||||||
| Tag | Date (UTC) | Notes |
|
| Tag | Date (UTC) | Notes |
|
||||||
|-----|------------|--------|
|
|-----|------------|--------|
|
||||||
|
| **v1.13.12** | 2026-07-19 | **Bugfix:** SUMMARY chrome (`[ WARN ] 2`, `warnings only`, OK/ERROR counts without `#NNN`) is **meta**, not warn/error — sticky counts + warn filter no longer double SUMMARY rows; filter context skips blank lines. |
|
||||||
| **v1.13.11** | 2026-07-19 | **Bugfix:** sticky error/warn filter keeps **±3 dimmed context lines** around each match (gray/grayscale) so phase/group context stays readable; dashed gap between distant clusters. |
|
| **v1.13.11** | 2026-07-19 | **Bugfix:** sticky error/warn filter keeps **±3 dimmed context lines** around each match (gray/grayscale) so phase/group context stays readable; dashed gap between distant clusters. |
|
||||||
| **v1.13.10** | 2026-07-19 | **Bugfix:** multi-phase runs print **one global SUMMARY** at parent end (aggregated OK/ERROR/WARN/INFO/BLOCK via `TALER_MON_STATE`); no phase SUMMARY at all (not even last phase); mid-phase still lists ERRORS/BLOCKERS; solo `check_*.sh` unchanged. |
|
| **v1.13.10** | 2026-07-19 | **Bugfix:** multi-phase runs print **one global SUMMARY** at parent end (aggregated OK/ERROR/WARN/INFO/BLOCK via `TALER_MON_STATE`); no phase SUMMARY at all (not even last phase); mid-phase still lists ERRORS/BLOCKERS; solo `check_*.sh` unchanged. |
|
||||||
| **v1.13.9** | 2026-07-19 | **Bugfix:** no mid-run SUMMARY / progress standings between phases (no more 34/52 + SUMMARY after urls while monpages still runs); full stand only on last phase or solo check script; `progress_finish` remains. |
|
| **v1.13.9** | 2026-07-19 | **Bugfix:** no mid-run SUMMARY / progress standings between phases (no more 34/52 + SUMMARY after urls while monpages still runs); full stand only on last phase or solo check script; `progress_finish` remains. |
|
||||||
|
|
|
||||||
|
|
@ -261,31 +261,64 @@ def strip_ansi(s: str) -> str:
|
||||||
return ANSI_RE.sub("", s)
|
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:
|
def classify(line: str) -> str:
|
||||||
u = line.upper()
|
u = line.upper()
|
||||||
|
low = line.lower()
|
||||||
# section / summary headers before badge matching (they contain the word ERROR)
|
# 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:
|
if "SUMMARY" in u or "--- ERRORS" in u or "ERRORS ·" in u or "ERRORS (" in u:
|
||||||
return "meta"
|
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"
|
return "meta"
|
||||||
# host-agent tees converter "wrote … (errors=N …)" into the same log
|
# 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"
|
return "meta"
|
||||||
# git pull / reset noise (commit subjects may contain the word ERROR)
|
# git pull / reset noise (commit subjects may contain the word ERROR)
|
||||||
if re.match(r"\s*HEAD is now at\b", line):
|
if re.match(r"\s*HEAD is now at\b", line):
|
||||||
return "meta"
|
return "meta"
|
||||||
if "BLOCKER" in u or "┌ BLOCKER" in u:
|
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"
|
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 re.search(r"┌\s*ERROR\b|\[\s*ERROR\b", u):
|
||||||
|
if not is_numbered_check_line(line):
|
||||||
|
return "meta"
|
||||||
return "error"
|
return "error"
|
||||||
if re.search(r"\bERROR monpages\b", line, re.I):
|
if re.search(r"\bERROR monpages\b", line, re.I):
|
||||||
return "error"
|
return "error"
|
||||||
if re.search(r"┌\s*WARN\b|\[\s*WARN\b", u):
|
if re.search(r"┌\s*WARN\b|\[\s*WARN\b", u):
|
||||||
|
if not is_numbered_check_line(line):
|
||||||
|
return "meta"
|
||||||
return "warn"
|
return "warn"
|
||||||
if re.search(r"┌\s*INFO\b|\[\s*INFO\b", u):
|
if re.search(r"┌\s*INFO\b|\[\s*INFO\b", u):
|
||||||
|
if not is_numbered_check_line(line):
|
||||||
|
return "meta"
|
||||||
return "info"
|
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"
|
return "ok"
|
||||||
if u.strip().startswith("-- ") or u.strip().startswith("=="):
|
if u.strip().startswith("-- ") or u.strip().startswith("=="):
|
||||||
return "section"
|
return "section"
|
||||||
|
|
@ -394,6 +427,13 @@ def is_summary_error_line(ln: str) -> bool:
|
||||||
return True
|
return True
|
||||||
if "totals:" in low:
|
if "totals:" in low:
|
||||||
return True
|
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
|
# 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.
|
# host-agent log; "errors=" uppercases to "ERRORS=" and must not count as ERROR.
|
||||||
if low.lstrip().startswith("wrote ") and "errors=" in low:
|
if low.lstrip().startswith("wrote ") and "errors=" in low:
|
||||||
|
|
@ -1419,20 +1459,41 @@ STICKY_JS = """
|
||||||
if (mode === "warn") return el.classList.contains("warn");
|
if (mode === "warn") return el.classList.contains("warn");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
function isBlankLine(el) {
|
||||||
|
var t = (el.textContent || "").replace(/\u00a0/g, " ").trim();
|
||||||
|
return t.length === 0;
|
||||||
|
}
|
||||||
// 0 = hide, 1 = match, 2 = context
|
// 0 = hide, 1 = match, 2 = context
|
||||||
var keep = new Array(lines.length);
|
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++) keep[i] = 0;
|
||||||
for (i = 0; i < lines.length; i++) {
|
for (i = 0; i < lines.length; i++) {
|
||||||
if (!isMatch(lines[i])) continue;
|
if (!isMatch(lines[i])) continue;
|
||||||
keep[i] = 1;
|
keep[i] = 1;
|
||||||
for (d = 1; d <= FILTER_CTX; d++) {
|
// ±FILTER_CTX *non-empty* neighbours (skip blank lines so filter is not full of voids)
|
||||||
if (i - d >= 0 && keep[i - d] !== 1) keep[i - d] = 2;
|
n = 0;
|
||||||
if (i + d < lines.length && keep[i + d] !== 1) keep[i + d] = 2;
|
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++) {
|
for (j = 0; j < lines.length; j++) {
|
||||||
if (keep[j] === 2) lines[j].classList.add("filter-ctx");
|
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
|
// dashed gap between non-contiguous visible clusters
|
||||||
var prevVisible = -2;
|
var prevVisible = -2;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue