Skip to content

Commit 8fc71e5

Browse files
committed
Merge pull request readthedocs#1354 from gregmuellegger/version-handling-improvements
Version handling improvements
2 parents 3f7a96d + 3d4bada commit 8fc71e5

36 files changed

+332
-136
lines changed

readthedocs/api/base.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
from tastypie.http import HttpCreated, HttpApplicationError
1313
from tastypie.utils import dict_strip_unicode_keys, trailing_slash
1414

15+
from builds.constants import LATEST
1516
from builds.models import Build, Version
1617
from core.utils import trigger_build
1718
from projects.models import Project, ImportedFile
@@ -150,7 +151,7 @@ def version_compare(self, request, **kwargs):
150151
if highest[0]:
151152
ret_val['url'] = highest[0].get_absolute_url()
152153
ret_val['slug'] = highest[0].slug,
153-
if base and base != 'latest':
154+
if base and base != LATEST:
154155
try:
155156
ver_obj = project.versions.get(slug=base)
156157
base_ver = mkversion(ver_obj)
@@ -167,7 +168,7 @@ def version_compare(self, request, **kwargs):
167168

168169
def build_version(self, request, **kwargs):
169170
project = get_object_or_404(Project, slug=kwargs['project_slug'])
170-
version = kwargs.get('version_slug', 'latest')
171+
version = kwargs.get('version_slug', LATEST)
171172
version_obj = project.versions.get(slug=version)
172173
trigger_build(project=project, version=version_obj)
173174
return self.create_response(request, {'building': True})

readthedocs/betterversion/better.py

+15-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,14 @@
11
from distlib.version import AdaptiveVersion
22
from collections import defaultdict
33

4-
class BetterVersion(AdaptiveVersion):
4+
5+
class VersionIdentifier(AdaptiveVersion):
6+
"""
7+
An extended variant of ``distlib.version.AdaptiveVersion``. The constructor
8+
takes a version string like ``0.7.3`` and the class then provides a nice
9+
interface to access the different major/minor version numbers etc.
10+
"""
11+
512
@property
613
def major_version(self):
714
return self._parts[0][0]
@@ -14,8 +21,8 @@ def minor_version(self):
1421
except IndexError, e:
1522
return 0
1623

17-
class VersionManager(object):
1824

25+
class VersionManager(object):
1926
def __init__(self):
2027
self._state = defaultdict(lambda: defaultdict(list))
2128

@@ -50,13 +57,18 @@ def prune_point(self, num_latest):
5057
# Raise these for now.
5158
raise
5259

60+
5361
def version_windows(versions, major=1, minor=1, point=1, flat=False):
62+
# TODO: This needs some documentation on how VersionManager etc works and
63+
# some examples what the expected outcome is.
64+
5465
major_version_window = major
5566
minor_version_window = minor
5667
point_version_window = point
5768

5869
manager = VersionManager()
59-
[ manager.add(v) for v in versions]
70+
for v in versions:
71+
manager.add(v)
6072
manager.prune_major(major_version_window)
6173
manager.prune_minor(minor_version_window)
6274
manager.prune_point(point_version_window)

readthedocs/builds/constants.py

+6
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,9 @@
2424
('tag', _('Tag')),
2525
('unknown', _('Unknown')),
2626
)
27+
28+
LATEST = 'latest'
29+
LATEST_VERBOSE_NAME = 'latest'
30+
31+
STABLE = 'stable'
32+
STABLE_VERBOSE_NAME = 'stable'

readthedocs/builds/models.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
from guardian.shortcuts import assign
1010
from taggit.managers import TaggableManager
1111

12+
from builds.constants import LATEST
1213
from privacy.loader import VersionManager, RelatedProjectManager
1314
from projects.models import Project
1415
from projects import constants
@@ -79,7 +80,7 @@ def save(self, *args, **kwargs):
7980

8081
@property
8182
def remote_slug(self):
82-
if self.slug == 'latest':
83+
if self.slug == LATEST:
8384
if self.project.default_branch:
8485
return self.project.default_branch
8586
else:

