Skip to content

PR Builds tab added to project dashboard #5807

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

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions readthedocs/builds/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -746,6 +746,11 @@ def is_stale(self):
def using_latest_config(self):
return int(self.config.get('version', '1')) == LATEST_CONFIGURATION_VERSION

@property
def is_external(self):
"""Return if build is a External ie: Pull/Merge Request Build."""
return self.version.type == EXTERNAL


class BuildCommandResultMixin:

Expand Down
31 changes: 31 additions & 0 deletions readthedocs/builds/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,37 @@ def get_context_data(self, **kwargs):
return context


class ExternalBuildList(BuildBase, ListView):
template_name = 'builds/external_build_list.html'
allow_empty = False

def get_queryset(self):
# this is used to include only external version
# builds in the build list page
self.project_slug = self.kwargs.get('project_slug', None)
self.project = get_object_or_404(
Project.objects.protected(self.request.user),
slug=self.project_slug,
)
queryset = Build.external.public(
user=self.request.user,
project=self.project,
).select_related('project', 'version')

return queryset

def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['project'] = self.project
context['versions'] = Version.external.public(
user=self.request.user,
project=self.project,
)
context['build_qs'] = self.get_queryset()

return context


class BuildDetail(BuildBase, DetailView):
pk_url_kwarg = 'build_pk'

Expand Down
14 changes: 13 additions & 1 deletion readthedocs/projects/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
from taggit.managers import TaggableManager

from readthedocs.api.v2.client import api
from readthedocs.builds.constants import LATEST, STABLE, INTERNAL
from readthedocs.builds.constants import LATEST, STABLE, INTERNAL, EXTERNAL
from readthedocs.core.resolver import resolve, resolve_domain
from readthedocs.core.utils import broadcast, slugify
from readthedocs.projects import constants
Expand Down Expand Up @@ -519,6 +519,14 @@ def get_builds_url(self):
},
)

def get_external_builds_url(self):
return reverse(
'external_builds_project_list',
kwargs={
'project_slug': self.slug,
},
)

def get_canonical_url(self):
if settings.DONT_HIT_DB:
return api.project(self.pk).canonical_url().get()['url']
Expand Down Expand Up @@ -1107,6 +1115,10 @@ def environment_variables(self):
for variable in self.environmentvariable_set.all()
}

@property
def has_external_builds(self):
return self.builds(manager=EXTERNAL).exists()


class APIProject(Project):

