From f7ff9f0a3b780cdf35734f1f6a26d92aae357235 Mon Sep 17 00:00:00 2001 From: Jeppe Bundgaard Date: Wed, 20 May 2026 18:53:41 +0200 Subject: [PATCH] Use Dockerfile builds for frontend release targets --- .../nginx/app/classes/coolify_manager.php | 23 ++++++---- .../nginx/app/classes/release_manager.php | 10 +++- .../tests/Unit/Coolify/CoolifyManagerTest.php | 46 +++++++++++++++++++ .../ReleaseManager/ReleaseManagerTest.php | 22 ++++----- 4 files changed, 78 insertions(+), 23 deletions(-) diff --git a/services/nginx/app/classes/coolify_manager.php b/services/nginx/app/classes/coolify_manager.php index e89c0931..e98db220 100644 --- a/services/nginx/app/classes/coolify_manager.php +++ b/services/nginx/app/classes/coolify_manager.php @@ -2106,13 +2106,20 @@ class coolify_manager $context['coolify_build_pack'] = 'dockerfile'; $context['coolify_dockerfile_location'] = '/Dockerfile.coolify-api'; } else { - $context['coolify_build_pack'] = $context['coolify_build_pack'] ?? 'static'; - $context['coolify_install_command'] = $context['coolify_install_command'] ?? 'npm ci'; - $context['coolify_build_command'] = $context['coolify_build_command'] ?? 'npm run build'; - $context['coolify_publish_directory'] = $context['coolify_publish_directory'] ?? 'dist'; - $context['coolify_is_static'] = true; - $context['coolify_is_spa'] = true; - unset($context['coolify_dockerfile_location'], $context['dockerfile_location']); + $context['coolify_build_pack'] = 'dockerfile'; + $context['coolify_dockerfile_location'] = '/Dockerfile.coolify-frontend'; + unset( + $context['coolify_install_command'], + $context['install_command'], + $context['coolify_build_command'], + $context['build_command'], + $context['coolify_publish_directory'], + $context['publish_directory'], + $context['coolify_is_static'], + $context['is_static'], + $context['coolify_is_spa'], + $context['is_spa'] + ); } unset( @@ -2129,7 +2136,7 @@ class coolify_manager $context['coolify_start_command'], $context['start_command'] ); - if ($app === 'api') { + if ($app === 'api' || $app === 'frontend') { unset( $context['coolify_is_static'], $context['is_static'], diff --git a/services/nginx/app/classes/release_manager.php b/services/nginx/app/classes/release_manager.php index a30efb1b..e79a8920 100644 --- a/services/nginx/app/classes/release_manager.php +++ b/services/nginx/app/classes/release_manager.php @@ -3964,12 +3964,12 @@ class release_manager $buildPack = strtolower(trim((string)($context['coolify_build_pack'] ?? $context['build_pack'] ?? ''))); if ($buildPack !== '') { if ($app === 'frontend' && $buildPack === 'nixpacks') { - return 'static'; + return 'dockerfile'; } return $buildPack; } - return $app === 'api' ? 'dockerfile' : 'static'; + return in_array($app, ['api', 'frontend'], true) ? 'dockerfile' : 'static'; } private function releaseCoolifyPortsExposes(array $target, array $context): string @@ -4063,6 +4063,12 @@ class release_manager ]; } + if ($app === 'frontend' && $buildPack === 'dockerfile') { + return [ + 'dockerfile_location' => '/Dockerfile.coolify-frontend', + ]; + } + if ($app !== 'frontend' || $buildPack !== 'static') { return []; } diff --git a/services/nginx/app/tests/Unit/Coolify/CoolifyManagerTest.php b/services/nginx/app/tests/Unit/Coolify/CoolifyManagerTest.php index 180dd145..fa546ba4 100644 --- a/services/nginx/app/tests/Unit/Coolify/CoolifyManagerTest.php +++ b/services/nginx/app/tests/Unit/Coolify/CoolifyManagerTest.php @@ -373,6 +373,52 @@ it('builds gateway API auto-provision context for connected Coolify servers', fu expect($context)->not->toHaveKey('coolify_start_command'); }); +it('builds gateway frontend auto-provision context with the release Dockerfile', function (): void { + $manager = new coolify_manager(); + $contextMethod = new ReflectionMethod(coolify_manager::class, 'gatewayRouteProvisionDeployContext'); + $contextMethod->setAccessible(true); + + $server = [ + 'uuid' => 'server-node3', + 'name' => 'node3.truckwash.io', + 'public_ip' => '23.88.23.183', + 'settings' => ['is_reachable' => true, 'is_usable' => true], + ]; + + $context = $contextMethod->invoke($manager, [ + 'id' => 43, + 'channel_slug' => 'internal', + 'app' => 'frontend', + 'deploy_context_json' => json_encode([ + 'coolify_project_uuid' => 'project-internal', + 'coolify_build_pack' => 'static', + 'coolify_install_command' => 'npm ci', + 'coolify_build_command' => 'npm run build', + 'coolify_publish_directory' => 'dist', + 'coolify_is_static' => true, + 'coolify_is_spa' => true, + ]), + ], $server, '23.88.23.183', 'api-v2.truckwash.io', 'https://api-v2.truckwash.io/internal/frontend'); + + expect($context)->toMatchArray([ + 'coolify_project_uuid' => 'project-internal', + 'coolify_build_pack' => 'dockerfile', + 'coolify_dockerfile_location' => '/Dockerfile.coolify-frontend', + 'coolify_ports_exposes' => '80', + 'coolify_port' => '80', + 'coolify_public_url' => 'https://api-v2.truckwash.io/internal/frontend', + 'coolify_server_uuid' => 'server-node3', + 'coolify_service_name' => 'release-internal-frontend-node3-truckwash-io', + 'gateway_route_autoprovision' => true, + 'gateway_route_source_target_id' => 43, + 'gateway_route_target_ip' => '23.88.23.183', + ]); + expect($context)->not->toHaveKey('coolify_install_command'); + expect($context)->not->toHaveKey('coolify_publish_directory'); + expect($context)->not->toHaveKey('coolify_is_static'); + expect($context)->not->toHaveKey('coolify_is_spa'); +}); + it('adds explicit Coolify application route labels for gateway API domains', function (): void { $payloadMethod = new ReflectionMethod(coolify_manager::class, 'gatewayRouteApplicationPayload'); $payloadMethod->setAccessible(true); diff --git a/services/nginx/app/tests/Unit/ReleaseManager/ReleaseManagerTest.php b/services/nginx/app/tests/Unit/ReleaseManager/ReleaseManagerTest.php index ae4a77c5..e8327ca7 100644 --- a/services/nginx/app/tests/Unit/ReleaseManager/ReleaseManagerTest.php +++ b/services/nginx/app/tests/Unit/ReleaseManager/ReleaseManagerTest.php @@ -158,7 +158,7 @@ it('supports isolated stack mode and names new Coolify services explicitly', fun expect(base64_decode($payload['docker_compose_raw'], true))->toContain('ghcr.io/copenhagentruckwash/front-end-vue:main'); }); -it('creates Coolify GitHub App application payloads so pulls use the app token', function (): void { +it('creates frontend Coolify GitHub App application payloads with the release Dockerfile', function (): void { $manager = new release_manager(); $payloadMethod = new ReflectionMethod(release_manager::class, 'releaseCoolifyApplicationPayload'); $payloadMethod->setAccessible(true); @@ -189,14 +189,12 @@ it('creates Coolify GitHub App application payloads so pulls use the app token', expect($payload['github_app_uuid'])->toBe('github-app-copenhagentruckwash-github'); expect($payload['git_repository'])->toBe('copenhagentruckwash/pleno-vue'); expect($payload['git_branch'])->toBe('release/canary'); - expect($payload['build_pack'])->toBe('static'); + expect($payload['build_pack'])->toBe('dockerfile'); expect($payload['ports_exposes'])->toBe('80'); - expect($payload['install_command'])->toBe('npm ci'); - expect($payload['build_command'])->toBe('npm run build'); - expect($payload['publish_directory'])->toBe('dist'); - expect($payload['is_static'])->toBeTrue(); - expect($payload['is_spa'])->toBeTrue(); + expect($payload['dockerfile_location'])->toBe('/Dockerfile.coolify-frontend'); expect($payload['domains'])->toBe('https://canary.example.test/canary/frontend'); + expect($payload)->not->toHaveKey('publish_directory'); + expect($payload)->not->toHaveKey('is_static'); expect($payload)->not->toHaveKey('docker_compose_raw'); }); @@ -275,13 +273,11 @@ it('updates existing frontend Coolify applications away from legacy Nixpacks det expect($payload['git_repository'])->toBe('copenhagentruckwash/pleno-vue'); expect($payload['git_branch'])->toBe('master'); expect($payload['git_commit_sha'])->toBe('1132c8c2560e44478d1bb777c88c762a5e1d0b20'); - expect($payload['build_pack'])->toBe('static'); + expect($payload['build_pack'])->toBe('dockerfile'); expect($payload['ports_exposes'])->toBe('80'); - expect($payload['install_command'])->toBe('npm ci'); - expect($payload['build_command'])->toBe('npm run build'); - expect($payload['publish_directory'])->toBe('dist'); - expect($payload['is_static'])->toBeTrue(); - expect($payload['is_spa'])->toBeTrue(); + expect($payload['dockerfile_location'])->toBe('/Dockerfile.coolify-frontend'); + expect($payload)->not->toHaveKey('publish_directory'); + expect($payload)->not->toHaveKey('is_static'); }); it('can use the Coolify instance default GitHub App when source targets do not store it yet', function (): void {