CI/CD
PrintStudio uses GitHub Actions for CI. The pipeline is designed to fail fast — cheap checks (lint, types) run first, expensive checks (database tests) only run when upstream jobs pass.
Pipeline Overview
Section titled “Pipeline Overview”push / PR │ ├── changes (detect changed packages) │ ├── workflow-lint (actionlint) │ ├── quality (lint + types + unit tests) ← depends on: changes │ ├── core-db-tests (integration tests with Postgres + Redis) ← depends on: quality │ └── ci-ok (required status check — all jobs must pass)changes
Section titled “changes”Detects which packages changed in the PR/push using dorny/paths-filter. Downstream jobs use these outputs to skip work when irrelevant code changes.
outputs: core: ${{ steps.filter.outputs.core }} integrations: ${{ steps.filter.outputs.integrations }} api: ${{ steps.filter.outputs.api }} web: ${{ steps.filter.outputs.web }}workflow-lint
Section titled “workflow-lint”Runs actionlint to validate all GitHub Actions workflow files in .github/workflows/. Catches YAML syntax errors and type issues in workflow expressions before they cause mysterious CI failures.
# Run locallybrew install actionlintactionlintquality
Section titled “quality”The main unit test and static analysis job. Runs on every push:
- Bun install — installs workspace dependencies
- Build packages —
bun run buildwith Turbo cache - Typecheck —
tsc --noEmitacross all packages - Unit tests —
bun testwithTEST_INFRA_SKIP=true(no Docker required) - Lint — ESLint + Prettier check
This job runs without Docker services, keeping it fast (<2 min on typical PRs).
core-db-tests
Section titled “core-db-tests”Integration tests that need a real database and Redis. Only runs when packages/core or packages/integrations change (using the changes job outputs).
Services started by the job:
services: postgres: image: postgres:16 env: POSTGRES_DB: printstudio_test POSTGRES_PASSWORD: postgres options: >- --health-cmd pg_isready --health-interval 10s
redis: image: redis:7 options: >- --health-cmd "redis-cli ping" --health-interval 10sSteps:
- Bun install
- Run migrations against the test DB
bun test(with real Postgres and Redis)
A synthetic job that depends on all other jobs. GitHub branch protection rules require this job to pass before merging. This pattern allows the required check list to be stable even as individual jobs are added or removed.
ci-ok: needs: [quality, core-db-tests] runs-on: ubuntu-latest steps: - run: echo "All checks passed"Local CI Simulation
Section titled “Local CI Simulation”Run the same checks locally before pushing:
# Quality checks (no Docker)TEST_INFRA_SKIP=true bun run testbun run typecheck
# Integration tests (needs Docker)bun run test:infra:upbun run testbun run test:infra:downBranch Protection
Section titled “Branch Protection”The main branch requires:
ci-okto pass (covers all jobs)- At least 1 approving review
- No unresolved review comments
Deployment
Section titled “Deployment”A minimal deploy job pattern:
deploy: needs: [ci-ok] if: github.ref == 'refs/heads/main' runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Deploy API run: fly deploy --app printstudio-api env: FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }}