diff --git a/.gitignore b/.gitignore index b09e074f7..480066d6a 100644 --- a/.gitignore +++ b/.gitignore @@ -42,4 +42,6 @@ tests/Browser/Screenshots tests/v4/Browser/Screenshots # Local generated Lima configs +.dev/bin/ .dev/lima/*.generated.yaml +.dev/lima/ssh.config diff --git a/app/Http/Controllers/V5/HomeController.php b/app/Http/Controllers/V5/HomeController.php index 116952153..0974f820f 100644 --- a/app/Http/Controllers/V5/HomeController.php +++ b/app/Http/Controllers/V5/HomeController.php @@ -5,7 +5,9 @@ namespace App\Http\Controllers\V5; use App\Http\Controllers\Controller; use App\Models\Team; use App\Models\User; +use App\Services\Coold\CoolifyCliVersion; use App\Services\Flux\FluxHealth; +use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; use Inertia\Inertia; use Inertia\Response; @@ -43,6 +45,11 @@ class HomeController extends Controller ]); } + public function coolifyCliVersion(CoolifyCliVersion $coolifyCliVersion): JsonResponse + { + return response()->json($coolifyCliVersion->check()); + } + /** * @return array, builderEnabled: bool, builderCapacity: int}> */ diff --git a/app/Services/Coold/CoolifyCliVersion.php b/app/Services/Coold/CoolifyCliVersion.php new file mode 100644 index 000000000..c8bef86f5 --- /dev/null +++ b/app/Services/Coold/CoolifyCliVersion.php @@ -0,0 +1,55 @@ +unavailable(null, 'coolify binary is not configured.'); + } + + try { + $result = Process::timeout(5)->run(escapeshellarg($binary).' --version'); + } catch (Throwable $exception) { + return $this->unavailable($binary, $exception->getMessage()); + } + + if (! $result->successful()) { + return $this->unavailable($binary, trim($result->errorOutput()) ?: 'coolify version check failed.'); + } + + $version = trim($result->output()); + + return [ + 'available' => true, + 'label' => 'Installed', + 'version' => $version !== '' ? $version : null, + 'message' => $version !== '' ? "Installed version: {$version}." : 'coolify is installed.', + 'binary' => $binary, + ]; + } + + /** + * @return array{available: false, label: string, version: null, message: string, binary: string|null} + */ + private function unavailable(?string $binary, string $message): array + { + return [ + 'available' => false, + 'label' => 'Unavailable', + 'version' => null, + 'message' => $message, + 'binary' => $binary, + ]; + } +} diff --git a/config/coold.php b/config/coold.php index 20dac4445..22a30b393 100644 --- a/config/coold.php +++ b/config/coold.php @@ -1,11 +1,12 @@ env('COOLIFY_CLI_BIN', '/usr/local/bin/coolify'), 'dev_host_count' => (int) env('COOLIFY_COOLD_VM_COUNT', 2), - 'dev_host_id' => env('COOLIFY_COOLD_DEV_HOST_ID', 'coolify-coold-dev'), - 'dev_host_id_2' => env('COOLIFY_COOLD_LIMA_INSTANCE_2', env('COOLIFY_COOLD_DEV_HOST_ID', 'coolify-coold-dev').'-2'), - 'dev_wireguard_ip_1' => env('COOLIFY_COOLD_VM_WG_IP_1', '100.64.0.10'), - 'dev_wireguard_ip_2' => env('COOLIFY_COOLD_VM_WG_IP_2', '100.64.0.11'), + 'dev_host_id' => env('COOLIFY_COOLD_DEV_HOST_ID', 'coold-dev'), + 'dev_host_id_2' => env('COOLIFY_COOLD_LIMA_INSTANCE_2', env('COOLIFY_COOLD_DEV_HOST_ID', 'coold-dev').'-2'), + 'dev_wireguard_ip_1' => env('COOLIFY_COOLD_VM_WG_IP_1', '100.64.0.1'), + 'dev_wireguard_ip_2' => env('COOLIFY_COOLD_VM_WG_IP_2', '100.64.0.2'), 'dev_builder_capacity' => (int) env('COOLIFY_COOLD_VM_BUILDER_CAPACITY', 2), 'dev_builder_enabled' => (int) env('COOLIFY_COOLD_VM_BUILDER_CAPACITY', 2) > 0, ]; diff --git a/dev/coold-dev.md b/dev/coold-dev.md index 249c522b5..a1f2d5036 100644 --- a/dev/coold-dev.md +++ b/dev/coold-dev.md @@ -6,7 +6,7 @@ This file documents the current local v5/coold dev setup in Coolify. - `scripts/dev.sh` owns local developer convenience. - Lima VMs act like real deployment servers. -- `cooldctl init bootstrap` owns host wiring: +- `coolify init bootstrap` owns host wiring: - WireGuard - Podman mesh networks - Corrosion config/schema/service @@ -32,16 +32,16 @@ scripts/dev.sh list containers, WireGuard keys, Corrosion DB, installed binaries, and firewall state. It does not delete the Coolify repo. -## cooldctl helper +## coolify helper ```bash -scripts/dev.sh cooldctl install -scripts/dev.sh cooldctl path -scripts/dev.sh cooldctl bootstrap-command -scripts/dev.sh cooldctl run +scripts/dev.sh coolify install +scripts/dev.sh coolify path +scripts/dev.sh coolify bootstrap-command +scripts/dev.sh coolify run ``` -On macOS, the helper builds `cooldctl` from the local coold repo because the +On macOS, the helper builds `coolify` from the local coold repo because the nightly release currently publishes Linux binaries. On Linux, it downloads the nightly release artifact. @@ -49,7 +49,7 @@ The generated bootstrap command uses Lima's forwarded SSH ports and dev WireGuard endpoint overrides, for example: ```bash -.dev/bin/cooldctl init bootstrap \ +.dev/bin/coolify init bootstrap \ --nodes "127.0.0.1:,127.0.0.1:" \ --ssh-key "$HOME/.lima/_config/user" \ --ssh-user "$USER" \ @@ -61,12 +61,12 @@ WireGuard endpoint overrides, for example: ``` Lima does not allow direct root SSH by default, so dev uses the normal Lima user -with passwordless sudo. `cooldctl` wraps remote commands in `sudo -n bash -lc` +with passwordless sudo. `coolify` wraps remote commands in `sudo -n bash -lc` when the SSH user is not `root`. ## Default dev topology -After `cooldctl init bootstrap`, defaults are: +After `coolify init bootstrap`, defaults are: | VM | WireGuard IP | WireGuard endpoint | Podman subnet | Gateway | | --- | --- | --- | --- | --- | diff --git a/dev/lima/coold.yaml b/dev/lima/coold.yaml index b1fcd3713..4629d61cc 100644 --- a/dev/lima/coold.yaml +++ b/dev/lima/coold.yaml @@ -1,4 +1,4 @@ -# Lima VM for testing Coolify v5 against cooldctl-provisioned hosts. +# Lima VM for testing Coolify v5 against coolify-provisioned hosts. # Start with: scripts/coold-vm.sh up # # This file is copied into .dev/lima/coold.generated.yaml by the wrapper script, @@ -58,4 +58,4 @@ provision: mkdir -p /etc/coolify /var/lib/coolify-dev chmod 755 /etc/coolify - echo "[coold-vm] Minimal provisioning complete. cooldctl bootstrap will install WireGuard, Podman, Corrosion, coold, and builder." + echo "[coold-vm] Minimal provisioning complete. coolify bootstrap will install WireGuard, Podman, Corrosion, coold, and builder." diff --git a/docker-compose-maxio.dev.yml b/docker-compose-maxio.dev.yml index 164b1b338..fe80a91e9 100644 --- a/docker-compose-maxio.dev.yml +++ b/docker-compose-maxio.dev.yml @@ -8,10 +8,14 @@ services: args: - USER_ID=${USERID:-1000} - GROUP_ID=${GROUPID:-1000} + - COOLIFY_FLUX_VERSION=${COOLIFY_FLUX_VERSION:-nightly} + - COOLIFY_CLI_VERSION=${COOLIFY_CLI_VERSION:-nightly} ports: - "${APP_PORT:-8000}:8080" environment: AUTORUN_ENABLED: false + COOLIFY_FLUX_VERSION: "${COOLIFY_FLUX_VERSION:-nightly}" + COOLIFY_CLI_VERSION: "${COOLIFY_CLI_VERSION:-nightly}" PUSHER_HOST: "${PUSHER_HOST:-}" PUSHER_PORT: "${PUSHER_PORT:-}" PUSHER_SCHEME: "${PUSHER_SCHEME:-http}" diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml index ea095f17f..83dfad68d 100644 --- a/docker-compose.dev.yml +++ b/docker-compose.dev.yml @@ -9,6 +9,7 @@ services: - USER_ID=${USERID:-1000} - GROUP_ID=${GROUPID:-1000} - COOLIFY_FLUX_VERSION=${COOLIFY_FLUX_VERSION:-nightly} + - COOLIFY_CLI_VERSION=${COOLIFY_CLI_VERSION:-nightly} ports: - "${APP_PORT:-8000}:8080" - "${FORWARD_FLUX_PORT:-6443}:6443" @@ -17,6 +18,7 @@ services: COOLIFY_CONTAINER_ROLE: "${COOLIFY_CONTAINER_ROLE:-all}" COOLIFY_COOLD_VERSION: "${COOLIFY_COOLD_VERSION:-nightly}" COOLIFY_FLUX_VERSION: "${COOLIFY_FLUX_VERSION:-nightly}" + COOLIFY_CLI_VERSION: "${COOLIFY_CLI_VERSION:-nightly}" COOLIFY_CORROSION_VERSION: "${COOLIFY_CORROSION_VERSION:-v1.0.0}" PUSHER_HOST: "${PUSHER_HOST:-}" PUSHER_PORT: "${PUSHER_PORT:-}" diff --git a/docker/development/Dockerfile b/docker/development/Dockerfile index 08450e817..73fcbd409 100644 --- a/docker/development/Dockerfile +++ b/docker/development/Dockerfile @@ -7,6 +7,7 @@ ARG MINIO_VERSION=RELEASE.2025-05-21T01-59-54Z ARG CLOUDFLARED_VERSION=2025.7.0 # https://github.com/coollabsio/coold/releases/tag/nightly ARG COOLIFY_FLUX_VERSION=nightly +ARG COOLIFY_CLI_VERSION=nightly # https://www.postgresql.org/support/versioning/ # Note: We are using version 18 of the postgres client (while still using postgres 15 for the postgres server) as version 15 has been removed from Alpine 3.23+ https://pkgs.alpinelinux.org/packages?name=postgresql*-client&branch=v3.23&repo=&arch=x86_64&origin=&flagged=&maintainer= ARG POSTGRES_VERSION=18 @@ -30,6 +31,7 @@ ARG TARGETARCH ARG POSTGRES_VERSION ARG CLOUDFLARED_VERSION ARG COOLIFY_FLUX_VERSION +ARG COOLIFY_CLI_VERSION ARG NGINX_VERSION WORKDIR /var/www/html @@ -108,6 +110,27 @@ RUN set -eux; \ install -m 0755 /tmp/flux /usr/local/bin/flux; \ rm -f /tmp/flux /tmp/flux.tar.gz +# Install coolify from coold nightly release based on architecture +RUN set -eux; \ + mkdir -p /usr/local/bin; \ + case "${TARGETARCH:-}" in \ + amd64|arm64) COOLIFY_CLI_ARCH="${TARGETARCH}" ;; \ + "") \ + case "$(uname -m)" in \ + x86_64) COOLIFY_CLI_ARCH="amd64" ;; \ + aarch64) COOLIFY_CLI_ARCH="arm64" ;; \ + *) echo "unsupported coolify arch: $(uname -m)" >&2; exit 1 ;; \ + esac ;; \ + *) echo "unsupported coolify TARGETARCH: ${TARGETARCH}" >&2; exit 1 ;; \ + esac; \ + curl -fsSL --retry 3 --max-time 120 \ + -o /tmp/coolify.tar.gz \ + "https://github.com/coollabsio/coold/releases/download/${COOLIFY_CLI_VERSION}/coolify-linux-musl-${COOLIFY_CLI_ARCH}.tar.gz"; \ + tar -xzf /tmp/coolify.tar.gz -C /tmp; \ + test -f /tmp/coolify; \ + install -m 0755 /tmp/coolify /usr/local/bin/coolify; \ + rm -f /tmp/coolify /tmp/coolify.tar.gz + # Configure PHP COPY docker/development/etc/php/conf.d/zzz-custom-php.ini /usr/local/etc/php/conf.d/zzz-custom-php.ini ENV PHP_OPCACHE_ENABLE=0 diff --git a/docker/production/Dockerfile b/docker/production/Dockerfile index b6dd5fac0..46fde62e6 100644 --- a/docker/production/Dockerfile +++ b/docker/production/Dockerfile @@ -7,6 +7,7 @@ ARG MINIO_VERSION=RELEASE.2025-05-21T01-59-54Z ARG CLOUDFLARED_VERSION=2025.7.0 # https://github.com/coollabsio/coold/releases/tag/nightly ARG COOLIFY_FLUX_VERSION=nightly +ARG COOLIFY_CLI_VERSION=nightly # https://www.postgresql.org/support/versioning/ # Note: We are using version 18 of the postgres client (while still using postgres 15 for the postgres server) as version 15 has been removed from Alpine 3.23+ https://pkgs.alpinelinux.org/packages?name=postgresql*-client&branch=v3.23&repo=&arch=x86_64&origin=&flagged=&maintainer= ARG POSTGRES_VERSION=18 @@ -79,6 +80,7 @@ ARG TARGETARCH ARG POSTGRES_VERSION ARG CLOUDFLARED_VERSION ARG COOLIFY_FLUX_VERSION +ARG COOLIFY_CLI_VERSION ARG NGINX_VERSION ARG CI=true @@ -155,6 +157,27 @@ RUN set -eux; \ install -m 0755 /tmp/flux /usr/local/bin/flux; \ rm -f /tmp/flux /tmp/flux.tar.gz +# Install coolify from coold nightly release based on architecture +RUN set -eux; \ + mkdir -p /usr/local/bin; \ + case "${TARGETARCH:-}" in \ + amd64|arm64) COOLIFY_CLI_ARCH="${TARGETARCH}" ;; \ + "") \ + case "$(uname -m)" in \ + x86_64) COOLIFY_CLI_ARCH="amd64" ;; \ + aarch64) COOLIFY_CLI_ARCH="arm64" ;; \ + *) echo "unsupported coolify arch: $(uname -m)" >&2; exit 1 ;; \ + esac ;; \ + *) echo "unsupported coolify TARGETARCH: ${TARGETARCH}" >&2; exit 1 ;; \ + esac; \ + curl -fsSL --retry 3 --max-time 120 \ + -o /tmp/coolify.tar.gz \ + "https://github.com/coollabsio/coold/releases/download/${COOLIFY_CLI_VERSION}/coolify-linux-musl-${COOLIFY_CLI_ARCH}.tar.gz"; \ + tar -xzf /tmp/coolify.tar.gz -C /tmp; \ + test -f /tmp/coolify; \ + install -m 0755 /tmp/coolify /usr/local/bin/coolify; \ + rm -f /tmp/coolify /tmp/coolify.tar.gz + # Configure PHP COPY docker/production/etc/php/conf.d/zzz-custom-php.ini /usr/local/etc/php/conf.d/zzz-custom-php.ini ENV PHP_OPCACHE_ENABLE=1 diff --git a/resources/js/v5/Pages/Home.jsx b/resources/js/v5/Pages/Home.jsx index 4ed49d968..a48f2469d 100644 --- a/resources/js/v5/Pages/Home.jsx +++ b/resources/js/v5/Pages/Home.jsx @@ -1,6 +1,34 @@ import { Head } from '@inertiajs/react'; +import { useState } from 'react'; export default function Home({ status, currentTeam, teams, flux, cooldHosts }) { + const [coolify, setCoolify] = useState(null); + const [checkingCoolify, setCheckingCoolify] = useState(false); + + async function checkCoolifyCliVersion() { + setCheckingCoolify(true); + + try { + const response = await fetch('/v5/coolify/version', { + headers: { + Accept: 'application/json', + }, + }); + + setCoolify(await response.json()); + } catch (error) { + setCoolify({ + available: false, + label: 'Unavailable', + version: null, + message: 'Could not check the installed coolify version.', + binary: null, + }); + } finally { + setCheckingCoolify(false); + } + } + return ( <> @@ -45,6 +73,25 @@ export default function Home({ status, currentTeam, teams, flux, cooldHosts }) { +
+