readthedocs/builds/utils.py

+4-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22
import logging
33
from shutil import rmtree
44

5+
from builds.constants import LATEST
6+
7+
58
log = logging.getLogger(__name__)
69

710

@@ -42,7 +45,7 @@ def get_bitbucket_username_repo(version, repo_url=None):
4245

4346
def get_vcs_version_slug(version):
4447
slug = None
45-
if version.slug == 'latest':
48+
if version.slug == LATEST:
4649
if version.project.default_branch:
4750
slug = version.project.default_branch
4851
else:

readthedocs/core/djangome_urls.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
from django.conf.urls import patterns, url
2+
from builds.constants import LATEST
3+
24

35
urlpatterns = patterns(
46
'', # base view, flake8 complains if it is on the previous line.
57
url('^$',
68
'djangome.views.redirect_home',
7-
{'version': 'latest'}),
9+
{'version': LATEST}),
810
)

readthedocs/core/management/commands/build_files.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
from django.conf import settings
66

77
from projects import tasks
8+
from builds.constants import LATEST
89
from builds.models import Version
910

1011
log = logging.getLogger(__name__)
@@ -35,7 +36,7 @@ def handle(self, *args, **options):
3536
queryset = Version.objects.public(project__slug=project)
3637
log.info("Building all versions for %s" % project)
3738
elif getattr(settings, 'INDEX_ONLY_LATEST', True):
38-
queryset = Version.objects.filter(slug='latest')
39+
queryset = Version.objects.filter(slug=LATEST)
3940
else:
4041
queryset = Version.objects.public()
4142
for v in queryset:
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
from django.core.management.base import BaseCommand
22

3+
from builds.constants import LATEST
34
from builds.models import Version
45
from projects.tasks import update_intersphinx
56

67

78
class Command(BaseCommand):
89
def handle(self, *args, **options):
9-
for version in Version.objects.filter(slug="latest"):
10+
for version in Version.objects.filter(slug=LATEST):
1011
update_intersphinx(version.pk)

readthedocs/core/management/commands/pull.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from django.core.management.base import BaseCommand
44
from django.conf import settings
55

6+
from builds.constants import LATEST
67
from projects import tasks, utils
78

89
import redis
@@ -14,5 +15,5 @@ def handle(self, *args, **options):
1415
if len(args):
1516
for slug in args:
1617
tasks.update_imported_docs(
17-
utils.version_from_slug(slug, 'latest').pk
18+
utils.version_from_slug(slug, LATEST).pk
1819
)

readthedocs/core/management/commands/reindex_elasticsearch.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from django.core.management.base import BaseCommand
55
from django.conf import settings
66

7+
from builds.constants import LATEST
78
from builds.models import Version
89
from search import parse_json
910
from restapi.utils import index_search_request
@@ -30,7 +31,7 @@ def handle(self, *args, **options):
3031
queryset = Version.objects.public(project__slug=project)
3132
log.info("Building all versions for %s" % project)
3233
elif getattr(settings, 'INDEX_ONLY_LATEST', True):
33-
queryset = Version.objects.public().filter(slug='latest')
34+
queryset = Version.objects.public().filter(slug=LATEST)
3435
else:
3536
queryset = Version.objects.public()
3637
for version in queryset:

readthedocs/core/utils.py

+5-3
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
from django.template.loader import get_template
1010
from django.template import Context
1111

12+
from builds.constants import LATEST
13+
from builds.constants import LATEST_VERBOSE_NAME
1214
from builds.models import Build
1315

1416
log = logging.getLogger(__name__)
@@ -44,10 +46,10 @@ def make_latest(project):
4446
branch = project.default_branch or project.vcs_repo().fallback_branch
4547
version_data, created = Version.objects.get_or_create(
4648
project=project,
47-
slug='latest',
49+
slug=LATEST,
4850
type='branch',
4951
active=True,
50-
verbose_name='latest',
52+
verbose_name=LATEST_VERBOSE_NAME,
5153
identifier=branch,
5254
)
5355

