mirror of
https://github.com/coollabsio/coolify.git
synced 2026-09-27 17:55:59 -04:00
feat(v5): add server bootstrap job with realtime cluster broadcasting
- Add V5BootstrapServerJob: SSH into new servers, install coold/WireGuard, track bootstrap progress via last_bootstrap_action/status/output fields - Add V5ClusterUpdated event: broadcasts full cluster+servers payload to team private channel on bootstrap state changes - Add V5RealtimeTestEvent + RealtimeTest page for WebSocket connectivity testing - Consolidate 3 dropped migrations into base cluster/server migrations: WireGuard config, builder CPU quota, status check fields, uuid - Auto-generate uuid on V5Model create via Schema::hasColumn guard - Expose currentTeam.id in Inertia shared props - Add showCluster, realtimeTest, broadcastRealtimeTest controller endpoints - Add dropdown-menu UI component
This commit is contained in:
@@ -46,6 +46,9 @@ it('supports a naked up mode that starts VMs and Spin but skips server bootstrap
|
||||
->and($script)->toContain('if [ "$naked" = "true" ]; then')
|
||||
->and($script)->toContain('Skipping coolify bootstrap and Flux VM wiring')
|
||||
->and($script)->toContain('coolify_bootstrap_with_retry')
|
||||
->and($script)->toContain('--concurrency "$(coolify_bootstrap_concurrency)"')
|
||||
->and($script)->toContain('--ssh-timeout "$(coolify_bootstrap_ssh_timeout)"')
|
||||
->and($script)->toContain('--debug')
|
||||
->and($script)->toContain('configure_flux_dev_for_vm "$index"')
|
||||
->and($script)->toContain('sync_v5_dev_lima_servers');
|
||||
});
|
||||
@@ -56,6 +59,9 @@ it('retries dev coolify bootstrap because fresh Lima setup can complete across p
|
||||
expect($script)->toContain('coolify_bootstrap_with_retry()')
|
||||
->and($script)->toContain('local attempts=5')
|
||||
->and($script)->toContain('if coolify_bootstrap; then')
|
||||
->and($script)->toContain('diagnose_coold_bootstrap_failure')
|
||||
->and($script)->toContain('systemctl --failed --no-pager')
|
||||
->and($script)->toContain('systemctl --no-pager --full status wg-quick@wg0 podman.socket corrosion coold')
|
||||
->and($script)->toContain('fresh Lima hosts can finish setup after partial bootstrap phases');
|
||||
});
|
||||
|
||||
@@ -122,3 +128,40 @@ it('supports down cleanup as the preferred VM cleanup command', function () {
|
||||
->and($script)->toContain('down --cleanup')
|
||||
->and($script)->toContain('clean-vms Delete the coold Lima VMs and all VM-local runtime state (alias for down --cleanup)');
|
||||
});
|
||||
|
||||
it('scripts a full fresh dev reset with bounded Lima startup retries', function () {
|
||||
$script = file_get_contents(base_path('scripts/dev.sh'));
|
||||
$vmScript = file_get_contents(base_path('scripts/coold-vm.sh'));
|
||||
|
||||
expect($script)->toContain('fresh()')
|
||||
->and($script)->toContain('down --cleanup')
|
||||
->and($script)->toContain('COOLIFY_DEV_FOLLOW_LOGS=false up')
|
||||
->and($script)->toContain('php artisan migrate:fresh --seed --force')
|
||||
->and($script)->toContain('sync_v5_dev_lima_servers')
|
||||
->and($script)->toContain('recreate_naked_lima_vm')
|
||||
->and($script)->toContain('COOLIFY_NAKED_VM_START_TIMEOUT')
|
||||
->and($script)->toContain('limactl start --tty=false --name="$instance" "$config"')
|
||||
->and($script)->toContain('cleanup_lima_instance_processes "$instance"')
|
||||
->and($script)->toContain('did not become ready after ${attempts} attempts')
|
||||
->and($script)->toContain('refresh_test_host_key')
|
||||
->and($script)->toContain('coold_vm_up_with_retry()')
|
||||
->and($script)->toContain('COOLIFY_COOLD_BOOTSTRAP_CONCURRENCY 1')
|
||||
->and($script)->toContain('COOLIFY_COOLD_BOOTSTRAP_SSH_TIMEOUT 90s')
|
||||
->and($script)->toContain('local attempts=2')
|
||||
->and($script)->toContain('deleting and retrying with a fresh Lima instance')
|
||||
->and($script)->toContain('cleanup_lima_instance_processes()')
|
||||
->and($script)->toContain('kill_matching_processes()')
|
||||
->and($script)->toContain('kill -9 $pids')
|
||||
->and($script)->toContain('limactl hostagent .*${instance}')
|
||||
->and($script)->toContain('ssh: .*/.lima/${instance}/ssh.sock')
|
||||
->and($vmScript)->toContain('COOLIFY_COOLD_VM_START_TIMEOUT')
|
||||
->and($vmScript)->toContain('lima_shell_timeout()')
|
||||
->and($vmScript)->toContain('cleanup_lima_probe_processes()')
|
||||
->and($vmScript)->toContain('cleanup_lima_hostagent_processes()')
|
||||
->and($vmScript)->toContain('kill_matching_processes()')
|
||||
->and($vmScript)->toContain('pkill -P "$pid"')
|
||||
->and($vmScript)->toContain('lima_shell_timeout 5 true')
|
||||
->and($vmScript)->toContain('Lima start timed out after ${START_TIMEOUT}s')
|
||||
->and($vmScript)->toContain('Guest SSH timed out after ${START_TIMEOUT}s')
|
||||
->and($vmScript)->toContain('Guest provisioning timed out after ${START_TIMEOUT}s');
|
||||
});
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
it('renders the Coolify dashboard icon smaller than the nav height', function () {
|
||||
$navbar = file_get_contents(resource_path('js/v5/components/app-navbar.tsx'));
|
||||
|
||||
expect($navbar)->toContain('<img src="/coolify-logo.svg" alt="Coolify" className="size-6" />')
|
||||
->and($navbar)->not->toContain('<img src="/coolify-logo.svg" alt="Coolify" className="size-8" />');
|
||||
});
|
||||
|
||||
it('shows keyboard focus on ghost select dropdown triggers', function () {
|
||||
$selectComponent = file_get_contents(resource_path('js/v5/components/ui/select.tsx'));
|
||||
|
||||
expect($selectComponent)
|
||||
->toContain("variant === 'ghost'")
|
||||
->toContain('focus-visible:border-ring')
|
||||
->not->toContain('focus-visible:border-transparent');
|
||||
});
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
it('uses yellow focus borders for normal v5 controls and purple focus borders for coolify buttons', function () {
|
||||
$v5Css = file_get_contents(resource_path('css/v5/app.css'));
|
||||
$buttonComponent = file_get_contents(resource_path('js/v5/components/ui/button.tsx'));
|
||||
$inputComponent = file_get_contents(resource_path('js/v5/components/ui/input.tsx'));
|
||||
$selectComponent = file_get_contents(resource_path('js/v5/components/ui/select.tsx'));
|
||||
$textareaComponent = file_get_contents(resource_path('js/v5/components/ui/textarea.tsx'));
|
||||
|
||||
expect($v5Css)
|
||||
->toContain(':focus-visible')
|
||||
->toContain('ring-2 ring-ring ring-offset-2')
|
||||
->toContain('--tw-ring-offset-color: var(--background)')
|
||||
->and($buttonComponent)
|
||||
->toContain('focus-visible:border-ring')
|
||||
->toContain('focus-visible:border-coollabs-100')
|
||||
->toContain('dark:focus-visible:border-coollabs-100')
|
||||
->not->toContain('dark:focus-visible:border-coollabs-50')
|
||||
->not->toContain('focus-visible:ring-')
|
||||
->not->toContain('focus-visible:border-destructive')
|
||||
->and($inputComponent)
|
||||
->toContain('focus:border-ring')
|
||||
->toContain('focus:ring-0')
|
||||
->not->toContain('focus:ring-1')
|
||||
->and($selectComponent)
|
||||
->toContain('focus-visible:border-ring')
|
||||
->not->toContain('focus-visible:ring-')
|
||||
->and($textareaComponent)
|
||||
->toContain('focus:border-ring')
|
||||
->toContain('focus:ring-0')
|
||||
->not->toContain('focus:ring-1');
|
||||
});
|
||||
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
it('does not render server capability summaries on the cluster page', function () {
|
||||
$clustersPage = file_get_contents(resource_path('js/v5/Pages/Clusters.tsx'));
|
||||
|
||||
expect($clustersPage)
|
||||
->not->toContain('Capabilities:')
|
||||
->not->toContain('normalizeCapabilities');
|
||||
});
|
||||
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
it('keeps the cluster selector and add button the same height', function () {
|
||||
$clustersPage = file_get_contents(resource_path('js/v5/Pages/Clusters.tsx'));
|
||||
|
||||
expect($clustersPage)->toContain('<SelectTrigger')
|
||||
->and($clustersPage)->toContain('className="w-full sm:w-72"')
|
||||
->and($clustersPage)->toContain('variant="coolify"')
|
||||
->and($clustersPage)->toContain('size="default"')
|
||||
->and($clustersPage)->not->toContain('variant="coolify"\n size="sm"');
|
||||
});
|
||||
+661
-117
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user