Skip to content

Commit a370ade

Browse files
committed
Handle .x in version sorting
1 parent 4b38e82 commit a370ade

File tree

2 files changed

+77
-2
lines changed

2 files changed

+77
-2
lines changed

readthedocs/projects/version_handling.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,21 @@ def parse_version_failsafe(version_string):
3030
else:
3131
uni_version = version_string
3232

33+
final_form = ''
34+
3335
try:
3436
normalized_version = unicodedata.normalize('NFKD', uni_version)
3537
ascii_version = normalized_version.encode('ascii', 'ignore')
3638
final_form = ascii_version.decode('ascii')
3739
return Version(final_form)
38-
except (UnicodeError, InvalidVersion):
39-
return None
40+
except InvalidVersion:
41+
# Handle the special case of 1.x, 2.x or 1.0.x, 1.1.x
42+
if final_form and '.x' in final_form:
43+
return parse_version_failsafe(final_form.replace('.x', '.0'))
44+
except UnicodeError:
45+
pass
46+
47+
return None
4048

4149

4250
def comparable_version(version_string):
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
from django.test import TestCase
2+
from django_dynamic_fixture import get
3+
4+
from readthedocs.builds.constants import BRANCH
5+
from readthedocs.builds.models import Version
6+
from readthedocs.projects.models import Project
7+
from readthedocs.projects.templatetags.projects_tags import sort_version_aware
8+
9+
10+
class SortVersionsTest(TestCase):
11+
12+
def setUp(self):
13+
self.project = get(Project)
14+
15+
def test_basic_sort(self):
16+
identifiers = ['1.0', '2.0', '1.1', '1.9', '1.10']
17+
for identifier in identifiers:
18+
get(
19+
Version,
20+
project=self.project,
21+
type=BRANCH,
22+
identifier=identifier,
23+
verbose_name=identifier,
24+
slug=identifier,
25+
)
26+
27+
versions = list(Version.objects.filter(project=self.project))
28+
self.assertEqual(
29+
['latest', '2.0', '1.10', '1.9', '1.1', '1.0'],
30+
[v.slug for v in sort_version_aware(versions)],
31+
)
32+
33+
def test_sort_wildcard(self):
34+
identifiers = ['1.0.x', '2.0.x', '1.1.x', '1.9.x', '1.10.x']
35+
for identifier in identifiers:
36+
get(
37+
Version,
38+
project=self.project,
39+
type=BRANCH,
40+
identifier=identifier,
41+
verbose_name=identifier,
42+
slug=identifier,
43+
)
44+
45+
versions = list(Version.objects.filter(project=self.project))
46+
self.assertEqual(
47+
['latest', '2.0.x', '1.10.x', '1.9.x', '1.1.x', '1.0.x'],
48+
[v.slug for v in sort_version_aware(versions)],
49+
)
50+
51+
def test_sort_alpha(self):
52+
identifiers = ['banana', 'apple', 'carrot']
53+
for identifier in identifiers:
54+
get(
55+
Version,
56+
project=self.project,
57+
type=BRANCH,
58+
identifier=identifier,
59+
verbose_name=identifier,
60+
slug=identifier,
61+
)
62+
63+
versions = list(Version.objects.filter(project=self.project))
64+
self.assertEqual(
65+
['latest', 'carrot', 'banana', 'apple'],
66+
[v.slug for v in sort_version_aware(versions)],
67+
)

0 commit comments

Comments
 (0)