Publish palace-util and palace-opds to PyPI on release (PP-4076)#3238
Draft
jonathangreen wants to merge 4 commits intomainfrom
Draft
Publish palace-util and palace-opds to PyPI on release (PP-4076)#3238jonathangreen wants to merge 4 commits intomainfrom
jonathangreen wants to merge 4 commits intomainfrom
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #3238 +/- ##
=======================================
Coverage 93.30% 93.30%
=======================================
Files 498 502 +4
Lines 46147 46157 +10
Branches 6318 6318
=======================================
+ Hits 43059 43069 +10
Misses 2003 2003
Partials 1085 1085 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
f42c076 to
568b49d
Compare
Both packages now declare `dynamic = ["version"]` and source the version from a committed `_version.py` stub via hatchling's regex version source. The stub carries a dev placeholder (0.0.0.dev0) so local / developer builds succeed out-of-box; the PyPI publish workflow overwrites `_version.py` with the dunamai-computed release version right before `uv build` to get the real version into the wheel metadata. `_version.py` also carries `__commit__` and `__branch__` (None on dev, populated in CI) to match the shape of palace-manager's `_version.py` — useful for `import palace.util; palace.util.__commit__` style runtime lookup. Each package's `__init__.py` re-exports the three attributes; since `_version.py` is committed, no try/except fallback is needed (palace-manager keeps its try/except only because its `_version.py` is generated at Docker build time and never committed). palace-manager's own versioning is unchanged; it's not yet PyPI-publishable for unrelated reasons.
Add a GitHub Actions workflow that builds and uploads both workspace packages to PyPI when a GitHub Release is published, using PyPI's Trusted Publishing (OIDC) flow — no API tokens stored. The workflow: - Runs a matrix job per package on parallel runners. - Computes version / commit / branch from the release tag via dunamai. - Overwrites the package's _version.py with the computed values so the wheel metadata picks up the release version (see the previous commit for why _version.py is the source of truth). - Pins the intra-workspace dependency before building palace-opds: uv build leaves workspace deps as bare `palace-util` in the wheel's Requires-Dist, which would fail to resolve on PyPI; we sed in `palace-util==<version>` so consumers installing palace-opds get the matching palace-util. - Uploads via pypa/gh-action-pypi-publish@release/v1 with OIDC. One-time setup required on PyPI (see comment in the workflow file): create the palace-util and palace-opds projects and register this workflow + repo + `pypi` environment as a trusted publisher for each. palace-manager is intentionally NOT published here — it needs more work first (alembic etc. prevent a clean wheel build).
[tool.hatch.version] only needs the path — source = 'regex' is the default, and hatch's default pattern matches plain __version__ = "…" assignments. Drop the type annotation from __version__ in _version.py (keep them on __commit__ / __branch__ where they still convey useful optionality) so the default pattern matches. Update the publish workflow to emit the same unannotated __version__ line.
uv add --package palace-opds 'palace-util==X.Y.Z' rewrites the dependency spec in pyproject.toml without relying on a literal text match (sed would break if the dep line ever changes formatting). It resolves against the workspace source, so the pinned version does not need to exist on PyPI yet — important for the publish step, where the version is being uploaded now.
f1f8058 to
8d9177c
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Two things:
Dynamic versioning for both workspace packages. Each package's
pyproject.tomlnow declaresdynamic = ["version"]and sources the version from a committed_version.pystub via hatchling's built-inregexversion source — no plugins. The stub carries a dev placeholder (0.0.0.dev0,__commit__ = None,__branch__ = None) souv build --package …works out-of-box for local and CI builds without an explicit version override. The release workflow overwrites_version.pywith real dunamai-computed values right beforeuv build, so the wheel metadata picks up the real version.publish-pypi.ymlworkflow triggered by published GitHub Releases. Matrix-builds both packages in parallel, uses PyPI's Trusted Publishing (OIDC) flow — no API tokens stored in the repo or in GitHub secrets. The workflow also pins the intra-workspace dep:uv buildleaves workspace deps as barepalace-utilinRequires-Dist, which would fail to resolve on PyPI, so the workflow seds inpalace-util==<version>before buildingpalace-opds.Motivation and Context
With
palace-utilandpalace-opdsextracted as standalone packages, they should be installable from PyPI so downstream Palace services (and the wider OPDS-consuming community forpalace-opds) can depend on them without pulling in thepalace-managermonorepo.palace-manageritself is intentionally NOT published here — it needs additional work first (alembic and friends prevent a clean wheel build).One-time PyPI setup
For each of the two projects (do once per project):
ThePalaceProjectcirculationpublish-pypi.ymlpypipypienvironment in the repo's Settings → Environments and add an approval gate / branch restriction for an extra guard.After that, publishing a GitHub Release with a tag that dunamai can parse as semver (e.g.
v1.0.0) will automatically upload both wheels.How Has This Been Tested?
uv build --package palace-utilproducespalace_util-0.0.0.dev0-py3-none-any.whl.uv build --package palace-opdsproducespalace_opds-0.0.0.dev0-py3-none-any.whl._version.pywith__version__ = "1.2.3", then rebuilt) — wheel correctly taggedpalace_util-1.2.3-py3-none-any.whl. Reverted the stub afterward.python -c "import palace.util; print(palace.util.__version__)"→0.0.0.dev0.python -c "import palace.opds; print(palace.opds.__version__)"→0.0.0.dev0.mypypasses (1128 source files).pytest tests/palace_util tests/palace_opds— 232 tests pass.First real end-to-end verification happens on the first tagged release after this lands.
Checklist