Expand Down
5 changes: 5 additions & 0 deletions readthedocs/projects/urls/public.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,11 @@
build_views.BuildList.as_view(),
name='builds_project_list',
),
url(
(r'^(?P<project_slug>{project_slug})/builds/external/$'.format(**pattern_opts)),
build_views.ExternalBuildList.as_view(),
name='external_builds_project_list',
),
url(
r'^(?P<project_slug>{project_slug})/versions/$'.format(**pattern_opts),
public.project_versions,
Expand Down
25 changes: 25 additions & 0 deletions readthedocs/rtd_tests/tests/test_builds.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from django_dynamic_fixture import fixture, get
from django.utils import timezone

from readthedocs.builds.constants import EXTERNAL
from readthedocs.builds.models import Build, Version
from readthedocs.doc_builder.config import load_yaml_config
from readthedocs.doc_builder.environments import LocalBuildEnvironment
Expand Down Expand Up @@ -582,3 +583,27 @@ def test_using_latest_config(self):
build.save()

self.assertTrue(build.using_latest_config())

def test_build_is_external(self):
# Turn the build version to EXTERNAL type.
self.version.type = EXTERNAL
self.version.save()

external_build = get(
Build,
project=self.project,
version=self.version,
config={'version': 1},
)

self.assertTrue(external_build.is_external)

def test_build_is_not_external(self):
build = get(
Build,
project=self.project,
version=self.version,
config={'version': 1},
)

self.assertFalse(build.is_external)
7 changes: 6 additions & 1 deletion readthedocs/rtd_tests/tests/test_privacy_urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
from django_dynamic_fixture import get
from taggit.models import Tag

from readthedocs.builds.models import Build, BuildCommandResult
from readthedocs.builds.constants import EXTERNAL
from readthedocs.builds.models import Build, BuildCommandResult, Version
from readthedocs.core.utils.tasks import TaskNoPermission
from readthedocs.integrations.models import HttpExchange, Integration
from readthedocs.oauth.models import RemoteOrganization, RemoteRepository
Expand Down Expand Up @@ -139,7 +140,11 @@ class ProjectMixin(URLAccessMixin):

def setUp(self):
super().setUp()
self.external_version = get(Version, project=self.pip, type=EXTERNAL)
self.build = get(Build, project=self.pip)
self.external_build = get(
Build, project=self.pip, version=self.external_version
)
self.tag = get(Tag, slug='coolness')
self.subproject = get(
Project, slug='sub', language='ja',
Expand Down
13 changes: 13 additions & 0 deletions readthedocs/rtd_tests/tests/test_project.py
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,19 @@ def test_has_good_build_excludes_external_versions(self):
# Test that PR Version is not considered for has_good_build.
self.assertFalse(self.pip.has_good_build)

def test_get_external_builds_url(self):
self.assertEqual(
self.pip.get_external_builds_url(),
f'/projects/{self.pip.slug}/builds/external/'
)

def test_project_has_external_builds(self):
external_build = Build.objects.create(
project=self.pip,
version=self.external_version,
)
self.assertTrue(self.pip.has_external_builds)


class TestProjectTranslations(ProjectMixin, TestCase):

Expand Down
29 changes: 27 additions & 2 deletions readthedocs/rtd_tests/tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from django.urls import reverse
from django_dynamic_fixture import get, new

from readthedocs.builds.constants import LATEST, EXTERNAL
from readthedocs.builds.constants import LATEST, EXTERNAL, BRANCH
from readthedocs.builds.models import Build, Version
from readthedocs.core.permissions import AdminPermission
from readthedocs.projects.forms import UpdateProjectForm
Expand Down Expand Up @@ -294,6 +294,31 @@ def test_build_list_does_not_include_external_versions(self):
reverse('builds_project_list', args=[self.pip.slug]),
)
self.assertEqual(response.status_code, 200)

self.assertNotIn(external_version_build, response.context['build_qs'])
self.assertNotIn(external_version_build, response.context['active_builds'])

def test_external_build_list_includes_external_version_builds(self):
external_version = get(
Version,
project = self.pip,
active = True,
type = EXTERNAL,
)
external_version_build = get(
Build,
project = self.pip,
version = external_version
)
response = self.client.get(
reverse('external_builds_project_list', args=[self.pip.slug]),
)

self.assertEqual(response.status_code, 200)
self.assertIn(external_version_build, response.context['build_qs'])

def test_external_build_list_returns_404_if_no_external_build_available(self):
response = self.client.get(
reverse('external_builds_project_list', args=[self.pip.slug]),
)

self.assertEqual(response.status_code, 404)
16 changes: 13 additions & 3 deletions readthedocs/templates/builds/build_detail.html
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,19 @@
{% endblock %}

{% block project_editing %}
{% with builds_active="active" %}
{% include "core/project_bar.html" %}
{% endwith %}

{% if build.is_external %}

{% with external_builds_active="active" %}
{% include "core/project_bar.html" %}
{% endwith %}
{% else %}
{% with builds_active="active" %}
{% include "core/project_bar.html" %}
{% endwith %}

{% endif %}

{% endblock %}

{% block content %}
Expand Down
46 changes: 46 additions & 0 deletions readthedocs/templates/builds/external_build_list.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
{% extends "projects/base_project.html" %}

{% load i18n %}
{% load static %}

{% load pagination_tags %}
{% load privacy_tags %}
{% load projects_tags %}

{% block title %}Builds{% endblock %}

{% block project_editing %}
{% with external_builds_active="active" %}
{% include "core/project_bar.html" %}
{% endwith %}
{% endblock %}

{% block content %}


<div id="build_list">

{% autopaginate build_qs 15 %}

<!-- BEGIN builds list -->
<div class="module">
<div class="module-wrapper">
<h1>{% trans "Recent External Builds" %}</h1>

<div class="module-list">
<div class="module-list-wrapper">
<ul>
{% include "core/build_list_detailed.html" %}
</ul>
</div>
</div>

</div>
</div>
<!-- END builds list -->

{% paginate %}

</div>

{% endblock %}
4 changes: 4 additions & 0 deletions readthedocs/templates/core/project_bar_base.html
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ <h1>

<li class="{{ builds_active }}"><a href="{{ project.get_builds_url }}">{% trans "Builds" %}</a></li>

{% if project.has_external_builds %}
<li class="{{ external_builds_active }}"><a href="{{ project.get_external_builds_url }}">{% trans "External Builds" %}</a></li>
{% endif %}

<li class="{{ versions_active }}"><a href="{% url "project_version_list" project.slug %}">{% trans "Versions" %}</a></li>

{% comment %}
Expand Down