dorfteich/.gitea/workflows/ci.yml
Claude Opus 4.8 7244b89215
All checks were successful
CD / Build and push images (push) Successful in 3m2s
CI / Lint, typecheck, test (push) Successful in 2m15s
CI / Auth e2e pack (push) Successful in 2m42s
CI / Build container images (push) Has been skipped
CD / Deploy to Test (push) Successful in 8s
CD / Smoke tests against Test (push) Successful in 1m13s
CD / Promote to Int (push) Successful in 11s
Add wikilink node with autocomplete (#46)
Introduce Obsidian-style `[[page links]]` (ADR 0004).

- shared: reserved `wikilink` inline atom in the editor schema (attrs
  `targetSlug`, optional `displayText`); markdown mapping `[[slug]]` /
  `[[slug|text]]` via a markdown-it inline rule + serializer node; plain-text
  and HTML derivation include the shown text. Round-trip + parse unit tests.
- web:
  - `Wikilink` node extension with a React NodeView: shows the explicit
    display text or the target's current title (so a rename updates the link),
    renders a missing target as a dashed phantom with a tooltip, navigates on
    click in read mode.
  - `[[` autocomplete popup (`WikilinkAutocomplete`), dependency-free: filters
    the pond's pages as you type with a create-new-page hint for misses,
    Enter/click inserts the node and removes the typed `[[query`; ↑/↓/Enter/Esc
    intercepted in the capture phase so ProseMirror does not act on them.
  - `WikilinkContext` provides the pond's pages (slug→title) for live
    resolution and the autocomplete, populated by the page editor.
  - i18n `editor.wikilink.*` (de + en); wikilink + phantom + popup styles.
- e2e `wikilink.spec.ts` (new CI pack): type `[[`, autocomplete filters and
  inserts a working link that resolves the target title and persists across a
  reload. Phantom → live resolution on page creation is verified in #47.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PGdhRiwU1WRL4XxJfZYipY
2026-07-09 12:42:01 +02:00

220 lines
7.6 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:
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
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
- 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: Dump server logs on failure
if: failure()
run: tail -50 /tmp/api.log /tmp/collab.log /tmp/web.log || true
images:
name: Build container images
# 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 .