Derive the version from the git tag instead of a checked-in file - #27
Merged
Conversation
`regionate/version.py` held a literal that had to be bumped in its own commit before every release, and nothing tied that commit to the tag the release was actually cut from. The two could disagree, and when they did the symptom was a 400 from PyPI at the very end of the release. hatch-vcs derives the version from the tag at build time and writes it to a generated `regionate/_version.py`, so tagging *is* the bump. `version.py` becomes a shim over the generated file, with a `0.0.0+unknown` fallback for a checkout that has never been built. Engineering norm 5 in CLAUDE.md said to bump that literal, so it is restated here. The tag has to be visible for that to work, so the CI and publish checkouts use `fetch-depth: 0` and Read the Docs unshallows in `post_checkout`; without it the build quietly produces a `.devN` artifact. The publish workflow also asserts that the version it built matches the tag it was fired from, which is the check that would have caught the failure mode described above. conda/meta.yaml gains `hatch-vcs` in `host`: the recipe builds with `--no-build-isolation`, so the backend's own requirements must be installed there or the wheel build fails. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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.
Ports the scheme from hdrake/xeos#10 to
regionate: the version is derived from the git tag byhatch-vcsinstead of being read from a literal inregionate/version.py.Why
regionate/version.pyheld__version__ = "0.5.5", which had to be bumped in its own commit before every release (engineering norm 5 said exactly that). Nothing tied that commit to the tag the release was actually cut from, so the two could disagree — and when they did, the symptom was a400 File already existsfrom PyPI at the very end of the release. That is exactly how thexeosv0.2.1 release failed: the tag was placed one commit before the bump, the workflow built the previous version, and PyPI rejected it.With the tag as the source of truth, tagging is the bump. There is no second commit to remember and no way for the tag and the artifact to disagree.
What changed
pyproject.toml—hatch-vcsadded tobuild-system.requires;[tool.hatch.version]switches frompath = "regionate/version.py"tosource = "vcs";local_scheme = "no-local-version"so untagged builds areX.Y.Z.devNrather than PEP 440 local versions that indexes refuse; a build hook writes the resolved version toregionate/_version.py.regionate/version.py— now a shim that imports from the generated_version.py, with a0.0.0+unknownfallback for a checkout that has never been built or installed.regionate.__version__is unchanged for anything installed from a release..gitignore— ignores the generatedregionate/_version.py..github/workflows/publish-to-pypi.yml—fetch-depth: 0(a shallow clone has no tag, so the build would silently produce a.devNartifact), plus a step asserting the built version matches the release tag.checkout/setup-pythonbumped off the long-EOL v2..github/workflows/ci.yml—fetch-depth: 0on the checkout, since the job installs the package..readthedocs.yaml—post_checkoutunshallows and fetches tags.docs/source/conf.pytitles the pages with the installed version, so without this they would read.devN.conda/meta.yaml—hatch-vcsadded tohost. The recipe builds with--no-build-isolation, so the backend's requirements must be installed there; I confirmed locally that without it the wheel build fails inhatchling.builders.plugin.interface.get_build_hooks. The same addition is needed on conda-forge/regionate-feedstock before the next release builds.README.md— aReleasingsection documenting the tag-is-the-version procedure.CLAUDE.md— aVersioningsection with the invariants, and norm 5 restated (there is no longer a literal to bump).Verified locally
v9.9.9producesregionate-9.9.9.tar.gz/.whl, no suffix, with the generatedregionate/_version.pyinside the sdist.mainbuilds as0.5.6.devN(last tagv0.5.5+ distance).Note on untagged checkouts
A checkout without tags — a shallow clone, or a fork that never fetched them — now resolves a
.devNversion rather than the release line. CI and Read the Docs are handled above. The one to watch ispip install git+https://github.com/<fork>/regionate.git@<branch>: if that fork has no tags it reports0.1.devN, which can fall below a downstreamregionate >= 0.5.5floor and get silently replaced by the PyPI build. Pushing the release tags to the fork (git push <fork> --tags) fixes it; otherwise install such a branch last with--force-reinstall --no-deps, exactly as regionate's own dev branches already do forxgcm.CI is red for an unrelated, pre-existing reason
The four
buildjobs fail onValueError: Argument 'boundary' has been renamed to 'padding'fromxgcm/grid.py— an xgcm 1.0 API break inregionate/tests/test_gridded_regions.py.mainis already red for the samereason: the last push run (
Add AI Usage Policy and engineering norms to CLAUDE.md,2026-07-13) failed identically. Nothing in this PR touches Python outside
version.py.What this PR is responsible for did pass in those same runs:
pip install -e .resolved the version from the tag, and
conda listreportsregionate 0.5.6.dev9—the tag
v0.5.5plus distance, which is exactly right.🤖 Generated with Claude Code