Merge lp:~salgado/offspring/builder-list into lp:~linaro-automation/offspring/private-builds

Proposed by Guilherme Salgado
Status: Merged
Approved by: James Tunnicliffe
Approved revision: 67
Merged at revision: 63
Proposed branch: lp:~salgado/offspring/builder-list
Merge into: lp:~linaro-automation/offspring/private-builds
Diff against target: 223 lines (+91/-32)
5 files modified
lib/offspring/web/queuemanager/tests/test_views.py (+48/-0)
lib/offspring/web/queuemanager/views.py (+30/-10)
lib/offspring/web/templates/queuemanager/builders.html (+9/-5)
lib/offspring/web/urls.py (+2/-16)
requirements/requirements.web.txt (+2/-1)
To merge this branch: bzr merge lp:~salgado/offspring/builder-list
Reviewer Review Type Date Requested Status
James Tunnicliffe (community) Approve
Review via email: mp+79709@code.launchpad.net

Description of the change

This branch changes the builder list to redact information about private projects the user doesn't have the rights to see.

I've also noticed that no versions of django are able to work with Oneiric's psycopg2 package (version 2.4.2), so I've changed the requirements to specify we need psycopg2>=2.0.6,<=2.4.1. (I've created a new WI to get the new dependencies added to lp:~oem-solutions-releng/offspring/offspring-deps/)

To post a comment you must log in.
lp:~salgado/offspring/builder-list updated
67. By Guilherme Salgado

Stub Lexbuilder.average_load on BuilderListTests so that we can run the tests there with sqlite3

Revision history for this message
James Tunnicliffe (dooferlad) wrote :