@@ -82,7 +84,7 @@ def trigger_build(project, version=None, record=True, force=False, basic=False):
8284
return None
8385

8486
if not version:
85-
version = project.versions.get(slug='latest')
87+
version = project.versions.get(slug=LATEST)
8688

8789
if record:
8890
build = Build.objects.create(

readthedocs/core/views.py

+5-4
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
from core.forms import FacetedSearchForm
2525
from core.utils import trigger_build
2626
from donate.mixins import DonateProgressMixin
27+
from builds.constants import LATEST
2728
from projects import constants
2829
from projects.models import Project, ImportedFile, ProjectRelationship
2930
from projects.tasks import remove_dir, update_imported_docs
@@ -152,7 +153,7 @@ def _build_version(project, slug, already_built=()):
152153
# short circuit versions that are default
153154
# these will build at "latest", and thus won't be
154155
# active
155-
latest_version = project.versions.get(slug='latest')
156+
latest_version = project.versions.get(slug=LATEST)
156157
trigger_build(project=project, version=latest_version, force=True)
157158
pc_log.info(("(Version build) Building %s:%s"
158159
% (project.slug, latest_version.slug)))
@@ -162,7 +163,7 @@ def _build_version(project, slug, already_built=()):
162163
trigger_build(project=project, version=slug_version, force=True)
163164
pc_log.info(("(Version build) Building %s:%s"
164165
% (project.slug, slug_version.slug)))
165-
return "latest"
166+
return LATEST
166167
elif project.versions.exclude(active=True).filter(slug=slug).exists():
167168
pc_log.info(("(Version build) Not Building %s" % slug))
168169
return None
@@ -201,7 +202,7 @@ def _build_url(url, branches):
201202
for project in projects:
202203
(to_build, not_building) = _build_branches(project, branches)
203204
if not to_build:
204-
update_imported_docs.delay(project.versions.get(slug='latest').pk)
205+
update_imported_docs.delay(project.versions.get(slug=LATEST).pk)
205206
msg = '(URL Build) Syncing versions for %s' % project.slug
206207
pc_log.info(msg)
207208
if to_build:
@@ -293,7 +294,7 @@ def generic_build(request, pk=None):
293294
_build_version(project, slug)
294295
else:
295296
pc_log.info(
296-
"(Incoming Generic Build) %s [%s]" % (project.slug, 'latest'))
297+
"(Incoming Generic Build) %s [%s]" % (project.slug, LATEST))
297298
trigger_build(project=project, force=True)
298299
else:
299300
return HttpResponse("You must POST to this resource.")

readthedocs/privacy/backend.py

+28
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@
33

44
from guardian.shortcuts import get_objects_for_user
55

6+
from builds.constants import LATEST
7+
from builds.constants import LATEST_VERBOSE_NAME
8+
from builds.constants import STABLE
9+
from builds.constants import STABLE_VERBOSE_NAME
610
from projects import constants
711

812

@@ -113,6 +117,30 @@ def public(self, user=None, project=None, only_active=True, *args, **kwargs):
113117
def api(self, user=None, *args, **kwargs):
114118
return self.public(user, only_active=False)
115119

120+
def create_stable(self, **kwargs):
121+
defaults = {
122+
'slug': STABLE,
123+
'verbose_name': STABLE_VERBOSE_NAME,
124+
'machine': True,
125+
'active': True,
126+
'identifier': STABLE,
127+
'type': 'branch',
128+
}
129+
defaults.update(kwargs)
130+
return self.create(**defaults)
131+
132+
def create_latest(self, **kwargs):
133+
defaults = {
134+
'slug': LATEST,
135+
'verbose_name': LATEST_VERBOSE_NAME,
136+
'machine': True,
137+
'active': True,
138+
'identifier': LATEST,
139+
'type': 'branch',
140+
}
141+
defaults.update(kwargs)
142+
return self.create(**defaults)
143+
116144

117145
class AdminPermission(object):
118146

0 commit comments

Comments
 (0)