From deea1a802ced72f59c4067f13aae7c491221ed96 Mon Sep 17 00:00:00 2001 From: boban Date: Fri, 19 Jun 2026 18:43:46 +0200 Subject: [PATCH] fix(versions): never show a 'latest release' older than the installed version A stale 30-minute update-check cache could render a latest tag below the installed version right after an update (e.g. 'latest v0.9.9' next to 'installed v0.9.10'), which reads backwards. The passive display now discards a cached value lower than the installed version until a fresh check resolves it. Co-Authored-By: Claude Opus 4.8 (1M context) --- CHANGELOG.md | 9 +++++++++ app/Livewire/Versions/Index.php | 6 ++++++ config/clusev.php | 2 +- tests/Feature/VersionUpdateCheckTest.php | 10 ++++++++++ 4 files changed, 26 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 81f587c..697e026 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,15 @@ getaggte Releases (Kanal `stable`, optional `beta`) — niemals Entwicklungs-Bui _Keine offenen Änderungen — der nächste Stand wird hier gesammelt und als `vX.Y.Z` getaggt._ +## [0.9.11] - 2026-06-19 + +### Behoben +- **„Neuestes Release" zeigt nie mehr eine ältere Version als die installierte.** Direkt nach einem + Update konnte der 30-Minuten-Cache der Update-Prüfung noch den vorherigen Stand halten, sodass die + Karte „Installiert" z. B. „Neuestes Release v0.9.9" neben „installiert v0.9.10" zeigte (wirkte + rückwärts). Ist der gecachte Wert kleiner als die installierte Version, wird er jetzt verworfen + (Anzeige „—"), bis „Nach Updates suchen" den echten neuesten Tag auflöst. + ## [0.9.10] - 2026-06-19 ### Behoben diff --git a/app/Livewire/Versions/Index.php b/app/Livewire/Versions/Index.php index 4fd99ee..285162a 100644 --- a/app/Livewire/Versions/Index.php +++ b/app/Livewire/Versions/Index.php @@ -365,6 +365,12 @@ class Index extends Component $releases = $this->releases(); // Passive (no network): cached remote result if a check has run, else local .git. $latestTag = $this->resolveLatestTag($this->channel()); + // A stale cache can hold a "latest" older than what's now installed (e.g. right after an + // update, before the next check). Never present yourself as behind a release you've + // already passed — hide it until a fresh check resolves the true latest. + if ($latestTag !== null && version_compare(ltrim($latestTag, 'vV'), ltrim((string) config('clusev.version'), 'vV'), '<')) { + $latestTag = null; + } return view('livewire.versions.index', [ 'version' => config('clusev.version'), diff --git a/config/clusev.php b/config/clusev.php index 9fe09a9..61f5ebb 100644 --- a/config/clusev.php +++ b/config/clusev.php @@ -2,7 +2,7 @@ return [ // First tagged release is v0.1.0 (semantic, not -dev). - 'version' => '0.9.10', + 'version' => '0.9.11', // Deployed commit + branch. install.sh bakes these into .env from the host's .git (the prod // image ships no .git); the Versions page prefers them and falls back to a live .git read in diff --git a/tests/Feature/VersionUpdateCheckTest.php b/tests/Feature/VersionUpdateCheckTest.php index 5de1818..31f576c 100644 --- a/tests/Feature/VersionUpdateCheckTest.php +++ b/tests/Feature/VersionUpdateCheckTest.php @@ -127,6 +127,16 @@ class VersionUpdateCheckTest extends TestCase ); } + public function test_passive_latest_release_never_shows_older_than_installed(): void + { + // A stale cache from before an update must not render a "latest" below the installed + // version (which would look like the panel is behind a release it has already passed). + config()->set('clusev.version', '0.9.10'); + Cache::put('clusev:latest-release:stable', '0.9.9', now()->addMinutes(30)); + + Livewire::test(Index::class)->assertViewHas('latestTag', null); + } + public function test_build_info_prefers_the_baked_config_over_a_git_read(): void { // Production bakes sha/branch into config via .env (no .git in the image).