Page:
Development and CI
Clone
1
Development and CI
Latte edited this page 2026-06-29 13:55:51 +00:00
Development & CI
How to develop, test, and ship familiar.
Commands
uv sync # install deps (incl. dev group)
uv run pytest # full suite; FAILS under 80% coverage
uv run pytest tests/test_market.py::test_get_market_price # a single test
uv run ruff format . # format
uv run ruff check . # lint
uv run familiar # run the MCP server over stdio
Run ruff format and ruff check before committing — CI enforces both.
There is no separate build step; uv build produces the sdist + wheel (CI does this on merge).
Project layout
src/familiar/— the package. One module per tool group (see Architecture), plus the sharedesi,zkill,sde,auth,charutil,config,writes, andservermodules.tests/— one test module per source module, driven bytests/conftest.py.pyproject.toml— deps, scripts, and tool config (ruff line length 100, pytest coverage gate).
Testing conventions
Tests use tests/conftest.py:
- The
mock_esifixture installs a mock ESI client driven by a request handler;route(req, {substring: body})dispatches by path substring. - Async tools are driven with
asyncio.run(...)— there is no async-test plugin. - Authenticated-tool tests monkeypatch
auth.list_characters/auth.get_auth/auth.resolve_characterrather than touching the real token store. - Write tests set
FAMILIAR_DATA_DIRto a tmp dir and toggleFAMILIAR_ENABLE_WRITES. make_jwt(claims)builds fake access tokens.- The ESI/zKill clients and the SDE connection are swapped for mocks via
esi.set_client/zkill.set_client/sde.set_connection.
Coverage is gated at 80% (--cov-fail-under=80 in pyproject.toml addopts), so the suite fails if coverage drops below that.
Git workflow
- Work happens on
dev. Feature branches → PR → fast-forward merge intodev→ delete the branch. - Cut a release by bumping the version in
pyproject.toml/src/familiar/__init__.pyand opening adev → mainfast-forward PR (which publishes the clean version). mainanddevare protected: no direct pushes, signed commits required (the user's git auto-signs), merge via PR only.
CI / publish pipeline
.gitea/workflows/ci.yml runs on every PR and push to main/dev:
- lint —
ruff check .andruff format --check .. - test —
uv run pytest(the 80% coverage gate). - publish — only on a real push/merge into
mainordev(never on PRs), and only after lint + test pass. It builds the sdist + wheel withuv buildand uploads to the Gitea PyPI registry with twine.
Version rules in the publish job:
mainpublishes the clean version frompyproject.toml.devpublishes a unique pre-releaseX.Y.Z.devN(whereNis the run number) so merges never collide.
Notes:
- Auth uses the
REGISTRY_TOKENsecret (a Gitea token with package read/write scope) as the twine password. - Gitea's PyPI registry does not support twine's
--skip-existing; the workflow runs a plain upload and tolerates an "already exists"/409 conflict in the shell (which only bites amainre-run of an already-published release).
A note on attribution
Commits, merges, and PRs in this repo are authored plainly by the maintainer — no AI co-author trailers or "generated with" footers. Keep messages clean.
familiar
familiar — an EVE Online MCP server · repository · MIT