From dbd2b68a08f2b7a782381491dc9ca77e8a2b87fc Mon Sep 17 00:00:00 2001 From: Andras Bacsai <5845193+andrasbacsai@users.noreply.github.com> Date: Thu, 9 Apr 2026 14:31:12 +0200 Subject: [PATCH] fix(upgrade): clear stale upgrade flag when version is already current Refactor upgrade state initialization into a shared `refreshUpgradeState()` method used by both `mount()` and `checkUpdate()`. The method now uses `version_compare` to validate upgrade availability and clears the `new_version_available` flag in InstanceSettings when the current version is already equal to or newer than the latest version, preventing stale upgrade notifications from persisting after a successful update. --- app/Livewire/Upgrade.php | 35 ++++++++++---- tests/Feature/UpgradeComponentTest.php | 65 +++++++++++++++++++++++++- 2 files changed, 90 insertions(+), 10 deletions(-) diff --git a/app/Livewire/Upgrade.php b/app/Livewire/Upgrade.php index 25cedc71b..1b8701d94 100644 --- a/app/Livewire/Upgrade.php +++ b/app/Livewire/Upgrade.php @@ -23,25 +23,42 @@ class Upgrade extends Component public function mount() { - $this->currentVersion = config('constants.coolify.version'); - $this->latestVersion = get_latest_version_of_coolify(); - $this->devMode = isDev(); + $this->refreshUpgradeState(); } public function checkUpdate() { try { - $this->latestVersion = get_latest_version_of_coolify(); - $this->currentVersion = config('constants.coolify.version'); - $this->isUpgradeAvailable = data_get(InstanceSettings::get(), 'new_version_available', false); - if (isDev()) { - $this->isUpgradeAvailable = true; - } + $this->refreshUpgradeState(); } catch (\Throwable $e) { return handleError($e, $this); } } + protected function refreshUpgradeState(): void + { + $this->currentVersion = config('constants.coolify.version'); + $this->latestVersion = get_latest_version_of_coolify(); + $this->devMode = isDev(); + + if ($this->devMode) { + $this->isUpgradeAvailable = true; + + return; + } + + $settings = InstanceSettings::find(0); + $hasNewerVersion = version_compare($this->latestVersion, $this->currentVersion, '>'); + $newVersionAvailable = (bool) data_get($settings, 'new_version_available', false); + + if ($settings && $newVersionAvailable && ! $hasNewerVersion) { + $settings->update(['new_version_available' => false]); + $newVersionAvailable = false; + } + + $this->isUpgradeAvailable = $hasNewerVersion && $newVersionAvailable; + } + public function upgrade() { try { diff --git a/tests/Feature/UpgradeComponentTest.php b/tests/Feature/UpgradeComponentTest.php index 612e989ae..896e0fa3b 100644 --- a/tests/Feature/UpgradeComponentTest.php +++ b/tests/Feature/UpgradeComponentTest.php @@ -1,11 +1,19 @@ '4.0.0-beta.998']); + InstanceSettings::create([ + 'id' => 0, + 'new_version_available' => true, + ]); Cache::shouldReceive('remember') ->once() @@ -21,12 +29,17 @@ Livewire::test(Upgrade::class) ->assertSet('currentVersion', '4.0.0-beta.998') ->assertSet('latestVersion', '4.0.0-beta.999') - ->set('isUpgradeAvailable', true) + ->assertSet('isUpgradeAvailable', true) ->assertSee('4.0.0-beta.998') ->assertSee('4.0.0-beta.999'); }); it('falls back to 0.0.0 during mount when cached versions data is unavailable', function () { + InstanceSettings::create([ + 'id' => 0, + 'new_version_available' => false, + ]); + Cache::shouldReceive('remember') ->once() ->with('coolify:versions:all', 3600, Mockery::type(\Closure::class)) @@ -35,3 +48,53 @@ Livewire::test(Upgrade::class) ->assertSet('latestVersion', '0.0.0'); }); + +it('clears stale upgrade availability when current version already matches latest version', function () { + config(['constants.coolify.version' => '4.0.0-beta.999']); + InstanceSettings::create([ + 'id' => 0, + 'new_version_available' => true, + ]); + + Cache::shouldReceive('remember') + ->once() + ->with('coolify:versions:all', 3600, Mockery::type(\Closure::class)) + ->andReturn([ + 'coolify' => [ + 'v4' => [ + 'version' => '4.0.0-beta.999', + ], + ], + ]); + + Livewire::test(Upgrade::class) + ->assertSet('latestVersion', '4.0.0-beta.999') + ->assertSet('isUpgradeAvailable', false); + + expect(InstanceSettings::findOrFail(0)->new_version_available)->toBeFalse(); +}); + +it('clears stale upgrade availability when current version is newer than cached latest version', function () { + config(['constants.coolify.version' => '4.0.0-beta.1000']); + InstanceSettings::create([ + 'id' => 0, + 'new_version_available' => true, + ]); + + Cache::shouldReceive('remember') + ->once() + ->with('coolify:versions:all', 3600, Mockery::type(\Closure::class)) + ->andReturn([ + 'coolify' => [ + 'v4' => [ + 'version' => '4.0.0-beta.999', + ], + ], + ]); + + Livewire::test(Upgrade::class) + ->assertSet('latestVersion', '4.0.0-beta.999') + ->assertSet('isUpgradeAvailable', false); + + expect(InstanceSettings::findOrFail(0)->new_version_available)->toBeFalse(); +});