Skip to content

Continuous integration

Understand the repository gates for types, tests, samples, docs, and releases.

Workflow: .github/workflows/ci.yml (single workflow, runs on push to main and on every PR targeting main).

Jobs

Job What it runs
lint pnpm lint — ESLint 10 flat config plus the TSDoc public-export gate — and pnpm --filter blog-admin lint, which runs the integration fixture’s AdonisJS ESLint config
typecheck pnpm -r typecheck checks package and docs source, then pnpm typecheck:tests runs tsc --noEmit with every package’s tsconfig.test.json. Existing package-level test debt is explicit in scripts/test-typecheck-baseline.json; every listed package is still checked, new failing packages fail CI, and a newly passing package fails until its stale baseline entry is removed
unit Package Japa suites run under c8 and the UI Vitest suite runs with V8 coverage; LCOV and JSON summaries are retained in the package-coverage-* artifact for 30 days. Coverage is informational until the baseline supports defensible thresholds
security Required §19 gatepackages/core/tests/security/*.spec.ts (route sweep, mass-assignment probes, allowlist fuzzing, upload spoofing, the XSS corpus over the persist path, the authorization cross-check, serialization leakage) plus examples/blog-admin/tests/functional/adonia_security.spec.ts on sqlite (guest sweep over the committed router, Shield XSRF, compiled SQL). mapping.spec.ts fails the job when docs/security-conformance.md and the suite drift apart in either direction
build pnpm build on the supported Node 24 baseline
docs pnpm docs:api:diff then pnpm docs:build — G2-1/G2-2’s gate. docs:api:diff compares the generated public API inventory with the PR base and requires a new major Changeset for removals. docs:build verifies generated references, compiles checked fenced samples, enforces the no-check budget, and fails on dead relative links. Neither command needs pnpm build
test-blog-admin examples/blog-admin suite matrixed over DB_CONNECTION=pg|mysql|sqlite; the pg axis starts postgres:17, the mysql axis starts mysql:8.4 (health-checked), the sqlite axis starts no real services (in-process)
install-from-scratch Phase-1 exit gate (never leaves CI): scripts/test-fresh-install.sh — packs @adonia/* to tarballs, scaffolds a FRESH AdonisJS v7 inertia-react starter, installs the tarballs, runs node ace add @adonia/core (configure hook, zero manual edits), adds one posts resource, and curl-asserts the CRUD flow (XSRF cookie-jar flow, mass-assignment guard, validation failures) over HTTP; matrixed over DB_CONNECTION=pg|mysql|sqlite with the same service pattern as test-blog-admin
playwright caches Chromium and Firefox, maps lvh.me test domains, runs both desktop projects, and uploads retained traces and failure screenshots from test-results/ when the suite fails
bundle-size pnpm build then pnpm size — bundles the scaffolded panel entry with React/Inertia external, gates the base chunks at TECH_SPEC §18’s 225 kB gzip, asserts the rich-text/code/image editors stay behind import(), and posts a per-chunk report to the job summary and a sticky PR comment. See bundle budget
performance Required §18 gatepnpm perf benchmarks validated production descriptor/index/export/render/controller paths, asserts fixed N+1 and widget request counts, enforces cold descriptor p95 plus bundle/lazy-editor budgets, publishes the report to the job summary, and uploads raw JSON/chunks for 90 days. The same raw JSON is committed durably at docs/public/performance-report.json and linked from the generated report

Notes on design decisions:

  • GHA does not support conditional services. The test-blog-admin and install-from-scratch matrices give a non-matching service a no-op alpine image with no health check, so GHA never waits on it; only the service matching matrix.db is real and health-gated.
  • install-from-scratch runs the exact verdaccio@6.9.0 release on 127.0.0.1:54573 because node ace add @adonia/core installs from a registry before running the configure hook; the starter kit and create-adonisjs are pinned too.
  • /etc/hosts has no wildcard support, so the Playwright job enumerates the subdomains the domain-mounted/tenant panel tests will use instead of *.lvh.me.
  • examples/blog-admin, the fresh-install script, and test:e2e are required inputs. CI invokes them directly, so deleting or renaming any of them fails instead of turning a required job into a green no-op.
  • bundle-size measures a bundle, not a file: packages/ui builds with tsc -b, so gating dist/index.js would gate a barrel of re-export statements. scripts/panel_bundle.js bundles the scaffolded panel entry with esbuild instead, and .size-limit.json points at the resulting .size-limit-build/base/*.js chunks.
  • docs is separate from lint: root ESLint ignores extracted documentation samples, while docs:build checks them against the real API. A red docs job therefore reports documentation drift directly instead of hiding it under lint.
  • The PR-comment step is skipped for fork PRs (their token is read-only) and is continue-on-error, so the required check never goes red over a comment permission. The job summary carries the same report either way.

Required status checks (branch protection)

Branch protection cannot be configured from this repo — it must be set once in the GitHub UI: Settings → Branches → Add branch ruleset for main, enable “Require status checks to pass before merging” and mark all of the following as required:

  • Lint (ESLint flat config)
  • Typecheck
  • Unit tests
  • Security conformance (§19)
  • Build (Node 24)
  • Docs (samples + site build)
  • blog-admin tests (pg)
  • blog-admin tests (mysql)
  • blog-admin tests (sqlite)
  • install-from-scratch (pg)
  • install-from-scratch (mysql)
  • install-from-scratch (sqlite)
  • Playwright e2e
  • Performance (§18)
  • Bundle size (size-limit)

Also enable “Require branches to be up to date before merging” so the matrix cannot go stale against main.

Navigation

Type to search…

↑↓ navigate↵ selectEsc close