Skip to content

Add ability to rebuild a specific build #6995

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Jun 9, 2021
2 changes: 2 additions & 0 deletions readthedocs/builds/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,9 @@

BUILD_STATUS_NORMAL = 'normal'
BUILD_STATUS_DUPLICATED = 'duplicated'
BUILD_STATUS_RETRIGGERED = 'retriggered'
BUILD_STATUS_CHOICES = (
(BUILD_STATUS_NORMAL, 'Normal'),
(BUILD_STATUS_DUPLICATED, 'Duplicated'),
(BUILD_STATUS_RETRIGGERED, 'Retriggered'),
)
21 changes: 20 additions & 1 deletion readthedocs/builds/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,14 +54,33 @@ def post(self, request, project_slug):
return HttpResponseForbidden()

version_slug = request.POST.get('version_slug')
commit = request.POST.get('commit')
build_pk = request.POST.get('build_pk')

version = get_object_or_404(
self._get_versions(project),
# Don't filter by internal/external here so we can build all versions
Version.objects.public(self.request.user),
slug=version_slug,
)

# Set either the build or None
build = version.builds.filter(pk=build_pk).first()

if build:

log.info(
'Rebuilding build. project=%s version=%s commit=%s build=%s',
project.slug,
version.slug,
commit,
build.pk
)

update_docs_task, build = trigger_build(
project=project,
version=version,
build=build,
commit=commit,
)
if (update_docs_task, build) == (None, None):
# Build was skipped
Expand Down
33 changes: 22 additions & 11 deletions readthedocs/core/utils/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
"""Common utilty functions."""

from datetime import datetime
import errno
import logging
import os
Expand All @@ -16,8 +17,8 @@
BUILD_STATE_FINISHED,
BUILD_STATUS_PENDING,
EXTERNAL,
BUILD_STATUS_RETRIGGERED
)
from readthedocs.doc_builder.constants import DOCKER_LIMITS
from readthedocs.projects.constants import CELERY_LOW, CELERY_MEDIUM, CELERY_HIGH
from readthedocs.doc_builder.exceptions import BuildMaxConcurrencyError, DuplicatedBuildError

Expand Down Expand Up @@ -64,6 +65,7 @@ def broadcast(type, task, args, kwargs=None, callback=None): # pylint: disable=
def prepare_build(
project,
version=None,
build=None,
commit=None,
record=True,
force=False,
Expand Down Expand Up @@ -93,8 +95,6 @@ def prepare_build(
send_notifications,
)

build = None

if not Project.objects.is_active(project):
log.warning(
'Build not triggered because Project is not active: project=%s',
Expand All @@ -112,7 +112,16 @@ def prepare_build(
'commit': commit,
}

if record:
if build:
build.state = BUILD_STATE_TRIGGERED
build.status = BUILD_STATUS_RETRIGGERED
build.success = True
build.commit = commit
build.commands.all().delete()
build.save()
kwargs['build_pk'] = build.pk

if record and not build:
build = Build.objects.create(
project=project,
version=version,
Expand Down Expand Up @@ -234,7 +243,7 @@ def prepare_build(
)


def trigger_build(project, version=None, commit=None, record=True, force=False):
def trigger_build(project, version=None, build=None, commit=None, record=True, force=False):
"""
Trigger a Build.

Expand All @@ -250,17 +259,19 @@ def trigger_build(project, version=None, commit=None, record=True, force=False):
:rtype: tuple
"""
log.info(
'Triggering build. project=%s version=%s commit=%s',
'Triggering build. project=%s version=%s commit=%s build=%s',
project.slug,
version.slug if version else None,
commit,
build.pk if build else None
)
update_docs_task, build = prepare_build(
project,
version,
commit,
record,
force,
project=project,
version=version,
build=build,
commit=commit,
record=record,
force=force,
immutable=True,
)

Expand Down
16 changes: 16 additions & 0 deletions readthedocs/rtd_tests/tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,22 @@ def test_build_list_includes_external_versions(self):
self.assertEqual(response.status_code, 200)
self.assertIn(external_version_build, response.context['build_qs'])

@mock.patch('readthedocs.projects.tasks.update_docs_task')
def test_build_commit_external_version(self, mock):
ver = self.pip.versions.first()
ver.commit = 'asd324653546'
ver.type = 'external'
ver.save()
build = get(Build, version=ver, project=self.pip)
build.save()
r = self.client.post('/projects/pip/builds/',
{'version_slug': ver.slug, 'commit': ver.commit, 'build_pk': build.pk}
)
self.assertEqual(r.status_code, 302)
self.assertEqual(
r._headers['location'][1],
'/projects/pip/builds/%s/' % build.pk,
)

class TestSearchAnalyticsView(TestCase):

Expand Down
16 changes: 16 additions & 0 deletions readthedocs/templates/builds/build_detail.html
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,22 @@
</a>
</li>
</div>


{% if request.user|is_admin:project %}
<div data-bind="visible: finished()">
<form method="post" name="rebuild_commit" action="{% url "builds_project_list" project.slug %}">
{% csrf_token %}
<a href="#" onclick="document.forms['rebuild_commit'].submit();">
Rebuild this build
</a>
<input type="hidden" name="version_slug" value="{{ build.version.slug }}">
<input type="hidden" name="commit" value="{{ build.commit }}">
<input type="hidden" name="build_pk" value="{{ build.pk }}">
</form>
</div>
{% endif %}

</ul>

<div class="build-id">
Expand Down