CI: start Postgres as a step rather than a service container
CI / verify (push) Failing after 5s

The first run got through install, typecheck and all 39 tests, then failed on
`getaddrinfo EAI_AGAIN postgres`. This runner does not attach service
containers to the job's network, so the `services:` hostname never resolves.

Fixed by starting Postgres with `--network container:$HOSTNAME`, sharing the
job container's own network namespace so it appears on 127.0.0.1. That works
regardless of how the runner is configured — which matters here because the
runner is shared with other repositories and should not need reconfiguring to
suit this one.

Also queries row counts through `docker exec` rather than a local psql, since
the runner image is not guaranteed to ship postgresql-client, and removes the
container in an `if: always()` step so a failed run does not leave it behind.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-12 20:29:25 -07:00
parent 73231a8944
commit 40f6fd993d
+34 -16
View File
@@ -30,21 +30,17 @@ jobs:
verify:
runs-on: ubuntu-latest
services:
postgres:
image: postgres:16-alpine
# Postgres is started as a step rather than through `services:`.
#
# The runner here does not put service containers on the job's network, so
# `services:` yields "getaddrinfo EAI_AGAIN postgres". Sharing the job
# container's own network namespace (`--network container:$HOSTNAME`) puts
# Postgres on 127.0.0.1 and works regardless of how the runner is
# configured — which matters because this runner is shared with other
# repositories and should not have to be reconfigured to suit this one.
env:
POSTGRES_USER: pig
POSTGRES_PASSWORD: pig
POSTGRES_DB: pig
options: >-
--health-cmd "pg_isready -U pig"
--health-interval 5s
--health-timeout 5s
--health-retries 10
env:
DATABASE_URL: postgres://pig:pig@postgres:5432/pig
DATABASE_URL: postgres://pig:pig@127.0.0.1:5432/pig
PG_CONTAINER: pig-ci-pg-${{ github.run_id }}
steps:
- uses: actions/checkout@v4
@@ -53,6 +49,23 @@ jobs:
with:
node-version: '22'
- name: Start Postgres
run: |
docker rm -f "$PG_CONTAINER" 2>/dev/null || true
docker run -d --name "$PG_CONTAINER" \
--network "container:$(cat /etc/hostname)" \
-e POSTGRES_USER=pig -e POSTGRES_PASSWORD=pig -e POSTGRES_DB=pig \
postgres:16-alpine
for i in $(seq 1 60); do
if docker exec "$PG_CONTAINER" pg_isready -U pig -q; then
echo "Postgres ready after ${i}s"; exit 0
fi
sleep 1
done
echo "Postgres did not become ready"
docker logs "$PG_CONTAINER" | tail -30
exit 1
- name: Install
run: npm install --no-audit --no-fund
@@ -79,9 +92,10 @@ jobs:
# pointed at twice, and nobody notices until the counts look odd.
run: |
npx tsx packages/db/src/seed/index.ts > /dev/null
BEFORE=$(psql "$DATABASE_URL" -tAc "select count(*) from contacts")
count() { docker exec "$PG_CONTAINER" psql -U pig -d pig -tAc "select count(*) from contacts"; }
BEFORE=$(count)
npx tsx packages/db/src/seed/index.ts > /dev/null
AFTER=$(psql "$DATABASE_URL" -tAc "select count(*) from contacts")
AFTER=$(count)
echo "contacts: $BEFORE -> $AFTER"
test "$BEFORE" = "$AFTER" || { echo "SEED IS NOT IDEMPOTENT"; exit 1; }
@@ -122,3 +136,7 @@ jobs:
- name: Docker image builds
run: docker build -t pig:ci .
- name: Stop Postgres
if: always()
run: docker rm -f "$PG_CONTAINER" 2>/dev/null || true