Releasing to PyPI¶
The five publishable workspace members ship to PyPI in lockstep — every release tags every package at the same version. The internal dhis2w-codegen package is workspace-only and does not ship.
| Package | PyPI |
|---|---|
dhis2w-client |
https://pypi.org/project/dhis2w-client/ |
dhis2w-core |
https://pypi.org/project/dhis2w-core/ |
dhis2w-cli |
https://pypi.org/project/dhis2w-cli/ |
dhis2w-browser |
https://pypi.org/project/dhis2w-browser/ |
dhis2w-mcp |
https://pypi.org/project/dhis2w-mcp/ |
Versioning policy¶
- Lockstep. All five publishable packages share the same
version =value in theirpyproject.toml. Bump them together, never one at a time. - SemVer.
MAJOR.MINOR.PATCHfor stable releases; pre-releases use SemVer suffixes (0.6.0a1,0.6.0rc1). Pre-1.0 means breaking changes can land on minor bumps. - Inter-package deps are pinned to
>=<current>,<<next-major>(e.g.dhis2w-client>=0.5.0,<0.6). When the next minor lands, every consumer's pin needs the same shift.
How to cut a release¶
-
Decide the version: pick a SemVer next from the current
version =in anypackages/*/pyproject.toml. For 0.5.0 → 0.5.1 (patch), 0.5.0 → 0.6.0 (minor with possibly-breaking changes), 0.5.0 → 1.0.0 (committed stable surface). -
Bump every
packages/*/pyproject.tomlin lockstep. Update both: - The package's own
version = "X.Y.Z". -
Every workspace dep pin like
"dhis2w-core>=0.5.0,<0.6". The lower bound should match the new release; the upper bound shifts to the next major (<0.6→<0.7only on minor bumps, never on patch). -
Refresh the lockfile:
-
Commit the bump with a short conventional-commit message —
chore(release): v0.6.0. -
Tag the commit and push:
-
Watch the workflow. The tag triggers
.github/workflows/pypi-publish.yml. Fivebuildjobs produce wheels in parallel; onepublishjob uploads them all via PyPI Trusted Publishing (OIDC, no API token). -
Verify:
- https://github.com/winterop-com/dhis2w-utils/actions — all green.
uvx --refresh --from 'dhis2w-client==0.6.0' python -c 'import dhis2w_client; print(dhis2w_client.__file__)'pulls and imports the new wheel.uv tool list(oruv tool upgrade dhis2w-cli) shows the right version.
Pre-release flow¶
For dry runs without committing to a SemVer slot:
The workflow accepts the pre-release pattern and uploads as a pre-release to PyPI. Consumers get it only with uv tool install dhis2w-cli --prerelease=allow (or uv add dhis2w-client --prerelease=allow inside a project).
Yanking a release¶
Don't delete published wheels — yank them instead. Yanking keeps the file available so existing pins still resolve, but new resolves skip it:
(Or do it through PyPI's web UI under each project's Manage page.)
When to bump major (1.0.0)¶
The pre-1.0 marker says "API is still moving". Move to 1.0.0 when:
- The dhis2w-client public surface (the imported names from dhis2w_client) is committed for at least 6 months across two minor releases.
- The CLI command names + flags are stable.
- The MCP tool catalogue is committed.
After 1.0.0, breaking changes require a major bump.