ci: switch to tag-driven releases via hatch-vcs - #97
Merged
Conversation
The release workflow pushed a version-bump commit directly to `main`,
which the branch protection rules reject ("Changes must be made through
a pull request", enforce_admins=true). Every release attempt failed at
the push step and left an orphaned tag behind.
Derive the package version from the Git tag instead:
- pyproject: use hatch-vcs as the version source and write the resolved
value to a git-ignored `_version.py` via the vcs build hook. Drop the
dead `[tool.semantic_release]` config that referenced the old file.
- version.py: read `__version__` from the generated `_version.py`,
falling back to installed package metadata, then a sentinel.
- gitignore: ignore the generated `_version.py`.
- release.yml: rewrite as build -> publish -> tag. The version is
computed from the latest tag plus a `bump` input and forced into the
build via SETUPTOOLS_SCM_PRETEND_VERSION, so the build needs no tag.
The Git tag and GitHub Release are created last, only after a
successful PyPI publish, so a failed run never leaves an orphaned tag.
No step pushes to `main`, so the flow is compatible with branch
protection.
- CONTRIBUTING: document the tag-driven release process.
Verified locally: hatch-vcs resolves the version from existing tags,
the vcs build hook generates _version.py on install, the runtime import
chain (version.py -> __init__ -> client repr) reports the derived
version, and a pretend-version build produces correctly named
swgoh_comlink-X.Y.Z artifacts. Full unit suite (598 tests) passes.
Co-Authored-By: Claude Opus 4.8 (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.
Problem
The release workflow has never succeeded. It bumps the version in
src/swgoh_comlink/version.py, commits it, and runsgit push origin main --follow-tags. Branch protection onmainrejects that push:With
enforce_admins: trueand PRs required, nothing can push a commit directly tomain. Worse,--follow-tagssucceeds in pushing the tag even when the branch push is rejected, so each failed run leaves an orphaned tag pointing at a bump commit that never landed (this happened today withv2.1.0; I deleted it).Fix: tag-driven versioning
Derive the version from the Git tag instead of committing it, so the release never touches
main.pyproject.toml— usehatch-vcsas the version source; write the resolved value to a git-ignored_version.pyvia the vcs build hook. Removed the dead[tool.semantic_release]block (it referenced the oldversion.pymechanism).version.py— read__version__from the generated_version.py, falling back toimportlib.metadata, then a sentinel for unbuilt trees..gitignore— ignore the generated_version.py.release.yml— rewritten as build → publish → tag:bumpinput (patch/minor/major).SETUPTOOLS_SCM_PRETEND_VERSIONso no tag is needed yet.gh release create --target <sha> --generate-notes). A failed run therefore never leaves an orphaned tag, and no step pushes tomain.CONTRIBUTING.md— documents the new process.Behavior change
The repo no longer carries a committed version string, and
CHANGELOG.mdis no longer regenerated into the repo on release — release notes are auto-generated into the GitHub Release body instead. The existingCHANGELOG.mdremains as historical record.Verification (local)
hatch versionresolves2.0.8.dev7+g…from existing tags ✅uv syncruns the vcs build hook → generates_version.py; runtime chain (version.py→__init__→ client repr) reports the derived version ✅SETUPTOOLS_SCM_PRETEND_VERSION=2.1.0 hatch buildproduces correctly namedswgoh_comlink-2.1.0.tar.gz/…-py3-none-any.whl✅ruff check src/clean; workflow YAML parses; job graph is build → pypi-publish → tag-release ✅After merge
Trigger the release from the Actions tab → "comlink-python release" → choose
bump. It will publish to PyPI and tagvX.Y.Zon themaincommit.🤖 Generated with Claude Code