diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8644fbc..18d7428 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -70,6 +70,8 @@ jobs: set: | *.cache-from=type=gha,scope=${{github.ref}}-devbuild - name: Start services + env: + HTTP_PORT: "80" run: docker compose up php database --wait --no-build - name: Warm up dev cache run: docker compose exec -T php bin/console cache:warmup --env=dev diff --git a/CLAUDE.md b/CLAUDE.md index 01a09a2..ced2ff6 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -40,6 +40,24 @@ just shell # Interactive shell inside the PHP container just shell-run # Shell in a fresh one-off container ``` +### Working in git worktrees + +`just up` auto-runs `just init` first, which generates a gitignored `.env.local` per checkout with a unique +`COMPOSE_PROJECT_NAME`, `IMAGES_PREFIX`, and free `HTTP_PORT`/`HTTPS_PORT`/`POSTGRES_PORT`/`MAILPIT_PORT`/ +`SPOTLIGHT_PORT`. This means every worktree gets its own containers, network, volumes, and image tag — running +`just up` in two worktrees at the same time does **not** make them share a database, image, or port, even if the +worktree directories have the same basename. + +- Run `just ports` to see the ports assigned to the *current* checkout — the app for that worktree is at + `https://localhost:`, not a fixed port. Never assume port 8080/8443/5432/etc. when working inside a + worktree; always check `.env.local` or `just ports` first. +- `.env.local` is generated once and reused; it's safe to run `just init`/`just up` repeatedly. Delete `.env.local` + and re-run `just init` to force new ports (e.g. if the assigned ones are now taken by something else). +- Each worktree's Postgres data, uploaded files, and Caddy state live in per-worktree Docker volumes — nothing is + shared with the main checkout or other worktrees. Migrations/fixtures must be (re-)run per worktree. +- `just down`/`just clean` in one worktree only ever affects that worktree's own containers/volumes — safe to run + without impacting other worktrees. + ### Database ```bash diff --git a/Justfile b/Justfile index 3ea6bc6..dfd5d6e 100644 --- a/Justfile +++ b/Justfile @@ -1,9 +1,70 @@ -up *args: +# Load per-worktree overrides (project name, image tag, ports) generated by `just init` +set dotenv-load := true +set dotenv-filename := ".env.local" + +# Generate a per-worktree COMPOSE_PROJECT_NAME, IMAGES_PREFIX and free host ports in .env.local, +# so multiple worktrees/checkouts of this repo can run `just up` at the same time without their +# containers, volumes, images or ports colliding. Safe to re-run; no-ops if already configured. +init: + #!/usr/bin/env bash + set -euo pipefail + if [ -f .env.local ] && grep -q '^COMPOSE_PROJECT_NAME=' .env.local; then + echo ".env.local already configured for this worktree, skipping (delete it to regenerate)." + exit 0 + fi + free_port() { + local port="$1" max="$2" + while [ "$port" -le "$max" ]; do + if ! (exec 3<>/dev/tcp/127.0.0.1/"$port") 2>/dev/null; then + echo "$port" + return + fi + exec 3>&- 2>/dev/null || true + port=$((port + 1)) + done + echo "no free port found between $1 and $2" >&2 + exit 1 + } + if command -v sha1sum >/dev/null 2>&1; then + hash_cmd=(sha1sum) + elif command -v shasum >/dev/null 2>&1; then + hash_cmd=(shasum) + else + hash_cmd=(sha256sum) + fi + hash=$(pwd | "${hash_cmd[@]}" | cut -c1-8) + project="tvdt-${hash}" + http_port=$(free_port 8080 8179) + https_port=$(free_port 8443 8542) + postgres_port=$(free_port 5430 5529) + mailpit_port=$(free_port 8025 8124) + spotlight_port=$(free_port 8969 9068) + { + echo "COMPOSE_PROJECT_NAME=${project}" + echo "IMAGES_PREFIX=${project}-" + echo "HTTP_PORT=${http_port}" + echo "HTTPS_PORT=${https_port}" + echo "POSTGRES_PORT=${postgres_port}" + echo "MAILPIT_PORT=${mailpit_port}" + echo "SPOTLIGHT_PORT=${spotlight_port}" + } >> .env.local + echo "Generated .env.local for this worktree:" + cat .env.local + +up *args: init + #!/usr/bin/env bash + set -a + [ -f .env.local ] && source .env.local + set +a docker compose up -d {{ args }} down *args: docker compose down --remove-orphans {{ args }} +# Show the host ports assigned to this worktree (see `just init`) +ports: + @cat .env.local 2>/dev/null || echo "No .env.local yet, run 'just up' or 'just init' first." + stop: docker compose stop diff --git a/README.md b/README.md index c6e28ec..86adf97 100644 --- a/README.md +++ b/README.md @@ -25,8 +25,13 @@ just migrate # Run pending database migrations just fixtures # Load dev fixtures (truncates first) ``` -The app is available at **https://localhost** (self-signed cert — run -`just trust-cert` on macOS to trust it). +`just up` first runs `just init`, which generates a `.env.local` (gitignored) +with a unique `COMPOSE_PROJECT_NAME`, image tag and free host ports for this +checkout, so multiple worktrees/clones can run at the same time without their +containers, volumes, images or ports colliding. Run `just ports` to see the +ports assigned to the current checkout — the app is served at +`https://localhost:` (self-signed cert — run `just trust-cert` on +macOS to trust it). ### Useful commands diff --git a/compose.override.yaml b/compose.override.yaml index 7c718e0..b0f1cda 100644 --- a/compose.override.yaml +++ b/compose.override.yaml @@ -24,15 +24,15 @@ services: ports: # HTTP - target: 80 - published: ${HTTP_PORT:-80} + published: ${HTTP_PORT:-8080} protocol: tcp # HTTPS - target: 443 - published: ${HTTPS_PORT:-443} + published: ${HTTPS_PORT:-8443} protocol: tcp # HTTP/3 - target: 443 - published: ${HTTP3_PORT:-443} + published: ${HTTPS_PORT:-8443} protocol: udp sass: image: ${IMAGES_PREFIX:-}app-php @@ -56,7 +56,7 @@ services: ###> doctrine/doctrine-bundle ### database: ports: - - "5432:5432" + - "${POSTGRES_PORT:-5430}:5432" ###< doctrine/doctrine-bundle ### ###> symfony/mailer ### @@ -64,7 +64,7 @@ services: image: axllent/mailpit ports: - "1025" - - "8025:8025" + - "${MAILPIT_PORT:-8025}:8025" environment: MP_SMTP_AUTH_ACCEPT_ANY: 1 MP_SMTP_AUTH_ALLOW_INSECURE: 1 @@ -73,7 +73,7 @@ services: spotlight: image: ghcr.io/getsentry/spotlight:latest ports: - - "8969:8969" + - "${SPOTLIGHT_PORT:-8969}:8969" volumes: sass: