release 1.3.0: sticky bar suite version + Forgejo tag link

This commit is contained in:
Hernâni Marques 2026-07-18 17:03:48 +02:00
parent 9eac6e58b4
commit db8b474d39
No known key found for this signature in database
GPG key ID: CB5738652768F7E9
6 changed files with 121 additions and 2 deletions

View file

@ -364,3 +364,8 @@ LADDER_LOAD=0 ./taler-monitoring.sh ladder
## Languages (i18n) ## Languages (i18n)
Default **English**. FrancPaysan stacks use **French** (`TALER_MON_LANG=fr`, auto for `*lefrancpaysan*`). See `VERSIONS.md` and `i18n.sh`. Default **English**. FrancPaysan stacks use **French** (`TALER_MON_LANG=fr`, auto for `*lefrancpaysan*`). See `VERSIONS.md` and `i18n.sh`.
## Version on monitoring pages (v1.3.0+)
The sticky bar shows the suite **tag** (e.g. `v1.3.0`) and links to that tag on Forgejo.
Planned **v1.4.0**: fuller L10n (fr-CH for FrancPaysan, de-CH for hacktivism/Taler CH).

View file

@ -1 +1 @@
1.2.0 1.3.0

View file

@ -5,10 +5,21 @@ Release history for the standalone **taler-monitoring** suite
| Tag | Date (UTC) | Notes | | Tag | Date (UTC) | Notes |
|-----|------------|--------| |-----|------------|--------|
| **v1.4.0** | *planned* | **L10n** for user-facing outputs that need localization: **fr-CH** (FrancPaysan, Suisse romande) and **de-CH** (hacktivism / Taler CH German). Not implemented yet — after **1.3**. |
| **v1.3.0** | 2026-07-18 | Sticky bar shows **suite version** and links to the Forgejo **tag** (`…/src/tag/vX.Y.Z`). |
| **v1.2** | 2026-07-18 | Language selection: `--lang` / `TALER_MON_LANG` (en\|fr). | | **v1.2** | 2026-07-18 | Language selection: `--lang` / `TALER_MON_LANG` (en\|fr). |
| **v1.1** | 2026-07-18 | i18n chrome: English default; French for FrancPaysan. | | **v1.1** | 2026-07-18 | i18n chrome: English default; French for FrancPaysan. |
| **v1.0** / **v1** | 2026-07-18 | Initial standalone release (split from `koopa-admin-log`). | | **v1.0** / **v1** | 2026-07-18 | Initial standalone release (split from `koopa-admin-log`). |
## Sticky bar version (v1.3.0+)
Generated HTML shows the installed release tag (e.g. `v1.3.0`) next to the host line.
Clicking opens the tag page on Forgejo:
`https://git.hacktivism.ch/hernani/taler-monitoring/src/tag/<tag>`
Resolved via `git describe --tags` after `update-suite.sh`, with fallback to the `VERSION` file.
## Language (v1.2+) ## Language (v1.2+)
| Method | Example | | Method | Example |
@ -17,9 +28,11 @@ Release history for the standalone **taler-monitoring** suite
| Env | `TALER_MON_LANG=en` or `fr` | | Env | `TALER_MON_LANG=en` or `fr` |
| Auto | `*lefrancpaysan*` → fr, else en | | Auto | `*lefrancpaysan*` → fr, else en |
**Note:** Full locale packs (fr-CH / de-CH) for all check messages are scheduled for **v1.4.0**, not 1.3.
## Pin a release ## Pin a release
```bash ```bash
git clone https://git.hacktivism.ch/hernani/taler-monitoring.git ~/src/taler-monitoring git clone https://git.hacktivism.ch/hernani/taler-monitoring.git ~/src/taler-monitoring
cd ~/src/taler-monitoring && git checkout v1.2 cd ~/src/taler-monitoring && git checkout v1.3.0
``` ```

View file