Looks fine.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/offspring/web/queuemanager/tests/test_views.py'
2--- lib/offspring/web/queuemanager/tests/test_views.py 2011-10-10 21:15:48 +0000
3+++ lib/offspring/web/queuemanager/tests/test_views.py 2011-10-18 15:56:27 +0000
4@@ -9,6 +9,7 @@
5
6 from offspring.enums import ProjectBuildStates
7 from offspring.web.queuemanager.models import (
8+ Lexbuilder,
9 Project,
10 )
11 from offspring.web.queuemanager.views import get_possibly_private_object
12@@ -104,6 +105,53 @@
13 status_code=200, msg_prefix=response.content)
14
15
16+class BuilderListTests(TestCase):
17+ view_name = 'offspring.web.queuemanager.views.builders'
18+
19+ def setUp(self):
20+ super(BuilderListTests, self).setUp()
21+ # Stub Lexbuilder.average_load because it executes some SQL that's not
22+ # supported by sqlite3 and we're not interested in testing it here.
23+ self.orig_load_average = Lexbuilder.average_load
24+ def average_load(obj):
25+ return '10'
26+ Lexbuilder.average_load = property(average_load)
27+
28+ def tearDown(self):
29+ super(BuilderListTests, self).tearDown()
30+ Lexbuilder.average_load = self.orig_load_average
31+
32+ def test_build_details_always_shown_when_building_public_project(self):
33+ builder = factory.makeLexbuilder()
34+ make_user_and_login(self.client)
35+ response = self.client.get(reverse(self.view_name))
36+ self.assertContains(
37+ response, builder.current_job.project.name, status_code=200,
38+ msg_prefix=response.content)
39+
40+ def test_private_build_details_shown_if_user_is_allowed_to_see_it(self):
41+ project = factory.makeProject(is_private=True)
42+ job = factory.makeBuildResult(project=project)
43+ builder = factory.makeLexbuilder(current_job=job)
44+ user = project.owner
45+ self.assertTrue(
46+ self.client.login(username=user.username, password=user.username))
47+ response = self.client.get(reverse(self.view_name))
48+ self.assertContains(
49+ response, builder.current_job.project.name, status_code=200,
50+ msg_prefix=response.content)
51+
52+ def test_private_build_details_not_shown_if_user_not_allowed_to_see(self):
53+ project = factory.makeProject(is_private=True)
54+ job = factory.makeBuildResult(project=project)
55+ builder = factory.makeLexbuilder(current_job=job)
56+ make_user_and_login(self.client)
57+ response = self.client.get(reverse(self.view_name))
58+ self.assertNotContains(
59+ response, builder.current_job.project.name, status_code=200,
60+ msg_prefix=response.content)
61+
62+
63 class BuildViewTests(TestCase):
64
65 def test_public_build(self):
66
67=== modified file 'lib/offspring/web/queuemanager/views.py'
68--- lib/offspring/web/queuemanager/views.py 2011-10-13 22:59:59 +0000
69+++ lib/offspring/web/queuemanager/views.py 2011-10-18 15:56:27 +0000
70@@ -34,10 +34,6 @@
71 create_object,
72 update_object
73 )
74-from django.views.generic.list_detail import (
75- object_list,
76- object_detail
77-)
78
79 from pygooglechart import PieChart3D
80
81@@ -56,6 +52,7 @@
82 BuildRequest,
83 BuildResult,
84 LaunchpadProjectMilestone,
85+ Lexbuilder,
86 Project,
87 ProjectGroup,
88 Release
89@@ -78,14 +75,37 @@
90 #TODO: Thanks to reduced duplication, lets start using more generic views.
91
92 @login_required
93-def secure_object_list(request, **page_info):
94- '''Wrap object_list in login_required decorator.'''
95- return object_list(request, **page_info)
96+def builders(request):
97+ # builder_list is a dictionary where keys are Lexbuilder instances to be
98+ # shown and the values represent whether or not the information about the
99+ # builder's current job should be shown to the current user.
100+ builder_list = {}
101+ builders = Lexbuilder.all_objects.order_by(
102+ "-is_active", "-machine_type", "-created_at")
103+ for builder in builders:
104+ job = builder.current_job
105+ if job is not None and job.is_visible_to(request.user):
106+ builder_list[builder] = True
107+ else:
108+ builder_list[builder] = False
109+ pageData = {
110+ 'pillar': 'builders',
111+ 'builder_list': builder_list,
112+ }
113+ return render_to_response(
114+ 'queuemanager/builders.html', pageData,
115+ context_instance=RequestContext(request))
116
117 @login_required
118-def secure_object_detail(request, **page_info):
119- '''Wrap object_detail in login_required decorator.'''
120- return object_detail(request, **page_info)
121+def builder_details(request, builderName):
122+ builder = Lexbuilder.objects.get(name=builderName)
123+ pageData = {
124+ 'builder': builder,
125+ 'pillar': 'builders',
126+ }
127+ return render_to_response(
128+ 'queuemanager/builder_details.html', pageData,
129+ context_instance=RequestContext(request))
130
131 def projects(request):
132 projects = Project.objects.select_related('project_group').order_by("project_group")
133
134=== modified file 'lib/offspring/web/templates/queuemanager/builders.html'
135--- lib/offspring/web/templates/queuemanager/builders.html 2011-01-22 05:41:23 +0000
136+++ lib/offspring/web/templates/queuemanager/builders.html 2011-10-18 15:56:27 +0000
137@@ -10,10 +10,10 @@
138 <tr>
139 <td width="10%"><h3>Builder</h3></td><td width="50px" align="center"><h3>Active</h3></td><td width="50px" align="center"><h3 title="If the master is unable to contact a slave, the slave is unhealthy">Health</h3></td><td align="center"><h3>Type</h3></td><td align="center"><h3>State</h3></td><td align="center" width="20%"><h3>Current Build</h3></td><td align="center" width="20%"><h3>Last Scan</h3></td><td align="right"><h3 title="The average number of hours spent each day building projects">Load</h3></td>
140 </tr>
141- {% for builder in builder_list %}
142+ {% for builder, build_visible in builder_list.items %}
143 <tr height="20px">
144 <td>
145- <a class="{% if builder.is_active %}{% if builder.is_okay %}{% ifequal builder.current_state "BUILDING" %}busy{% else %}online{% endifequal %}{% else %}problem{% endif %}{% else %}offline{% endif %}" href="{% url builder_details builder %}">{{builder.name}}</a>
146+ <a class="{% if builder.is_active %}{% if builder.is_okay %}{% ifequal builder.current_state "BUILDING" %}busy{% else %}online{% endifequal %}{% else %}problem{% endif %}{% else %}offline{% endif %}" href="{% url builder_details builder.name %}">{{builder.name}}</a>
147 </td>
148 <td align="center">
149 <a style="margin-left: 10px;">{% if builder.is_active %}<img src="/assets/images/10.png" title="Builder Active"/>{% else %}<img src="/assets/images/12.png" title="Builder Deactivated"/>{% endif %}</a>
150@@ -28,9 +28,13 @@
151 <span title="{{builder.name}} is currently {{builder.current_state}}{% ifequal builder.current_state "BUILDING" %}, estimated completion {{builder.estimated_completion}}{% endifequal %}">{{builder.current_state}}</span>
152 </td>
153 <td align="center">
154- {% if builder.current_build_projectname %}
155- <a href="{% url offspring.web.queuemanager.views.project_details builder.current_build_projectname %}">{{builder.current_build_projectname}}</a> (<a href="{{builder.current_build_projectname|link_results:builder.current_build_buildname}}">{{builder.current_build_buildname}}</a>)
156- {% endif %}
157+ {% if not build_visible %}
158+ <span>Private build</span>
159+ {% else %}
160+ {% if builder.current_build_projectname %}
161+ <a href="{% url offspring.web.queuemanager.views.project_details builder.current_build_projectname %}">{{builder.current_build_projectname}}</a> (<a href="{{builder.current_build_projectname|link_results:builder.current_build_buildname}}">{{builder.current_build_buildname}}</a>)
162+ {% endif %}
163+ {% endif %}
164 </td>
165 <td>
166 <span title="This field indicates the last time the master made contact with the slave.">
167
168=== modified file 'lib/offspring/web/urls.py'
169--- lib/offspring/web/urls.py 2011-10-10 14:12:28 +0000
170+++ lib/offspring/web/urls.py 2011-10-18 15:56:27 +0000
171@@ -17,7 +17,6 @@
172 from piston.resource import Resource
173
174 import offspring.web
175-from offspring.web.queuemanager.models import Lexbuilder
176 from offspring.web.queuemanager.handlers import (
177 BuildManifestHandler,
178 BuildManifestComparisonHandler,
179@@ -31,8 +30,6 @@
180 project_acl,
181 project_create,
182 project_edit,
183- secure_object_list,
184- secure_object_detail
185 )
186
187 admin.autodiscover()
188@@ -58,19 +55,8 @@
189 (r'^admin/', include(admin.site.urls)),
190 (r'^openid/', include('django_openid_auth.urls')),
191 (r'^logout/', 'django.contrib.auth.views.logout'),
192- (r'^builders/$', secure_object_list, {
193- 'queryset' : Lexbuilder.objects.order_by("-is_active", "-machine_type", "-created_at"),
194- 'template_name' : 'queuemanager/builders.html',
195- 'template_object_name' : 'builder',
196- 'extra_context' : { 'pillar' : 'builders', },
197- }, 'builders_list'),
198- (r'^builders/(?P<slug>[^/]+)/$', secure_object_detail, {
199- 'queryset' : Lexbuilder.objects.all(),
200- 'slug_field' : 'name',
201- 'template_name' : 'queuemanager/builder_details.html',
202- 'template_object_name' : 'builder',
203- 'extra_context' : { 'pillar' : 'builders', },
204- }, 'builder_details'),
205+ url(r'^builders/$', 'offspring.web.queuemanager.views.builders', name='builder_list'),
206+ url(r'^builders/(?P<builderName>[^/]+)/$', 'offspring.web.queuemanager.views.builder_details', name='builder_details'),
207 (r'^builders/\+api/(?P<builderName>[^/]+)/builds/$', buildresult_handler),
208 (r'^builds/\+api/$', buildresult_handler),
209 (r'^builds/\+api/(?P<projectName>[^/]+)/$', buildresult_handler),
210
211=== modified file 'requirements/requirements.web.txt'
212--- requirements/requirements.web.txt 2011-09-22 14:15:21 +0000
213+++ requirements/requirements.web.txt 2011-10-18 15:56:27 +0000
214@@ -6,7 +6,8 @@
215 launchpadlib==1.6.4
216 oauth==1.0.1
217 python-openid>=2.2.4
218-psycopg2>=2.0.6
219+# Need <=2.4.1 because of https://code.djangoproject.com/ticket/16250
220+psycopg2>=2.0.6,<=2.4.1
221 pygooglechart>=0.2.1
222 celery>=2.3.1
223 django-celery>=2.3.0

Subscribers

People subscribed via source and target branches