Skip to content

Commit 5fc0164

Browse files
committed
Continue refactor
- Split into tags and branches data - Update with latest changes from sync_versions - Make it backwards compatible
1 parent c03eaa8 commit 5fc0164

File tree

4 files changed

+136
-153
lines changed

4 files changed

+136
-153
lines changed

readthedocs/api/v2/utils.py

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -165,14 +165,16 @@ def _set_or_create_version(project, slug, version_id, verbose_name, type_):
165165
return version, False
166166

167167

168-
def _get_deleted_versions_qs(project, version_data):
168+
def _get_deleted_versions_qs(project, tags_data, branches_data):
169169
# We use verbose_name for tags
170170
# because several tags can point to the same identifier.
171171
versions_tags = [
172-
version['verbose_name'] for version in version_data.get('tags', [])
172+
version['verbose_name']
173+
for version in tags_data
173174
]
174175
versions_branches = [
175-
version['identifier'] for version in version_data.get('branches', [])
176+
version['identifier']
177+
for version in branches_data
176178
]
177179

178180
to_delete_qs = (
@@ -192,14 +194,18 @@ def _get_deleted_versions_qs(project, version_data):
192194
return to_delete_qs
193195

194196

195-
def delete_versions_from_db(project, version_data):
197+
def delete_versions_from_db(project, tags_data, branches_data):
196198
"""
197199
Delete all versions not in the current repo.
198200
199201
:returns: The slug of the deleted versions from the database.
200202
"""
201203
to_delete_qs = (
202-
_get_deleted_versions_qs(project, version_data)
204+
_get_deleted_versions_qs(
205+
project=project,
206+
tags_data=tags_data,
207+
branches_data=branches_data,
208+
)
203209
.exclude(active=True)
204210
)
205211
deleted_versions = set(to_delete_qs.values_list('slug', flat=True))
@@ -213,10 +219,14 @@ def delete_versions_from_db(project, version_data):
213219
return deleted_versions
214220

215221

216-
def get_deleted_active_versions(project, version_data):
222+
def get_deleted_active_versions(project, tags_data, branches_data):
217223
"""Return the slug of active versions that were deleted from the repository."""
218224
to_delete_qs = (
219-
_get_deleted_versions_qs(project, version_data)
225+
_get_deleted_versions_qs(
226+
project=project,
227+
tags_data=tags_data,
228+
branches_data=branches_data,
229+
)
220230
.filter(active=True)
221231
)
222232
return set(to_delete_qs.values_list('slug', flat=True))

readthedocs/api/v2/views/model_views.py

Lines changed: 19 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -6,35 +6,21 @@
66
from allauth.socialaccount.models import SocialAccount
77
from django.conf import settings
88
from django.core.files.storage import get_storage_class
9-
from django.db.models import Q
109
from django.shortcuts import get_object_or_404
1110
from django.template.loader import render_to_string
1211
from rest_framework import decorators, permissions, status, viewsets
1312
from rest_framework.parsers import JSONParser, MultiPartParser
1413
from rest_framework.renderers import BaseRenderer, JSONRenderer
1514
from rest_framework.response import Response
1615

17-
from readthedocs.builds.constants import (
18-
BRANCH,
19-
BUILD_STATE_FINISHED,
20-
BUILD_STATE_TRIGGERED,
21-
INTERNAL,
22-
TAG,
23-
)
16+
from readthedocs.builds.constants import INTERNAL
2417
from readthedocs.builds.models import Build, BuildCommandResult, Version
25-
from readthedocs.core.utils import trigger_build
26-
from readthedocs.core.utils.extend import SettingsOverrideObject
18+
from readthedocs.builds.tasks import sync_versions_task
2719
from readthedocs.oauth.models import RemoteOrganization, RemoteRepository
2820
from readthedocs.oauth.services import GitHubService, registry
29-
from readthedocs.projects.models import Domain, EmailHook, Project
30-
from readthedocs.projects.version_handling import determine_stable_version
31-
32-
from ..permissions import (
33-
APIPermission,
34-
APIRestrictedPermission,
35-
IsOwner,
36-
RelatedProjectIsOwner,
37-
)
21+
from readthedocs.projects.models import Domain, Project
22+
23+
from ..permissions import APIPermission, APIRestrictedPermission, IsOwner
3824
from ..serializers import (
3925
BuildAdminSerializer,
4026
BuildCommandSerializer,
@@ -52,10 +38,6 @@
5238
ProjectPagination,
5339
RemoteOrganizationPagination,
5440
RemoteProjectPagination,
55-
delete_versions_from_db,
56-
get_deleted_active_versions,
57-
run_automation_rules,
58-
sync_versions_to_db,
5941
)
6042

6143
log = logging.getLogger(__name__)
@@ -188,47 +170,26 @@ def sync_versions(self, request, **kwargs): # noqa
188170
Version data in the repo is synced with what we have in the database.
189171
190172
:returns: the identifiers for the versions that have been deleted.
191-
"""
192-
# TODO: Delete this code. It has been moved to ``readthedocs.builds.tasks.sync_versions_task``.
193-
# This is here just to migrate our existing code
194173
195-
#################
196-
# WARNING: Do not edit or update this code
197-
#################
174+
.. note::
175+
176+
This endpoint is deprecated in favor of `sync_versions_task`.
198177
"""
199178
project = get_object_or_404(
200179
Project.objects.api(request.user),
201180
pk=kwargs['pk'],
202181
)
203182

204-
# If the currently highest non-prerelease version is active, then make
205-
# the new latest version active as well.
206-
current_stable = project.get_original_stable_version()
207-
if current_stable is not None:
208-
activate_new_stable = current_stable.active
209-
else:
210-
activate_new_stable = False
183+
added_versions = []
184+
deleted_versions = []
211185

212186
try:
213-
# Update All Versions
214187
data = request.data
215-
added_versions = set()
216-
if 'tags' in data:
217-
ret_set = sync_versions_to_db(
218-
project=project,
219-
versions=data['tags'],
220-
type=TAG,
221-
)
222-
added_versions.update(ret_set)
223-
if 'branches' in data:
224-
ret_set = sync_versions_to_db(
225-
project=project,
226-
versions=data['branches'],
227-
type=BRANCH,
228-
)
229-
added_versions.update(ret_set)
230-
deleted_versions = delete_versions_from_db(project, data)
231-
deleted_active_versions = get_deleted_active_versions(project, data)
188+
added_versions, deleted_versions = sync_versions_task(
189+
project_pk=project.pk,
190+
tags_data=data.get('tags', []),
191+
branches_data=data.get('branches', []),
192+
)
232193
except Exception as e:
233194
log.exception('Sync Versions Error')
234195
return Response(
@@ -238,19 +199,10 @@ def sync_versions(self, request, **kwargs): # noqa
238199
status=status.HTTP_400_BAD_REQUEST,
239200
)
240201

241-
try:
242-
# The order of added_versions isn't deterministic.
243-
# We don't track the commit time or any other metadata.
244-
# We usually have one version added per webhook.
245-
run_automation_rules(project, added_versions, deleted_active_versions)
246-
except Exception:
247-
# Don't interrupt the request if something goes wrong
248-
# in the automation rules.
249-
log.exception(
250-
'Failed to execute automation rules for [%s]: %s',
251-
project.slug, added_versions
252-
)
253-
"""
202+
return Response({
203+
'added_versions': added_versions,
204+
'deleted_versions': deleted_versions,
205+
})
254206

255207

256208
class VersionViewSet(UserSelectViewSet):

readthedocs/builds/tasks.py

Lines changed: 60 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -6,25 +6,19 @@
66
from celery import Task
77
from django.conf import settings
88
from django.core.files.storage import get_storage_class
9-
from django.shortcuts import get_object_or_404
109

1110
from readthedocs.api.v2.serializers import BuildSerializer
1211
from readthedocs.api.v2.utils import (
13-
ProjectPagination,
14-
RemoteOrganizationPagination,
15-
RemoteProjectPagination,
1612
delete_versions_from_db,
13+
get_deleted_active_versions,
1714
run_automation_rules,
1815
sync_versions_to_db,
1916
)
2017
from readthedocs.builds.constants import (
2118
BRANCH,
22-
BUILD_STATE_FINISHED,
23-
BUILD_STATE_TRIGGERED,
2419
BUILD_STATUS_FAILURE,
2520
BUILD_STATUS_PENDING,
2621
BUILD_STATUS_SUCCESS,
27-
INTERNAL,
2822
MAX_BUILD_COMMAND_SIZE,
2923
TAG,
3024
)
@@ -33,7 +27,6 @@
3327
from readthedocs.core.utils import trigger_build
3428
from readthedocs.projects.models import Project
3529
from readthedocs.projects.tasks import send_build_status
36-
from readthedocs.projects.version_handling import determine_stable_version
3730
from readthedocs.worker import app
3831

3932
log = logging.getLogger(__name__)
@@ -188,55 +181,103 @@ def archive_builds_task(days=14, limit=200, include_cold=False, delete=False):
188181
log.exception('Cold Storage save failure')
189182

190183

184+
def delete_inactive_external_versions(limit=200, days=30 * 3):
185+
"""
186+
Delete external versions that have been marked as inactive after ``days``.
187+
188+
The commit status is updated to link to the build page, as the docs are removed.
189+
"""
190+
days_ago = datetime.now() - timedelta(days=days)
191+
queryset = Version.external.filter(
192+
active=False,
193+
modified__lte=days_ago,
194+
)[:limit]
195+
for version in queryset:
196+
try:
197+
last_build = version.last_build
198+
if last_build:
199+
status = BUILD_STATUS_PENDING
200+
if last_build.finished:
201+
status = BUILD_STATUS_SUCCESS if last_build.success else BUILD_STATUS_FAILURE
202+
send_build_status(
203+
build_pk=last_build.pk,
204+
commit=last_build.commit,
205+
status=status,
206+
link_to_build=True,
207+
)
208+
except Exception:
209+
log.exception(
210+
"Failed to send status: project=%s version=%s",
211+
version.project.slug, version.slug,
212+
)
213+
else:
214+
log.info(
215+
"Removing external version. project=%s version=%s",
216+
version.project.slug, version.slug,
217+
)
218+
version.delete()
219+
220+
191221
@app.task(
192222
max_retries=1,
193223
default_retry_delay=60,
194224
queue='web'
195225
)
196-
def sync_versions_task(project_pk, version_data, **kwargs):
226+
def sync_versions_task(project_pk, tags_data, branches_data, **kwargs):
197227
"""
198228
Sync the version data in the repo (on the build server).
199229
200230
Version data in the repo is synced with what we have in the database.
201231
232+
:param version_data: a dictionary of branches and tags from the project.
202233
:returns: the identifiers for the versions that have been deleted.
203234
"""
204235
project = Project.objects.get(pk=project_pk)
205236

206237
# If the currently highest non-prerelease version is active, then make
207238
# the new latest version active as well.
208-
old_highest_version = determine_stable_version(project.versions.all())
209-
if old_highest_version is not None:
210-
activate_new_stable = old_highest_version.active
239+
current_stable = project.get_original_stable_version()
240+
if current_stable is not None:
241+
activate_new_stable = current_stable.active
211242
else:
212243
activate_new_stable = False
213244

214245
try:
215246
# Update All Versions
216247
added_versions = set()
217-
if 'tags' in version_data:
248+
if tags_data:
218249
ret_set = sync_versions_to_db(
219250
project=project,
220-
versions=version_data['tags'],
251+
versions=tags_data,
221252
type=TAG,
222253
)
223254
added_versions.update(ret_set)
224-
if 'branches' in version_data:
255+
if branches_data:
225256
ret_set = sync_versions_to_db(
226257
project=project,
227-
versions=version_data['branches'],
258+
versions=branches_data,
228259
type=BRANCH,
229260
)
230261
added_versions.update(ret_set)
231-
deleted_versions = delete_versions_from_db(project, version_data)
262+
deleted_versions = delete_versions_from_db(
263+
project=project,
264+
tags_data=tags_data,
265+
branches_data=branches_data,
266+
)
267+
deleted_active_versions = get_deleted_active_versions(
268+
project=project,
269+
tags_data=tags_data,
270+
branches_data=branches_data,
271+
)
232272
except Exception:
233273
log.exception('Sync Versions Error')
274+
return [], []
234275

235276
try:
236277
# The order of added_versions isn't deterministic.
237278
# We don't track the commit time or any other metadata.
238279
# We usually have one version added per webhook.
239-
run_automation_rules(project, added_versions)
280+
run_automation_rules(project, added_versions, deleted_active_versions)
240281
except Exception:
241282
# Don't interrupt the request if something goes wrong
242283
# in the automation rules.
@@ -268,41 +309,4 @@ def sync_versions_task(project_pk, version_data, **kwargs):
268309
promoted_version.save()
269310
trigger_build(project=project, version=promoted_version)
270311

271-
return (list(added_versions), list(deleted_versions))
272-
273-
274-
def delete_inactive_external_versions(limit=200, days=30 * 3):
275-
"""
276-
Delete external versions that have been marked as inactive after ``days``.
277-
278-
The commit status is updated to link to the build page, as the docs are removed.
279-
"""
280-
days_ago = datetime.now() - timedelta(days=days)
281-
queryset = Version.external.filter(
282-
active=False,
283-
modified__lte=days_ago,
284-
)[:limit]
285-
for version in queryset:
286-
try:
287-
last_build = version.last_build
288-
if last_build:
289-
status = BUILD_STATUS_PENDING
290-
if last_build.finished:
291-
status = BUILD_STATUS_SUCCESS if last_build.success else BUILD_STATUS_FAILURE
292-
send_build_status(
293-
build_pk=last_build.pk,
294-
commit=last_build.commit,
295-
status=status,
296-
link_to_build=True,
297-
)
298-
except Exception:
299-
log.exception(
300-
"Failed to send status: project=%s version=%s",
301-
version.project.slug, version.slug,
302-
)
303-
else:
304-
log.info(
305-
"Removing external version. project=%s version=%s",
306-
version.project.slug, version.slug,
307-
)
308-
version.delete()
312+
return list(added_versions), list(deleted_versions)

0 commit comments

Comments
 (0)