Skip to content

Commit

Permalink
API: support rebuilding external version builds with build create end…
Browse files Browse the repository at this point in the history
…point (#11407)

* API: support rebuilding external version builds with build create endpoint

On the old dashboard, we are using a hidden form on two views to retry
builds, but the API is a more consistent way to do this. The feature
this endpoint is missing that BuildTriggerMixin has is retrying a build
for a version using the last build commit.

What is different in this method is that we don't give the user an error
if the build isn't the latest build for a version. To the user, this
detail shouldn't matter and this endpoint instead automatically uses the last
build to get the commit to start the new build.

* Add basic test case for external build trigger

* Refactor tests

* Lint
  • Loading branch information
agjohnson authored Jul 1, 2024
1 parent d2ad47b commit aeb60b3
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 2 deletions.
32 changes: 32 additions & 0 deletions readthedocs/api/v3/tests/test_builds.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from django.test import override_settings
from django.urls import reverse

from readthedocs.builds.constants import EXTERNAL
from readthedocs.subscriptions.constants import TYPE_CONCURRENT_BUILDS
from readthedocs.subscriptions.products import RTDProductFeature

Expand Down Expand Up @@ -82,6 +83,37 @@ def test_projects_versions_builds_list_post(self):
self._get_response_dict("projects-versions-builds-list_POST"),
)

def test_external_version_projects_versions_builds_list_post(self):
"""Build starts using last commit against external version."""
self.version.type = EXTERNAL
self.build.commit = "d4e5f6"
self.version.save()
self.build.save()
url = reverse(
"projects-versions-builds-list",
kwargs={
"parent_lookup_project__slug": self.project.slug,
"parent_lookup_version__slug": self.version.slug,
},
)

self.client.credentials(HTTP_AUTHORIZATION=f"Token {self.token.key}")
self.assertEqual(self.project.builds.count(), 1)
response = self.client.post(url)
self.assertEqual(response.status_code, 202)
self.assertEqual(self.project.builds.count(), 2)

response_json = response.json()
response_json["build"]["created"] = "2019-04-29T14:00:00Z"
expected = self._get_response_dict("projects-versions-builds-list_POST")
expected["build"]["commit"] = "d4e5f6"
expected["version"]["type"] = "external"
expected["version"]["urls"][
"documentation"
] = "http://project--v1.0.external-builds.readthedocs.io/en/v1.0/"
expected["version"]["urls"]["vcs"] = "https://github.com/rtfd/project/pull/v1.0"
self.assertDictEqual(response_json, expected)

def test_projects_builds_notifications_list(self):
url = reverse(
"projects-builds-notifications-list",
Expand Down
17 changes: 15 additions & 2 deletions readthedocs/api/v3/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -369,8 +369,21 @@ def get_serializer_class(self):
def create(self, request, **kwargs): # pylint: disable=arguments-differ
project = self._get_parent_project()
version = self._get_parent_version()

_, build = trigger_build(project, version=version)
build_retry = None
commit = None

if version.is_external:
# We use the last build for a version here as we want to update VCS
# providers and need to reference the latest commit to do so.
build_retry = version.last_build
if build_retry:
commit = build_retry.commit

_, build = trigger_build(
project=project,
version=version,
commit=commit,
)

# TODO: refactor this to be a serializer
# BuildTriggeredSerializer(build, project, version).data
Expand Down
3 changes: 3 additions & 0 deletions readthedocs/builds/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ def get_queryset(self):
return queryset


# TODO this class and views that extend this class can be removed when the old
# dashboard goes away and RTD_EXT_THEME_ENABLED is removed. Instead of using a
# hidden form on views, the new dashboard uses APIv3 to trigger new builds.
class BuildTriggerMixin:
@method_decorator(login_required)
def post(self, request, project_slug):
Expand Down

0 comments on commit aeb60b3

Please sign in to comment.