Skip to content

Commit 75ba30d

Browse files
OpenClaw Botgreenbonebot
authored andcommitted
Add: Accept dot-separated pre-release identifiers in SemVer scheme
The SemVer specification (semver.org) uses dot-separated pre-release identifiers (e.g. 1.0.0-alpha.1). Pontos previously only accepted the compact format (e.g. 1.0.0-alpha1). Updated the pre-release regex to accept an optional dot separator between the pre-release name and version number, supporting both: - 1.2.3-alpha1 (compact, existing behavior preserved) - 1.2.3-alpha.1 (dot-separated, SemVer standard) This is relevant for Rust/Cargo projects where 0.2.1-alpha.1 is the established convention. Includes tests for parsing, property verification, and equivalence between dot-separated and compact formats.
1 parent 74c6967 commit 75ba30d

File tree

2 files changed

+88
-4
lines changed

2 files changed

+88
-4
lines changed

pontos/version/schemes/_semantic.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,13 @@
1313
from .._version import Version
1414
from ._scheme import VersioningScheme
1515

16-
# Note: This regex currently support any kind of
17-
# word-number combination for pre releases
16+
# Note: This regex supports word-number combinations for pre releases.
17+
# An optional dot separator is allowed between name and version to support
18+
# both SemVer-standard format (e.g. "alpha.1") and the compact format
19+
# (e.g. "alpha1"). The same applies to the extra (dev) segment.
1820
_PRE_RELEASE_REGEXP = re.compile(
19-
r"^(?P<name>[a-zA-Z]+)(?P<version>0|[1-9][0-9]*)"
20-
r"(?:-(?P<extra>[a-zA-Z]+)(?P<extra_version>0|[1-9][0-9]*))?$"
21+
r"^(?P<name>[a-zA-Z]+)\.?(?P<version>0|[1-9][0-9]*)"
22+
r"(?:-(?P<extra>[a-zA-Z]+)\.?(?P<extra_version>0|[1-9][0-9]*))?$"
2123
)
2224

2325

tests/version/schemes/test_semantic.py

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,14 @@ def test_parse_version(self):
3838
"22.4.1",
3939
"22.4.1-dev1",
4040
"22.4.1-dev3",
41+
# Dot-separated pre-release identifiers (SemVer standard)
42+
"1.2.3-alpha.1",
43+
"1.2.3-beta.1",
44+
"1.2.3-rc.1",
45+
"1.2.3-dev.1",
46+
"1.2.3-alpha.1-dev.1",
47+
"1.2.3-beta.3-dev.2",
48+
"0.2.1-alpha.5",
4149
]
4250
for version in versions:
4351
self.assertEqual(Version.from_string(version), Version(version))
@@ -103,6 +111,80 @@ def test_parse_prerelease_error(self):
103111
):
104112
Version.from_string(version)
105113

114+
def test_dot_separated_prerelease_properties(self):
115+
"""Dot-separated pre-release identifiers should parse to the
116+
same semantic properties as compact identifiers."""
117+
# alpha.1 has same properties as alpha1
118+
v = Version.from_string("1.2.3-alpha.1")
119+
self.assertTrue(v.is_pre_release)
120+
self.assertTrue(v.is_alpha_release)
121+
self.assertFalse(v.is_beta_release)
122+
self.assertFalse(v.is_release_candidate)
123+
self.assertEqual(v.pre, ("alpha", 1))
124+
125+
# beta.3 has same properties as beta3
126+
v = Version.from_string("1.2.3-beta.3")
127+
self.assertTrue(v.is_pre_release)
128+
self.assertTrue(v.is_beta_release)
129+
self.assertEqual(v.pre, ("beta", 3))
130+
131+
# rc.2 has same properties as rc2
132+
v = Version.from_string("1.2.3-rc.2")
133+
self.assertTrue(v.is_pre_release)
134+
self.assertTrue(v.is_release_candidate)
135+
self.assertEqual(v.pre, ("rc", 2))
136+
137+
# dev.1 is a dev release
138+
v = Version.from_string("1.2.3-dev.1")
139+
self.assertTrue(v.is_dev_release)
140+
self.assertEqual(v.dev, 1)
141+
142+
# alpha.1-dev.1 has both pre-release and dev
143+
v = Version.from_string("1.2.3-alpha.1-dev.1")
144+
self.assertTrue(v.is_pre_release)
145+
self.assertTrue(v.is_dev_release)
146+
self.assertTrue(v.is_alpha_release)
147+
self.assertEqual(v.pre, ("alpha", 1))
148+
self.assertEqual(v.dev, 1)
149+
150+
def test_dot_separated_equals_compact(self):
151+
"""Dot-separated and compact pre-release versions with the same
152+
name and number should be semantically equal."""
153+
pairs = [
154+
("1.2.3-alpha.1", "1.2.3-alpha1"),
155+
("1.2.3-beta.3", "1.2.3-beta3"),
156+
("1.2.3-rc.2", "1.2.3-rc2"),
157+
("1.2.3-dev.1", "1.2.3-dev1"),
158+
]
159+
for dot_version, compact_version in pairs:
160+
v_dot = Version.from_string(dot_version)
161+
v_compact = Version.from_string(compact_version)
162+
self.assertEqual(
163+
v_dot.pre,
164+
v_compact.pre,
165+
f"pre mismatch: {dot_version} vs {compact_version}",
166+
)
167+
self.assertEqual(
168+
v_dot.dev,
169+
v_compact.dev,
170+
f"dev mismatch: {dot_version} vs {compact_version}",
171+
)
172+
self.assertEqual(
173+
v_dot.major,
174+
v_compact.major,
175+
f"major mismatch: {dot_version} vs {compact_version}",
176+
)
177+
self.assertEqual(
178+
v_dot.minor,
179+
v_compact.minor,
180+
f"minor mismatch: {dot_version} vs {compact_version}",
181+
)
182+
self.assertEqual(
183+
v_dot.patch,
184+
v_compact.patch,
185+
f"patch mismatch: {dot_version} vs {compact_version}",
186+
)
187+
106188
def test_equal(self):
107189
versions = [
108190
("1.0.0", "1.0.0"),

0 commit comments

Comments
 (0)