From 81a9e4d641a24196ae2164290550198ac5dae376 Mon Sep 17 00:00:00 2001 From: boban Date: Fri, 19 Jun 2026 18:35:35 +0200 Subject: [PATCH] fix(versions): show build commit + branch in production MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Version page read the deployed commit/branch from .git at runtime, which the prod Docker image does not contain — so it showed 'Build —' and the channel as the branch. install.sh now bakes the host's git short-SHA and branch into .env (CLUSEV_BUILD_SHA / CLUSEV_BUILD_BRANCH); the page prefers those and keeps the live .git read as the dev fallback. Co-Authored-By: Claude Opus 4.8 (1M context) --- .env.example | 4 ++++ CHANGELOG.md | 10 ++++++++++ app/Livewire/Versions/Index.php | 12 +++++++++++- config/clusev.php | 13 ++++++++++--- install.sh | 6 ++++++ tests/Feature/VersionUpdateCheckTest.php | 12 ++++++++++++ 6 files changed, 53 insertions(+), 4 deletions(-) diff --git a/.env.example b/.env.example index 0d13858..c89bd30 100644 --- a/.env.example +++ b/.env.example @@ -81,6 +81,10 @@ IMAGE_TAG=latest APP_DOMAIN= APP_SCHEME=http ACME_EMAIL= +# Deployed commit + branch, shown on the Version page. install.sh fills these from the host's +# .git (the prod image ships none) — leave empty; in dev the page reads .git directly. +CLUSEV_BUILD_SHA= +CLUSEV_BUILD_BRANCH= # External reverse-proxy TLS: set to the upstream proxy's address/CIDR so Caddy trusts its # X-Forwarded-Proto. Leave as 127.0.0.1/32 (trust nothing) when Caddy terminates TLS itself. TRUSTED_PROXY_CIDR=127.0.0.1/32 diff --git a/CHANGELOG.md b/CHANGELOG.md index 4b40799..81f587c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,16 @@ 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.10] - 2026-06-19 + +### Behoben +- **Build-Commit & Branch werden jetzt auch in Produktion angezeigt** (System → Version & Releases, + Karte „Installiert"). Sie wurden zur Laufzeit aus `.git` gelesen — das im Docker-Prod-Image + fehlt — also stand dort „Build —" und als Branch der Kanal. `install.sh` bäckt den deployten + Commit (`git rev-parse --short HEAD`) und Branch jetzt aus dem `.git` des Hosts in die `.env` + (`CLUSEV_BUILD_SHA`/`CLUSEV_BUILD_BRANCH`); die Versions-Seite bevorzugt diese und liest im Dev + weiterhin direkt aus `.git`. + ## [0.9.9] - 2026-06-19 ### Hinzugefügt diff --git a/app/Livewire/Versions/Index.php b/app/Livewire/Versions/Index.php index 5e30d7d..4fd99ee 100644 --- a/app/Livewire/Versions/Index.php +++ b/app/Livewire/Versions/Index.php @@ -245,9 +245,19 @@ class Index extends Component return version_compare(ltrim($tag, 'vV'), ltrim($installed, 'vV'), '>'); } - /** Resolve the current commit from .git without needing the git binary. */ + /** + * Resolve the deployed commit + branch. In production this comes from config (install.sh + * baked it into .env from the host's .git — the prod image ships none); in dev it falls back + * to a live .git read. Branch defaults to the channel only when nothing is known. + */ private function build(): array { + $sha = config('clusev.build.sha'); + $branch = config('clusev.build.branch'); + if ($sha || $branch) { + return ['sha' => $sha, 'branch' => $branch ?: $this->channel()]; + } + $root = base_path('.git'); $head = @file_get_contents($root.'/HEAD'); diff --git a/config/clusev.php b/config/clusev.php index 0c829c9..9fe09a9 100644 --- a/config/clusev.php +++ b/config/clusev.php @@ -1,9 +1,16 @@ '0.9.9', + // First tagged release is v0.1.0 (semantic, not -dev). + 'version' => '0.9.10', + + // 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 + // dev. Empty in dev (no install.sh run) → the .git fallback fills them in. + 'build' => [ + 'sha' => env('CLUSEV_BUILD_SHA') ?: null, + 'branch' => env('CLUSEV_BUILD_BRANCH') ?: null, + ], // Default user channel. Only 'stable' and 'beta' are ever offered to users. 'channel' => 'stable', diff --git a/install.sh b/install.sh index 24430df..553f0f6 100755 --- a/install.sh +++ b/install.sh @@ -208,6 +208,12 @@ if [ -n "$DOMAIN" ]; then force_kv SESSION_SECURE_COOKIE true; else force_kv SES # Containers run as the dedicated clusev user (it owns the install dir + ./run). force_kv HOST_UID "$(id -u clusev)" force_kv HOST_GID "$(id -g clusev)" +# Bake the deployed commit + branch into .env so the dashboard's Version page can show them in +# production. The prod image ships NO .git (dockerignored), so a runtime .git read is impossible +# there; we capture it here on the HOST (where .git exists) and config:cache freezes it later. +git config --global --add safe.directory "$(pwd)" 2>/dev/null || true +force_kv CLUSEV_BUILD_SHA "$(git rev-parse --short=7 HEAD 2>/dev/null || true)" +force_kv CLUSEV_BUILD_BRANCH "$(git rev-parse --abbrev-ref HEAD 2>/dev/null || true)" info "Secrets ok; Proxy/URL aus APP_DOMAIN abgeleitet" # ── [4/9] image ────────────────────────────────────────────────────── diff --git a/tests/Feature/VersionUpdateCheckTest.php b/tests/Feature/VersionUpdateCheckTest.php index 1795577..5de1818 100644 --- a/tests/Feature/VersionUpdateCheckTest.php +++ b/tests/Feature/VersionUpdateCheckTest.php @@ -127,6 +127,18 @@ class VersionUpdateCheckTest extends TestCase ); } + 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). + config()->set('clusev.build.sha', 'abc1234'); + config()->set('clusev.build.branch', 'feat/v1-foundation'); + + Livewire::test(Index::class) + ->assertViewHas('build', ['sha' => 'abc1234', 'branch' => 'feat/v1-foundation']) + ->assertSee('abc1234') + ->assertSee('feat/v1-foundation'); + } + public function test_request_update_is_throttled_per_user(): void { config()->set('clusev.version', '0.9.4');