From 3e8eff5f21ba418d34b5dbb83c0c9a18559af1e4 Mon Sep 17 00:00:00 2001 From: Elmehdi Aitbrahim Date: Fri, 7 Aug 2026 17:31:36 -0400 Subject: [PATCH] feat(tui): show the patch segment in the dashboard header The header rendered `keel v0.5` for 0.5.0, 0.5.1 and 0.5.2 alike, so it could not answer the question an operator actually asks it: is this box running the build I just shipped, or the one before it? It now renders `keel v0.5.2`. The load-bearing detail is that build metadata rides on the PATCH segment. A released version is `0.5.2+79f35b9e73d5`, so `parts[2]` is `2+79f35b9e73d5` and a naive `.isdigit()` check is False -- meaning the patch would have silently vanished on precisely the shape a release build emits, i.e. the common case rather than an edge case. The patch is split on `+` and the numeric head kept. Two other degradations, each keeping the most it can vouch for rather than falling all the way back to `v?`: a version with no patch segment (`2.0`) renders `v2.0` rather than inventing a `.0` it never claimed, and a non-numeric patch (`0.5.2rc1`) renders `v0.5` rather than discarding the two segments that did parse. `v?` remains reserved for an unparseable major/minor. Co-Authored-By: Claude Opus 5 (1M context) --- keel/commands/tui.py | 32 +++++++++++++++++++++++++++----- tests/commands/test_tui.py | 15 ++++++++++++--- 2 files changed, 39 insertions(+), 8 deletions(-) diff --git a/keel/commands/tui.py b/keel/commands/tui.py index 306cb841..dd65708b 100644 --- a/keel/commands/tui.py +++ b/keel/commands/tui.py @@ -136,12 +136,34 @@ def _human_dt(ts: int) -> str: def _short_version(raw: str) -> str: - """`v.` from a full version string (`0.1.0` -> `v0.1`). Falls back to `v?` for an - unknown or unparseable version, so the header never shows a bare `unknown` or raises.""" + """`v..` from a full version string (`0.5.2` -> `v0.5.2`). + + The patch segment is shown because major.minor alone cannot tell two deployments apart: every + release in the 0.5 line rendered as `v0.5`, so an operator glancing at the header could not + see whether the box was running the build they just shipped or the one before it. + + Three degradations, each preferring the most information it can still vouch for: + + * **Build metadata is stripped from the patch.** A release version is `0.5.2+79f35b9e73d5`, so + `parts[2]` is `2+79f35b9e73d5` -- not a digit. Taking it verbatim would print the whole + commit hash into a header line budgeted for a version; rejecting it would drop the patch on + precisely the shape a released build emits. Split on `+` and keep the numeric head. + * **No patch segment** (`2.0`) -> `v2.0`. Show what exists rather than inventing a `.0` the + version string never claimed. + * **A non-numeric patch** (`0.5.2rc1`) -> `v0.5`. Falling all the way back to `v?` would throw + away the two segments that did parse. + + Falls back to `v?` only when major/minor themselves are unparseable, so the header never shows + a bare `unknown` and never raises. + """ parts = raw.split(".") - if len(parts) >= 2 and parts[0].isdigit() and parts[1].isdigit(): - return f"v{parts[0]}.{parts[1]}" - return "v?" + if len(parts) < 2 or not parts[0].isdigit() or not parts[1].isdigit(): + return "v?" + head = f"v{parts[0]}.{parts[1]}" + if len(parts) < 3: + return head + patch = parts[2].split("+", 1)[0] + return f"{head}.{patch}" if patch.isdigit() else head #: The short header version, resolved ONCE at import (it never changes within a run). Uses the diff --git a/tests/commands/test_tui.py b/tests/commands/test_tui.py index 75c00ee1..b0585b0f 100644 --- a/tests/commands/test_tui.py +++ b/tests/commands/test_tui.py @@ -424,10 +424,19 @@ def test_build_screen_title_shows_version_and_mode_without_datetime() -> None: @pytest.mark.parametrize( "raw,expected", [ - ("0.1.0", "v0.1"), - ("0.2.5", "v0.2"), + ("0.1.0", "v0.1.0"), + ("0.2.5", "v0.2.5"), + ("0.5.2", "v0.5.2"), + # Build metadata rides on the PATCH segment (`0.5.2+79f35b9e73d5`), so a naive + # `parts[2].isdigit()` is False and the patch would silently vanish -- which is exactly + # the shape `keel --version` emits, i.e. the common case, not the edge case. + ("10.34.1+abc", "v10.34.1"), + ("0.5.2+79f35b9e73d5", "v0.5.2"), + # No patch segment at all: show what exists rather than inventing a `.0`. ("2.0", "v2.0"), - ("10.34.1+abc", "v10.34"), + # A non-numeric patch (pre-release) degrades to major.minor -- still useful -- rather + # than to `v?`, which would throw away the two segments we did parse. + ("0.5.2rc1", "v0.5"), ("unknown", "v?"), ("1", "v?"), ("", "v?"),