Files
EpicNext-Cms/.gitea/workflows/ci.yaml
T
openhands 4007b01da9
CI / check (push) Successful in 1m10s
CI / deploy (push) Successful in 1m25s
CI / e2e (push) Successful in 22s
ci: run e2e smoke against deployed app and ignore playwright artifacts
- Add e2e job (needs deploy, main/master only) that installs the
  Playwright browser and smoke-tests the live container on :3002
- Keep deploy-job contract slice from bleeding into the e2e job
- Cover the e2e job in the CI workflow contract test
- Ignore Playwright output dirs (test-results, playwright-report,
  blob-report)
2026-09-04 13:32:51 +02:00

189 lines
7.2 KiB
YAML

name: CI
on:
push:
branches: [main, master]
tags: ["v*"]
pull_request:
branches: [main, master]
workflow_dispatch:
jobs:
# ─────────────────────────────────────────────
# Lint, typecheck & unit tests
# Draait op de host (self-hosted) waar Node 26 +
# pnpm 11 geïnstalleerd zijn en internet beschikbaar is.
# De job-container (docker mode) heeft GEEN outbound
# internet, dus we draaien alles direct op de host.
# ─────────────────────────────────────────────
check:
runs-on: self-hosted
steps:
- name: Checkout
uses: actions/checkout@v4
with:
repository: ${{ gitea.repository }}
token: ${{ gitea.token }}
- name: Toolchain check
run: node scripts/check-node-toolchain.mjs
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Lint
run: pnpm biome:lint
- name: Typecheck
run: pnpm typecheck
- name: Test
env:
SKIP_ENV_VALIDATION: 1
NODE_ENV: test
DATABASE_URL: "mysql://test:test@localhost:3306/test?charset=utf8mb4"
REDIS_URL: "redis://127.0.0.1:6379?connect_timeout=2"
AUTH_SECRET: "ci-test-secret-key-that-is-long-enough"
BCRYPT_ROUNDS: 4
run: pnpm test --maxWorkers=1
- name: Knip (unused files/exports)
run: pnpm knip
# ─────────────────────────────────────────────
# Docker build & deploy
# Draait op de host (self-hosted) zodat Docker
# toegang heeft tot de daemon en volumes.
# ─────────────────────────────────────────────
deploy:
needs: check
if: gitea.event_name == 'push' && (gitea.ref_name == 'main' || gitea.ref_name == 'master')
runs-on: self-hosted
steps:
- name: Checkout
uses: actions/checkout@v4
with:
repository: ${{ gitea.repository }}
token: ${{ gitea.token }}
- name: Provide production env for build
run: |
# De Next.js-build bakt NEXT_PUBLIC_* in de client-bundle en
# valideert DATABASE_URL/HOTEL_NAME (zie src/env.ts — validatie
# overslaan is verboden voor productie). .env staat niet in git,
# dus kopieer de productie-.env van de host in de build-context.
# Hij belandt alleen in de wegwerp-builder-stage, niet in de
# runtime-image (die krijgt env via -e flags bij docker run).
cp /var/www/atom-nexst/.env .env
- name: Build image
run: |
# --network=host is vereist: deze host heeft Docker iptables
# uitgeschakeld, dus build-containers op het bridge-netwerk
# hebben geen outbound internet (npm/pnpm zouden hangen).
DOCKER_BUILDKIT=1 docker build \
--network=host \
--build-arg NODE_OPTIONS="--max-old-space-size=1536" \
--cache-from epicnext-cms:latest \
-t epicnext-cms:latest .
- name: Run migrations
run: |
# Draai DB-migraties van deze commit op de host (de slimme
# runtime-image heeft geen source/tsx, zie docker-compose.yml).
# Idempotent: al toegepaste migraties worden overgeslagen.
# Gebruikt .env uit de eerdere stap (productie-DB). Vóór het
# vervangen van de container, zodat het schema klaarstaat.
pnpm install --frozen-lockfile
pnpm db:migrate
- name: Deploy container
shell: bash
run: |
# Maak poort 3002 vrij: stop zowel de vorige CI-container als de
# compose-container (beide draaien op het host-netwerk).
docker stop epicnext-cms-app 2>/dev/null || true
docker rm epicnext-cms-app 2>/dev/null || true
docker stop epicnext-cms 2>/dev/null || true
docker rm epicnext-cms 2>/dev/null || true
# Geef de productie-env 1-op-1 door. GEEN env-file-flag: `docker run`
# behoudt letterlijke quotes uit het bestand (DATABASE_URL="..." →
# ongeldige URL en crash), terwijl de shell ze correct stript.
# Sourcen + elke sleutel met -e doorgeven geeft de container exact
# dezelfde waarden als waarmee de image gebouwd is.
set -a
# shellcheck disable=SC1091
. /var/www/atom-nexst/.env
set +a
ENV_ARGS=()
while IFS='=' read -r key _; do
case "$key" in
''|'#'*|*[!A-Za-z0-9_]* ) continue ;;
esac
ENV_ARGS+=(-e "$key")
done < /var/www/atom-nexst/.env
# Zelfde env + volumes als docker-compose.yml, zodat de CI-container
# functioneel gelijk is aan de compose-container die hij vervangt.
docker run -d \
--name epicnext-cms-app \
--restart always \
--net=host \
"${ENV_ARGS[@]}" \
-v /var/www/atom-nexst/public/nitro-assets:/app/public/nitro-assets \
-v /var/www/atom-nexst/public/swf:/app/public/swf \
-v /var/www/atom-nexst/storage:/app/storage \
-v /var/www/Gamedata:/var/www/Gamedata \
epicnext-cms:latest
docker image prune -f
- name: Health check
run: |
for i in $(seq 1 30); do
if curl -sf --max-time 5 http://127.0.0.1:3002/api/health \
| grep -q '"database":true'; then
echo "Deploy OK"
exit 0
fi
echo "Waiting... ($i/30)"
sleep 3
done
echo "ERROR: Health check failed" >&2
docker logs epicnext-cms-app --tail 50 >&2 || true
echo "Rolling back to compose container..." >&2
docker stop epicnext-cms-app 2>/dev/null || true
docker rm epicnext-cms-app 2>/dev/null || true
docker compose -f /var/www/atom-nexst/docker-compose.yml up -d --no-build 2>&1 || true
exit 1
# ─────────────────────────────────────────────
# E2E smoke against the freshly deployed container.
# Runs after a successful deploy on main/master only
# (on PRs the deploy job is skipped, so this is skipped too).
# Public read-only endpoints only — safe against production.
# ─────────────────────────────────────────────
e2e:
needs: deploy
if: gitea.event_name == 'push' && (gitea.ref_name == 'main' || gitea.ref_name == 'master')
runs-on: self-hosted
steps:
- name: Checkout
uses: actions/checkout@v4
with:
repository: ${{ gitea.repository }}
token: ${{ gitea.token }}
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Install Playwright browser
run: pnpm exec playwright install chromium
- name: Smoke test deployed app
env:
PLAYWRIGHT_BASE_URL: "http://127.0.0.1:3002"
run: pnpm test:e2e