diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b5301e9..7729818 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -484,23 +484,39 @@ jobs: - name: Build and start app (full profile) run: docker compose -f docker-compose.yml -f docker-compose.ci.yml --profile full up -d --build app - - name: Wait for /api/health (up to 3 minutes) - # docker-compose.ci.yml attaches app/postgres/redis to gitea_gitea so the - # act_runner job container can reach them by compose service name. + - name: Resolve and pin app IP + # 'app' hostname collides on shared gitea_gitea network — same split + # -brain as e2epg. Smoke test #2 hit ERR_CONNECTION_REFUSED even + # after both warm-ups returned the expected codes, because curl and + # Playwright-launched Chromium picked different IPs from the DNS set. + # Probe each resolved IP for /api/health and pin the winner as + # APP_BASE_URL so every subsequent step (wait, warm-up, smoke run) + # hits the same container. run: | for i in $(seq 1 36); do - STATUS=$(curl -s -o /dev/null -w "%{http_code}" http://app:3100/api/health || echo "000") - echo "Attempt $i: HTTP $STATUS" - if [ "$STATUS" = "200" ]; then exit 0; fi + IPS=$(getent hosts app | awk '{print $1}') + if [ -n "$IPS" ]; then + for ip in $IPS; do + CODE=$(curl -s -o /dev/null -w "%{http_code}" --max-time 5 "http://$ip:3100/api/health" || echo "000") + echo "Attempt $i: $ip -> HTTP $CODE" + if [ "$CODE" = "200" ]; then + echo "APP_IP=$ip" >> "$GITHUB_ENV" + echo "APP_BASE_URL=http://$ip:3100" >> "$GITHUB_ENV" + exit 0 + fi + done + else + echo "Attempt $i: 'app' not yet in DNS" + fi sleep 5 done - echo "Health check timed out" + echo "No reachable app:3100 found" docker compose -f docker-compose.yml -f docker-compose.ci.yml logs app --tail=50 exit 1 - name: Verify health response contains status ok run: | - BODY=$(curl -sf http://app:3100/api/health) + BODY=$(curl -sf "$APP_BASE_URL/api/health") echo "$BODY" echo "$BODY" | grep '"status":"ok"' @@ -519,7 +535,7 @@ jobs: local path="$1" local expect="$2" for i in $(seq 1 24); do - CODE=$(curl -s -o /dev/null -w "%{http_code}" --max-time 30 "http://app:3100${path}" || echo "000") + CODE=$(curl -s -o /dev/null -w "%{http_code}" --max-time 30 "${APP_BASE_URL}${path}" || echo "000") echo "Warm-up ${path} $i: HTTP $CODE" if [ "$CODE" = "$expect" ]; then return 0; fi sleep 5 @@ -572,11 +588,9 @@ jobs: /tmp/pw-install/node_modules/.bin/playwright install chromium --with-deps - name: Run smoke tests - env: - # App runs on the compose network; act_runner job is on gitea_gitea - # (docker-compose.ci.yml attaches services to both). Override baseURL. - PLAYWRIGHT_BASE_URL: http://app:3100 - run: /tmp/pw-install/node_modules/.bin/playwright test --config apps/web/playwright.ci.config.ts + # Use the pinned APP_BASE_URL (explicit IP) so Chromium hits the same + # container as the warm-up probes. + run: PLAYWRIGHT_BASE_URL="$APP_BASE_URL" /tmp/pw-install/node_modules/.bin/playwright test --config apps/web/playwright.ci.config.ts - name: Upload Playwright report if: failure()