@ -103,6 +103,23 @@ HTML_ERR_DIR="${HTML_ERR_DIR:-monitoring_err}"
HTML_URL_OK="${HTML_URL_OK:-/monitoring/}" HTML_URL_OK="${HTML_URL_OK:-/monitoring/}"
HTML_URL_ERR="${HTML_URL_ERR:-/monitoring_err/}" HTML_URL_ERR="${HTML_URL_ERR:-/monitoring_err/}"
PAGE_LABEL="${PAGE_LABEL:-monitoring}" PAGE_LABEL="${PAGE_LABEL:-monitoring}"
SUITE_VERSION="${SUITE_VERSION:-}"
SUITE_VERSION_URL="${SUITE_VERSION_URL:-}"
if [ -z "$SUITE_VERSION" ] && [ -d "${ROOT:-$AGENT_MON}/.git" ]; then
_vd="${ROOT:-$AGENT_MON}"
SUITE_VERSION=$(git -C "$_vd" describe --tags --exact-match 2>/dev/null || git -C "$_vd" describe --tags --abbrev=0 2>/dev/null || true)
fi
if [ -z "$SUITE_VERSION" ] && [ -f "${ROOT:-$AGENT_MON}/VERSION" ]; then
SUITE_VERSION="v$(tr -d '[:space:]' <"${ROOT:-$AGENT_MON}/VERSION" | sed 's/^v//')"
fi
[ -z "$SUITE_VERSION" ] && SUITE_VERSION="unknown"
case "$SUITE_VERSION" in unknown|v*) ;; *) SUITE_VERSION="v$SUITE_VERSION" ;; esac
if [ -z "$SUITE_VERSION_URL" ] && [ "$SUITE_VERSION" != "unknown" ]; then
_web="${SOURCE_REPO_WEB:-https://git.hacktivism.ch/hernani/taler-monitoring}"
SUITE_VERSION_URL="${_web}/src/tag/${SUITE_VERSION}"
fi
export SUITE_VERSION SUITE_VERSION_URL
# Sensible MON_HOSTS from domain if not set # Sensible MON_HOSTS from domain if not set
if [ -z "$MON_HOSTS" ]; then if [ -z "$MON_HOSTS" ]; then
@ -308,6 +325,8 @@ htmlify_host() {
--mode err \ --mode err \
--commit "${COMMIT:-}" \ --commit "${COMMIT:-}" \
--commit-url "${COMMIT_URL:-}" \ --commit-url "${COMMIT_URL:-}" \
--suite-version "${SUITE_VERSION:-unknown}" \
--suite-version-url "${SUITE_VERSION_URL:-}" \
--suite-path "$SUITE_PATH" \ --suite-path "$SUITE_PATH" \
--page-label "$PAGE_LABEL" \ --page-label "$PAGE_LABEL" \
--path-err "$HTML_URL_ERR" \ --path-err "$HTML_URL_ERR" \
@ -321,6 +340,8 @@ htmlify_host() {
--mode ok \ --mode ok \
--commit "${COMMIT:-}" \ --commit "${COMMIT:-}" \
--commit-url "${COMMIT_URL:-}" \ --commit-url "${COMMIT_URL:-}" \
--suite-version "${SUITE_VERSION:-unknown}" \
--suite-version-url "${SUITE_VERSION_URL:-}" \
--suite-path "$SUITE_PATH" \ --suite-path "$SUITE_PATH" \
--page-label "$PAGE_LABEL" \ --page-label "$PAGE_LABEL" \
--path-err "$HTML_URL_ERR" \ --path-err "$HTML_URL_ERR" \
@ -336,6 +357,8 @@ htmlify_host() {
--mode redirect \ --mode redirect \
--commit "${COMMIT:-}" \ --commit "${COMMIT:-}" \
--commit-url "${COMMIT_URL:-}" \ --commit-url "${COMMIT_URL:-}" \
--suite-version "${SUITE_VERSION:-unknown}" \
--suite-version-url "${SUITE_VERSION_URL:-}" \
--suite-path "$SUITE_PATH" \ --suite-path "$SUITE_PATH" \
--page-label "$PAGE_LABEL" \ --page-label "$PAGE_LABEL" \
--path-err "$HTML_URL_ERR" --path-err "$HTML_URL_ERR"

View file

@ -39,6 +39,33 @@ COMMIT_SHORT=$(git rev-parse --short=12 HEAD)
SOURCE_REPO_WEB="${SOURCE_REPO_WEB:-https://git.hacktivism.ch/hernani/taler-monitoring}" SOURCE_REPO_WEB="${SOURCE_REPO_WEB:-https://git.hacktivism.ch/hernani/taler-monitoring}"
COMMIT_URL="${SOURCE_REPO_WEB}/src/commit/${COMMIT}" COMMIT_URL="${SOURCE_REPO_WEB}/src/commit/${COMMIT}"
export COMMIT COMMIT_SHORT COMMIT_URL SOURCE_REPO_WEB export COMMIT COMMIT_SHORT COMMIT_URL SOURCE_REPO_WEB
# Release tag for sticky bar (exact tag if HEAD is tagged, else nearest)
SUITE_VERSION=""
if command -v git >/dev/null 2>&1; then
SUITE_VERSION=$(git describe --tags --exact-match 2>/dev/null || true)
if [ -z "$SUITE_VERSION" ]; then
SUITE_VERSION=$(git describe --tags --abbrev=0 2>/dev/null || true)
fi
fi
if [ -z "$SUITE_VERSION" ] && [ -f "$SUITE_DIR/VERSION" ]; then
SUITE_VERSION="v$(tr -d '[:space:]' <"$SUITE_DIR/VERSION" | sed 's/^v//')"
case "$SUITE_VERSION" in v*) ;; *) SUITE_VERSION="v${SUITE_VERSION#v}" ;; esac
fi
[ -z "$SUITE_VERSION" ] && SUITE_VERSION="unknown"
# normalize: ensure leading v for tags
case "$SUITE_VERSION" in
unknown) ;;
v*) ;;
*) SUITE_VERSION="v${SUITE_VERSION}" ;;
esac
SUITE_VERSION_URL=""
if [ -n "$SOURCE_REPO_WEB" ] && [ "$SUITE_VERSION" != "unknown" ]; then
SUITE_VERSION_URL="${SOURCE_REPO_WEB}/src/tag/${SUITE_VERSION}"
fi
export SUITE_VERSION SUITE_VERSION_URL
echo " version=$SUITE_VERSION ${SUITE_VERSION_URL:$SUITE_VERSION_URL}"
echo "suite @ $COMMIT_SHORT $COMMIT_URL" echo "suite @ $COMMIT_SHORT $COMMIT_URL"
echo " dir=$SUITE_DIR" echo " dir=$SUITE_DIR"
ln -sfn "$SUITE_DIR" "$HOME/taler-monitoring" 2>/dev/null || true ln -sfn "$SUITE_DIR" "$HOME/taler-monitoring" 2>/dev/null || true

