Merge branch 'next' into 8035-public-port-stays-open

This commit is contained in:
Andras Bacsai
2026-02-09 10:00:06 +01:00
committed by GitHub
39 changed files with 945 additions and 921 deletions

View File

@@ -1208,7 +1208,7 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
}
$services = data_get($dockerCompose, 'services', []);
foreach ($services as $serviceName => $_) {
$envs->push('SERVICE_NAME_'.str($serviceName)->upper().'='.$serviceName);
$envs->push('SERVICE_NAME_'.str($serviceName)->replace('-', '_')->replace('.', '_')->upper().'='.$serviceName);
}
}
@@ -1265,8 +1265,8 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
$coolifyScheme = $coolifyUrl->getScheme();
$coolifyFqdn = $coolifyUrl->getHost();
$coolifyUrl = $coolifyUrl->withScheme($coolifyScheme)->withHost($coolifyFqdn)->withPort(null);
$envs->push('SERVICE_URL_'.str($forServiceName)->upper().'='.$coolifyUrl->__toString());
$envs->push('SERVICE_FQDN_'.str($forServiceName)->upper().'='.$coolifyFqdn);
$envs->push('SERVICE_URL_'.str($forServiceName)->replace('-', '_')->replace('.', '_')->upper().'='.$coolifyUrl->__toString());
$envs->push('SERVICE_FQDN_'.str($forServiceName)->replace('-', '_')->replace('.', '_')->upper().'='.$coolifyFqdn);
}
}
@@ -1274,7 +1274,7 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
$rawDockerCompose = Yaml::parse($this->application->docker_compose_raw);
$rawServices = data_get($rawDockerCompose, 'services', []);
foreach ($rawServices as $rawServiceName => $_) {
$envs->push('SERVICE_NAME_'.str($rawServiceName)->upper().'='.addPreviewDeploymentSuffix($rawServiceName, $this->pull_request_id));
$envs->push('SERVICE_NAME_'.str($rawServiceName)->replace('-', '_')->replace('.', '_')->upper().'='.addPreviewDeploymentSuffix($rawServiceName, $this->pull_request_id));
}
}
@@ -1476,7 +1476,7 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
}
$services = data_get($dockerCompose, 'services', []);
foreach ($services as $serviceName => $_) {
$envs_dict['SERVICE_NAME_'.str($serviceName)->upper()] = escapeBashEnvValue($serviceName);
$envs_dict['SERVICE_NAME_'.str($serviceName)->replace('-', '_')->replace('.', '_')->upper()] = escapeBashEnvValue($serviceName);
}
// Generate SERVICE_FQDN & SERVICE_URL for non-PR deployments
@@ -1489,8 +1489,8 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
$coolifyScheme = $coolifyUrl->getScheme();
$coolifyFqdn = $coolifyUrl->getHost();
$coolifyUrl = $coolifyUrl->withScheme($coolifyScheme)->withHost($coolifyFqdn)->withPort(null);
$envs_dict['SERVICE_URL_'.str($forServiceName)->upper()] = escapeBashEnvValue($coolifyUrl->__toString());
$envs_dict['SERVICE_FQDN_'.str($forServiceName)->upper()] = escapeBashEnvValue($coolifyFqdn);
$envs_dict['SERVICE_URL_'.str($forServiceName)->replace('-', '_')->replace('.', '_')->upper()] = escapeBashEnvValue($coolifyUrl->__toString());
$envs_dict['SERVICE_FQDN_'.str($forServiceName)->replace('-', '_')->replace('.', '_')->upper()] = escapeBashEnvValue($coolifyFqdn);
}
}
} else {
@@ -1498,7 +1498,7 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
$rawDockerCompose = Yaml::parse($this->application->docker_compose_raw);
$rawServices = data_get($rawDockerCompose, 'services', []);
foreach ($rawServices as $rawServiceName => $_) {
$envs_dict['SERVICE_NAME_'.str($rawServiceName)->upper()] = escapeBashEnvValue(addPreviewDeploymentSuffix($rawServiceName, $this->pull_request_id));
$envs_dict['SERVICE_NAME_'.str($rawServiceName)->replace('-', '_')->replace('.', '_')->upper()] = escapeBashEnvValue(addPreviewDeploymentSuffix($rawServiceName, $this->pull_request_id));
}
// Generate SERVICE_FQDN & SERVICE_URL for preview deployments with PR-specific domains
@@ -1511,8 +1511,8 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
$coolifyScheme = $coolifyUrl->getScheme();
$coolifyFqdn = $coolifyUrl->getHost();
$coolifyUrl = $coolifyUrl->withScheme($coolifyScheme)->withHost($coolifyFqdn)->withPort(null);
$envs_dict['SERVICE_URL_'.str($forServiceName)->upper()] = escapeBashEnvValue($coolifyUrl->__toString());
$envs_dict['SERVICE_FQDN_'.str($forServiceName)->upper()] = escapeBashEnvValue($coolifyFqdn);
$envs_dict['SERVICE_URL_'.str($forServiceName)->replace('-', '_')->replace('.', '_')->upper()] = escapeBashEnvValue($coolifyUrl->__toString());
$envs_dict['SERVICE_FQDN_'.str($forServiceName)->replace('-', '_')->replace('.', '_')->upper()] = escapeBashEnvValue($coolifyFqdn);
}
}
}

