commit
cefb86f6d0
|
@ -102,6 +102,8 @@ class BuildSerializer(serializers.ModelSerializer):
|
|||
"""Build serializer for user display, doesn't display internal fields."""
|
||||
|
||||
commands = BuildCommandSerializer(many=True, read_only=True)
|
||||
project_slug = serializers.ReadOnlyField(source='project.slug')
|
||||
version_slug = serializers.ReadOnlyField(source='version.slug')
|
||||
docs_url = serializers.ReadOnlyField(source='version.get_absolute_url')
|
||||
state_display = serializers.ReadOnlyField(source='get_state_display')
|
||||
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
Read the Docs build information
|
||||
Build id: {{ build.id }}
|
||||
Project: {{ build.project_slug }}
|
||||
Version: {{ build.version_slug }}
|
||||
Commit: {{ build.commit }}
|
||||
Date: {{ build.date }}
|
||||
State: {{ build.state }}
|
||||
Success: {% if build.state == 'finished' %}{{ build.success }}{% else %}Unknown{% endif %}
|
||||
|
||||
{% for command in build.commands %}
|
||||
[rtd-command-info] start-time: {{ command.start_time }}, end-time: {{ command.end_time }}, duration: {{ command.run_time }}, exit-code: {{ command.exit_code }}
|
||||
{{ command.command|safe }}
|
||||
{{ command.output|safe }}
|
||||
{% endfor %}
|
|
@ -9,8 +9,9 @@ import logging
|
|||
from allauth.socialaccount.models import SocialAccount
|
||||
from django.shortcuts import get_object_or_404
|
||||
from rest_framework import decorators, permissions, status, viewsets
|
||||
from django.template.loader import render_to_string
|
||||
from rest_framework.decorators import detail_route
|
||||
from rest_framework.renderers import JSONRenderer
|
||||
from rest_framework.renderers import BaseRenderer, JSONRenderer
|
||||
from rest_framework.response import Response
|
||||
|
||||
from readthedocs.builds.constants import BRANCH, TAG
|
||||
|
@ -34,6 +35,28 @@ from ..serializers import (
|
|||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class PlainTextBuildRenderer(BaseRenderer):
|
||||
|
||||
"""
|
||||
Custom renderer for text/plain format.
|
||||
|
||||
charset is 'utf-8' by default.
|
||||
"""
|
||||
|
||||
media_type = 'text/plain'
|
||||
format = 'txt'
|
||||
|
||||
def render(self, data, accepted_media_type=None, renderer_context=None):
|
||||
renderer_context = renderer_context or {}
|
||||
response = renderer_context.get('response')
|
||||
if not response or response.exception:
|
||||
return data.get('detail', '').encode(self.charset)
|
||||
data = render_to_string(
|
||||
'restapi/log.txt', {'build': data}
|
||||
)
|
||||
return data.encode(self.charset)
|
||||
|
||||
|
||||
class UserSelectViewSet(viewsets.ModelViewSet):
|
||||
|
||||
"""
|
||||
|
@ -213,7 +236,7 @@ class VersionViewSet(UserSelectViewSet):
|
|||
|
||||
class BuildViewSetBase(UserSelectViewSet):
|
||||
permission_classes = [APIRestrictedPermission]
|
||||
renderer_classes = (JSONRenderer,)
|
||||
renderer_classes = (JSONRenderer, PlainTextBuildRenderer)
|
||||
serializer_class = BuildSerializer
|
||||
admin_serializer_class = BuildAdminSerializer
|
||||
model = Build
|
||||
|
|
|
@ -17,7 +17,7 @@ from django_dynamic_fixture import get
|
|||
from rest_framework import status
|
||||
from rest_framework.test import APIClient
|
||||
|
||||
from readthedocs.builds.models import Build, Version
|
||||
from readthedocs.builds.models import Build, BuildCommandResult, Version
|
||||
from readthedocs.integrations.models import Integration
|
||||
from readthedocs.oauth.models import RemoteOrganization, RemoteRepository
|
||||
from readthedocs.projects.models import Feature, Project
|
||||
|
@ -277,6 +277,140 @@ class APIBuildTests(TestCase):
|
|||
self.assertEqual(build['commands'][0]['run_time'], 5)
|
||||
self.assertEqual(build['commands'][0]['description'], 'foo')
|
||||
|
||||
def test_get_raw_log_success(self):
|
||||
build = get(Build, project_id=1, version_id=1, builder='foo')
|
||||
get(
|
||||
BuildCommandResult,
|
||||
build=build,
|
||||
command='python setup.py install',
|
||||
output='Installing dependencies...'
|
||||
)
|
||||
get(
|
||||
BuildCommandResult,
|
||||
build=build,
|
||||
command='git checkout master',
|
||||
output='Switched to branch "master"'
|
||||
)
|
||||
client = APIClient()
|
||||
|
||||
api_user = get(User, user='test', password='test')
|
||||
client.force_authenticate(user=api_user)
|
||||
resp = client.get('/api/v2/build/{0}.txt'.format(build.pk))
|
||||
self.assertEqual(resp.status_code, 200)
|
||||
|
||||
self.assertIn('Read the Docs build information', resp.content.decode())
|
||||
self.assertIn('Build id: {}'.format(build.id), resp.content.decode())
|
||||
self.assertIn('Project: {}'.format(build.project.slug), resp.content.decode())
|
||||
self.assertIn('Version: {}'.format(build.version.slug), resp.content.decode())
|
||||
self.assertIn('Commit: {}'.format(build.commit), resp.content.decode())
|
||||
self.assertIn('Date: ', resp.content.decode())
|
||||
self.assertIn('State: finished', resp.content.decode())
|
||||
self.assertIn('Success: True', resp.content.decode())
|
||||
self.assertIn('[rtd-command-info]', resp.content.decode())
|
||||
self.assertIn(
|
||||
'python setup.py install\nInstalling dependencies...',
|
||||
resp.content.decode()
|
||||
)
|
||||
self.assertIn(
|
||||
'git checkout master\nSwitched to branch "master"',
|
||||
resp.content.decode()
|
||||
)
|
||||
|
||||
def test_get_raw_log_building(self):
|
||||
build = get(
|
||||
Build, project_id=1, version_id=1,
|
||||
builder='foo', success=False,
|
||||
exit_code=1, state='building',
|
||||
)
|
||||
get(
|
||||
BuildCommandResult,
|
||||
build=build,
|
||||
command='python setup.py install',
|
||||
output='Installing dependencies...',
|
||||
exit_code=1,
|
||||
)
|
||||
get(
|
||||
BuildCommandResult,
|
||||
build=build,
|
||||
command='git checkout master',
|
||||
output='Switched to branch "master"'
|
||||
)
|
||||
client = APIClient()
|
||||
|
||||
api_user = get(User, user='test', password='test')
|
||||
client.force_authenticate(user=api_user)
|
||||
resp = client.get('/api/v2/build/{0}.txt'.format(build.pk))
|
||||
self.assertEqual(resp.status_code, 200)
|
||||
|
||||
self.assertIn('Read the Docs build information', resp.content.decode())
|
||||
self.assertIn('Build id: {}'.format(build.id), resp.content.decode())
|
||||
self.assertIn('Project: {}'.format(build.project.slug), resp.content.decode())
|
||||
self.assertIn('Version: {}'.format(build.version.slug), resp.content.decode())
|
||||
self.assertIn('Commit: {}'.format(build.commit), resp.content.decode())
|
||||
self.assertIn('Date: ', resp.content.decode())
|
||||
self.assertIn('State: building', resp.content.decode())
|
||||
self.assertIn('Success: Unknow', resp.content.decode())
|
||||
self.assertIn('[rtd-command-info]', resp.content.decode())
|
||||
self.assertIn(
|
||||
'python setup.py install\nInstalling dependencies...',
|
||||
resp.content.decode()
|
||||
)
|
||||
self.assertIn(
|
||||
'git checkout master\nSwitched to branch "master"',
|
||||
resp.content.decode()
|
||||
)
|
||||
|
||||
def test_get_raw_log_failure(self):
|
||||
build = get(
|
||||
Build, project_id=1, version_id=1,
|
||||
builder='foo', success=False, exit_code=1
|
||||
)
|
||||
get(
|
||||
BuildCommandResult,
|
||||
build=build,
|
||||
command='python setup.py install',
|
||||
output='Installing dependencies...',
|
||||
exit_code=1,
|
||||
)
|
||||
get(
|
||||
BuildCommandResult,
|
||||
build=build,
|
||||
command='git checkout master',
|
||||
output='Switched to branch "master"'
|
||||
)
|
||||
client = APIClient()
|
||||
|
||||
api_user = get(User, user='test', password='test')
|
||||
client.force_authenticate(user=api_user)
|
||||
resp = client.get('/api/v2/build/{0}.txt'.format(build.pk))
|
||||
self.assertEqual(resp.status_code, 200)
|
||||
|
||||
self.assertIn('Read the Docs build information', resp.content.decode())
|
||||
self.assertIn('Build id: {}'.format(build.id), resp.content.decode())
|
||||
self.assertIn('Project: {}'.format(build.project.slug), resp.content.decode())
|
||||
self.assertIn('Version: {}'.format(build.version.slug), resp.content.decode())
|
||||
self.assertIn('Commit: {}'.format(build.commit), resp.content.decode())
|
||||
self.assertIn('Date: ', resp.content.decode())
|
||||
self.assertIn('State: finished', resp.content.decode())
|
||||
self.assertIn('Success: False', resp.content.decode())
|
||||
self.assertIn('[rtd-command-info]', resp.content.decode())
|
||||
self.assertIn(
|
||||
'python setup.py install\nInstalling dependencies...',
|
||||
resp.content.decode()
|
||||
)
|
||||
self.assertIn(
|
||||
'git checkout master\nSwitched to branch "master"',
|
||||
resp.content.decode()
|
||||
)
|
||||
|
||||
def test_get_invalid_raw_log(self):
|
||||
client = APIClient()
|
||||
|
||||
api_user = get(User, user='test', password='test')
|
||||
client.force_authenticate(user=api_user)
|
||||
resp = client.get('/api/v2/build/{0}.txt'.format(404))
|
||||
self.assertEqual(resp.status_code, status.HTTP_404_NOT_FOUND)
|
||||
|
||||
|
||||
class APITests(TestCase):
|
||||
fixtures = ['eric.json', 'test_data.json']
|
||||
|
|
|
@ -61,6 +61,14 @@ $(document).ready(function () {
|
|||
</a>
|
||||
</li>
|
||||
</div>
|
||||
|
||||
<div data-bind="visible: finished()">
|
||||
<li>
|
||||
<a href="{% url "build-detail" build.pk "txt" %}">
|
||||
{% trans "View raw" %}
|
||||
</a>
|
||||
</li>
|
||||
</div>
|
||||
</ul>
|
||||
|
||||
<div class="build-id">
|
||||
|
|
Loading…
Reference in New Issue