Trovella Wiki

CI Integration

How tests run in GitHub Actions -- service containers, the --affected optimization, pre-commit hooks, and the path from local to CI.

Tests in the CI Pipeline

Tests run in the quality job of .github/workflows/ci.yml. The job runs on every push and every PR targeting main.

The test step uses Turborepo's --affected flag to run only tests for packages that changed:

- name: Test
  run: pnpm turbo test --affected

This means a PR that only modifies packages/ai will only run @repo/ai tests, not the full suite. Turborepo determines "affected" by comparing the current commit against the merge base.

Service Containers

The quality job starts three service containers alongside the runner for integration tests:

ServiceImagePortUsed By
PostgreSQL 18pgvector/pgvector:pg185433@repo/db RLS tests
Redis 8redis:8-alpine6379@repo/cache tests
Typesense 27.1typesense/typesense:27.18108@repo/search tests

The PostgreSQL container includes the pgvector extension, matching the production Cloud SQL configuration. Health checks on PostgreSQL and Redis ensure the containers are ready before tests start.

Database migrations run before tests:

- name: Migrate database
  run: pnpm db:migrate

This applies all schema changes and RLS policies to the CI PostgreSQL instance so that RLS integration tests run against real, up-to-date policies.

Why Real PostgreSQL in CI?

The PostgreSQL service container was added specifically because RLS tests cannot be mocked. The critical RLS bug in TRO-10 -- where tenantProcedure silently bypassed all RLS policies by passing the bare db pool instead of the transaction-scoped tx -- validated this decision. The service container adds approximately 10 seconds to CI startup. See ADR-014 for the full decision rationale.

Environment Variables in CI

The quality job sets environment variables that match the service container configuration:

env:
  DATABASE_URL: postgresql://trovella:trovella_dev@localhost:5433/trovella
  REDIS_URL: redis://localhost:6379
  BETTER_AUTH_SECRET: ci-test-secret-at-least-32-characters-long
  BETTER_AUTH_URL: http://localhost:3000
  GOOGLE_CLIENT_ID: ci-placeholder
  GOOGLE_CLIENT_SECRET: ci-placeholder
  ANTHROPIC_API_KEY: ci-placeholder
  GOOGLE_AI_API_KEY: ci-placeholder
  TYPESENSE_API_KEY: ci-test-key
  TYPESENSE_URL: http://localhost:8108

Non-secret values use ci-placeholder or ci-test-* values. The DATABASE_URL matches the PostgreSQL service container's credentials and port.

Pre-Commit Hooks

Pre-commit hooks run via Husky and lint-staged. The .lintstagedrc.mjs configuration runs ESLint and Prettier on staged files, grouped by their nearest package directory:

export default {
  "*.{ts,tsx}": (files) => {
    const byPackage = groupByPackage(files);
    const commands = [];
    for (const [pkgDir, pkgFiles] of byPackage) {
      commands.push(`node scripts/lint-staged-eslint.mjs "${pkgDir}" ${fileArgs}`);
    }
    commands.push(`prettier --write ${files.join(" ")}`);
    return commands;
  },
  "*.{js,jsx,mjs,cjs,json,md,mdx,yml,yaml,css}": "prettier --write",
};

Note: pre-commit hooks run linting and formatting, not tests. Tests run via pnpm ci:check (manual) or in CI.

Local CI Parity

Before pushing, run pnpm ci:check to match CI quality checks locally:

# Runs: format, lint, dep-cruise, dead code, duplication,
# typecheck, test, doc-update-detection
pnpm ci:check

# Full CI parity including build
pnpm ci:full

The test step within ci:check runs pnpm turbo test, which runs all package tests. For faster iteration during development, run tests for a single package:

pnpm turbo test --filter=@repo/ai

CI Coverage Gates -- Descoped

Per-package coverage thresholds in CI were descoped in favor of mutation testing as the primary quality signal. The plan is to add a minimal CI check that flags new source files with zero test coverage. See ADR-014 for the rationale.

Currently, coverage data is generated on demand via pnpm test:coverage and analyzed by trovella-test-audit, not as a CI gate.

Test Order in CI

Within the quality job, the test step runs after linting, type-checking, and database migration:

  1. Install dependencies (pnpm install --frozen-lockfile)
  2. Lint (pnpm turbo lint --affected)
  3. Type-check (pnpm turbo typecheck --affected)
  4. Migrate database (pnpm db:migrate)
  5. Test (pnpm turbo test --affected)
  6. Build (pnpm turbo build --affected)

Tests run after migration so that the PostgreSQL service container has the latest schema and RLS policies applied. Tests run before build so that test failures surface before the slower Docker image build.

On this page