From 4a09cca46eb727b38f0917f8b12220bddd0a770f Mon Sep 17 00:00:00 2001 From: Bryan Van Deusen Date: Thu, 21 May 2026 09:19:30 -0400 Subject: [PATCH] feat(ci): pin container.image to ci-python:3.14 + ship ci-requirements.md Co-Authored-By: Claude Opus 4.7 (1M context) --- .forgejo/workflows/build.yml | 4 ++++ .forgejo/workflows/ci.yml | 35 +++++++++++++++++----------------- ci-requirements.md | 37 ++++++++++++++++++++++++++++++++++++ 3 files changed, 58 insertions(+), 18 deletions(-) create mode 100644 ci-requirements.md diff --git a/.forgejo/workflows/build.yml b/.forgejo/workflows/build.yml index 9c561ba..3743cd0 100644 --- a/.forgejo/workflows/build.yml +++ b/.forgejo/workflows/build.yml @@ -13,6 +13,8 @@ on: jobs: build-web: runs-on: python-ci + container: + image: git.fabledsword.com/bvandeusen/ci-python:3.14 steps: - uses: actions/checkout@v4 @@ -42,6 +44,8 @@ jobs: build-ml: runs-on: python-ci + container: + image: git.fabledsword.com/bvandeusen/ci-python:3.14 steps: - uses: actions/checkout@v4 diff --git a/.forgejo/workflows/ci.yml b/.forgejo/workflows/ci.yml index 09f329c..829aa4c 100644 --- a/.forgejo/workflows/ci.yml +++ b/.forgejo/workflows/ci.yml @@ -1,14 +1,9 @@ name: CI -# CI policy (amends the older FabledRulebook/forgejo.md "lint + unit only" -# stance — operator opted in to running integration in CI): -# - backend-lint-and-test: fast feedback — ruff + `pytest -m "not -# integration"`, no service containers. +# CI lanes per FabledRulebook/forgejo.md "CI philosophy": +# - backend-lint-and-test: ruff + `pytest -m "not integration"`, no service containers. # - frontend-build: vitest unit + vite build. -# - integration: spins up pgvector Postgres + Redis service containers, -# migrates a throwaway test DB, runs `pytest -m integration`. This is -# the first time the integration suite runs anywhere, so expect a -# debugging tail until it goes green. +# - integration: pgvector + redis service containers; alembic + `pytest -m integration`. on: push: @@ -18,10 +13,9 @@ on: jobs: backend-lint-and-test: - # Runner must have Python 3.14 + ruff + Node 22 pre-installed. The - # python-ci runner image lives at CI-Runner/CI-python/ in the operator's - # workspace; see that Dockerfile + Makefile to roll/push the image. runs-on: python-ci + container: + image: git.fabledsword.com/bvandeusen/ci-python:3.14 env: # DB_PASSWORD and SECRET_KEY are required by config.py at import time # even though unit tests don't actually touch the DB or use the secret. @@ -31,9 +25,9 @@ jobs: - uses: actions/checkout@v4 - name: Install Python deps - # ruff is pre-installed in the python-ci runner image (see - # CI-Runner/CI-python/Dockerfile's RUFF_VERSION). Per FabledRulebook - # forgejo.md, toolchain versions live on the runner image, not here. + # ruff is pre-installed in the ci-python image (see CI-Runner/CI-python/ + # Dockerfile's RUFF_VERSION). Per FabledRulebook ci-runners.md, toolchain + # versions live on the runner image, not here. run: pip install -r requirements.txt pytest pytest-asyncio - name: Ruff lint @@ -44,6 +38,8 @@ jobs: frontend-build: runs-on: python-ci + container: + image: git.fabledsword.com/bvandeusen/ci-python:3.14 defaults: run: working-directory: frontend @@ -67,11 +63,14 @@ jobs: # ports collides with the operator's running docker-compose dev stack on # the same shared daemon. Workaround: publish NO host ports, and reach # each service by its bridge IP — discovered at runtime via the mounted - # docker socket (the python-ci image ships /usr/bin/docker; build.yml - # relies on it). Default-bridge containers can talk by IP (only embedded - # DNS is missing), so IP addressing is reliable here. Everything runs in - # ONE step so resolved values don't depend on cross-step env passing. + # docker socket (the ci-python image ships /usr/bin/docker). Default-bridge + # containers can talk by IP (only embedded DNS is missing), so IP + # addressing is reliable here. Everything runs in ONE step so resolved + # values don't depend on cross-step env passing. Pattern documented in + # FabledRulebook/forgejo.md "CI philosophy". runs-on: python-ci + container: + image: git.fabledsword.com/bvandeusen/ci-python:3.14 env: DB_USER: fabledcurator DB_PASSWORD: ci_integration diff --git a/ci-requirements.md b/ci-requirements.md new file mode 100644 index 0000000..c2265ca --- /dev/null +++ b/ci-requirements.md @@ -0,0 +1,37 @@ +# CI Requirements — FabledCurator + +> Spec: https://git.fabledsword.com/bvandeusen/CI-runner/src/branch/main/docs/process.md + +## Runtime image + +git.fabledsword.com/bvandeusen/ci-python:3.14 + +## Image deps used + +- python 3.14 +- ruff (analyzer for `backend/`, `tests/`, `alembic/`) +- node (frontend job: `npm install` + vitest + vite build) +- docker CLI + buildx (`.forgejo/workflows/build.yml`: build-web, build-ml — Forgejo registry push) + +## Per-job tool installs + +- `pip install -r requirements.txt pytest pytest-asyncio` — in `backend-lint-and-test` and `integration` jobs +- `npm install --no-audit --no-fund` — in `frontend-build` job + +## Notes + +- Integration wall time ~3 min, dominated by pgvector container start + the + `pip install` step (~30-45s on cold cache) + alembic + 300+ integration tests. +- The `pip install` in two jobs is intentional and per `docs/process.md`'s + "add deps to image when used by >1 project" rule: FC alone is one Python + project, so the deps live in `requirements.txt` and install per-job. + Reconsider when a second Fabled-family Python backend lands. +- Integration uses Forgejo Actions `services:` + socket-discovered bridge IPs + because `act_runner` (swarm-runner v0.6+) puts services on the default + bridge with no embedded DNS. The pattern is documented in the rulebook's + `forgejo.md` "CI philosophy" section and FC's `ci.yml` is the canonical + example. +- No `package-lock.json` is tracked yet (FC's `feedback_no_local_runs` + memory bans `npm install` locally). Using `npm install` rather than + `npm ci` until a lockfile lands. +- No `imagemagick` / `pandoc` per-job installs needed.