View File

@@ -257,7 +257,7 @@ class GlobalSearch extends Component
// Get all applications
$applications = Application::ownedByCurrentTeam()
->with(['environment.project'])
->with(['environment.project', 'previews:id,application_id,pull_request_id'])
->get()
->map(function ($app) {
// Collect all FQDNs from the application
@@ -286,6 +286,16 @@ class GlobalSearch extends Component
$fqdnsString = $fqdns->implode(' ');
// Add PR search terms if preview is enabled
$prSearchTerms = '';
if ($app->preview_enabled ?? false) {
$prIds = collect($app->previews ?? [])
->pluck('pull_request_id')
->map(fn ($id) => "pr-{$id} pr{$id} {$id}")
->implode(' ');
$prSearchTerms = $prIds;
}
return [
'id' => $app->id,
'name' => $app->name,
@@ -296,13 +306,13 @@ class GlobalSearch extends Component
'project' => $app->environment->project->name ?? null,
'environment' => $app->environment->name ?? null,
'fqdns' => $fqdns->take(2)->implode(', '), // Show first 2 FQDNs in UI
'search_text' => strtolower($app->name.' '.$app->description.' '.$fqdnsString.' application applications app apps'),
'search_text' => strtolower($app->name.' '.$app->description.' '.$fqdnsString.' '.$app->uuid.' '.$prSearchTerms.' application applications app apps'),
];
});
// Get all services
$services = Service::ownedByCurrentTeam()
->with(['environment.project', 'applications'])
->with(['environment.project', 'applications', 'databases'])
->get()
->map(function ($service) {
// Collect all FQDNs from service applications
@@ -315,6 +325,10 @@ class GlobalSearch extends Component
}
$fqdnsString = $fqdns->implode(' ');
// Collect service component names for container search
$serviceAppNames = collect($service->applications ?? [])->pluck('name')->implode(' ');
$serviceDbNames = collect($service->databases ?? [])->pluck('name')->implode(' ');
return [
'id' => $service->id,
'name' => $service->name,
@@ -325,7 +339,7 @@ class GlobalSearch extends Component
'project' => $service->environment->project->name ?? null,
'environment' => $service->environment->name ?? null,
'fqdns' => $fqdns->take(2)->implode(', '), // Show first 2 FQDNs in UI
'search_text' => strtolower($service->name.' '.$service->description.' '.$fqdnsString.' service services'),
'search_text' => strtolower($service->name.' '.$service->description.' '.$fqdnsString.' '.$service->uuid.' '.$serviceAppNames.' '.$serviceDbNames.' service services'),
];
});
@@ -348,7 +362,7 @@ class GlobalSearch extends Component
'link' => $db->link(),
'project' => $db->environment->project->name ?? null,
'environment' => $db->environment->name ?? null,
'search_text' => strtolower($db->name.' postgresql '.$db->description.' database databases db'),
'search_text' => strtolower($db->name.' '.$db->uuid.' postgresql '.$db->description.' database databases db'),
];
})
);
@@ -369,7 +383,7 @@ class GlobalSearch extends Component
'link' => $db->link(),
'project' => $db->environment->project->name ?? null,
'environment' => $db->environment->name ?? null,
'search_text' => strtolower($db->name.' mysql '.$db->description.' database databases db'),
'search_text' => strtolower($db->name.' '.$db->uuid.' mysql '.$db->description.' database databases db'),
];
})
);
@@ -390,7 +404,7 @@ class GlobalSearch extends Component
'link' => $db->link(),
'project' => $db->environment->project->name ?? null,
'environment' => $db->environment->name ?? null,
'search_text' => strtolower($db->name.' mariadb '.$db->description.' database databases db'),
'search_text' => strtolower($db->name.' '.$db->uuid.' mariadb '.$db->description.' database databases db'),
];
})
);
@@ -411,7 +425,7 @@ class GlobalSearch extends Component
'link' => $db->link(),
'project' => $db->environment->project->name ?? null,
'environment' => $db->environment->name ?? null,
'search_text' => strtolower($db->name.' mongodb '.$db->description.' database databases db'),
'search_text' => strtolower($db->name.' '.$db->uuid.' mongodb '.$db->description.' database databases db'),
];
})
);
@@ -432,7 +446,7 @@ class GlobalSearch extends Component
'link' => $db->link(),
'project' => $db->environment->project->name ?? null,
'environment' => $db->environment->name ?? null,
'search_text' => strtolower($db->name.' redis '.$db->description.' database databases db'),
'search_text' => strtolower($db->name.' '.$db->uuid.' redis '.$db->description.' database databases db'),
];
})
);
@@ -453,7 +467,7 @@ class GlobalSearch extends Component
'link' => $db->link(),
'project' => $db->environment->project->name ?? null,
'environment' => $db->environment->name ?? null,
'search_text' => strtolower($db->name.' keydb '.$db->description.' database databases db'),
'search_text' => strtolower($db->name.' '.$db->uuid.' keydb '.$db->description.' database databases db'),
];
})
);
@@ -474,7 +488,7 @@ class GlobalSearch extends Component
'link' => $db->link(),
'project' => $db->environment->project->name ?? null,
'environment' => $db->environment->name ?? null,
'search_text' => strtolower($db->name.' dragonfly '.$db->description.' database databases db'),
'search_text' => strtolower($db->name.' '.$db->uuid.' dragonfly '.$db->description.' database databases db'),
];
})
);
@@ -495,7 +509,7 @@ class GlobalSearch extends Component
'link' => $db->link(),
'project' => $db->environment->project->name ?? null,
'environment' => $db->environment->name ?? null,
'search_text' => strtolower($db->name.' clickhouse '.$db->description.' database databases db'),
'search_text' => strtolower($db->name.' '.$db->uuid.' clickhouse '.$db->description.' database databases db'),
];
})
);

