fe57dde57b
Add the rule-46 image-publish lane: a `publish` job gated on [lint, unit, integration] that builds the runtime Dockerfile in ci-builder and pushes git.fabledsword.com/bvandeusen/steward:<sha> always, :dev on dev and :latest on main. Authenticates with the REGISTRY_TOKEN repo secret (the injected GITHUB_TOKEN lacks write:package). Steward is the first family app to implement the publish lane; mechanics mirror CI-runner's build-ci-python.yml. Add compose.deploy.yml for a persistent remote instance that pulls :dev (no source bind-mounts, persistent app_data+pgdata volumes, bundled Postgres), plus a README "Remote dev instance" runbook and the POSTGRES_PASSWORD env key. Fix .env.example's database URL var to the canonical STEWARD_DATABASE_URL (single underscore) and document the publish lane in ci-requirements.md. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2.9 KiB
2.9 KiB
CI Requirements — Steward
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
steward/,plugins/,tests/) - docker CLI (integration lane: bridge-IP discovery of the Postgres service container)
Per-job tool installs
-
uv pip install --system -e '.[dev]'(pip fallback) — in theunitjob. -
uv pip install --system -e '.[dev,ansible]'(pip fallback) — in theintegrationjob, which boots the real app and exercises the Ansible runner, so it needs theansibleextra (ansible>=10,<13) at import time.Steward declares its deps in
pyproject.toml; the[dev]extra addspytest+pytest-asyncio. Norequirements.txtis tracked.
Lanes
- lint —
ruff check steward/ plugins/ tests/, no dep install. - unit —
pytest -m "not integration". The whole current suite runs here: it builds the app withtesting=True, which mocksdb_sessionmaker, so no DB is touched. First-party plugins are bundled in-tree underplugins/, so plugin unit tests import them directly — no cross-repo checkout. - integration —
pytest tests/integration -m integrationagainst apostgres:16-alpineservice. The single test boots the real app (create_app(testing=False)), which runs core + every bundled plugin's migrations, then round-trips the DB. This is the guard that the folded-in plugin migration graph resolves. - publish — builds the runtime
Dockerfileand pushes to the package registry. Runs inci-builder:latest(docker + buildx, socket auto-mounted), gated onneeds: [lint, unit, integration]so a red commit never ships an image. Publishesgit.fabledsword.com/bvandeusen/steward:<sha>always, plus:devondevand:latestonmain(FabledRulebook rule 46). Needs theREGISTRY_TOKENrepo Actions secret (read:package+write:package) — the injectedGITHUB_TOKENcan't push packages.
Notes
- Steward has no frontend and no Redis/Celery (no external workers), so there is no frontend-build lane and the only service container is Postgres.
- Integration uses Forgejo Actions
services:+ a socket-discovered bridge IP becauseact_runner(swarm-runner v0.6+) puts services on the default bridge with no embedded DNS. FabledCurator'sci.ymlis the canonical example of the pattern; Steward's is the same shape minus Redis and minus sharding. - The job name
integrationhas no underscore —act_runnerstrips underscores from job names when building service-container labels, so thedocker psname filter uses the bare job name. - Migrations run via the app itself (
create_app→run_core_migrations, async throughasyncpg), so the integration lane needs no separatealembic upgradestep and no psycopg/sync driver.