Skip to content

use-case: deepen semver-tag selection; finalize prereleases via next_version#40

Merged
lesnik512 merged 4 commits into
mainfrom
refactor/semver-tag-selection
Jun 26, 2026
Merged

use-case: deepen semver-tag selection; finalize prereleases via next_version#40
lesnik512 merged 4 commits into
mainfrom
refactor/semver-tag-selection

Conversation

@lesnik512

Copy link
Copy Markdown
Member

What

Deepens the semver-tag selection step in semvertag/_use_case.py. The four-helper chain (_try_parse_semver_parse_semver_tags_pick_latest_semver_tag_compute_new_version) folds into one _select_latest_semver_tag(tags) -> tuple[Tag, semver.Version] | None that carries the parsed Version, killing a double-parse (the winning tag used to be parsed once to select and again to bump).

Why

The four helpers were the textbook "extracted for testability, but the real bug is in how they're composed" shape — each trivially correct alone, but the composed behaviour (skip-unparseable → sort → pick-max → bump) had emergent, untested semantics: PEP 440 prereleases and v-prefixed tags silently skipped, ties order-dependent, and a latent prerelease bug. Spec/trail: planning/changes/2026-06-26.03-semver-tag-selection/ + planning/decisions/2026-06-26-semver-form-tags-only.md.

Behaviour change (one, deliberate)

Bump now uses Version.next_version instead of bump_*, so a SemVer-form prerelease baseline finalizes: 1.0.0-rc.1 + patch → 1.0.0 (was 1.0.1). On every stable, build-free baseline next_version equals bump_* exactly, so all existing tags behave identically.

Build-metadata handling (caught in review, fixed): next_version also finalizes on build metadata, which would have regressed a stable 1.0.0+build baseline (patch → 1.0.0, no bump). The selector now strips build metadata (.replace(build=None)) before carrying the Version — build is precedence-irrelevant and semvertag never emits it — so 1.0.0+build + patch → 1.0.1 as before. Locked by two tests.

Scope (decided, see decision record)

SemVer-form selection only. PEP 440 prereleases rejected (needs packaging + a dual version model — a form a SemVer tagger shouldn't consume); v-prefix recognition deferred (a real adoption footgun, tracked with a revisit trigger). architecture/cli.md Use-case section promoted to match.

Verification

just test → 473 passed, 100% branch coverage · just lint-ci clean (ruff/ty/planning) · just docs-build (strict) passes. New direct tests cover: PEP 440/v0 skip, SemVer-form prerelease ordering + finalize, tie last-wins, build-metadata strip, and the no-double-parse contract.

🤖 Generated with Claude Code

@lesnik512 lesnik512 merged commit e9d3a32 into main Jun 26, 2026
6 checks passed
@lesnik512 lesnik512 deleted the refactor/semver-tag-selection branch June 26, 2026 20:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant