From 6cb1cae215247820e2b655d416f23d0856daee10 Mon Sep 17 00:00:00 2001 From: Vincent Gao Date: Wed, 24 Jun 2026 12:50:26 +0200 Subject: [PATCH 1/2] fix: next_version should bump version for build-only versions next_version('patch') on a version with build metadata but no prerelease (e.g. 1.2.3+build.5) would strip the build and return the same version (1.2.3) instead of bumping the patch (1.2.4). The condition in next_version was (version.prerelease or version.build), which caused build-only versions to enter the 'finalization' path meant for prereleases. Build metadata does not affect version precedence, so its presence should not trigger version finalization. Change the condition to only check version.prerelease. --- src/semver/version.py | 2 +- tests/test_parsing.py | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/semver/version.py b/src/semver/version.py index f9450f95..c3625f4a 100644 --- a/src/semver/version.py +++ b/src/semver/version.py @@ -471,7 +471,7 @@ def next_version(self, part: str, prerelease_token: str = "rc") -> "Version": f"Invalid part. Expected one of {validparts}, but got {part!r}" ) version = self - if (version.prerelease or version.build) and ( + if version.prerelease and ( part == "patch" or (part == "minor" and version.patch == 0) or (part == "major" and version.minor == version.patch == 0) diff --git a/tests/test_parsing.py b/tests/test_parsing.py index ddf52196..e4e78588 100644 --- a/tests/test_parsing.py +++ b/tests/test_parsing.py @@ -198,6 +198,16 @@ def test_next_version_with_invalid_parts(): ("0.2.0-rc.1", "patch", "0.2.0"), # same as "minor" ("1.0.0-rc.1", "patch", "1.0.0"), # same as "major" ("1.0.0-rc.1", "minor", "1.0.0"), # same as "major" + # build-only versions: build metadata does not affect precedence, + # so next_version should bump the version, not just strip the build + ("1.2.3+build.5", "patch", "1.2.4"), + ("1.0.0+build.5", "patch", "1.0.1"), + ("0.1.4+build.5", "patch", "0.1.5"), + ("1.2.0+build.5", "minor", "1.3.0"), + ("1.0.0+build.5", "major", "2.0.0"), + # prerelease+build: build is stripped along with prerelease during finalization + ("1.2.3-rc.1+build.5", "patch", "1.2.3"), + ("1.2.3-rc.1+build.5", "prerelease", "1.2.3-rc.2"), ], ) def test_next_version_with_versioninfo(version, part, expected): From 0f85fd8e386c8846c301d837ace24a55d4a04325 Mon Sep 17 00:00:00 2001 From: Vincent Gao Date: Wed, 15 Jul 2026 10:04:46 +0200 Subject: [PATCH 2/2] docs: update next_version build-only example for new bump behavior --- docs/usage/increase-parts-of-a-version_prereleases.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/usage/increase-parts-of-a-version_prereleases.rst b/docs/usage/increase-parts-of-a-version_prereleases.rst index 845f2290..c2088c51 100644 --- a/docs/usage/increase-parts-of-a-version_prereleases.rst +++ b/docs/usage/increase-parts-of-a-version_prereleases.rst @@ -19,6 +19,6 @@ would perhaps a better fit. >>> str(Version.parse("3.4.5-pre.2+build.4").next_version(part="patch")) '3.4.5' >>> str(Version.parse("3.4.5+build.4").next_version(part="patch")) - '3.4.5' + '3.4.6' >>> str(Version.parse("0.1.4").next_version("prerelease")) '0.1.5-rc.1'