coolify

+ + + + {coolify ? ( +
+

+ {coolify.label} +

+ {coolify.version ?

Version: {coolify.version}

: null} +

{coolify.message}

+ {coolify.binary ?

Binary: {coolify.binary}

: null} +
+ ) : null} +
+

Current team

{currentTeam ? ( diff --git a/routes/v5.php b/routes/v5.php index 16525bf73..766047255 100644 --- a/routes/v5.php +++ b/routes/v5.php @@ -5,4 +5,5 @@ use Illuminate\Support\Facades\Route; Route::middleware('v5.authenticated')->group(function () { Route::get('/', HomeController::class)->name('home'); + Route::get('/coolify/version', [HomeController::class, 'coolifyCliVersion'])->name('coolify.version'); }); diff --git a/scripts/coold-vm.sh b/scripts/coold-vm.sh index b43f50c32..177c289d3 100755 --- a/scripts/coold-vm.sh +++ b/scripts/coold-vm.sh @@ -40,7 +40,7 @@ if [ "$BUILDER_CAPACITY" = "0" ]; then BUILDER_ENABLED="false" fi TEMPLATE="$ROOT/dev/lima/coold.yaml" -GENERATED="$ROOT/.dev/lima/coold.generated.yaml" +GENERATED="$ROOT/.dev/lima/${INSTANCE}.generated.yaml" GUEST_COOLIFY_ROOT="/workspace/coolify" usage() { @@ -436,8 +436,11 @@ wait_for_lima_start() { lima_shell sudo sh -c 'test -f /var/log/cloud-init-output.log && tail -n 12 /var/log/cloud-init-output.log || true' 2>/dev/null | awk '{ print "[guest] " $0; fflush(); }' || true if ! printf '%s' "$status" | grep -q running; then - kill "$start_pid" >/dev/null 2>&1 || true - break + if kill -0 "$start_pid" 2>/dev/null; then + kill "$start_pid" >/dev/null 2>&1 || true + disown "$start_pid" >/dev/null 2>&1 || true + fi + return fi else message="$(latest_lima_message)" @@ -503,7 +506,7 @@ up_with_logs() { wait_for_lima_start wait_for_guest_provisioning - echo "==> VM is ready. Run cooldctl bootstrap via: scripts/dev.sh up" + echo "==> VM is ready. Run coolify bootstrap via: scripts/dev.sh up" } cmd="${1:-}" diff --git a/scripts/dev.sh b/scripts/dev.sh index 1d389a0c3..45f8a8f03 100755 --- a/scripts/dev.sh +++ b/scripts/dev.sh @@ -100,30 +100,11 @@ host_os() { esac } -cooldctl_bin() { - printf '%s\n' "$ROOT/.dev/bin/cooldctl" +coolify_cli_bin() { + printf '%s\n' "$ROOT/.dev/bin/coolify" } -build_local_cooldctl() { - local bin - local coold_repo - - bin="$(cooldctl_bin)" - coold_repo="$(read_coolify_env COOLIFY_COOLD_REPO /Users/heyandras/devel/coold)" - - if [ ! -d "$coold_repo/cooldctl" ]; then - echo "ERROR: macOS cooldctl release artifact is not available yet and local coold repo was not found at ${coold_repo}." >&2 - echo "Set COOLIFY_COOLD_REPO=/path/to/coold or build/copy cooldctl to ${bin}." >&2 - exit 1 - fi - - echo "==> Building local macOS cooldctl from ${coold_repo}" - (cd "$coold_repo" && cargo build -p cooldctl) - mkdir -p "$(dirname "$bin")" - install -m 0755 "$coold_repo/target/debug/cooldctl" "$bin" -} - -ensure_cooldctl() { +ensure_coolify() { local bin local version local arch @@ -131,63 +112,84 @@ ensure_cooldctl() { local url local tmpdir - bin="$(cooldctl_bin)" - version="$(read_coolify_env COOLIFY_COOLDCTL_VERSION "$(read_coolify_env COOLIFY_COOLD_VERSION nightly)")" + bin="$(coolify_cli_bin)" + version="$(read_coolify_env COOLIFY_CLI_VERSION "$(read_coolify_env COOLIFY_COOLD_VERSION nightly)")" arch="$(host_arch)" os="$(host_os)" - if [ "$os" = "darwin" ]; then - build_local_cooldctl + if [ -x "$bin" ] && "$bin" --version >/dev/null 2>&1 && [ "${COOLIFY_CLI_FORCE_DOWNLOAD:-false}" != "true" ]; then return fi - if [ -x "$bin" ] && "$bin" --version >/dev/null 2>&1 && [ "${COOLIFY_COOLDCTL_FORCE_DOWNLOAD:-false}" != "true" ]; then - return - fi - - url="https://github.com/coollabsio/coold/releases/download/${version}/cooldctl-${os}-${arch}.tar.gz" - echo "==> Installing cooldctl from ${url}" + url="https://github.com/coollabsio/coold/releases/download/${version}/coolify-${os}-${arch}.tar.gz" + echo "==> Installing coolify from ${url}" mkdir -p "$(dirname "$bin")" tmpdir="$(mktemp -d)" - trap 'rm -rf "$tmpdir"' RETURN - curl -fsSL --retry 3 --max-time 120 -o "$tmpdir/cooldctl.tar.gz" "$url" - tar -xzf "$tmpdir/cooldctl.tar.gz" -C "$tmpdir" - install -m 0755 "$tmpdir/cooldctl" "$bin" + if ! curl -fsSL --retry 3 --max-time 120 -o "$tmpdir/coolify.tar.gz" "$url"; then + rm -rf "$tmpdir" + return 1 + fi + tar -xzf "$tmpdir/coolify.tar.gz" -C "$tmpdir" + install -m 0755 "$tmpdir/coolify" "$bin" + rm -rf "$tmpdir" } lima_ssh_target() { local index="$1" local instance - local ssh instance="$(coold_vm_instance "$index")" - ssh="$(limactl list 2>/dev/null | awk -v name="$instance" 'NR > 1 && $1 == name {print $3}')" - if [ -z "$ssh" ] || [ "$ssh" = "-" ]; then - echo "ERROR: could not determine SSH target for Lima VM ${instance}. Start it first with scripts/dev.sh up." >&2 + if [ ! -f "$HOME/.lima/${instance}/ssh.config" ]; then + echo "ERROR: Lima SSH config for ${instance} was not found. Start it first with scripts/dev.sh up." >&2 exit 1 fi - printf '%s\n' "$ssh" + printf 'lima-%s\n' "$instance" } -cooldctl_nodes_arg() { +lima_ssh_config() { + local count + local config="$ROOT/.dev/lima/ssh.config" + local instance + count="$(coold_vm_count)" + + mkdir -p "$(dirname "$config")" + : > "$config" + + for index in $(seq 1 "$count"); do + instance="$(coold_vm_instance "$index")" + if [ ! -f "$HOME/.lima/${instance}/ssh.config" ]; then + echo "ERROR: Lima SSH config for ${instance} was not found. Start it first with scripts/dev.sh up." >&2 + exit 1 + fi + + cat "$HOME/.lima/${instance}/ssh.config" >> "$config" + printf '\n' >> "$config" + done + + printf '%s\n' "$config" +} + +coolify_nodes_arg() { local count local nodes="" + local node count="$(coold_vm_count)" for index in $(seq 1 "$count"); do + node="$(lima_ssh_target "$index")" || return 1 if [ -n "$nodes" ]; then nodes="${nodes}," fi - nodes="${nodes}$(lima_ssh_target "$index")" + nodes="${nodes}${node}" done printf '%s\n' "$nodes" } -cooldctl_wg_listen_overrides_arg() { +coolify_wg_listen_overrides_arg() { local count local overrides="" local node @@ -204,7 +206,7 @@ cooldctl_wg_listen_overrides_arg() { printf '%s\n' "$overrides" } -cooldctl_wg_endpoint_overrides_arg() { +coolify_wg_endpoint_overrides_arg() { local count local overrides="" local node @@ -221,45 +223,63 @@ cooldctl_wg_endpoint_overrides_arg() { printf '%s\n' "$overrides" } -cooldctl_ssh_key() { - read_coolify_env COOLIFY_COOLDCTL_SSH_KEY "$HOME/.lima/_config/user" +coolify_ssh_key() { + read_coolify_env COOLIFY_CLI_SSH_KEY "$HOME/.lima/_config/user" } -cooldctl_ssh_user() { - read_coolify_env COOLIFY_COOLDCTL_SSH_USER "$USER" +coolify_ssh_user() { + read_coolify_env COOLIFY_CLI_SSH_USER "$USER" } -cooldctl_bootstrap_command() { - ensure_cooldctl +coolify_bootstrap_command() { + local nodes + local ssh_config + local listen_overrides + local endpoint_overrides + ensure_coolify + + nodes="$(coolify_nodes_arg)" || return 1 + ssh_config="$(lima_ssh_config)" || return 1 + listen_overrides="$(coolify_wg_listen_overrides_arg)" || return 1 + endpoint_overrides="$(coolify_wg_endpoint_overrides_arg)" || return 1 cat < +Usage: scripts/dev.sh coolify Commands: - install Download/install the nightly cooldctl dev binary - path Print the local cooldctl path + install Download/install the nightly coolify dev binary + path Print the local coolify path bootstrap-command Print the dev Lima bootstrap command without running it - run Run cooldctl with arbitrary args + run Run coolify with arbitrary args Example: - scripts/dev.sh cooldctl bootstrap-command + scripts/dev.sh coolify bootstrap-command USAGE ;; *) - echo "unknown cooldctl command: $command" >&2 - echo "Run: scripts/dev.sh cooldctl help" >&2 + echo "unknown coolify command: $command" >&2 + echo "Run: scripts/dev.sh coolify help" >&2 exit 1 ;; esac @@ -415,15 +435,8 @@ up() { if [ "$coold_vm_enabled" != "false" ]; then echo "==> Starting ${count} Coolify coold VM(s) before Spin..." - vm_pids="" for index in $(seq 1 "$count"); do - ( - coold_vm "$index" up - ) & - vm_pids="${vm_pids} $!" - done - for pid in $vm_pids; do - wait "$pid" + coold_vm "$index" up done else echo "==> COOLIFY_COOLD_VM_ENABLED=false; skipping coold VM." @@ -433,8 +446,8 @@ up() { spin up -d "$@" if [ "$coold_vm_enabled" != "false" ]; then - echo "==> Bootstrapping coold VM mesh with cooldctl..." - cooldctl_bootstrap + echo "==> Bootstrapping coold VM mesh with coolify..." + coolify_bootstrap for index in $(seq 1 "$count"); do configure_flux_dev_for_vm "$index" @@ -911,7 +924,7 @@ Commands: corrosion Inspect Corrosion state, config, logs, and registered containers firewall Manage dev coold firewall allow rules example-nginx Start/check example nginx containers with coold DNS - cooldctl Install/run the released cooldctl dev helper + coolify Install/run the released coolify dev helper USAGE } @@ -945,8 +958,8 @@ case "$cmd" in example-nginx) example_nginx "$@" ;; - cooldctl) - cooldctl_dev "$@" + coolify) + coolify_dev "$@" ;; -h|--help|help|"") usage diff --git a/tests/Feature/V5/HomeTest.php b/tests/Feature/V5/HomeTest.php index d4b4b96dc..26914cf3a 100644 --- a/tests/Feature/V5/HomeTest.php +++ b/tests/Feature/V5/HomeTest.php @@ -9,6 +9,7 @@ use App\Models\Team; use App\Models\User; use App\Services\Flux\FluxHealth; use Illuminate\Support\Facades\Config; +use Illuminate\Support\Facades\Process; use Illuminate\Support\Facades\Route; use Illuminate\Support\Facades\Schema; use Mockery\MockInterface; @@ -105,10 +106,10 @@ it('serves the v5 inertia shell', function () { ->assertSee('v5-ready', false) ->assertSee('Running') ->assertSee('Flux is running.') - ->assertSee('coolify-coold-dev') - ->assertSee('coolify-coold-dev-2') - ->assertSee('100.64.0.10') - ->assertSee('100.64.0.11') + ->assertSee('coold-dev') + ->assertSee('coold-dev-2') + ->assertSee('100.64.0.1') + ->assertSee('100.64.0.2') ->assertSee('builder') ->assertSee('builderCapacity') ->assertSee('V5 Shared Team') @@ -173,6 +174,50 @@ it('shows when flux is unavailable', function () { ->assertSee('Flux socket was not found.'); }); +it('checks the installed coolify version', function () { + createSharedUserAndTeamTables(); + [$user, $team] = createV5UserWithTeam(); + + Process::fake([ + '*' => Process::result(output: 'coolify nightly-20260616', exitCode: 0), + ]); + + $this + ->actingAs($user) + ->withSession(['currentTeam' => $team]) + ->getJson('/v5/coolify/version') + ->assertSuccessful() + ->assertJson([ + 'available' => true, + 'label' => 'Installed', + 'version' => 'coolify nightly-20260616', + 'message' => 'Installed version: coolify nightly-20260616.', + 'binary' => '/usr/local/bin/coolify', + ]); +}); + +it('shows when coolify version check fails', function () { + createSharedUserAndTeamTables(); + [$user, $team] = createV5UserWithTeam(); + + Process::fake([ + '*' => Process::result(errorOutput: 'not found', exitCode: 127), + ]); + + $this + ->actingAs($user) + ->withSession(['currentTeam' => $team]) + ->getJson('/v5/coolify/version') + ->assertSuccessful() + ->assertJson([ + 'available' => false, + 'label' => 'Unavailable', + 'version' => null, + 'message' => 'not found', + 'binary' => '/usr/local/bin/coolify', + ]); +}); + function fakeFluxHealth(bool $available = true, string $message = 'Flux is running.'): void { app()->instance(FluxHealth::class, Mockery::mock(FluxHealth::class, function (MockInterface $mock) use ($available, $message) { @@ -218,3 +263,25 @@ function createSharedUserAndTeamTables(): void $table->unique(['team_id', 'user_id']); }); } + +/** + * @return array{0: User, 1: Team} + */ +function createV5UserWithTeam(): array +{ + $user = User::withoutEvents(fn () => User::query()->create([ + 'name' => 'Margaret Hamilton', + 'email' => 'margaret@example.com', + 'email_verified_at' => now(), + 'password' => 'password', + ])); + $team = Team::withoutEvents(fn () => Team::query()->create([ + 'name' => 'V5 Tooling Team', + 'description' => null, + 'personal_team' => false, + 'show_boarding' => false, + ])); + $user->teams()->attach($team, ['role' => 'owner']); + + return [$user, $team]; +}