release 1.18.1: FR mon badges + stage-lfp host-podman + suite keep mode
This commit is contained in:
parent
84588f2648
commit
7b3a345b7d
5 changed files with 154 additions and 58 deletions
2
VERSION
2
VERSION
|
|
@ -1 +1 @@
|
||||||
1.18.0
|
1.18.1
|
||||||
|
|
|
||||||
|
|
@ -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.18.1** | 2026-07-19 | **Bugfix:** (1) mon HTML sticky/err counts honor French badges **ERREUR** / **AVERT** (were plain → 0 errors on FP pages); (2) `stage-lfp` + `INSIDE_PODMAN=1` uses **host-podman** (no empty `INSIDE_SSH` fail); (3) reaffirm filter JS has no box-glyph/`\\-` regex (charCodeAt only — kills SyntaxWarning “geheimsprache” noise). |
|
||||||
| **v1.18.0** | 2026-07-19 | **Feature:** mattermost — client compatibility matrix: **mobile**, **desktop**, **vendor support** floors (default ≥10.11.0, ERROR) + **web** WARN on EOL; env `MATTERMOST_DESKTOP/SUPPORT_MIN_SERVER`, `MATTERMOST_CLIENT_CHECK`. |
|
| **v1.18.0** | 2026-07-19 | **Feature:** mattermost — client compatibility matrix: **mobile**, **desktop**, **vendor support** floors (default ≥10.11.0, ERROR) + **web** WARN on EOL; env `MATTERMOST_DESKTOP/SUPPORT_MIN_SERVER`, `MATTERMOST_CLIENT_CHECK`. |
|
||||||
| **v1.17.0** | 2026-07-19 | **Feature:** mattermost phase — check **server version** (`X-Version-Id`) against **mobile store min** (default **≥10.11.0**); ERROR when too old (newest Android/iOS apps break); env `MATTERMOST_MOBILE_MIN_SERVER` / `MATTERMOST_MOBILE_CHECK=0`. |
|
| **v1.17.0** | 2026-07-19 | **Feature:** mattermost phase — check **server version** (`X-Version-Id`) against **mobile store min** (default **≥10.11.0**); ERROR when too old (newest Android/iOS apps break); env `MATTERMOST_MOBILE_MIN_SERVER` / `MATTERMOST_MOBILE_CHECK=0`. |
|
||||||
| **v1.16.0** | 2026-07-19 | **Feature:** mon sticky — blue **info** + green **ok** filter badges; suite **version tag under status pill** (not blue badge); filters `#filter-info` / `#filter-ok`. |
|
| **v1.16.0** | 2026-07-19 | **Feature:** mon sticky — blue **info** + green **ok** filter badges; suite **version tag under status pill** (not blue badge); filters `#filter-info` / `#filter-ok`. |
|
||||||
|
|
|
||||||
|
|
@ -29,12 +29,14 @@ if [ -z "$PROFILE" ]; then
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Resolve host-podman vs ssh before first check ID
|
# Resolve host-podman vs ssh before first check ID.
|
||||||
|
# stage-lfp on the FP host itself uses local podman (INSIDE_PODMAN=1 /
|
||||||
|
# INSIDE_MODE=local-podman); laptop → stage still uses INSIDE_SSH.
|
||||||
_use_local_podman=0
|
_use_local_podman=0
|
||||||
if [ "$PROFILE" != "stage-lfp" ]; then
|
if [ "${INSIDE_PODMAN:-0}" = "1" ] || [ "${INSIDE_MODE:-}" = "local-podman" ]; then
|
||||||
if [ "${INSIDE_PODMAN:-0}" = "1" ] || [ "${INSIDE_MODE:-}" = "local-podman" ]; then
|
_use_local_podman=1
|
||||||
_use_local_podman=1
|
elif [ "$PROFILE" != "stage-lfp" ]; then
|
||||||
elif command -v podman >/dev/null 2>&1 \
|
if command -v podman >/dev/null 2>&1 \
|
||||||
&& podman ps --format '{{.Names}}' 2>/dev/null | grep -qE 'taler-hacktivism'; then
|
&& podman ps --format '{{.Names}}' 2>/dev/null | grep -qE 'taler-hacktivism'; then
|
||||||
_use_local_podman=1
|
_use_local_podman=1
|
||||||
fi
|
fi
|
||||||
|
|
@ -52,7 +54,7 @@ section "inside · collect (${PROFILE} · access=${INSIDE_ACCESS})"
|
||||||
info "flags" "INSIDE_ACCESS=${INSIDE_ACCESS} INSIDE_PODMAN=${INSIDE_PODMAN:-0} INSIDE_MODE=${INSIDE_MODE:-} LOCAL_STACK=${LOCAL_STACK:-0} SKIP_SSH=${SKIP_SSH:-0} KOOPA_SSH=${KOOPA_SSH:-} INSIDE_SSH=${INSIDE_SSH:-}"
|
info "flags" "INSIDE_ACCESS=${INSIDE_ACCESS} INSIDE_PODMAN=${INSIDE_PODMAN:-0} INSIDE_MODE=${INSIDE_MODE:-} LOCAL_STACK=${LOCAL_STACK:-0} SKIP_SSH=${SKIP_SSH:-0} KOOPA_SSH=${KOOPA_SSH:-} INSIDE_SSH=${INSIDE_SSH:-}"
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
# stage-lfp: low-priv stagepaysan on the FP stage host (INSIDE_SSH)
|
# stage-lfp: stagepaysan podman (host-local or SSH INSIDE_SSH from laptop)
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
if [ "$PROFILE" = "stage-lfp" ]; then
|
if [ "$PROFILE" = "stage-lfp" ]; then
|
||||||
SSH_HOST="${INSIDE_SSH:-}"
|
SSH_HOST="${INSIDE_SSH:-}"
|
||||||
|
|
@ -69,15 +71,23 @@ if [ "$PROFILE" = "stage-lfp" ]; then
|
||||||
STAGE_SSH_T="${INSIDE_SSH_TIMEOUT:-${SSH_CMD_TIMEOUT:-24}}"
|
STAGE_SSH_T="${INSIDE_SSH_TIMEOUT:-${SSH_CMD_TIMEOUT:-24}}"
|
||||||
if [ "${STAGE_SSH_T}" -lt 24 ] 2>/dev/null; then STAGE_SSH_T=24; fi
|
if [ "${STAGE_SSH_T}" -lt 24 ] 2>/dev/null; then STAGE_SSH_T=24; fi
|
||||||
|
|
||||||
if ! mon_ssh_ok "$SSH_HOST"; then
|
if [ "$_use_local_podman" = "1" ]; then
|
||||||
err "ssh" "cannot reach ${SSH_HOST} (stagepaysan low-priv) — set INSIDE_SSH= or SKIP"
|
if ! command -v podman >/dev/null 2>&1; then
|
||||||
|
err "host" "INSIDE_PODMAN/host-podman but podman missing"
|
||||||
|
summary
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
ok "host→container" "podman exec on this host (INSIDE_ACCESS=host-podman · no SSH)"
|
||||||
|
elif ! mon_ssh_ok "$SSH_HOST"; then
|
||||||
|
err "ssh" "cannot reach ${SSH_HOST:-?} (stagepaysan low-priv) — set INSIDE_SSH= or INSIDE_PODMAN=1"
|
||||||
summary
|
summary
|
||||||
exit 1
|
exit 1
|
||||||
|
else
|
||||||
|
ok "ssh ${SSH_HOST}" "stagepaysan (podman, no sudo)"
|
||||||
fi
|
fi
|
||||||
ok "ssh ${SSH_HOST}" "stagepaysan (podman, no sudo)"
|
|
||||||
|
|
||||||
# Inject names/ports into remote (ssh bash -s does not inherit local env).
|
# Inject names/ports (ssh bash -s does not inherit local env; local bash does).
|
||||||
RAW=$(
|
_stage_lfp_script() {
|
||||||
{
|
{
|
||||||
printf 'BANK_CTR=%q; EX_CTR=%q; MER_CTR=%q\n' "$BANK_CTR" "$EX_CTR" "$MER_CTR"
|
printf 'BANK_CTR=%q; EX_CTR=%q; MER_CTR=%q\n' "$BANK_CTR" "$EX_CTR" "$MER_CTR"
|
||||||
printf 'BANK_PORT=%q; EX_PORT=%q; MER_PORT=%q\n' "$BANK_PORT" "$EX_PORT" "$MER_PORT"
|
printf 'BANK_PORT=%q; EX_PORT=%q; MER_PORT=%q\n' "$BANK_PORT" "$EX_PORT" "$MER_PORT"
|
||||||
|
|
@ -173,11 +183,20 @@ fi
|
||||||
|
|
||||||
echo DONE
|
echo DONE
|
||||||
REMOTE
|
REMOTE
|
||||||
} | mon_ssh_bash "$SSH_HOST" "${STAGE_SSH_T}" || true
|
}
|
||||||
)
|
}
|
||||||
|
if [ "$_use_local_podman" = "1" ]; then
|
||||||
|
RAW=$(_stage_lfp_script | bash || true)
|
||||||
|
else
|
||||||
|
RAW=$(_stage_lfp_script | mon_ssh_bash "$SSH_HOST" "${STAGE_SSH_T}" || true)
|
||||||
|
fi
|
||||||
|
|
||||||
if [ -z "$RAW" ] || ! echo "$RAW" | grep -q '^E|'; then
|
if [ -z "$RAW" ] || ! echo "$RAW" | grep -q '^E|'; then
|
||||||
err "ssh" "stage remote timed out or empty (cap ${STAGE_SSH_T}s · host=${SSH_HOST})"
|
if [ "$_use_local_podman" = "1" ]; then
|
||||||
|
err "host" "stage collect timed out or empty (local podman)"
|
||||||
|
else
|
||||||
|
err "ssh" "stage remote timed out or empty (cap ${STAGE_SSH_T}s · host=${SSH_HOST})"
|
||||||
|
fi
|
||||||
summary
|
summary
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
@ -189,7 +208,7 @@ REMOTE
|
||||||
IFS='|' read -r _ comp level key detail <<<"$line"
|
IFS='|' read -r _ comp level key detail <<<"$line"
|
||||||
case "$comp" in
|
case "$comp" in
|
||||||
bank|exchange|merchant|caddy) _g="$comp" ;;
|
bank|exchange|merchant|caddy) _g="$comp" ;;
|
||||||
*) _g="ssh" ;;
|
*) _g="$INSIDE_ACCESS" ;;
|
||||||
esac
|
esac
|
||||||
if [ "$_g" != "$_last_inside_grp" ]; then
|
if [ "$_g" != "$_last_inside_grp" ]; then
|
||||||
set_group "$_g"
|
set_group "$_g"
|
||||||
|
|
@ -242,7 +261,29 @@ REMOTE
|
||||||
# Host load as stagepaysan (no container RSS from koopa metrics)
|
# Host load as stagepaysan (no container RSS from koopa metrics)
|
||||||
set_group load
|
set_group load
|
||||||
section "inside · load (stagepaysan host)"
|
section "inside · load (stagepaysan host)"
|
||||||
LOAD_LINE=$(mon_ssh_bash "$SSH_HOST" 8 <<'EOF' || true
|
_load_py() {
|
||||||
|
python3 - <<'PY'
|
||||||
|
import os
|
||||||
|
la=os.getloadavg()
|
||||||
|
print("loadavg=%.2f,%.2f,%.2f" % la)
|
||||||
|
try:
|
||||||
|
with open("/proc/meminfo") as f:
|
||||||
|
d={}
|
||||||
|
for line in f:
|
||||||
|
k,v=line.split(":")[0], line.split(":")[1].strip().split()[0]
|
||||||
|
d[k]=int(v)
|
||||||
|
total=d.get("MemTotal",0)/1024/1024
|
||||||
|
avail=d.get("MemAvailable",0)/1024/1024
|
||||||
|
used=total-avail
|
||||||
|
print("mem_used=%.2fGiB avail=%.2fGiB total=%.2fGiB" % (used, avail, total))
|
||||||
|
except Exception:
|
||||||
|
print("mem=?")
|
||||||
|
PY
|
||||||
|
}
|
||||||
|
if [ "$_use_local_podman" = "1" ]; then
|
||||||
|
LOAD_LINE=$(_load_py || true)
|
||||||
|
else
|
||||||
|
LOAD_LINE=$(mon_ssh_bash "$SSH_HOST" 8 <<'EOF' || true
|
||||||
python3 - <<'PY'
|
python3 - <<'PY'
|
||||||
import os
|
import os
|
||||||
la=os.getloadavg()
|
la=os.getloadavg()
|
||||||
|
|
@ -262,6 +303,7 @@ except Exception:
|
||||||
PY
|
PY
|
||||||
EOF
|
EOF
|
||||||
)
|
)
|
||||||
|
fi
|
||||||
if [ -n "$LOAD_LINE" ]; then
|
if [ -n "$LOAD_LINE" ]; then
|
||||||
info "stage host" "$(echo "$LOAD_LINE" | tr '\n' ' ')"
|
info "stage host" "$(echo "$LOAD_LINE" | tr '\n' ' ')"
|
||||||
else
|
else
|
||||||
|
|
@ -270,7 +312,8 @@ EOF
|
||||||
|
|
||||||
set_group disk
|
set_group disk
|
||||||
section "inside · disk free space (stage host + containers)"
|
section "inside · disk free space (stage host + containers)"
|
||||||
_disk_raw=$(mon_ssh_bash "$SSH_HOST" "${STAGE_SSH_T:-24}" <<'DISK' || true
|
_disk_script() {
|
||||||
|
cat <<'DISK'
|
||||||
set +e
|
set +e
|
||||||
echo "###HOST###"
|
echo "###HOST###"
|
||||||
df -Pk / /var /home /tmp /mnt/data 2>/dev/null || df -Pk
|
df -Pk / /var /home /tmp /mnt/data 2>/dev/null || df -Pk
|
||||||
|
|
@ -280,9 +323,16 @@ for c in $(podman ps --format '{{.Names}}' 2>/dev/null); do
|
||||||
podman exec "$c" df -Pk / /var /tmp 2>/dev/null || podman exec "$c" df -Pk 2>/dev/null
|
podman exec "$c" df -Pk / /var /tmp 2>/dev/null || podman exec "$c" df -Pk 2>/dev/null
|
||||||
done
|
done
|
||||||
DISK
|
DISK
|
||||||
)
|
}
|
||||||
|
if [ "$_use_local_podman" = "1" ]; then
|
||||||
|
_disk_raw=$(_disk_script | bash || true)
|
||||||
|
_disk_label="host"
|
||||||
|
else
|
||||||
|
_disk_raw=$(_disk_script | mon_ssh_bash "$SSH_HOST" "${STAGE_SSH_T:-24}" || true)
|
||||||
|
_disk_label="ssh:${SSH_HOST}"
|
||||||
|
fi
|
||||||
_host_df=$(printf '%s\n' "$_disk_raw" | sed -n '/^###HOST###$/,/^###CTRS###$/p' | sed '1d;$d')
|
_host_df=$(printf '%s\n' "$_disk_raw" | sed -n '/^###HOST###$/,/^###CTRS###$/p' | sed '1d;$d')
|
||||||
mon_disk_check_remote_text "ssh:${SSH_HOST}" "$_host_df" || true
|
mon_disk_check_remote_text "$_disk_label" "$_host_df" || true
|
||||||
_ctr=""; _buf=""
|
_ctr=""; _buf=""
|
||||||
while IFS= read -r _line || [ -n "$_line" ]; do
|
while IFS= read -r _line || [ -n "$_line" ]; do
|
||||||
case "$_line" in
|
case "$_line" in
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,8 @@
|
||||||
# SUITE_GIT_URL default https://git.hacktivism.ch/hernani/taler-monitoring.git
|
# SUITE_GIT_URL default https://git.hacktivism.ch/hernani/taler-monitoring.git
|
||||||
# SUITE_GIT_REF default main
|
# SUITE_GIT_REF default main
|
||||||
# SUITE_DIR default ~/src/taler-monitoring
|
# SUITE_DIR default ~/src/taler-monitoring
|
||||||
# SUITE_UPDATE_MODE reset (default) | pull
|
# SUITE_UPDATE_MODE reset (default) | pull | keep
|
||||||
|
# keep = no fetch/reset (local deploy / unpushed fixes)
|
||||||
# SUITE_UPDATE_STRICT 1 (default) = fetch/reset failure aborts the agent run
|
# SUITE_UPDATE_STRICT 1 (default) = fetch/reset failure aborts the agent run
|
||||||
# 0 = warn and continue on old tree (emergency only)
|
# 0 = warn and continue on old tree (emergency only)
|
||||||
#
|
#
|
||||||
|
|
@ -55,29 +56,41 @@ _before_ver=$(git describe --tags --exact-match 2>/dev/null \
|
||||||
|| git describe --tags --abbrev=0 2>/dev/null \
|
|| git describe --tags --abbrev=0 2>/dev/null \
|
||||||
|| echo unknown)
|
|| echo unknown)
|
||||||
|
|
||||||
echo "fetch origin ($SUITE_GIT_REF) + tags …"
|
case "$SUITE_UPDATE_MODE" in
|
||||||
if ! git fetch --tags --force --prune origin 2>&1; then
|
keep|skip|off|none)
|
||||||
_upd_die "git fetch failed — suite would stay at ${_before} (${_before_ver})"
|
echo "suite update skipped (SUITE_UPDATE_MODE=$SUITE_UPDATE_MODE) — keep local tree ${_before} (${_before_ver})"
|
||||||
# fall through only if STRICT=0
|
;;
|
||||||
else
|
*)
|
||||||
case "$SUITE_UPDATE_MODE" in
|
echo "fetch origin ($SUITE_GIT_REF) + tags …"
|
||||||
reset)
|
if ! git fetch --tags --force --prune origin 2>&1; then
|
||||||
if ! git checkout -B "$SUITE_GIT_REF" "origin/$SUITE_GIT_REF" 2>/dev/null \
|
_upd_die "git fetch failed — suite would stay at ${_before} (${_before_ver})"
|
||||||
&& ! git checkout -B "$SUITE_GIT_REF" FETCH_HEAD; then
|
# fall through only if STRICT=0
|
||||||
_upd_die "git checkout $SUITE_GIT_REF failed"
|
else
|
||||||
fi
|
case "$SUITE_UPDATE_MODE" in
|
||||||
if ! git reset --hard "origin/$SUITE_GIT_REF" 2>/dev/null \
|
reset)
|
||||||
&& ! git reset --hard FETCH_HEAD; then
|
if ! git checkout -B "$SUITE_GIT_REF" "origin/$SUITE_GIT_REF" 2>/dev/null \
|
||||||
_upd_die "git reset --hard origin/$SUITE_GIT_REF failed"
|
&& ! git checkout -B "$SUITE_GIT_REF" FETCH_HEAD; then
|
||||||
fi
|
_upd_die "git checkout $SUITE_GIT_REF failed"
|
||||||
;;
|
fi
|
||||||
*)
|
if ! git reset --hard "origin/$SUITE_GIT_REF" 2>/dev/null \
|
||||||
if ! git pull --ff-only origin "$SUITE_GIT_REF" 2>&1; then
|
&& ! git reset --hard FETCH_HEAD; then
|
||||||
_upd_die "git pull --ff-only failed"
|
_upd_die "git reset --hard origin/$SUITE_GIT_REF failed"
|
||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
esac
|
pull)
|
||||||
fi
|
if ! git pull --ff-only origin "$SUITE_GIT_REF" 2>&1; then
|
||||||
|
_upd_die "git pull --ff-only failed"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
if ! git pull --ff-only origin "$SUITE_GIT_REF" 2>&1; then
|
||||||
|
_upd_die "git pull --ff-only failed (mode=$SUITE_UPDATE_MODE)"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
COMMIT=$(git rev-parse HEAD)
|
COMMIT=$(git rev-parse HEAD)
|
||||||
COMMIT_SHORT=$(git rev-parse --short=12 HEAD)
|
COMMIT_SHORT=$(git rev-parse --short=12 HEAD)
|
||||||
|
|
|
||||||
|
|
@ -323,7 +323,15 @@ def classify(line: str) -> str:
|
||||||
# Double-line box frames from section() → section (no sum-* paint)
|
# Double-line box frames from section() → section (no sum-* paint)
|
||||||
if re.match(r"^\s*[╔╚].*═", line) or re.match(r"^\s*║\s", line):
|
if re.match(r"^\s*[╔╚].*═", line) or re.match(r"^\s*║\s", line):
|
||||||
return "section"
|
return "section"
|
||||||
if "--- ERRORS" in u or "ERRORS ·" in u or "ERRORS (" in u:
|
# EN + FR section headers (i18n_tag ERROR→ERREUR, ERRORS→ERREURS)
|
||||||
|
if (
|
||||||
|
"--- ERRORS" in u
|
||||||
|
or "--- ERREURS" in u
|
||||||
|
or "ERRORS ·" in u
|
||||||
|
or "ERREURS ·" in u
|
||||||
|
or "ERRORS (" in u
|
||||||
|
or "ERREURS (" in u
|
||||||
|
):
|
||||||
return "meta"
|
return "meta"
|
||||||
if "numbered checks" in low:
|
if "numbered checks" in low:
|
||||||
return "meta"
|
return "meta"
|
||||||
|
|
@ -350,14 +358,15 @@ def classify(line: str) -> str:
|
||||||
return "sum-block"
|
return "sum-block"
|
||||||
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")
|
# and not SUMMARY count rows like " [ ERROR ] 3").
|
||||||
if re.search(r"┌\s*ERROR\b|\[\s*ERROR\b", u):
|
# French console (i18n_tag): ERROR→ERREUR, WARN→AVERT (v1.18.1).
|
||||||
|
if re.search(r"┌\s*(?:ERROR|ERREUR)\b|\[\s*(?:ERROR|ERREUR)\b", u):
|
||||||
if not is_numbered_check_line(line):
|
if not is_numbered_check_line(line):
|
||||||
return "sum-err"
|
return "sum-err"
|
||||||
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|AVERT)\b|\[\s*(?:WARN|AVERT)\b", u):
|
||||||
if not is_numbered_check_line(line):
|
if not is_numbered_check_line(line):
|
||||||
return "sum-warn"
|
return "sum-warn"
|
||||||
return "warn"
|
return "warn"
|
||||||
|
|
@ -508,11 +517,25 @@ def extract_errors(lines: list[str]) -> list[str]:
|
||||||
timeout_detail = ""
|
timeout_detail = ""
|
||||||
in_block = False
|
in_block = False
|
||||||
for ln in lines:
|
for ln in lines:
|
||||||
if "--- ERRORS" in ln or "ERRORS (failed" in ln or "RUN TIMEOUT · extraordinary" in ln:
|
u = ln.upper()
|
||||||
|
if (
|
||||||
|
"--- ERRORS" in u
|
||||||
|
or "--- ERREURS" in u
|
||||||
|
or "ERRORS (FAILED" in u
|
||||||
|
or "ERREURS (CONTROLES" in u
|
||||||
|
or "ERREURS (FAILED" in u
|
||||||
|
or "RUN TIMEOUT · EXTRAORDINARY" in u
|
||||||
|
):
|
||||||
in_block = True
|
in_block = True
|
||||||
continue
|
continue
|
||||||
if in_block:
|
if in_block:
|
||||||
if ln.strip().startswith("---") or "[ SUMMARY" in ln or "totals:" in ln:
|
if (
|
||||||
|
ln.strip().startswith("---")
|
||||||
|
or "[ SUMMARY" in ln
|
||||||
|
or "[ RESUME" in u
|
||||||
|
or "totals:" in ln.lower()
|
||||||
|
or "totaux :" in ln.lower()
|
||||||
|
):
|
||||||
in_block = False
|
in_block = False
|
||||||
continue
|
continue
|
||||||
m = ERR_BULLET_RE.match(ln)
|
m = ERR_BULLET_RE.match(ln)
|
||||||
|
|
@ -522,10 +545,15 @@ def extract_errors(lines: list[str]) -> list[str]:
|
||||||
timeout_detail = body
|
timeout_detail = body
|
||||||
else:
|
else:
|
||||||
errs.append(body)
|
errs.append(body)
|
||||||
elif "ERROR" in ln.upper() and ln.strip() and not is_run_timeout_text(ln):
|
elif ("ERROR" in u or "ERREUR" in u) and ln.strip() and not is_run_timeout_text(ln):
|
||||||
errs.append(ln.strip())
|
errs.append(ln.strip())
|
||||||
# Only real check badges (not INFO text mentioning thresholds like "… ERROR (0=disable)")
|
# Only real check badges (not INFO text mentioning thresholds like "… ERROR (0=disable)")
|
||||||
if re.search(r"┌\s*ERROR\b|\[\s*ERROR\b", ln, re.I) and "--- ERRORS" not in ln:
|
# FR: i18n_tag ERROR→ERREUR (v1.18.1)
|
||||||
|
if (
|
||||||
|
re.search(r"┌\s*(?:ERROR|ERREUR)\b|\[\s*(?:ERROR|ERREUR)\b", ln, re.I)
|
||||||
|
and "--- ERRORS" not in u
|
||||||
|
and "--- ERREURS" not in u
|
||||||
|
):
|
||||||
if is_run_timeout_text(ln):
|
if is_run_timeout_text(ln):
|
||||||
if "run.timeout-01" in ln.lower() or "RUN_TIMEOUT exceeded" in ln:
|
if "run.timeout-01" in ln.lower() or "RUN_TIMEOUT exceeded" in ln:
|
||||||
timeout_detail = re.sub(r"\s+", " ", strip_ansi(ln)).strip()
|
timeout_detail = re.sub(r"\s+", " ", strip_ansi(ln)).strip()
|
||||||
|
|
@ -534,8 +562,10 @@ def extract_errors(lines: list[str]) -> list[str]:
|
||||||
continue
|
continue
|
||||||
if classify(ln) not in ("error", "blocker"):
|
if classify(ln) not in ("error", "blocker"):
|
||||||
continue
|
continue
|
||||||
body = re.sub(r"^.*\bERROR\b\s*\]?\s*", "", ln, flags=re.I).strip(" ·")
|
body = re.sub(
|
||||||
if body and body not in errs and "failed — see" not in body.lower():
|
r"^.*\b(?:ERROR|ERREUR)\b\s*[\]┐]?\s*", "", ln, flags=re.I
|
||||||
|
).strip(" ·")
|
||||||
|
if body and body not in errs and "failed — see" not in body.lower() and "echec — voir" not in body.lower():
|
||||||
if re.search(
|
if re.search(
|
||||||
r"#\d+|www\.|e2e\.|auth401\.|versions\.|inside\.|surface\.|aptdeploy\.",
|
r"#\d+|www\.|e2e\.|auth401\.|versions\.|inside\.|surface\.|aptdeploy\.",
|
||||||
body,
|
body,
|
||||||
|
|
@ -1699,13 +1729,15 @@ STICKY_JS = """
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
var t = (el.textContent || "").replace(/\u00a0/g, " ").trim();
|
var t = (el.textContent || "").replace(/\u00a0/g, " ").trim();
|
||||||
// Pure box-drawing / whitespace chrome (no literal box glyphs in source —
|
// Skip pure chrome lines (spaces/tabs/newlines/hyphen + Unicode box-drawing).
|
||||||
// those used to appear as "weird chars" in Python SyntaxWarning output).
|
// Do NOT use a JS character-class regex with box glyphs here: when this
|
||||||
|
// script is embedded in a Python string, Python emits SyntaxWarning for
|
||||||
|
// sequences like \\- and the glyphs show up as noise in mon logs.
|
||||||
if (!t.length) return true;
|
if (!t.length) return true;
|
||||||
for (var bi = 0; bi < t.length; bi++) {
|
for (var bi = 0; bi < t.length; bi++) {
|
||||||
var bc = t.charCodeAt(bi);
|
var bc = t.charCodeAt(bi);
|
||||||
if (bc === 32 || bc === 9 || bc === 10 || bc === 13 || bc === 0x2d) continue; // sp/tab/nl/cr/-
|
if (bc === 32 || bc === 9 || bc === 10 || bc === 13 || bc === 0x2d) continue;
|
||||||
if (bc >= 0x2500 && bc <= 0x257f) continue; // box drawing
|
if (bc >= 0x2500 && bc <= 0x257f) continue; // U+2500–U+257F box drawing
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue