Merge lp:~stevenk/launchpad/hide-related-blueprints into lp:launchpad

Proposed by Steve Kowalik
Status: Merged
Approved by: Steve Kowalik
Approved revision: no longer in the source branch.
Merged at revision: 16734
Proposed branch: lp:~stevenk/launchpad/hide-related-blueprints
Merge into: lp:launchpad
Diff against target: 263 lines (+44/-56)
2 files modified
lib/lp/bugs/browser/tests/test_bugtask.py (+43/-55)
lib/lp/bugs/templates/bug-portlet-specs.pt (+1/-1)
To merge this branch: bzr merge lp:~stevenk/launchpad/hide-related-blueprints
Reviewer Review Type Date Requested Status
William Grant code Approve
Review via email: mp+181198@code.launchpad.net

Commit message

Correctly show or hide the Related blueprints portlet for a bug.

Description of the change

Currently, the Related blueprints portlet for a bug is always shown even if the bug has no linked specs. The portlet code gets an ResultSet, which evaluates to True even though there are no results, so sort that out by using is_empty(). Also drive-by a bunch of whitespace cleanup to force this branch to be net-negative.

To post a comment you must log in.
Revision history for this message
William Grant (wgrant) :
review: Approve (code)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/lp/bugs/browser/tests/test_bugtask.py'
2--- lib/lp/bugs/browser/tests/test_bugtask.py 2013-07-26 14:58:20 +0000
3+++ lib/lp/bugs/browser/tests/test_bugtask.py 2013-08-21 05:20:32 +0000
4@@ -1,4 +1,4 @@
5-# Copyright 2009-2012 Canonical Ltd. This software is licensed under the
6+# Copyright 2009-2013 Canonical Ltd. This software is licensed under the
7 # GNU Affero General Public License version 3 (see the file LICENSE).
8
9 __metaclass__ = type
10@@ -211,9 +211,8 @@
11 self.getUserBrowser(url, owner) # This triggers the query recorder.
12 # Ideally this should be much fewer, but this tries to keep a win of
13 # removing more than half of these.
14- self.assertThat(recorder, HasQueryCount(
15- LessThan(count_with_no_branches + 46),
16- ))
17+ self.assertThat(
18+ recorder, HasQueryCount(LessThan(count_with_no_branches + 46)))
19
20 def test_interesting_activity(self):
21 # The interesting_activity property returns a tuple of interesting
22@@ -383,6 +382,24 @@
23 tag = soup.find('a', attrs={'id': "duplicate-of"})
24 self.assertIsNone(tag)
25
26+ def test_related_blueprints_is_hidden(self):
27+ # When a bug has no specifications linked, the Related blueprints
28+ # portlet is hidden.
29+ bug = self.factory.makeBug()
30+ browser = self.getUserBrowser(canonical_url(bug))
31+ self.assertNotIn('Related blueprints', browser.contents)
32+
33+ def test_related_blueprints_is_shown(self):
34+ # When a bug has specifications linked, the Related blueprints portlet
35+ # is shown.
36+ bug = self.factory.makeBug()
37+ spec = self.factory.makeSpecification(title='My brilliant spec')
38+ with person_logged_in(spec.owner):
39+ spec.linkBug(bug)
40+ browser = self.getUserBrowser(canonical_url(bug))
41+ self.assertIn('Related blueprints', browser.contents)
42+ self.assertIn('My brilliant spec', browser.contents)
43+
44
45 class TestBugTasksNominationsView(TestCaseWithFactory):
46
47@@ -392,25 +409,21 @@
48 super(TestBugTasksNominationsView, self).setUp()
49 login(ADMIN_EMAIL)
50 self.bug = self.factory.makeBug()
51- self.view = BugTasksNominationsView(
52- self.bug, LaunchpadTestRequest())
53+ self.view = BugTasksNominationsView(self.bug, LaunchpadTestRequest())
54
55 def refresh(self):
56 # The view caches, to see different scenarios, a refresh is needed.
57- self.view = BugTasksNominationsView(
58- self.bug, LaunchpadTestRequest())
59+ self.view = BugTasksNominationsView(self.bug, LaunchpadTestRequest())
60
61 def test_current_user_affected_status(self):
62 self.failUnlessEqual(
63 None, self.view.current_user_affected_status)
64 self.bug.markUserAffected(self.view.user, True)
65 self.refresh()
66- self.failUnlessEqual(
67- True, self.view.current_user_affected_status)
68+ self.assertTrue(self.view.current_user_affected_status)
69 self.bug.markUserAffected(self.view.user, False)
70 self.refresh()
71- self.failUnlessEqual(
72- False, self.view.current_user_affected_status)
73+ self.assertFalse(self.view.current_user_affected_status)
74
75 def test_current_user_affected_js_status(self):
76 self.failUnlessEqual(
77@@ -649,13 +662,11 @@
78 super(TestBugTasksTableView, self).setUp()
79 login(ADMIN_EMAIL)
80 self.bug = self.factory.makeBug()
81- self.view = BugTasksTableView(
82- self.bug, LaunchpadTestRequest())
83+ self.view = BugTasksTableView(self.bug, LaunchpadTestRequest())
84
85 def refresh(self):
86 # The view caches, to see different scenarios, a refresh is needed.
87- self.view = BugTasksNominationsView(
88- self.bug, LaunchpadTestRequest())
89+ self.view = BugTasksNominationsView(self.bug, LaunchpadTestRequest())
90
91 def test_not_many_bugtasks(self):
92 for count in range(10 - len(self.bug.bugtasks) - 1):
93@@ -680,28 +691,28 @@
94 target = self.factory.makeProduct()
95 bug_task = self.factory.makeBugTask(bug=self.bug, target=target)
96 self.view.initialize()
97- self.assertEqual(None, self.view.getTargetLinkTitle(bug_task.target))
98+ self.assertIs(None, self.view.getTargetLinkTitle(bug_task.target))
99
100 def test_getTargetLinkTitle_productseries(self):
101 # The target link title is always none for productseries.
102 target = self.factory.makeProductSeries()
103 bug_task = self.factory.makeBugTask(bug=self.bug, target=target)
104 self.view.initialize()
105- self.assertEqual(None, self.view.getTargetLinkTitle(bug_task.target))
106+ self.assertIs(None, self.view.getTargetLinkTitle(bug_task.target))
107
108 def test_getTargetLinkTitle_distribution(self):
109 # The target link title is always none for distributions.
110 target = self.factory.makeDistribution()
111 bug_task = self.factory.makeBugTask(bug=self.bug, target=target)
112 self.view.initialize()
113- self.assertEqual(None, self.view.getTargetLinkTitle(bug_task.target))
114+ self.assertIs(None, self.view.getTargetLinkTitle(bug_task.target))
115
116 def test_getTargetLinkTitle_distroseries(self):
117 # The target link title is always none for distroseries.
118 target = self.factory.makeDistroSeries()
119 bug_task = self.factory.makeBugTask(bug=self.bug, target=target)
120 self.view.initialize()
121- self.assertEqual(None, self.view.getTargetLinkTitle(bug_task.target))
122+ self.assertIs(None, self.view.getTargetLinkTitle(bug_task.target))
123
124 def test_getTargetLinkTitle_unpublished_distributionsourcepackage(self):
125 # The target link title states that the package is not published
126@@ -999,12 +1010,8 @@
127 bugtask_url = canonical_url(bugtask, rootsite='bugs')
128 target_name = bugtask.bugtargetdisplayname
129 login_person(bugtask.owner)
130- form = {
131- 'field.actions.delete_bugtask': 'Delete',
132- }
133- extra = {
134- 'HTTP_REFERER': bugtask_url,
135- }
136+ form = {'field.actions.delete_bugtask': 'Delete'}
137+ extra = {'HTTP_REFERER': bugtask_url}
138 server_url = canonical_url(
139 getUtility(ILaunchpadRoot), rootsite='bugs')
140 view = create_initialized_view(
141@@ -1020,9 +1027,7 @@
142 # Test that the deleting the only bugtask results in an error message.
143 bug = self.factory.makeBug()
144 login_person(bug.owner)
145- form = {
146- 'field.actions.delete_bugtask': 'Delete',
147- }
148+ form = {'field.actions.delete_bugtask': 'Delete'}
149 view = create_initialized_view(
150 bug.default_bugtask, name='+delete', form=form,
151 principal=bug.owner)
152@@ -1054,9 +1059,7 @@
153 'HTTP_X_REQUESTED_WITH': 'XMLHttpRequest',
154 'HTTP_REFERER': bugtask_url,
155 }
156- form = {
157- 'field.actions.delete_bugtask': 'Delete',
158- }
159+ form = {'field.actions.delete_bugtask': 'Delete'}
160 view = create_initialized_view(
161 bugtask, name='+delete', server_url=server_url, form=form,
162 principal=bugtask.owner, **extra)
163@@ -1082,12 +1085,8 @@
164 # from the URL of the bugtask we are deleting.
165 server_url = canonical_url(
166 getUtility(ILaunchpadRoot), rootsite='bugs')
167- extra = {
168- 'HTTP_X_REQUESTED_WITH': 'XMLHttpRequest',
169- }
170- form = {
171- 'field.actions.delete_bugtask': 'Delete',
172- }
173+ extra = {'HTTP_X_REQUESTED_WITH': 'XMLHttpRequest'}
174+ form = {'field.actions.delete_bugtask': 'Delete'}
175 view = create_initialized_view(
176 bug.default_bugtask, name='+delete', server_url=server_url,
177 form=form, principal=bug.owner, **extra)
178@@ -1121,9 +1120,7 @@
179 'HTTP_X_REQUESTED_WITH': 'XMLHttpRequest',
180 'HTTP_REFERER': default_bugtask_url,
181 }
182- form = {
183- 'field.actions.delete_bugtask': 'Delete',
184- }
185+ form = {'field.actions.delete_bugtask': 'Delete'}
186 view = create_initialized_view(
187 bugtask, name='+delete', server_url=server_url, form=form,
188 principal=bugtask.owner, **extra)
189@@ -1516,9 +1513,7 @@
190
191 def test_mustache_cache_is_none_for_advanced_form(self):
192 """No mustache model for the advanced search form."""
193- form = {
194- 'advanced': 1,
195- }
196+ form = {'advanced': 1}
197 view = create_initialized_view(
198 self.target, name=u'+bugs', rootsite='bugs', form=form)
199 cache = IJSONRequestCache(view.request)
200@@ -1686,8 +1681,7 @@
201 # bug portlets.
202 self.makeSubordinateProduct(False)
203 view = create_initialized_view(
204- self.target, name=u'+bugs', rootsite='bugs',
205- current_request=True)
206+ self.target, name=u'+bugs', rootsite='bugs', current_request=True)
207 self.assertFalse(view.should_show_bug_information)
208 contents = view.render()
209 report_a_bug = find_tag_by_id(contents, 'bug-portlets')
210@@ -1698,8 +1692,7 @@
211 # portlets.
212 self.makeSubordinateProduct(True)
213 view = create_initialized_view(
214- self.target, name=u'+bugs', rootsite='bugs',
215- current_request=True)
216+ self.target, name=u'+bugs', rootsite='bugs', current_request=True)
217 self.assertTrue(view.should_show_bug_information)
218 contents = view.render()
219 report_a_bug = find_tag_by_id(contents, 'bug-portlets')
220@@ -1710,8 +1703,7 @@
221 # a 'Getting started' help link.
222 self.makeSubordinateProduct(False)
223 view = create_initialized_view(
224- self.target, name=u'+bugs', rootsite='bugs',
225- current_request=True)
226+ self.target, name=u'+bugs', rootsite='bugs', current_request=True)
227 contents = view.render()
228 help_link = find_tag_by_id(contents, 'getting-started-help')
229 self.assertIsNot(None, help_link)
230@@ -1721,8 +1713,7 @@
231 # a 'Getting started' help link.
232 self.makeSubordinateProduct(True)
233 view = create_initialized_view(
234- self.target, name=u'+bugs', rootsite='bugs',
235- current_request=True)
236+ self.target, name=u'+bugs', rootsite='bugs', current_request=True)
237 contents = view.render()
238 help_link = find_tag_by_id(contents, 'getting-started-help')
239 self.assertIs(None, help_link)
240@@ -2017,10 +2008,7 @@
241
242 def invalidate_caches(self, obj):
243 store = Store.of(obj)
244- # Make sure everything is in the database.
245 store.flush()
246- # And invalidate the cache (not a reset, because that stops us using
247- # the domain objects)
248 store.invalidate()
249
250 def test_rendered_query_counts_constant_with_many_bugtasks(self):
251
252=== modified file 'lib/lp/bugs/templates/bug-portlet-specs.pt'
253--- lib/lp/bugs/templates/bug-portlet-specs.pt 2013-02-21 05:43:21 +0000
254+++ lib/lp/bugs/templates/bug-portlet-specs.pt 2013-08-21 05:20:32 +0000
255@@ -3,7 +3,7 @@
256 xmlns:metal="http://xml.zope.org/namespaces/metal"
257 xmlns:i18n="http://xml.zope.org/namespaces/i18n"
258 class="portlet vertical" id="portlet-blueprints"
259- tal:condition="view/specifications">
260+ tal:condition="not:view/specifications/is_empty">
261 <h2>Related blueprints</h2>
262 <ul>
263 <li tal:repeat="spec view/specifications"