Files
AegisGitea-MCP/docs/packaging.md
T
Latte 45641f8e2c
docker / test (push) Successful in 36s
docker / lint (push) Successful in 41s
lint / lint (push) Successful in 44s
docker / test (pull_request) Successful in 37s
lint / lint (pull_request) Successful in 44s
test / test (push) Successful in 45s
docker / lint (pull_request) Successful in 42s
test / package (push) Successful in 1m6s
test / test (pull_request) Successful in 40s
test / package (pull_request) Successful in 57s
docker / docker (pull_request) Successful in 56s
docker / docker (push) Successful in 1m7s
docs: document dev and stable package channels
Document the two publish channels (aegis-gitea-mcp from main,
aegis-gitea-mcp-dev from dev), install commands for each, that both share
the aegis_gitea_mcp module so only one installs per environment, and the
merge-driven stable release flow (bump version -> PR into dev -> promote
dev to main; re-pushing main at the same version is a --check-url no-op).
2026-06-27 15:59:37 +02:00

4.6 KiB

Packaging & publishing

AegisGitea-MCP is built with uv and published to the self-hosted Gitea package registry on every merge. There are two channels:

Channel Package Published on Versioning
stable aegis-gitea-mcp merge to main X.Y.Z
dev aegis-gitea-mcp-dev merge to dev X.Y.Z.devN (N = CI run number, always unique)

Both channels build from the same source and install the same import module, aegis_gitea_mcp, with the same two console scripts. They differ only in the distribution name and the version. Install one or the other in a given environment, not both — they would collide on the module.

Distribution layout

Each channel ships one distribution with two console scripts and one optional extra (the stable and dev packages are identical here — only the dist name and version differ):

Console script Entry point Requires
aegis-gitea-mcp aegis_gitea_mcp.stdio_app:main core only
aegis-gitea-mcp-server aegis_gitea_mcp.server_entry:main [server] extra
  • Core (default install): httpx, pydantic, pydantic-settings, PyYAML, python-dotenv, structlog, mcp. Enough to run the local stdio server.
  • [server] extra: fastapi, uvicorn[standard], PyJWT[crypto], python-multipart. The public HTTP/OAuth server.

The aegis-gitea-mcp-server entry point degrades gracefully: invoked without the web stack it prints install 'aegis-gitea-mcp[server]' instead of a ModuleNotFoundError traceback.

Build locally

uv build
# -> dist/aegis_gitea_mcp-<version>-py3-none-any.whl
# -> dist/aegis_gitea_mcp-<version>.tar.gz

Smoke-test the local stdio server from the built wheel:

GITEA_URL=https://git.hiddenden.cafe GITEA_TOKEN=<pat> \
  uvx --from ./dist/aegis_gitea_mcp-*.whl aegis-gitea-mcp

Install from the Gitea registry

Stable (aegis-gitea-mcp, published from main):

uv pip install \
  --index-url https://git.hiddenden.cafe/api/packages/Hiddenden/pypi/simple/ \
  aegis-gitea-mcp

# or run it one-off without installing into the environment:
uvx --index https://git.hiddenden.cafe/api/packages/Hiddenden/pypi/simple/ aegis-gitea-mcp

Dev (aegis-gitea-mcp-dev, published from dev — newest pre-release build):

uv pip install \
  --index-url https://git.hiddenden.cafe/api/packages/Hiddenden/pypi/simple/ \
  aegis-gitea-mcp-dev

(With pip, use --index-url the same way.) Both packages expose the same aegis-gitea-mcp / aegis-gitea-mcp-server console scripts and the same aegis_gitea_mcp import module, so install one or the other per environment.

Publishing channels

Publishing is merge-driven, not tag-driven. The publish workflow (.gitea/workflows/publish.yml) triggers on a push to dev or main, runs lint + tests first, then builds with uv and publishes to the Gitea PyPI registry. The package name + version are patched into pyproject.toml at build time only (never committed):

  • dev pushaegis-gitea-mcp-dev at X.Y.Z.dev<run_number>. The CI run number is monotonic, so every merge to dev yields a unique pre-release.
  • main pushaegis-gitea-mcp at the plain X.Y.Z from pyproject.toml. Publishing uses uv publish --check-url, so a main push that did not bump the version is a clean no-op (the existing files are skipped) rather than a 409.

Cutting a stable release

  1. Bump version in pyproject.toml (e.g. 0.2.00.3.0) on a branch off dev.
  2. Open a PR into dev and merge it (this publishes a fresh aegis-gitea-mcp-dev build).
  3. Promote devmain. The push to main publishes the new stable aegis-gitea-mcp X.Y.Z.

Re-pushing main at an unchanged version is harmless — --check-url skips the already-published files.

Required CI secrets

The publish job reuses the existing REGISTRY_TOKEN Actions secret — the same PAT (write:package) that docker.yml uses to push images — so no new secret is needed. The token authenticates as its owning Gitea user, so GITHUB_ACTOR is the username and the token is the password.

Secret Purpose
REGISTRY_TOKEN PAT with write:package; used for both image and package pushes

If the secret is absent the job fails loudly rather than publishing anonymously.

Publishing to public PyPI is intentionally not configured. A second, separately-gated uv publish step would be required and is left as a commented stub in the workflow.