name: CI # Every push, on every branch — not just main — so build breakage shows up # on the first commit of a branch, not only once a PR targets main. No # separate pull_request trigger: for a PR from a branch on this same repo, # push already fires on that branch, and GitHub attaches the run to the PR # by commit SHA regardless of which event triggered it — adding # pull_request too would just run every job twice per push. (Re-add it, # scoped to forks, only if this repo starts accepting fork PRs — push # events from a fork never reach here.) on: push: env: DATABASE_URL: "postgresql://ci:ci@localhost:5432/batchcooking_ci?schema=public" # Test-only secret, never used outside CI — real deployments must set their own. JWT_SECRET: "ci-only-secret-not-used-anywhere-else-32chars+" # Same reasoning as JWT_SECRET above — lets tech-step-worker.routes.test.ts # exercise the success path (matching secret), not just the "unset" # rejection every environment that doesn't set this gets by default. INTERNAL_WORKER_SECRET: "ci-only-worker-secret-not-used-anywhere-else-32chars+" # Shared between the `test` job's own uvicorn step (below) and apps/api's # IntentServiceClient — see the `test` job for why this can't be a # `services:` container like postgres above (GitHub Actions can only pull # a published image, not build services/tech-step-intent-service/Dockerfile). INTENT_SERVICE_BASE_URL: "http://localhost:8000" INTENT_SERVICE_SECRET: "ci-only-intent-secret-not-used-anywhere-else-32chars+" jobs: # Five independent jobs, no needs: between them — each starts in parallel # and reports as its own check, instead of the previous single chained # "lint-and-test then e2e" pipeline. lint: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: pnpm/action-setup@v4 - uses: actions/setup-node@v4 with: node-version: 22 cache: pnpm - run: pnpm install --frozen-lockfile - run: pnpm lint test: runs-on: ubuntu-latest services: postgres: image: postgres:16-alpine env: POSTGRES_USER: ci POSTGRES_PASSWORD: ci POSTGRES_DB: batchcooking_ci ports: - 5432:5432 options: >- --health-cmd pg_isready --health-interval 5s --health-timeout 5s --health-retries 10 steps: - uses: actions/checkout@v4 - uses: pnpm/action-setup@v4 - uses: actions/setup-node@v4 with: node-version: 22 cache: pnpm - uses: actions/setup-python@v5 with: python-version: "3.12" - uses: astral-sh/setup-uv@v3 with: enable-cache: true # `services:` (like the `postgres` container above) can only pull an # already-published image — it can't build # services/tech-step-intent-service/Dockerfile from this checkout. # Running `uvicorn` as a plain background step instead: it keeps # running for the rest of this job (GitHub Actions steps in one job # share the same runner process tree), and `pnpm --filter api test` # below needs a real instance to talk to per this repo's "never mock # an internal service" test convention — same reasoning as the real # `postgres` container just above, not a mock HTTP server. - name: Install services/tech-step-intent-service working-directory: services/tech-step-intent-service run: uv sync --frozen - name: Start services/tech-step-intent-service in the background working-directory: services/tech-step-intent-service run: | uv run uvicorn intent_service.main:app --host 0.0.0.0 --port 8000 & # `/health` only returns 200 once this service has finished # training itself from scratch (no model ever persisted to disk — # see its own README) — measured at ~335s per locale (~670s for # fr+en combined) against the current ~74-technique corpus, # trained on each technique's own synonyms in addition to its # example phrases, so this wait is generous rather than the fast # "base models only" check it used to be before that service # trained itself at startup (see docker-compose.yml's healthcheck # for the same reasoning). timeout 900 bash -c 'until curl -sf http://localhost:8000/health > /dev/null; do sleep 2; done' - run: pnpm install --frozen-lockfile - run: pnpm --filter api exec prisma migrate deploy - run: pnpm --filter api test intent-service-test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-python@v5 with: python-version: "3.12" - uses: astral-sh/setup-uv@v3 with: enable-cache: true - name: Install services/tech-step-intent-service working-directory: services/tech-step-intent-service run: uv sync --frozen - name: Run pytest working-directory: services/tech-step-intent-service run: uv run pytest -q build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: pnpm/action-setup@v4 - uses: actions/setup-node@v4 with: node-version: 22 cache: pnpm - run: pnpm install --frozen-lockfile - run: pnpm build e2e: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: pnpm/action-setup@v4 - uses: actions/setup-node@v4 with: node-version: 22 cache: pnpm - name: Cache Cypress binary uses: actions/cache@v4 with: path: ~/.cache/Cypress key: cypress-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }} - run: pnpm install --frozen-lockfile # pnpm install doesn't reliably trigger Cypress's postinstall binary # download (see apps/web's cypress caveat in the README) — install it # explicitly so `cypress run` finds it. - run: pnpm --filter web exec cypress install - run: pnpm --filter web e2e # No dev server needed here — Cypress spins up its own Vite dev # server internally for component testing (see cypress.config.ts's # `component.devServer`), unlike `e2e` above which needs the real app # running first. - run: pnpm --filter web cy:run:component