Neuer Block-Atom task_overview (Markdown-Fence dorfteich-tasks, HTML-Placeholder). Shared extractTaskRows liest Task-Zeilen mit Text, Mentions (#150) und Start-/Zieldaten (#152); TasksService sammelt zur Lesezeit den Teilbaum (rekursiv via collectSubtreeIds, canAccessPage- Filter je Quellseite) aus Basis-State + page_updates-Log — KEINE abgeleitete Tabelle nötig (Teilbäume sind klein, kein Drift). Neuer auth-Endpoint GET /read/:pond/:slug/tasks; die öffentliche Ansicht expandiert den Placeholder serverseitig zur statischen Tabelle (Instanz-Sprache). NodeView mit Live-Tabelle und Rückschreib-Checkboxen (optimistisch, Override bis der debounced Collab-Persist nachzieht); Einfügen über die Block-Auswahl (eingebauter Eintrag). Unit- + DB-Tests, neuer CI-Pack tasks.spec (voller Loop inkl. Rückschreiben end-to-end), User-Guide-Doku en+de. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0155v2aT8AG1kZDQEZiCLBWC
644 lines
26 KiB
YAML
644 lines
26 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: Run legal pack
|
|
run: |
|
|
E2E_BASE_URL=http://localhost:5173 \
|
|
pnpm --filter @dorfteich/web exec playwright test e2e/legal.spec.ts
|
|
|
|
- name: Reset login rate limit before system 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 system pack
|
|
run: |
|
|
E2E_BASE_URL=http://localhost:5173 \
|
|
pnpm --filter @dorfteich/web exec playwright test e2e/system.spec.ts
|
|
|
|
- name: Reset login rate limit before comments 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 comments pack
|
|
run: |
|
|
E2E_BASE_URL=http://localhost:5173 \
|
|
pnpm --filter @dorfteich/web exec playwright test e2e/comments.spec.ts
|
|
|
|
- name: Reset login rate limit before social 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 social pack
|
|
run: |
|
|
E2E_BASE_URL=http://localhost:5173 \
|
|
pnpm --filter @dorfteich/web exec playwright test e2e/social.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 page-tree 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-tree pack
|
|
run: |
|
|
E2E_BASE_URL=http://localhost:5173 \
|
|
pnpm --filter @dorfteich/web exec playwright test e2e/page-tree.spec.ts
|
|
|
|
- name: Reset login rate limit before graph 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 graph pack
|
|
run: |
|
|
E2E_BASE_URL=http://localhost:5173 \
|
|
pnpm --filter @dorfteich/web exec playwright test e2e/graph.spec.ts
|
|
|
|
- name: Reset login rate limit before favorites 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 favorites pack
|
|
run: |
|
|
E2E_BASE_URL=http://localhost:5173 \
|
|
pnpm --filter @dorfteich/web exec playwright test e2e/favorites.spec.ts
|
|
|
|
- name: Reset login rate limit before settings-nav 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 settings-nav pack
|
|
run: |
|
|
E2E_BASE_URL=http://localhost:5173 \
|
|
pnpm --filter @dorfteich/web exec playwright test e2e/settings-nav.spec.ts
|
|
|
|
- name: Reset login rate limit before tasks 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 tasks pack
|
|
run: |
|
|
E2E_BASE_URL=http://localhost:5173 \
|
|
pnpm --filter @dorfteich/web exec playwright test e2e/tasks.spec.ts
|
|
|
|
- name: Reset login rate limit before create-missing-page 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 create-missing-page pack
|
|
run: |
|
|
E2E_BASE_URL=http://localhost:5173 \
|
|
pnpm --filter @dorfteich/web exec playwright test e2e/create-missing-page.spec.ts
|
|
|
|
- name: Reset login rate limit before vault-import 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 vault-import pack
|
|
run: |
|
|
E2E_BASE_URL=http://localhost:5173 \
|
|
pnpm --filter @dorfteich/web exec playwright test e2e/import-vault.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 .
|
|
|
|
- name: Build backup image
|
|
run: docker build -f apps/backup/Dockerfile --build-arg APP_VERSION=${{ github.sha }} -t dorfteich-backup:ci .
|