View file

@ -32,6 +32,8 @@ def ui(lang: str, key: str, **kwargs) -> str:
"jump_first_error": "Jump to first error", "jump_first_error": "Jump to first error",
"jump_first_warn": "Jump to first warning", "jump_first_warn": "Jump to first warning",
"generated": "generated", "generated": "generated",
"version": "version",
"source": "source", "source": "source",
"what_monitors": "What this monitors", "what_monitors": "What this monitors",
"what_monitors_title": "Expand: what this page checks", "what_monitors_title": "Expand: what this page checks",
@ -83,6 +85,8 @@ def ui(lang: str, key: str, **kwargs) -> str:
"jump_first_error": "Aller à la première erreur", "jump_first_error": "Aller à la première erreur",
"jump_first_warn": "Aller au premier avertissement", "jump_first_warn": "Aller au premier avertissement",
"generated": "généré", "generated": "généré",
"version": "version",
"source": "source", "source": "source",
"what_monitors": "Ce que cette page contrôle", "what_monitors": "Ce que cette page contrôle",
"what_monitors_title": "Déplier : ce que cette page vérifie", "what_monitors_title": "Déplier : ce que cette page vérifie",
@ -412,6 +416,8 @@ def sticky_bar_html(
first_err_href: str | None, first_err_href: str | None,
first_warn_href: str | None, first_warn_href: str | None,
scope: dict[str, object] | None = None, scope: dict[str, object] | None = None,
suite_version: str = "",
suite_version_url: str = "",
) -> str: ) -> str:
level = status_level(n_err, n_warn) level = status_level(n_err, n_warn)
lang = "en" lang = "en"
@ -469,6 +475,20 @@ def sticky_bar_html(
f" · <code>{html.escape(suite_path)}</code>" if suite_path else "" f" · <code>{html.escape(suite_path)}</code>" if suite_path else ""
) )
# Version badge (linked to Forgejo tag when available)
ver = (suite_version or "").strip()
ver_url = (suite_version_url or "").strip()
if ver:
if ver_url:
version_html = (
f'<a class="version-link" href="{html.escape(ver_url)}" '
f'title="{html.escape(ui(lang, "version"))} {html.escape(ver)}" '
f'rel="noopener noreferrer">{html.escape(ver)}</a>'
)
else:
version_html = f'<span class="version-link muted">{html.escape(ver)}</span>'
else:
version_html = ""
# Compact sticky row always visible; "Was geprüft wird" expands inside sticky-bar # Compact sticky row always visible; "Was geprüft wird" expands inside sticky-bar
return f""" return f"""
<div class="sticky-bar sticky-{level}" id="status-bar" role="status" <div class="sticky-bar sticky-{level}" id="status-bar" role="status"
@ -482,6 +502,8 @@ def sticky_bar_html(
<span class="sep">·</span> <span class="sep">·</span>
{warn_stat} {warn_stat}
<span class="sep">·</span> <span class="sep">·</span>
{version_html}
<span class="sep">·</span>
<span class="generated" <span class="generated"
data-generated-iso="{html.escape(generated_iso)}" data-generated-iso="{html.escape(generated_iso)}"
title="{html.escape(generated_at)}"> title="{html.escape(generated_at)}">
@ -562,6 +584,13 @@ STICKY_CSS = """
.stat.warn { color: var(--warn); border-color: #664; background: #1a1608; } .stat.warn { color: var(--warn); border-color: #664; background: #1a1608; }
.stat.muted { opacity: 0.55; font-weight: 600; } .stat.muted { opacity: 0.55; font-weight: 600; }
a.stat:hover { text-decoration: underline; filter: brightness(1.15); } a.stat:hover { text-decoration: underline; filter: brightness(1.15); }
.version-link {
font-weight: 700; font-size: 12px; color: var(--info);
text-decoration: none; padding: 1px 8px; border-radius: 3px;
border: 1px solid #234; background: #0a1520;
}
.version-link:hover { text-decoration: underline; filter: brightness(1.15); }
.version-link.muted { opacity: 0.7; color: #8ab; }
.generated { color: var(--dim); font-size: 12px; } .generated { color: var(--dim); font-size: 12px; }
.generated time { color: #bbb; } .generated time { color: #bbb; }
.generated .age { color: #888; margin-left: 4px; } .generated .age { color: #888; margin-left: 4px; }
@ -739,6 +768,8 @@ def build_html(
generated_iso: str, generated_iso: str,
link_other: str | None, link_other: str | None,
page_label: str = "monitoring", page_label: str = "monitoring",
suite_version: str = "",
suite_version_url: str = "",
) -> str: ) -> str:
raw_lines = [strip_ansi(l).rstrip("\n") for l in log_text.splitlines()] raw_lines = [strip_ansi(l).rstrip("\n") for l in log_text.splitlines()]
while raw_lines and not raw_lines[-1].strip(): while raw_lines and not raw_lines[-1].strip():
@ -854,6 +885,8 @@ def build_html(
first_err_href=first_err_href, first_err_href=first_err_href,
first_warn_href=first_warn_href, first_warn_href=first_warn_href,
scope=scope, scope=scope,
suite_version=suite_version,
suite_version_url=suite_version_url,
) )
return f"""<!DOCTYPE html> return f"""<!DOCTYPE html>
@ -955,6 +988,8 @@ def build_redirect_html(
n_err: int = 0, n_err: int = 0,
n_warn: int = 0, n_warn: int = 0,
log_text: str = "", log_text: str = "",
suite_version: str = "",
suite_version_url: str = "",
) -> str: ) -> str:
commit_short = commit[:12] if commit else "unknown" commit_short = commit[:12] if commit else "unknown"
link = path_err if path_err.endswith("/") else path_err + "/" link = path_err if path_err.endswith("/") else path_err + "/"
@ -985,6 +1020,8 @@ def build_redirect_html(
first_err_href=link, first_err_href=link,
first_warn_href=None, first_warn_href=None,
scope=scope, scope=scope,
suite_version=suite_version,
suite_version_url=suite_version_url,
) )
return f"""<!DOCTYPE html> return f"""<!DOCTYPE html>
<html lang="{html.escape(lang if "lang" in dir() else "en")}"> <html lang="{html.escape(lang if "lang" in dir() else "en")}">
@ -1039,6 +1076,16 @@ def main() -> None:
default="/monitoring_err/", default="/monitoring_err/",
help="URL path for error page (redirect target)", help="URL path for error page (redirect target)",
) )
ap.add_argument(
"--suite-version",
default="",
help="Release tag shown in sticky bar (e.g. v1.3.0)",
)
ap.add_argument(
"--suite-version-url",
default="",
help="URL to tag on Forgejo (src/tag/...)",
)
ap.add_argument( ap.add_argument(
"--lang", "--lang",
default="", default="",
@ -1075,6 +1122,8 @@ def main() -> None:
n_err=n_err, n_err=n_err,
n_warn=n_warn, n_warn=n_warn,
log_text=log_text, log_text=log_text,
suite_version=getattr(args, "suite_version", "") or "",
suite_version_url=getattr(args, "suite_version_url", "") or "",
) )
else: else:
html_out = build_html( html_out = build_html(
@ -1089,6 +1138,8 @@ def main() -> None:
generated_iso=generated_iso, generated_iso=generated_iso,
link_other=args.link_other or None, link_other=args.link_other or None,
page_label=args.page_label, page_label=args.page_label,
suite_version=getattr(args, "suite_version", "") or "",
suite_version_url=getattr(args, "suite_version_url", "") or "",
) )
args.out.parent.mkdir(parents=True, exist_ok=True) args.out.parent.mkdir(parents=True, exist_ok=True)