mirror of
https://github.com/coollabsio/coolify.git
synced 2026-06-13 19:09:50 +00:00
fix(service): defer stop when pulling latest images
Ensure restart actions flow through StartService so pull-latest restarts can avoid stopping the service before image pulls. Also raise the changelog modal above the desktop sidebar toggle.
This commit is contained in:
@@ -13,8 +13,10 @@ class RestartService
|
||||
|
||||
public function handle(Service $service, bool $pullLatestImages)
|
||||
{
|
||||
StopService::run($service);
|
||||
|
||||
return StartService::run($service, $pullLatestImages);
|
||||
return StartService::run(
|
||||
service: $service,
|
||||
pullLatestImages: $pullLatestImages,
|
||||
stopBeforeStart: true,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ class StartService
|
||||
public function handle(Service $service, bool $pullLatestImages = false, bool $stopBeforeStart = false)
|
||||
{
|
||||
$service->parse();
|
||||
if ($stopBeforeStart) {
|
||||
if ($this->shouldStopBeforeStarting($pullLatestImages, $stopBeforeStart)) {
|
||||
StopService::run(service: $service, dockerCleanup: false);
|
||||
}
|
||||
$service->saveComposeConfigs();
|
||||
@@ -53,4 +53,9 @@ class StartService
|
||||
|
||||
return remote_process($commands, $service->server, type_uuid: $service->uuid, callEventOnFinish: 'ServiceStatusChanged');
|
||||
}
|
||||
|
||||
private function shouldStopBeforeStarting(bool $pullLatestImages, bool $stopBeforeStart): bool
|
||||
{
|
||||
return $stopBeforeStart && ! $pullLatestImages;
|
||||
}
|
||||
}
|
||||
|
||||
Generated
+2
-6
@@ -1261,8 +1261,7 @@
|
||||
"version": "5.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@xterm/xterm/-/xterm-5.5.0.tgz",
|
||||
"integrity": "sha512-hqJHYaQb5OptNunnyAnkHyM8aCjZ1MEIDTQu1iIbbTD/xops91NB5yq1ZK/dC2JDbVWtF23zUtl9JE2NqwT87A==",
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/clsx": {
|
||||
"version": "2.1.1",
|
||||
@@ -1752,7 +1751,6 @@
|
||||
"integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
@@ -1946,8 +1944,7 @@
|
||||
"version": "4.1.18",
|
||||
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.18.tgz",
|
||||
"integrity": "sha512-4+Z+0yiYyEtUVCScyfHCxOYP06L5Ne+JiHhY2IjR2KWMIWhJOYZKLSGZaP5HkZ8+bY0cxfzwDE5uOmzFXyIwxw==",
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/tapable": {
|
||||
"version": "2.3.0",
|
||||
@@ -1992,7 +1989,6 @@
|
||||
"integrity": "sha512-Bby3NOsna2jsjfLVOHKes8sGwgl4TT0E6vvpYgnAYDIF/tie7MRaFthmKuHx1NSXjiTueXH3do80FMQgvEktRg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"esbuild": "^0.27.0",
|
||||
"fdir": "^6.5.0",
|
||||
|
||||
@@ -198,7 +198,7 @@
|
||||
|
||||
<!-- What's New Modal -->
|
||||
@if ($showWhatsNewModal)
|
||||
<div class="fixed inset-0 z-50 flex items-center justify-center py-6 px-4"
|
||||
<div class="fixed inset-0 z-[60] flex items-center justify-center py-6 px-4"
|
||||
@keydown.escape.window="$wire.closeWhatsNewModal()">
|
||||
<!-- Background overlay -->
|
||||
<div class="absolute inset-0 w-full h-full bg-black/20 backdrop-blur-xs" wire:click="closeWhatsNewModal">
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
use App\Livewire\SettingsDropdown;
|
||||
use App\Models\User;
|
||||
use App\Services\ChangelogService;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Livewire\Livewire;
|
||||
|
||||
it('renders the changelog modal above the desktop sidebar toggle', function () {
|
||||
$user = new User(['email' => 'test@example.com']);
|
||||
$user->id = 1;
|
||||
|
||||
Auth::setUser($user);
|
||||
|
||||
app()->instance(ChangelogService::class, new class extends ChangelogService
|
||||
{
|
||||
public function getEntriesForUser(User $user): Collection
|
||||
{
|
||||
return collect([
|
||||
(object) [
|
||||
'tag_name' => 'v1.0.0',
|
||||
'title' => 'Test Release',
|
||||
'content' => 'Release notes',
|
||||
'content_html' => '<p>Release notes</p>',
|
||||
'published_at' => Carbon::parse('2026-05-01'),
|
||||
'is_read' => false,
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
public function getUnreadCountForUser(User $user): int
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
});
|
||||
|
||||
Livewire::test(SettingsDropdown::class, ['trigger' => 'changelog-sidebar'])
|
||||
->call('openWhatsNewModal')
|
||||
->assertSee('Changelog')
|
||||
->assertSee('z-[60]', false)
|
||||
->assertSee('closeWhatsNewModal', false);
|
||||
});
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
use App\Actions\Service\RestartService;
|
||||
use App\Actions\Service\StartService;
|
||||
use App\Actions\Service\StopService;
|
||||
use App\Models\Service;
|
||||
|
||||
it('does not stop a service before pulling latest images', function () {
|
||||
$method = new ReflectionMethod(StartService::class, 'shouldStopBeforeStarting');
|
||||
|
||||
expect($method->invoke(new StartService, pullLatestImages: true, stopBeforeStart: true))->toBeFalse();
|
||||
});
|
||||
|
||||
it('still stops a service before a regular restart', function () {
|
||||
$method = new ReflectionMethod(StartService::class, 'shouldStopBeforeStarting');
|
||||
|
||||
expect($method->invoke(new StartService, pullLatestImages: false, stopBeforeStart: true))->toBeTrue()
|
||||
->and($method->invoke(new StartService, pullLatestImages: false, stopBeforeStart: false))->toBeFalse();
|
||||
});
|
||||
|
||||
it('routes service restart actions through start service with deferred stop semantics', function () {
|
||||
$service = Mockery::mock(Service::class);
|
||||
|
||||
$stopService = Mockery::mock(StopService::class);
|
||||
$stopService->shouldNotReceive('handle');
|
||||
app()->instance(StopService::class, $stopService);
|
||||
|
||||
$startService = Mockery::mock(StartService::class);
|
||||
$startService->shouldReceive('handle')
|
||||
->once()
|
||||
->with($service, true, true)
|
||||
->andReturn('restart queued');
|
||||
app()->instance(StartService::class, $startService);
|
||||
|
||||
expect(RestartService::run($service, true))->toBe('restart queued');
|
||||
});
|
||||
Reference in New Issue
Block a user