From 01e2d2702c0f8864057b811773b5d22d855a8e81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kenji=20Sato=20=E2=80=94=20PO=20researchx?= Date: Mon, 26 Oct 2026 12:55:48 +0000 Subject: [PATCH] ci: register the phase-4 gating workflow (researchx#24) - backend (uv/Python 3.12: ruff, mypy, pytest) + frontend (Node 22/pnpm 12.6.0: typecheck, lint, test, build); one dispatched run on main with both jobs green opens the code phase --- .gitea/workflows/ci.yml | 128 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 .gitea/workflows/ci.yml diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml new file mode 100644 index 0000000..a1a3566 --- /dev/null +++ b/.gitea/workflows/ci.yml @@ -0,0 +1,128 @@ +# .gitea/workflows/ci.yml - ResearchX phase-4 CI gate (researchx#24). +# +# This file IS the gate. The pre-code clause (coreci/company#105, c14057): +# a code phase opens only when the product repo's gating workflow file has +# dispatched at least one run on `main` and every job in that file is green +# in that run. Until this file exists, coreci/researchx has no workflow and +# no run at all - that is the case the clause was amended for (researchx#24, +# c14093). A half-green pipeline does not open the phase either. +# +# Two jobs: +# backend - uv + Python 3.12: ruff, mypy, pytest +# frontend - Node 22 + pnpm 12.6.0: typecheck, lint, test, build +# +# Runner label: `employee-runner`, named by coreci-sre on researchx#24 +# (comment 14316): "runner label for uv+pnpm is employee-runner ... any +# employee label carries the fleet toolchain". The shared `ubuntu-latest` +# pool is deliberately not used: the toolchain (uv + pnpm 12.6.0) must come +# from ONE image, and a split across images is how a first fire comes back +# red on toolchain instead of on code. +# +# The commands are the repo's own documented gates (README "Monorepo +# command map"): backend `uv run ruff check src tests`, `uv run mypy src`, +# `uv run pytest`; frontend `pnpm typecheck`, `pnpm lint`, `pnpm test`, +# `pnpm build`. The frontend lane mirrors the release image's own recipe +# (frontend/Dockerfile: node:22-alpine, corepack, pnpm install +# --frozen-lockfile, pnpm build), so the gate tests what the product ships. +# +# Owner of a red leg (the clause asks for the owner of the fix next to the +# owner of the product line): toolchain / image / dispatch problems -> +# coreci-sre (employee-runner-fleet); product-line problems -> +# coreci-researchx-po. Approval for this file rides the merge request +# (merge = approval, constitution v1.3). + +name: ci + +on: + push: + branches: ["main"] + pull_request: + branches: ["main"] + +jobs: + backend: + name: backend (uv, Python 3.12: ruff/mypy/pytest) + runs-on: employee-runner + timeout-minutes: 20 + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Python 3.12 + uses: actions/setup-python@v5 + with: + python-version: "3.12" + + - name: Install dependencies (uv, from the committed lockfile) + working-directory: backend + run: uv sync --frozen + + - name: Lint (ruff) + working-directory: backend + run: uv run ruff check src tests + + - name: Typecheck (mypy) + working-directory: backend + run: uv run mypy src + + - name: Test (pytest) + working-directory: backend + run: uv run pytest + + frontend: + name: frontend (Next.js on pnpm: typecheck/lint/test/build) + runs-on: employee-runner + timeout-minutes: 25 + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Node 22 + uses: actions/setup-node@v4 + with: + node-version: "22" + + - name: Setup Python 3.12 (for the real-stack e2e bridge) + uses: actions/setup-python@v5 + with: + python-version: "3.12" + + - name: pnpm 12.6.0 (corepack, pinned by frontend/package.json) + working-directory: frontend + run: | + set -eu + # `corepack enable` exits EEXIST when the image already ships a pnpm + # shim; the shim below still resolves the pinned version. + corepack enable pnpm || true + pnpm --version + + - name: Install dependencies (from the committed lockfile) + working-directory: frontend + run: pnpm install --frozen-lockfile + + # frontend/src/lib/api/e2e-real-stack.test.ts drives the real FastAPI + # stack: it spawns `uv run python -m researchx.api.dev_bridge` from + # ../backend (loopback :8000, fakes only, zero API keys). Without a + # synced backend venv that test cannot come up, so the lane provisions + # it. Provisioning only - the backend gates stay in the backend job. + - name: Backend venv for the real-stack e2e bridge + working-directory: backend + run: uv sync --frozen + + - name: Typecheck + working-directory: frontend + run: pnpm typecheck + + - name: Lint + working-directory: frontend + run: pnpm lint + + - name: Test + working-directory: frontend + run: pnpm test + + - name: Build + working-directory: frontend + env: + NEXT_TELEMETRY_DISABLED: "1" + run: pnpm build -- 2.43.0