View File

@@ -14,7 +14,7 @@ class Index extends Component
public ?Server $server = null;
#[Validate('nullable|string|max:255')]
#[Validate('nullable|string|max:255|url')]
public ?string $fqdn = null;
#[Validate('required|integer|min:1025|max:65535')]
@@ -46,6 +46,11 @@ class Index extends Component
public $buildActivityId = null;
protected array $messages = [
'fqdn.url' => 'Invalid instance URL.',
'fqdn.max' => 'URL must not exceed 255 characters.',
];
public function render()
{
return view('livewire.settings.index');

View File

@@ -28,9 +28,23 @@ class StandalonePostgresql extends BaseModel
protected static function booted()
{
static::created(function ($database) {
// This is really stupid and it took me 1h to figure out why the image was not loading properly. This is exactly the reason why we need to use the action pattern because Model events and Accessors are a fragile mess!
$image = (string) ($database->getAttributes()['image'] ?? '');
$majorVersion = 0;
if (preg_match('/:(?:pg)?(\d+)/i', $image, $matches)) {
$majorVersion = (int) $matches[1];
}
// PostgreSQL 18+ uses /var/lib/postgresql as mount path
// Older versions use /var/lib/postgresql/data
$mountPath = $majorVersion >= 18
? '/var/lib/postgresql'
: '/var/lib/postgresql/data';
LocalPersistentVolume::create([
'name' => 'postgres-data-'.$database->uuid,
'mount_path' => '/var/lib/postgresql/data',
'mount_path' => $mountPath,
'host_path' => null,
'resource_id' => $database->id,
'resource_type' => $database->getMorphClass(),