fix: correct semver scheme handling of .dev0 tags and exact pre-releases#1349
Conversation
Apply first principles to semver-pep440 and semver-pep440-release-branch: - P1 (exact = tag): simplified_semver_version now returns the tag as-is for exact checkouts, matching release_branch_semver_version. Previously it stripped pre-release info (2.0.dev0 → 2.0.0, 1.0.0rc1 → 1.0.0). - P3 (.dev0 anchors): guess_next_simple_semver now recognizes .dev0 tags as explicit version anchors, returning the base version normalized to 3 segments without bumping. 2.0.dev0 at distance 5 → 2.0.0.dev5 (was incorrectly 2.0.1.dev5 or 2.1.0.dev5). Co-authored-by: Cursor AI <ai@cursor.sh> Co-authored-by: Anthropic Claude <claude@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Adjusts the semver-pep440 and semver-pep440-release-branch version schemes in vcs-versioning to preserve exact tag versions (including pre-releases) and to treat .dev0 tags as explicit anchors when guessing the next dev version, aligning behavior with PEP 440 ordering and the project’s intended semantics.
Changes:
- Preserve the tag verbatim for exact checkouts in
simplified_semver_version(includingrcand.dev0tags). - Treat
.dev0tags as anchors inguess_next_simple_semverso guessed dev versions don’t bump past the anchored release. - Add test coverage and a towncrier changelog fragment for the corrected behaviors.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
vcs-versioning/src/vcs_versioning/_version_schemes/_standard.py |
Updates semver-pep440 scheme logic for exact-tag preservation and .dev0 anchor handling. |
vcs-versioning/testing_vcs/test_version.py |
Adds/updates parametrized cases covering exact pre-release preservation and .dev0 anchor behavior across branches. |
vcs-versioning/changelog.d/523.bugfix.md |
Documents the behavior fixes for the semver-pep440 schemes. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| parts = list(version.tag.release) | ||
| while len(parts) < SEMVER_LEN: | ||
| parts.append(0) | ||
| return ".".join(str(i) for i in parts) |
There was a problem hiding this comment.
guess_next_simple_semver treats any PEP 440 dev release tag as an anchor via is_devrelease. That includes tags like 1.0.dev1, which can produce a guessed version that is not guaranteed to sort higher than the tag (e.g., distance=1 would yield 1.0.0.dev1, effectively equal to the tag). If the intended behavior is specifically for .dev0 anchors, gate this branch on version.tag.dev == 0 (or an equivalent .dev0 check) and either fall back to the normal incrementing behavior or raise a ValueError for nonzero .devN to match the existing .devX-unsupported policy in _modify_version._bump_dev.
| parts = list(version.tag.release) | |
| while len(parts) < SEMVER_LEN: | |
| parts.append(0) | |
| return ".".join(str(i) for i in parts) | |
| dev_number = getattr(version.tag, "dev", None) | |
| if dev_number == 0: | |
| parts = list(version.tag.release) | |
| while len(parts) < SEMVER_LEN: | |
| parts.append(0) | |
| return ".".join(str(i) for i in parts) |
Use `version.tag.dev == 0` instead of `is_devrelease` to match only .dev0 tags as version anchors. Tags like 1.0.dev1 would produce incorrect ordering (1.0.0.dev1 == 1.0.dev1) and are already rejected by _bump_dev. This keeps the semver schemes consistent with the existing .devX-unsupported policy. Co-authored-by: Cursor AI <ai@cursor.sh> Co-authored-by: Anthropic Claude <claude@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 3 out of 3 changed files in this pull request and generated no new comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Summary
simplified_semver_versionnow returns the tag as-is for exact checkouts (matchingrelease_branch_semver_version). Previously it stripped pre-release info —2.0.dev0exact became2.0.0,1.0.0rc1exact became1.0.0..dev0anchors (P3):guess_next_simple_semvernow recognizes.dev0tags as explicit version anchors, returning the base version normalized to 3 segments without bumping.2.0.dev0at distance 5 now correctly produces2.0.0.dev5instead of2.0.1.dev5or2.1.0.dev5..dev0as explicit anchor, guessed version must sort higher than tag.Behavior changes
semver-pep440exact2.0.dev02.0.0(wrong)2.0.dev0semver-pep440exact1.0.0rc11.0.0(wrong)1.0.0rc1semver-pep440exact1.01.0.01.0(PEP 440 equivalent)semver-pep4402.0.dev0dist=5 default2.0.1.dev5(wrong)2.0.0.dev5semver-pep4402.0.dev0dist=5 feature2.1.0.dev5(wrong)2.0.0.dev5semver-pep440-release-branch2.0.dev0dist=5 master2.1.0.dev5(wrong)2.0.0.dev5Fixes #523.
Test plan
.dev0andrc1tag preservation on both semver schemes.dev0anchor behavior on default, feature, and release branchesMade with Cursor