diff --git a/bootstrap/helpers/constants.php b/bootstrap/helpers/constants.php index 178876b89..9196f9fb8 100644 --- a/bootstrap/helpers/constants.php +++ b/bootstrap/helpers/constants.php @@ -48,6 +48,8 @@ const DATABASE_DOCKER_IMAGES = [ 'influxdb', 'clickhouse/clickhouse-server', 'timescaledb/timescaledb', + 'timescaledb', // Matches timescale/timescaledb + 'timescaledb-ha', // Matches timescale/timescaledb-ha 'pgvector/pgvector', ]; const SPECIFIC_SERVICES = [ diff --git a/bootstrap/helpers/docker.php b/bootstrap/helpers/docker.php index f6d69ef60..759d345b0 100644 --- a/bootstrap/helpers/docker.php +++ b/bootstrap/helpers/docker.php @@ -770,10 +770,26 @@ function isDatabaseImage(?string $image = null, ?array $serviceConfig = null) } $imageName = $image->before(':'); - // First check if it's a known database image + // Extract base image name (ignore registry prefix) + // Examples: + // docker.io/library/postgres -> postgres + // ghcr.io/postgrest/postgrest -> postgrest + // postgres -> postgres + // postgrest/postgrest -> postgrest + $baseImageName = $imageName; + if (str($imageName)->contains('/')) { + $baseImageName = str($imageName)->afterLast('/'); + } + + // Check if base image name exactly matches a known database image $isKnownDatabase = false; foreach (DATABASE_DOCKER_IMAGES as $database_docker_image) { - if (str($imageName)->contains($database_docker_image)) { + // Extract base name from database pattern for comparison + $databaseBaseName = str($database_docker_image)->contains('/') + ? str($database_docker_image)->afterLast('/') + : $database_docker_image; + + if ($baseImageName == $databaseBaseName) { $isKnownDatabase = true; break; } diff --git a/resources/views/livewire/project/service/configuration.blade.php b/resources/views/livewire/project/service/configuration.blade.php index 9b81e4bec..7379ca706 100644 --- a/resources/views/livewire/project/service/configuration.blade.php +++ b/resources/views/livewire/project/service/configuration.blade.php @@ -37,6 +37,16 @@

Services

+ @if($applications->isEmpty() && $databases->isEmpty()) +
+ No services defined in this Docker Compose file. +
+ @elseif($applications->isEmpty()) +
+ No applications with domains defined. Only database services are available. +
+ @endif + @foreach ($applications as $application)
str( diff --git a/tests/Unit/PostgRESTDetectionTest.php b/tests/Unit/PostgRESTDetectionTest.php new file mode 100644 index 000000000..edf3b203f --- /dev/null +++ b/tests/Unit/PostgRESTDetectionTest.php @@ -0,0 +1,73 @@ +toBeFalse(); +}); + +test('postgrest image with version is detected as application', function () { + $result = isDatabaseImage('postgrest/postgrest:v12.0.2'); + expect($result)->toBeFalse(); +}); + +test('postgrest with registry prefix is detected as application', function () { + $result = isDatabaseImage('ghcr.io/postgrest/postgrest:latest'); + expect($result)->toBeFalse(); +}); + +test('regular postgres image is still detected as database', function () { + $result = isDatabaseImage('postgres:15'); + expect($result)->toBeTrue(); +}); + +test('postgres with registry prefix is detected as database', function () { + $result = isDatabaseImage('docker.io/library/postgres:15'); + expect($result)->toBeTrue(); +}); + +test('postgres image with service config is detected correctly', function () { + $serviceConfig = [ + 'image' => 'postgres:15', + 'environment' => [ + 'POSTGRES_PASSWORD=secret', + ], + ]; + + $result = isDatabaseImage('postgres:15', $serviceConfig); + expect($result)->toBeTrue(); +}); + +test('postgrest without service config is still detected as application', function () { + $result = isDatabaseImage('postgrest/postgrest', null); + expect($result)->toBeFalse(); +}); + +test('supabase postgres-meta is detected as application', function () { + $result = isDatabaseImage('supabase/postgres-meta:latest'); + expect($result)->toBeFalse(); +}); + +test('mysql image is detected as database', function () { + $result = isDatabaseImage('mysql:8.0'); + expect($result)->toBeTrue(); +}); + +test('redis image is detected as database', function () { + $result = isDatabaseImage('redis:7'); + expect($result)->toBeTrue(); +}); + +test('timescale timescaledb is detected as database', function () { + $result = isDatabaseImage('timescale/timescaledb:latest'); + expect($result)->toBeTrue(); +}); + +test('mariadb is detected as database', function () { + $result = isDatabaseImage('mariadb:10.11'); + expect($result)->toBeTrue(); +}); + +test('mongodb is detected as database', function () { + $result = isDatabaseImage('mongo:7'); + expect($result)->toBeTrue(); +});