Skip to content

Commit bca8975

Browse files
committed
fix(version): recognize PEP 440 development tags
Keep development-release tags discoverable across sequential bumps while preserving custom tag embedding and existing suffix behavior. Constraint: Preserve custom tag formats and SemVer-compatible parsing. Rejected: Replace the shared parser with the anchored PEP 440 reference regex | it breaks embedded tag formats and unrelated schemes. Confidence: high Scope-risk: narrow Directive: Keep generated version forms round-trippable through TagRules. Tested: uv run poe all; 446 focused tag, version, bump, and changelog tests; exact uv-provider sequential bump regression; git diff --check. Not-tested: Full tox matrix across every supported Python version and operating system.
1 parent 40b409b commit bca8975

3 files changed

Lines changed: 72 additions & 1 deletion

File tree

commitizen/version_schemes.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
Increment: TypeAlias = Literal["MAJOR", "MINOR", "PATCH"] # TODO: deprecate
3535
Prerelease: TypeAlias = Literal["alpha", "beta", "rc"]
3636
_DEFAULT_VERSION_PARSER = re.compile(
37-
r"v?(?P<version>([0-9]+)\.([0-9]+)(?:\.([0-9]+))?(?:-([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?(?:\+[0-9A-Za-z.]+)?(\w+)?)"
37+
r"v?(?P<version>([0-9]+)\.([0-9]+)(?:\.([0-9]+))?(?:-([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?(?:\w+)?(?:\.dev\d+)?(?:\+[0-9A-Za-z.]+)?)"
3838
)
3939

4040

tests/commands/test_bump_command.py

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,55 @@ def test_bump_command_prerelease(util: UtilFixture):
237237
assert git.tag_exist("0.2.0") is True
238238

239239

240+
def test_bump_devrelease_with_incremental_changelog(
241+
tmp_commitizen_project: Path, util: UtilFixture, changelog_path: Path
242+
):
243+
config_path = tmp_commitizen_project / "pyproject.toml"
244+
config_path.write_text(
245+
dedent(
246+
"""\
247+
[project]
248+
name = "dev-project"
249+
version = "0.1.0"
250+
251+
[tool.commitizen]
252+
version_provider = "uv"
253+
update_changelog_on_bump = true
254+
changelog_incremental = true
255+
"""
256+
),
257+
encoding="utf-8",
258+
)
259+
lock_path = tmp_commitizen_project / "uv.lock"
260+
lock_path.write_text(
261+
dedent(
262+
"""\
263+
version = 1
264+
revision = 1
265+
266+
[[package]]
267+
name = "dev-project"
268+
version = "0.1.0"
269+
source = { virtual = "." }
270+
"""
271+
),
272+
encoding="utf-8",
273+
)
274+
275+
util.create_file_and_commit("feat: first development release")
276+
util.run_cli("bump", "--devrelease", "0", "--yes")
277+
assert git.tag_exist("0.2.0.dev0") is True
278+
279+
util.create_file_and_commit("feat: next development release")
280+
util.run_cli("bump", "--devrelease", "1", "--yes")
281+
assert git.tag_exist("0.2.0.dev1") is True
282+
changelog = changelog_path.read_text(encoding="utf-8")
283+
assert "0.2.0.dev1" in changelog
284+
assert "next development release" in changelog
285+
assert 'version = "0.2.0.dev1"' in config_path.read_text(encoding="utf-8")
286+
assert 'version = "0.2.0.dev1"' in lock_path.read_text(encoding="utf-8")
287+
288+
240289
@pytest.mark.usefixtures("tmp_commitizen_project")
241290
def test_bump_command_prerelease_increment(util: UtilFixture):
242291
# FINAL RELEASE

tests/test_tags.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,3 +140,25 @@ def test_is_version_tag_accepts_dotless_devrelease_in_custom_tag_format():
140140

141141
extracted = rules.extract_version(_git_tag("version-1.2.3dev1"))
142142
assert str(extracted) == "1.2.3.dev1"
143+
144+
145+
def test_is_version_tag_accepts_pep440_devrelease():
146+
rules = TagRules()
147+
148+
versions = [
149+
("0.2.0.dev0", "0.2.0.dev0"),
150+
("0.2.0dev0", "0.2.0.dev0"),
151+
("0.2.0.dev0+build.1", "0.2.0.dev0+build.1"),
152+
("0.2.0a1.dev0", "0.2.0a1.dev0"),
153+
("0.2.0a1.dev0+build.1", "0.2.0a1.dev0+build.1"),
154+
]
155+
for tag, expected in versions:
156+
assert rules.is_version_tag(tag) is True
157+
assert str(rules.extract_version(_git_tag(tag))) == expected
158+
159+
assert rules.is_version_tag("0.2.0.not-a-release") is False
160+
161+
custom_rules = TagRules(tag_format="release-$version-final")
162+
custom_tag = _git_tag("release-0.2.0.dev0-final")
163+
assert custom_rules.is_version_tag(custom_tag) is True
164+
assert str(custom_rules.extract_version(custom_tag)) == "0.2.0.dev0"

0 commit comments

Comments
 (0)