All checks were successful
CI / Lint, typecheck, test (push) Successful in 3m6s
CI / Build container images (push) Has been skipped
CD / Build and push images (push) Successful in 3m13s
CD / Deploy to Test (push) Successful in 12s
CD / Smoke tests against Test (push) Successful in 1m14s
CD / Promote to Int (push) Successful in 10s
CI / Auth e2e pack (push) Successful in 5m6s
CI / Import/export fidelity gate (push) Successful in 45s
The SPA now probes GET /setup on boot: while setup is pending it renders only the wizard at /setup, the login page (to resume a started wizard as the Site Admin), and a "setup pending" notice on every other route — without the regular chrome, whose pond/search queries would all 503. If the probe itself fails (offline reload), the app falls through to the normal routes. Once completed, /setup just goes home. The wizard walks six steps against the #80 api: welcome with language choice (drives i18n immediately and pre-fills the admin/instance locales), Site Admin account (signs in via the step-1 session cookie), instance basics, SMTP with live-test-before-save plus an explicit skip, registration mode, and a summary whose finish unlocks the app logged-in-ready. Every step validates through the shared Zod schemas before advancing; entered values live in the parent component, so Back preserves them, and re-submitting a step on a second forward pass just overwrites the same settings. A wizard someone else started shows a sign-in hand-off instead of dead admin-gated steps. New `setup` i18n namespace in de and en. Two #80 touch-ups fell out of verifying this end to end: the SMTP port's NaN case now maps to the translated required-message, and GET /setup's smtpConfigured uses `||` instead of `??` so the empty strings compose passes for unset vars fall through to the secret store. The e2e pack (setup.spec.ts) needs an instance where setup is still pending, so the CI job provisions a second api + static web against a virgin database on their own ports and runs the full wizard journey there, including the failing-relay path and both languages. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EwZ4jR4KFAPvpjWevfUGX1
536 lines
22 KiB
YAML
536 lines
22 KiB
YAML
# CI: every pull request and every push to main must pass these checks
|
|
# (ADR 0014). The deploy pipeline (CD) lives in cd.yml and only runs on
|
|
# main after this workflow's quality bar.
|
|
#
|
|
# Runner requirements: an act_runner with the `ubuntu-latest` label and
|
|
# Docker access (see deploy/stages.md, issue #9).
|
|
|
|
name: CI
|
|
|
|
on:
|
|
pull_request:
|
|
push:
|
|
branches: [main]
|
|
|
|
jobs:
|
|
# The pnpm jobs are chained (checks -> auth-e2e -> fidelity) so no two run
|
|
# at once. At runner capacity > 1 they otherwise start together and extract
|
|
# the same actions (setup-node, pnpm/action-setup) into the shared offline
|
|
# cache (`/run/act/actions`) concurrently, reading it half-written — a flaky
|
|
# "Cannot find module .../dist/…" in "Set up Node.js"/"Set up pnpm". Warming
|
|
# the cache first did not help (concurrent extraction still corrupts it);
|
|
# only serialization does. The CD image builds still run in parallel, so the
|
|
# runner's spare capacity is not wasted.
|
|
checks:
|
|
name: Lint, typecheck, test
|
|
runs-on: ubuntu-latest
|
|
services:
|
|
postgres:
|
|
image: postgres:17.5-alpine
|
|
env:
|
|
POSTGRES_USER: test
|
|
POSTGRES_PASSWORD: test
|
|
POSTGRES_DB: test
|
|
env:
|
|
# Enables the database-backed test suites (vitest.global-setup.ts).
|
|
TEST_DATABASE_URL: postgresql://test:test@postgres:5432/test
|
|
steps:
|
|
- name: Check out repository
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Set up pnpm
|
|
uses: pnpm/action-setup@v4
|
|
|
|
- name: Set up Node.js
|
|
uses: actions/setup-node@v4
|
|
with:
|
|
node-version: 22
|
|
cache: pnpm
|
|
|
|
- name: Install dependencies
|
|
run: pnpm install --frozen-lockfile
|
|
|
|
# Build first: package type checks resolve @dorfteich/shared through
|
|
# its built dist, and i18n:check imports the built helpers.
|
|
- name: Build all packages
|
|
run: pnpm build
|
|
|
|
- name: Lint (ESLint + Prettier)
|
|
run: pnpm lint
|
|
|
|
- name: Typecheck
|
|
run: pnpm typecheck
|
|
|
|
- name: Unit and integration tests
|
|
run: pnpm test
|
|
|
|
- name: Translation key parity (de/en)
|
|
run: pnpm i18n:check
|
|
|
|
# Job id/display name kept stable (branch-protection/status-check
|
|
# matching uses the reported "CI / Auth e2e pack" context) even though
|
|
# it now also runs the content pack (issue #32) against the same
|
|
# already-built-and-seeded stack, instead of spinning up a second one.
|
|
auth-e2e:
|
|
name: Auth e2e pack
|
|
needs: checks
|
|
runs-on: ubuntu-latest
|
|
services:
|
|
postgres:
|
|
image: postgres:17.5-alpine
|
|
env:
|
|
POSTGRES_USER: e2e
|
|
POSTGRES_PASSWORD: e2e
|
|
POSTGRES_DB: e2e
|
|
mailpit:
|
|
image: axllent/mailpit:latest
|
|
env:
|
|
DATABASE_URL: postgresql://e2e:e2e@postgres:5432/e2e
|
|
APP_BASE_URL: http://localhost:5173
|
|
SMTP_HOST: mailpit
|
|
SMTP_PORT: '1025'
|
|
steps:
|
|
- name: Check out repository
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Set up pnpm
|
|
uses: pnpm/action-setup@v4
|
|
|
|
- name: Set up Node.js
|
|
uses: actions/setup-node@v4
|
|
with:
|
|
node-version: 22
|
|
cache: pnpm
|
|
|
|
- name: Install dependencies
|
|
run: pnpm install --frozen-lockfile
|
|
|
|
- name: Build packages
|
|
run: pnpm build
|
|
|
|
- name: Apply migrations
|
|
run: pnpm --filter @dorfteich/api exec prisma migrate deploy
|
|
|
|
- name: Seed fixtures
|
|
run: pnpm --filter @dorfteich/api db:seed
|
|
|
|
- name: Start api, collab, and static web server
|
|
run: |
|
|
(cd apps/api && PORT=3001 node dist/main.js > /tmp/api.log 2>&1 &)
|
|
(cd apps/collab && PORT=3002 node dist/index.js > /tmp/collab.log 2>&1 &)
|
|
(PORT=5173 COLLAB_TARGET=http://127.0.0.1:3002 node scripts/e2e-static-server.mjs > /tmp/web.log 2>&1 &)
|
|
for i in $(seq 1 30); do
|
|
curl -sf http://localhost:3001/api/v1/readyz >/dev/null && break
|
|
sleep 2
|
|
done
|
|
for i in $(seq 1 30); do
|
|
curl -sf http://localhost:3002/healthz >/dev/null && break
|
|
sleep 2
|
|
done
|
|
curl -sf http://localhost:5173/ >/dev/null
|
|
|
|
- name: Install Playwright browser
|
|
run: pnpm --filter @dorfteich/web exec playwright install --with-deps chromium
|
|
|
|
- name: Run auth pack
|
|
run: |
|
|
E2E_BASE_URL=http://localhost:5173 E2E_MAILPIT_URL=http://mailpit:8025 \
|
|
pnpm --filter @dorfteich/web exec playwright test e2e/auth.spec.ts
|
|
|
|
# auth.spec.ts's own logins (contextForUser per test) already spend
|
|
# a good chunk of the login rate limit (10/min/IP, operations.md) —
|
|
# reset it before content.spec.ts's five more, or its later tests
|
|
# 429 (found by reproducing this job's failure locally, issue #32).
|
|
- name: Reset login rate limit between e2e packs
|
|
run: |
|
|
echo "DELETE FROM rate_limits WHERE key LIKE 'login%';" | \
|
|
pnpm --filter @dorfteich/api exec prisma db execute --stdin --url "$DATABASE_URL"
|
|
|
|
- name: Run content pack
|
|
run: |
|
|
E2E_BASE_URL=http://localhost:5173 \
|
|
pnpm --filter @dorfteich/web exec playwright test e2e/content.spec.ts
|
|
|
|
# The collab pack opens two browser contexts per test (more logins),
|
|
# so reset the login rate limit before it as well (see note above).
|
|
- name: Reset login rate limit before collab pack
|
|
run: |
|
|
echo "DELETE FROM rate_limits WHERE key LIKE 'login%';" | \
|
|
pnpm --filter @dorfteich/api exec prisma db execute --stdin --url "$DATABASE_URL"
|
|
|
|
- name: Run collab pack
|
|
run: |
|
|
E2E_BASE_URL=http://localhost:5173 \
|
|
pnpm --filter @dorfteich/web exec playwright test e2e/collab.spec.ts
|
|
|
|
# Two contexts per test (owner + a second regular account) and grant
|
|
# changes → reset the login rate limit first (see note above).
|
|
- name: Reset login rate limit before collab-permissions pack
|
|
run: |
|
|
echo "DELETE FROM rate_limits WHERE key LIKE 'login%';" | \
|
|
pnpm --filter @dorfteich/api exec prisma db execute --stdin --url "$DATABASE_URL"
|
|
|
|
- name: Run collab-permissions pack
|
|
run: |
|
|
E2E_BASE_URL=http://localhost:5173 \
|
|
pnpm --filter @dorfteich/web exec playwright test e2e/collab-permissions.spec.ts
|
|
|
|
# Two contexts per test (owner + a second regular account) → reset first.
|
|
- name: Reset login rate limit before members pack
|
|
run: |
|
|
echo "DELETE FROM rate_limits WHERE key LIKE 'login%';" | \
|
|
pnpm --filter @dorfteich/api exec prisma db execute --stdin --url "$DATABASE_URL"
|
|
|
|
- name: Run members pack
|
|
run: |
|
|
E2E_BASE_URL=http://localhost:5173 \
|
|
pnpm --filter @dorfteich/web exec playwright test e2e/members.spec.ts
|
|
|
|
# Three contexts per test (owner + editor + viewer) → reset first.
|
|
- name: Reset login rate limit before access-rules pack
|
|
run: |
|
|
echo "DELETE FROM rate_limits WHERE key LIKE 'login%';" | \
|
|
pnpm --filter @dorfteich/api exec prisma db execute --stdin --url "$DATABASE_URL"
|
|
|
|
- name: Run access-rules pack
|
|
run: |
|
|
E2E_BASE_URL=http://localhost:5173 \
|
|
pnpm --filter @dorfteich/web exec playwright test e2e/access-rules.spec.ts
|
|
|
|
- name: Reset login rate limit before public pack
|
|
run: |
|
|
echo "DELETE FROM rate_limits WHERE key LIKE 'login%';" | \
|
|
pnpm --filter @dorfteich/api exec prisma db execute --stdin --url "$DATABASE_URL"
|
|
|
|
- name: Run public pack
|
|
run: |
|
|
E2E_BASE_URL=http://localhost:5173 \
|
|
pnpm --filter @dorfteich/web exec playwright test e2e/public.spec.ts
|
|
|
|
- name: Reset login rate limit before admin-quotas pack
|
|
run: |
|
|
echo "DELETE FROM rate_limits WHERE key LIKE 'login%';" | \
|
|
pnpm --filter @dorfteich/api exec prisma db execute --stdin --url "$DATABASE_URL"
|
|
|
|
- name: Run admin-quotas pack
|
|
run: |
|
|
E2E_BASE_URL=http://localhost:5173 \
|
|
pnpm --filter @dorfteich/web exec playwright test e2e/admin-quotas.spec.ts
|
|
|
|
- name: Reset login rate limit before admin-users pack
|
|
run: |
|
|
echo "DELETE FROM rate_limits WHERE key LIKE 'login%';" | \
|
|
pnpm --filter @dorfteich/api exec prisma db execute --stdin --url "$DATABASE_URL"
|
|
|
|
- name: Run admin-users pack
|
|
run: |
|
|
E2E_BASE_URL=http://localhost:5173 \
|
|
pnpm --filter @dorfteich/web exec playwright test e2e/admin-users.spec.ts
|
|
|
|
- name: Reset login rate limit before permission-matrix pack
|
|
run: |
|
|
echo "DELETE FROM rate_limits WHERE key LIKE 'login%';" | \
|
|
pnpm --filter @dorfteich/api exec prisma db execute --stdin --url "$DATABASE_URL"
|
|
|
|
- name: Run permission-matrix pack
|
|
run: |
|
|
E2E_BASE_URL=http://localhost:5173 \
|
|
pnpm --filter @dorfteich/web exec playwright test e2e/permission-matrix.spec.ts
|
|
|
|
- name: Reset login rate limit before attachments pack
|
|
run: |
|
|
echo "DELETE FROM rate_limits WHERE key LIKE 'login%';" | \
|
|
pnpm --filter @dorfteich/api exec prisma db execute --stdin --url "$DATABASE_URL"
|
|
|
|
- name: Run attachments pack
|
|
run: |
|
|
E2E_BASE_URL=http://localhost:5173 \
|
|
pnpm --filter @dorfteich/web exec playwright test e2e/attachments.spec.ts
|
|
|
|
- name: Reset login rate limit before import pack
|
|
run: |
|
|
echo "DELETE FROM rate_limits WHERE key LIKE 'login%';" | \
|
|
pnpm --filter @dorfteich/api exec prisma db execute --stdin --url "$DATABASE_URL"
|
|
|
|
# The .docx case self-skips without a reachable pandoc sidecar (no
|
|
# E2E_PANDOC here); the .md, failure, and concurrent cases run (#64).
|
|
- name: Run import pack
|
|
run: |
|
|
E2E_BASE_URL=http://localhost:5173 \
|
|
pnpm --filter @dorfteich/web exec playwright test e2e/import.spec.ts
|
|
|
|
- name: Reset login rate limit before export pack
|
|
run: |
|
|
echo "DELETE FROM rate_limits WHERE key LIKE 'login%';" | \
|
|
pnpm --filter @dorfteich/api exec prisma db execute --stdin --url "$DATABASE_URL"
|
|
|
|
# The ZIP case runs; the .docx case self-skips without a pandoc sidecar (#65).
|
|
- name: Run export pack
|
|
run: |
|
|
E2E_BASE_URL=http://localhost:5173 \
|
|
pnpm --filter @dorfteich/web exec playwright test e2e/export.spec.ts
|
|
|
|
- name: Reset login rate limit before fonts pack
|
|
run: |
|
|
echo "DELETE FROM rate_limits WHERE key LIKE 'login%';" | \
|
|
pnpm --filter @dorfteich/api exec prisma db execute --stdin --url "$DATABASE_URL"
|
|
|
|
# Pond fonts (#66): the GDPR no-off-origin assertion + apply/persist.
|
|
- name: Run fonts pack
|
|
run: |
|
|
E2E_BASE_URL=http://localhost:5173 \
|
|
pnpm --filter @dorfteich/web exec playwright test e2e/fonts.spec.ts
|
|
|
|
- name: Reset login rate limit before offline pack
|
|
run: |
|
|
echo "DELETE FROM rate_limits WHERE key LIKE 'login%';" | \
|
|
pnpm --filter @dorfteich/api exec prisma db execute --stdin --url "$DATABASE_URL"
|
|
|
|
- name: Run offline pack
|
|
run: |
|
|
E2E_BASE_URL=http://localhost:5173 \
|
|
pnpm --filter @dorfteich/web exec playwright test e2e/offline.spec.ts
|
|
|
|
- name: Reset login rate limit before labels pack
|
|
run: |
|
|
echo "DELETE FROM rate_limits WHERE key LIKE 'login%';" | \
|
|
pnpm --filter @dorfteich/api exec prisma db execute --stdin --url "$DATABASE_URL"
|
|
|
|
- name: Run labels pack
|
|
run: |
|
|
E2E_BASE_URL=http://localhost:5173 \
|
|
pnpm --filter @dorfteich/web exec playwright test e2e/labels.spec.ts
|
|
|
|
- name: Reset login rate limit before reorder pack
|
|
run: |
|
|
echo "DELETE FROM rate_limits WHERE key LIKE 'login%';" | \
|
|
pnpm --filter @dorfteich/api exec prisma db execute --stdin --url "$DATABASE_URL"
|
|
|
|
- name: Run reorder pack
|
|
run: |
|
|
E2E_BASE_URL=http://localhost:5173 \
|
|
pnpm --filter @dorfteich/web exec playwright test e2e/reorder.spec.ts
|
|
|
|
- name: Reset login rate limit before wikilink pack
|
|
run: |
|
|
echo "DELETE FROM rate_limits WHERE key LIKE 'login%';" | \
|
|
pnpm --filter @dorfteich/api exec prisma db execute --stdin --url "$DATABASE_URL"
|
|
|
|
- name: Run wikilink pack
|
|
run: |
|
|
E2E_BASE_URL=http://localhost:5173 \
|
|
pnpm --filter @dorfteich/web exec playwright test e2e/wikilink.spec.ts
|
|
|
|
- name: Reset login rate limit before backlinks pack
|
|
run: |
|
|
echo "DELETE FROM rate_limits WHERE key LIKE 'login%';" | \
|
|
pnpm --filter @dorfteich/api exec prisma db execute --stdin --url "$DATABASE_URL"
|
|
|
|
- name: Run backlinks pack
|
|
run: |
|
|
E2E_BASE_URL=http://localhost:5173 \
|
|
pnpm --filter @dorfteich/web exec playwright test e2e/backlinks.spec.ts
|
|
|
|
- name: Reset login rate limit before search pack
|
|
run: |
|
|
echo "DELETE FROM rate_limits WHERE key LIKE 'login%';" | \
|
|
pnpm --filter @dorfteich/api exec prisma db execute --stdin --url "$DATABASE_URL"
|
|
|
|
- name: Run search pack
|
|
run: |
|
|
E2E_BASE_URL=http://localhost:5173 \
|
|
pnpm --filter @dorfteich/web exec playwright test e2e/search.spec.ts
|
|
|
|
- name: Run plugin sandbox pack
|
|
run: |
|
|
E2E_BASE_URL=http://localhost:5173 \
|
|
pnpm --filter @dorfteich/web exec playwright test e2e/plugins.spec.ts
|
|
|
|
- name: Run plugin admin pack
|
|
run: |
|
|
E2E_BASE_URL=http://localhost:5173 \
|
|
pnpm --filter @dorfteich/web exec playwright test e2e/plugin-admin.spec.ts
|
|
|
|
# Several contexts per test across these two packs → reset first.
|
|
- name: Reset login rate limit before plugin feature packs
|
|
run: |
|
|
echo "DELETE FROM rate_limits WHERE key LIKE 'login%';" | \
|
|
pnpm --filter @dorfteich/api exec prisma db execute --stdin --url "$DATABASE_URL"
|
|
|
|
- name: Run section-styles pack
|
|
run: |
|
|
E2E_BASE_URL=http://localhost:5173 \
|
|
pnpm --filter @dorfteich/web exec playwright test e2e/section-styles.spec.ts
|
|
|
|
- name: Run plugin blocks pack
|
|
run: |
|
|
E2E_BASE_URL=http://localhost:5173 \
|
|
pnpm --filter @dorfteich/web exec playwright test e2e/plugin-blocks.spec.ts
|
|
|
|
# Owner + admin + restricted viewer contexts → reset first.
|
|
- name: Reset login rate limit before page-tools pack
|
|
run: |
|
|
echo "DELETE FROM rate_limits WHERE key LIKE 'login%';" | \
|
|
pnpm --filter @dorfteich/api exec prisma db execute --stdin --url "$DATABASE_URL"
|
|
|
|
- name: Run page-tools pack
|
|
run: |
|
|
E2E_BASE_URL=http://localhost:5173 \
|
|
pnpm --filter @dorfteich/web exec playwright test e2e/page-tools.spec.ts
|
|
|
|
# Owner + admin contexts in the collab case → reset first.
|
|
- name: Reset login rate limit before mermaid pack
|
|
run: |
|
|
echo "DELETE FROM rate_limits WHERE key LIKE 'login%';" | \
|
|
pnpm --filter @dorfteich/api exec prisma db execute --stdin --url "$DATABASE_URL"
|
|
|
|
- name: Run mermaid pack
|
|
run: |
|
|
E2E_BASE_URL=http://localhost:5173 \
|
|
pnpm --filter @dorfteich/web exec playwright test e2e/mermaid.spec.ts
|
|
|
|
# The setup wizard (issue #81) needs an instance where setup is still
|
|
# pending — the main stack is seeded and long past it. Provision a
|
|
# second api + static web against a virgin database on their own ports.
|
|
# SMTP_HOST/PORT are forced empty so the fresh api boots unconfigured
|
|
# like a real first run (loadApiEnv drops empty strings, issue #80).
|
|
- name: Provision fresh setup stack
|
|
run: |
|
|
(cd apps/api && node -e '
|
|
const { PrismaClient } = require("@prisma/client");
|
|
const admin = new PrismaClient();
|
|
admin.$executeRawUnsafe("CREATE DATABASE setup_e2e")
|
|
.finally(() => admin.$disconnect());
|
|
')
|
|
DATABASE_URL=postgresql://e2e:e2e@postgres:5432/setup_e2e \
|
|
pnpm --filter @dorfteich/api exec prisma migrate deploy
|
|
(cd apps/api && PORT=3005 \
|
|
DATABASE_URL=postgresql://e2e:e2e@postgres:5432/setup_e2e \
|
|
APP_BASE_URL=http://localhost:5175 SMTP_HOST= SMTP_PORT= \
|
|
SECRETS_FILE=/tmp/setup-secrets.env \
|
|
node dist/main.js > /tmp/api-setup.log 2>&1 &)
|
|
(PORT=5175 API_TARGET=http://127.0.0.1:3005 \
|
|
node scripts/e2e-static-server.mjs > /tmp/web-setup.log 2>&1 &)
|
|
for i in $(seq 1 30); do
|
|
curl -sf http://localhost:3005/api/v1/readyz >/dev/null && break
|
|
sleep 2
|
|
done
|
|
|
|
- name: Run setup wizard pack
|
|
run: |
|
|
E2E_BASE_URL=http://localhost:5175 E2E_SETUP=1 \
|
|
pnpm --filter @dorfteich/web exec playwright test e2e/setup.spec.ts
|
|
|
|
- name: Dump server logs on failure
|
|
if: failure()
|
|
run: tail -50 /tmp/api.log /tmp/collab.log /tmp/web.log /tmp/api-setup.log /tmp/web-setup.log || true
|
|
|
|
# The import/export fidelity gate (issue #69, ADR 0009): runs the corpus
|
|
# snapshot suites and the PDF smoke check against the *pinned* sidecar images
|
|
# (the same versions the stages run), so a structural regression — ours or a
|
|
# pandoc/Gotenberg version bump that drifts the output — fails the pipeline
|
|
# instead of degrading "best effort" silently. Kept a small, separate job so
|
|
# it stays well under five minutes; the suites self-skip in the main `checks`
|
|
# job (no sidecars there).
|
|
fidelity:
|
|
name: Import/export fidelity gate
|
|
needs: auth-e2e
|
|
runs-on: ubuntu-latest
|
|
# A guard so a hung sidecar can never keep the job (and its containers)
|
|
# alive on the shared runner host; the suite itself finishes in ~1 min.
|
|
timeout-minutes: 10
|
|
steps:
|
|
- name: Check out repository
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Set up pnpm
|
|
uses: pnpm/action-setup@v4
|
|
|
|
- name: Set up Node.js
|
|
uses: actions/setup-node@v4
|
|
with:
|
|
node-version: 22
|
|
cache: pnpm
|
|
|
|
- name: Install dependencies
|
|
run: pnpm install --frozen-lockfile
|
|
|
|
# The fidelity tests import from @dorfteich/shared's built dist; they run
|
|
# TypeScript directly (vitest) so only shared needs building, not the api.
|
|
- name: Build shared package
|
|
run: pnpm --filter @dorfteich/shared build
|
|
|
|
# The import corpus test reaches through import.service, which imports the
|
|
# generated Prisma client — generate it (no DB or migration needed; these
|
|
# suites never touch a database).
|
|
- name: Generate Prisma client
|
|
run: pnpm --filter @dorfteich/api exec prisma generate
|
|
|
|
# Start the pinned sidecars with `docker run` (pandoc-server needs the
|
|
# `server` arg, which Actions `services:` cannot pass) and attach them to
|
|
# THIS job container's network namespace, so they are reachable at
|
|
# localhost — no dependency on `ip`/gateway routing (the minimal runner
|
|
# image has no iproute2). Sharing the netns means no published ports.
|
|
- name: Start pinned pandoc + Gotenberg sidecars
|
|
run: |
|
|
# Clear any leftovers from an earlier interrupted run so the named
|
|
# containers never collide, and nothing leaks on the shared host.
|
|
docker rm -f fidelity-pandoc fidelity-gotenberg 2>/dev/null || true
|
|
JOB_ID=$(cat /etc/hostname)
|
|
docker run -d --name fidelity-pandoc \
|
|
--network "container:${JOB_ID}" pandoc/core:3.6 server
|
|
docker run -d --name fidelity-gotenberg \
|
|
--network "container:${JOB_ID}" gotenberg/gotenberg:8
|
|
for i in $(seq 1 30); do
|
|
curl -sf http://localhost:3030/version >/dev/null && break
|
|
sleep 1
|
|
done
|
|
for i in $(seq 1 30); do
|
|
curl -sf http://localhost:3000/health >/dev/null && break
|
|
sleep 1
|
|
done
|
|
curl -sf http://localhost:3030/version
|
|
curl -sf http://localhost:3000/health
|
|
|
|
- name: Run fidelity suite (import + export snapshots, PDF smoke)
|
|
run: |
|
|
PANDOC_URL=http://localhost:3030 GOTENBERG_URL=http://localhost:3000 \
|
|
pnpm --filter @dorfteich/api exec vitest run \
|
|
src/import-export/import.fixtures.test.ts \
|
|
src/import-export/export.fidelity.test.ts \
|
|
src/import-export/pdf.fidelity.test.ts
|
|
|
|
- name: Dump sidecar logs on failure
|
|
if: failure()
|
|
run: |
|
|
echo '--- pandoc ---'; docker logs fidelity-pandoc 2>&1 | tail -30 || true
|
|
echo '--- gotenberg ---'; docker logs fidelity-gotenberg 2>&1 | tail -30 || true
|
|
|
|
# Always tear the sidecars down — they run on the shared runner host, so a
|
|
# leaked (especially Chromium-backed Gotenberg) container would waste its
|
|
# memory until the next run and break re-runs on the container name.
|
|
- name: Stop sidecars
|
|
if: always()
|
|
run: docker rm -f fidelity-pandoc fidelity-gotenberg 2>/dev/null || true
|
|
|
|
images:
|
|
name: Build container images
|
|
needs: checks
|
|
# PR-only: on main the CD workflow builds and pushes the same images —
|
|
# building twice would waste the runner (ADR 0014: build once, promote).
|
|
if: github.event_name == 'pull_request'
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- name: Check out repository
|
|
uses: actions/checkout@v4
|
|
|
|
# PRs prove the Dockerfiles still build; pushing happens in cd.yml.
|
|
- name: Build web image
|
|
run: docker build -f apps/web/Dockerfile --build-arg APP_VERSION=${{ github.sha }} -t dorfteich-web:ci .
|
|
|
|
- name: Build api image
|
|
run: docker build -f apps/api/Dockerfile --build-arg APP_VERSION=${{ github.sha }} -t dorfteich-api:ci .
|
|
|
|
- name: Build collab image
|
|
run: docker build -f apps/collab/Dockerfile --build-arg APP_VERSION=${{ github.sha }} -t dorfteich-collab:ci .
|