diff --git a/.github/workflows/pr-open.yml b/.github/workflows/pr-open.yml index f57f9ac..f5f7106 100644 --- a/.github/workflows/pr-open.yml +++ b/.github/workflows/pr-open.yml @@ -76,11 +76,50 @@ jobs: with: target: ${{ github.event.number }} + compose: + name: Docker Compose + runs-on: ubuntu-26.04 + timeout-minutes: 15 + permissions: + contents: read + steps: + - uses: actions/checkout@v7 + - uses: actions/setup-node@v7 + with: + node-version: "24.x" + + # docker-compose.yml serves frontend/dist from the host + - name: Build frontend + working-directory: frontend + run: npm ci --ignore-scripts && npm run build + + - name: Start stack + run: docker compose up --build --detach --wait --wait-timeout 300 + + - name: Smoke test + run: | + set -euo pipefail + curl -fsS --retry 5 --retry-all-errors --retry-delay 3 http://localhost:3005/api/pub-code/health + curl -fsS --retry 5 --retry-all-errors --retry-delay 3 http://localhost:3002/ | grep -q '
' + curl -fsS --retry 5 --retry-all-errors --retry-delay 3 http://localhost:3002/api/pub-code/health + # mongo-express may answer 401 (basic auth); anything below 500 means it's up + code=$(curl -sS --retry 5 --retry-all-errors --retry-delay 3 -o /dev/null -w '%{http_code}' http://localhost:8001/) + echo "mongo-express: HTTP ${code}" + [ "${code}" -lt 500 ] + + - name: Logs + if: failure() + run: docker compose logs + + - name: Stop stack + if: always() + run: docker compose down -v + # This job is the merge gate for this workflow. Every job in this # workflow must be listed in 'needs', or its failure won't block the PR. results: name: PR Results - needs: [builds, deploys, tests] + needs: [builds, compose, deploys, tests] if: always() runs-on: ubuntu-26.04 timeout-minutes: 1 diff --git a/docker-compose.yml b/docker-compose.yml index 8dcf8e9..6ee92a4 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -11,6 +11,11 @@ services: image: ghcr.io/bcgov/nr-containers/mongo:7.0.43 ports: ["27017:27017"] restart: unless-stopped + healthcheck: + test: ["CMD", "mongosh", "--quiet", "--eval", "db.adminCommand({ ping: 1 })"] + interval: 5s + timeout: 5s + retries: 20 mongo-express: # The admin UI container for mongoDB image: mongo-express @@ -27,7 +32,7 @@ services: ME_CONFIG_MONGODB_URL: mongodb://admin:DPEPGHbjUluRjetU@database:27017/ depends_on: database: - condition: service_started + condition: service_healthy api: image: pub-code-api:latest @@ -38,23 +43,43 @@ services: DB_USER: admin DB_PWD: DPEPGHbjUluRjetU DB_NAME: pubcode + # The API won't start without CHES settings. These placeholders let it + # start; set real values in your shell to send email locally. + CHES_TOKEN_URL: ${CHES_TOKEN_URL:-http://localhost/ches/token} + CHES_CLIENT_ID: ${CHES_CLIENT_ID:-placeholder} + CHES_CLIENT_SECRET: ${CHES_CLIENT_SECRET:-placeholder} + CHES_API_URL: ${CHES_API_URL:-http://localhost/ches} ports: - "3005:3000" restart: unless-stopped + # The image is distroless (no curl), so check with Node instead + healthcheck: + test: ["CMD", "/nodejs/bin/node", "-e", "fetch('http://localhost:3000/').then(r => process.exit(r.ok ? 0 : 1)).catch(() => process.exit(1))"] + interval: 5s + timeout: 5s + retries: 20 depends_on: database: - condition: service_started + condition: service_healthy #Run npm run build-watch in local before this. frontend: image: caddy:2.11.7-alpine working_dir: /app + environment: + BACKEND_URL: http://api:3000 + LOG_LEVEL: info volumes: - ./frontend/Caddyfile:/etc/caddy/Caddyfile - ./frontend/dist:/app/dist + healthcheck: + test: ["CMD", "wget", "-qO-", "http://localhost:3001/health"] + interval: 5s + timeout: 5s + retries: 20 depends_on: api: - condition: service_started + condition: service_healthy ports: - "3002:3000" restart: unless-stopped