|
6 | 6 | from celery import Task
|
7 | 7 | from django.conf import settings
|
8 | 8 | from django.core.files.storage import get_storage_class
|
9 |
| -from django.shortcuts import get_object_or_404 |
10 | 9 |
|
11 | 10 | from readthedocs.api.v2.serializers import BuildSerializer
|
12 | 11 | from readthedocs.api.v2.utils import (
|
13 |
| - ProjectPagination, |
14 |
| - RemoteOrganizationPagination, |
15 |
| - RemoteProjectPagination, |
16 | 12 | delete_versions_from_db,
|
| 13 | + get_deleted_active_versions, |
17 | 14 | run_automation_rules,
|
18 | 15 | sync_versions_to_db,
|
19 | 16 | )
|
20 | 17 | from readthedocs.builds.constants import (
|
21 | 18 | BRANCH,
|
22 |
| - BUILD_STATE_FINISHED, |
23 |
| - BUILD_STATE_TRIGGERED, |
24 | 19 | BUILD_STATUS_FAILURE,
|
25 | 20 | BUILD_STATUS_PENDING,
|
26 | 21 | BUILD_STATUS_SUCCESS,
|
27 |
| - INTERNAL, |
28 | 22 | MAX_BUILD_COMMAND_SIZE,
|
29 | 23 | TAG,
|
30 | 24 | )
|
|
33 | 27 | from readthedocs.core.utils import trigger_build
|
34 | 28 | from readthedocs.projects.models import Project
|
35 | 29 | from readthedocs.projects.tasks import send_build_status
|
36 |
| -from readthedocs.projects.version_handling import determine_stable_version |
37 | 30 | from readthedocs.worker import app
|
38 | 31 |
|
39 | 32 | log = logging.getLogger(__name__)
|
@@ -188,55 +181,103 @@ def archive_builds_task(days=14, limit=200, include_cold=False, delete=False):
|
188 | 181 | log.exception('Cold Storage save failure')
|
189 | 182 |
|
190 | 183 |
|
| 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 | + |
191 | 221 | @app.task(
|
192 | 222 | max_retries=1,
|
193 | 223 | default_retry_delay=60,
|
194 | 224 | queue='web'
|
195 | 225 | )
|
196 |
| -def sync_versions_task(project_pk, version_data, **kwargs): |
| 226 | +def sync_versions_task(project_pk, tags_data, branches_data, **kwargs): |
197 | 227 | """
|
198 | 228 | Sync the version data in the repo (on the build server).
|
199 | 229 |
|
200 | 230 | Version data in the repo is synced with what we have in the database.
|
201 | 231 |
|
| 232 | + :param version_data: a dictionary of branches and tags from the project. |
202 | 233 | :returns: the identifiers for the versions that have been deleted.
|
203 | 234 | """
|
204 | 235 | project = Project.objects.get(pk=project_pk)
|
205 | 236 |
|
206 | 237 | # If the currently highest non-prerelease version is active, then make
|
207 | 238 | # 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 |
211 | 242 | else:
|
212 | 243 | activate_new_stable = False
|
213 | 244 |
|
214 | 245 | try:
|
215 | 246 | # Update All Versions
|
216 | 247 | added_versions = set()
|
217 |
| - if 'tags' in version_data: |
| 248 | + if tags_data: |
218 | 249 | ret_set = sync_versions_to_db(
|
219 | 250 | project=project,
|
220 |
| - versions=version_data['tags'], |
| 251 | + versions=tags_data, |
221 | 252 | type=TAG,
|
222 | 253 | )
|
223 | 254 | added_versions.update(ret_set)
|
224 |
| - if 'branches' in version_data: |
| 255 | + if branches_data: |
225 | 256 | ret_set = sync_versions_to_db(
|
226 | 257 | project=project,
|
227 |
| - versions=version_data['branches'], |
| 258 | + versions=branches_data, |
228 | 259 | type=BRANCH,
|
229 | 260 | )
|
230 | 261 | 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 | + ) |
232 | 272 | except Exception:
|
233 | 273 | log.exception('Sync Versions Error')
|
| 274 | + return [], [] |
234 | 275 |
|
235 | 276 | try:
|
236 | 277 | # The order of added_versions isn't deterministic.
|
237 | 278 | # We don't track the commit time or any other metadata.
|
238 | 279 | # 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) |
240 | 281 | except Exception:
|
241 | 282 | # Don't interrupt the request if something goes wrong
|
242 | 283 | # in the automation rules.
|
@@ -268,41 +309,4 @@ def sync_versions_task(project_pk, version_data, **kwargs):
|
268 | 309 | promoted_version.save()
|
269 | 310 | trigger_build(project=project, version=promoted_version)
|
270 | 311 |
|
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