diff --git a/.gitea/workflows/deploy.yml b/.gitea/workflows/deploy.yml index 38b0c6f..d191eaf 100644 --- a/.gitea/workflows/deploy.yml +++ b/.gitea/workflows/deploy.yml @@ -28,14 +28,36 @@ jobs: run: | APP_DIR=/home/tyler/route-commerce mkdir -p $APP_DIR - # Free port 3001 if anything is still on it (stale container, leftover dev process) - if ss -tln 2>/dev/null | grep -q ':3001 '; then - echo "Port 3001 in use, attempting to free it..." - fuser -k 3001/tcp 2>/dev/null || true - docker ps -aq --filter "publish=3001" 2>/dev/null | xargs -r docker rm -f 2>/dev/null || true - docker compose -f $APP_DIR/docker-compose.yml down --remove-orphans 2>/dev/null || true - sleep 3 - fi + + # Free the dev-stack port (3001) and the port the previous deploy used + # (so a new deploy can pick it back up if it's the lowest free port) + PREV_PORT=$(cat .postgrest-port 2>/dev/null || echo "") + for port in 3001 $PREV_PORT; do + if [ -n "$port" ] && ss -tln 2>/dev/null | grep -q ":$port "; then + echo "Port $port in use, freeing..." + fuser -k -9 $port/tcp 2>/dev/null || true + docker ps -aq --filter "publish=$port" 2>/dev/null | xargs -r docker rm -f 2>/dev/null || true + fi + done + docker compose -f $APP_DIR/docker-compose.yml down --remove-orphans 2>/dev/null || true + sleep 3 + + # Find the first free host port starting from 3011. Persist the choice + # so the Build and Deploy steps below can use the same URL. + POSTGREST_HOST_PORT=3011 + while ss -tln 2>/dev/null | grep -q ":$POSTGREST_HOST_PORT "; do + echo "Port $POSTGREST_HOST_PORT in use, trying next..." + POSTGREST_HOST_PORT=$((POSTGREST_HOST_PORT + 1)) + if [ $POSTGREST_HOST_PORT -gt 30200 ]; then + echo "ERROR: no free port in 3011-30200 range" + exit 1 + fi + done + echo "Using PostgREST host port: $POSTGREST_HOST_PORT" + echo "$POSTGREST_HOST_PORT" > .postgrest-port + export NEXT_PUBLIC_API_URL="http://localhost:$POSTGREST_HOST_PORT" + export POSTGREST_HOST_PORT + # Seed config files into APP_DIR if missing (they live in the repo, not in APP_DIR) [ -f $APP_DIR/.env.example ] || cp .env.example $APP_DIR/.env.example [ -f $APP_DIR/docker-compose.yml ] || cp docker-compose.yml $APP_DIR/docker-compose.yml @@ -49,7 +71,8 @@ jobs: echo "MINIO_ROOT_USER=${MINIO_ROOT_USER}" echo "MINIO_ROOT_PASSWORD=${MINIO_ROOT_PASSWORD}" echo "POSTGREST_JWT_SECRET=${POSTGREST_JWT_SECRET}" - echo "NEXT_PUBLIC_API_URL=http://localhost:3011" + echo "POSTGREST_HOST_PORT=$POSTGREST_HOST_PORT" + echo "NEXT_PUBLIC_API_URL=$NEXT_PUBLIC_API_URL" } >> .env # Bring the stack up fresh — --force-recreate ensures no stale # network/container references from prior failed attempts @@ -86,7 +109,6 @@ jobs: - name: Build env: NODE_ENV: production - NEXT_PUBLIC_API_URL: http://localhost:3011 DATABASE_URL: ${{ secrets.DATABASE_URL }} BETTER_AUTH_SECRET: ${{ secrets.BETTER_AUTH_SECRET }} BETTER_AUTH_URL: ${{ secrets.BETTER_AUTH_URL }} @@ -107,11 +129,13 @@ jobs: MINIMAX_API_KEY: ${{ secrets.MINIMAX_API_KEY }} MINIMAX_BASE_URL: ${{ secrets.MINIMAX_BASE_URL }} FROM_EMAIL: ${{ secrets.FROM_EMAIL }} - run: npm run build + run: | + POSTGREST_HOST_PORT=$(cat .postgrest-port) + export NEXT_PUBLIC_API_URL="http://localhost:$POSTGREST_HOST_PORT" + npm run build - name: Deploy env: - NEXT_PUBLIC_API_URL: http://localhost:3011 DATABASE_URL: ${{ secrets.DATABASE_URL }} POSTGRES_USER: ${{ secrets.POSTGRES_USER }} POSTGRES_PASSWORD: ${{ secrets.POSTGRES_PASSWORD }} @@ -145,6 +169,9 @@ jobs: run: | APP_DIR=/home/tyler/route-commerce mkdir -p $APP_DIR + # Use the port chosen by Start Docker stack (persisted to .postgrest-port) + POSTGREST_HOST_PORT=$(cat .postgrest-port) + export NEXT_PUBLIC_API_URL="http://localhost:$POSTGREST_HOST_PORT" # Write env file from secrets (preserves existing .env for docker compose) { diff --git a/docker-compose.yml b/docker-compose.yml index e38d11e..69da5e5 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -36,7 +36,7 @@ services: PGRST_OPENAPI_MODE: disabled PGRST_DB_EXTRA_SEARCH_PATH: public,extensions ports: - - "127.0.0.1:3011:3001" + - "127.0.0.1:${POSTGREST_HOST_PORT:-3011}:3001" minio: image: minio/minio:latest