Merge lp:~deryck/launchpad/milestone-portlet-links-385719 into lp:launchpad

Proposed by Deryck Hodge
Status: Merged
Approved by: Barry Warsaw
Approved revision: no longer in the source branch.
Merged at revision: not available
Proposed branch: lp:~deryck/launchpad/milestone-portlet-links-385719
Merge into: lp:launchpad
Diff against target: None lines
To merge this branch: bzr merge lp:~deryck/launchpad/milestone-portlet-links-385719
Reviewer Review Type Date Requested Status
Brad Crittenden (community) release-critical Approve
Barry Warsaw (community) code ui* Approve
Review via email: mp+12092@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Deryck Hodge (deryck) wrote :

= Summary =

Bug #385719 notes that it's not possible to get to a milestone bug
listing from the bugs home page for a project (or distro either). This
branch adds a milestone-targeted bugs portlet to a bugs home page for a
distro or project, as well as for series bug pages.

= Implementation =

This code pretty much copies the work that creates the series-targeted
bugs portlet. I did change the view class slightly to break out the
bits that get a list of series, since the function for getting
milestones also needs this series list.

I added a page test to cover the new functionality.

== Tests ==

./bin/test -vv -t xx-portlets-bug-milestones.txt

== Demo and Q/A ==

To demo, use the dev server and hit:
https://bugs.launchpad.dev/debian/+bugs

There should be a portlet for the milestone links there.

To QA, visit any project bugs home that use milestones and verify there
is a portlet on the bugs home. https://bugs.launchpad.net/malone/
should have a milestone portlet linking the 3.0 and 2.2.8 milestones.

= Launchpad lint =

Checking for conflicts. and issues in doctests and templates.
Running jslint, xmllint, pyflakes, and pylint.
Using normal rules.

Linting changed files:
  lib/lp/bugs/templates/bugtask-portlet-milestonebugs.pt
  lib/lp/bugs/browser/bugtarget.py
  lib/lp/bugs/stories/bugs/xx-portlets-bug-milestones.txt
  lib/lp/bugs/browser/configure.zcml
  lib/lp/bugs/templates/buglisting-default.pt
  lib/lp/bugs/templates/bugtarget-bugs.pt

Revision history for this message
Barry Warsaw (barry) wrote :
Download full text (4.6 KiB)

On Sep 18, 2009, at 07:30 PM, Deryck Hodge wrote:

>Deryck Hodge has proposed merging lp:~deryck/launchpad/milestone-portlet-links-385719 into lp:launchpad/devel.
>
>Requested reviews:
> Canonical Launchpad Engineering (launchpad)
>
>= Summary =
>
>Bug #385719 notes that it's not possible to get to a milestone bug
>listing from the bugs home page for a project (or distro either). This
>branch adds a milestone-targeted bugs portlet to a bugs home page for a
>distro or project, as well as for series bug pages.

Nice. I often that with LP2.0 it's very difficult to get to a milestone
without url hacking. So making more links to milestones always makes me
happy. This is a nice branch, and thanks for working on it.

I have only minor style issues with the code, but they should be easy to fix,
so merge-conditional, r=me with their consideration.

 review approve code ui*
 status approve

=== modified file 'lib/lp/bugs/browser/bugtarget.py'
--- lib/lp/bugs/browser/bugtarget.py 2009-09-10 12:47:31 +0000
+++ lib/lp/bugs/browser/bugtarget.py 2009-09-18 19:01:31 +0000
> @@ -1142,11 +1136,20 @@
> elif IProductSeries(self.context, None):
> serieses = self.context.product.serieses
> else:
> - raise AssertionError, ("series_bug_counts called with "
> - "illegal context")
> -
> + raise AssertionError, ("series_list called with illegal context")

Better to spell that:

            raise AssertionError('series_list called with illegal context')

IOW, better to instantiate exceptions explicitly than to let Python do it
implicitly.

> + return serieses

"serieses" - waauugghh! ;)

> +
> + @property
> + def series_buglistings(self):
> + """Return a buglisting for each series.
> +
> + The list is sorted newest series to oldest.
> +
> + The count only considers bugs that the user would actually be
> + able to see in a listing.
> + """
> series_buglistings = []
> - for series in serieses:
> + for series in self.series_list:
> series_bug_count = series.open_bugtasks.count()
> if series_bug_count > 0:
> series_buglistings.append(
> @@ -1157,6 +1160,21 @@
>
> return series_buglistings
>
> + @property
> + def milestone_buglistings(self):
> + """Return a buglisting for each milestone."""
> + milestone_buglistings = []
> + for series in self.series_list:
> + for milestone in series.milestones:
> + milestone_bug_count = milestone.open_bugtasks.count()
> + if milestone_bug_count > 0:
> + milestone_buglistings.append(
> + dict(
> + title=milestone.name,
> + url=canonical_url(milestone),
> + count=milestone_bug_count))

That last line should be
                            count=milestone_bug_count,
                            ))

=== added file 'lib/lp/bugs/stories/bugs/xx-portlets-bug-milestones.txt'
--- lib/lp/bugs/stories/bugs/xx-portlets-bug-milestones.txt 1970-01-01 0...

Read more...

review: Approve (code ui*)
Revision history for this message
Brad Crittenden (bac) wrote :

Deryck,

Thanks for the fix. I note the visual confusion caused by the portlet counts not being aligned. Let's remember to fix that soon but not now. Please open a bug.

review: Approve (release-critical)
Revision history for this message
Deryck Hodge (deryck) wrote :

Bug #434781 is tracking the mis-alignment of numbers in the portlets.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/lp/bugs/browser/bugtarget.py'
2--- lib/lp/bugs/browser/bugtarget.py 2009-09-10 12:47:31 +0000
3+++ lib/lp/bugs/browser/bugtarget.py 2009-09-18 19:01:31 +0000
4@@ -279,7 +279,8 @@
5 # The user is trying to file a new Ubuntu bug via the web
6 # interface and without using apport. Redirect to a page
7 # explaining the preferred bug-filing procedure.
8- self.request.response.redirect(config.malone.ubuntu_bug_filing_url)
9+ self.request.response.redirect(
10+ config.malone.ubuntu_bug_filing_url)
11 if self.extra_data_token is not None:
12 # self.extra_data has been initialized in publishTraverse().
13 if self.extra_data.initial_summary:
14@@ -1125,14 +1126,7 @@
15 """Helper methods for rendering bug listings."""
16
17 @property
18- def series_buglistings(self):
19- """Return a buglisting for each series.
20-
21- The list is sorted newest series to oldest.
22-
23- The count only considers bugs that the user would actually be
24- able to see in a listing.
25- """
26+ def series_list(self):
27 if IDistribution(self.context, None):
28 serieses = self.context.serieses
29 elif IProduct(self.context, None):
30@@ -1142,11 +1136,20 @@
31 elif IProductSeries(self.context, None):
32 serieses = self.context.product.serieses
33 else:
34- raise AssertionError, ("series_bug_counts called with "
35- "illegal context")
36-
37+ raise AssertionError, ("series_list called with illegal context")
38+ return serieses
39+
40+ @property
41+ def series_buglistings(self):
42+ """Return a buglisting for each series.
43+
44+ The list is sorted newest series to oldest.
45+
46+ The count only considers bugs that the user would actually be
47+ able to see in a listing.
48+ """
49 series_buglistings = []
50- for series in serieses:
51+ for series in self.series_list:
52 series_bug_count = series.open_bugtasks.count()
53 if series_bug_count > 0:
54 series_buglistings.append(
55@@ -1157,6 +1160,21 @@
56
57 return series_buglistings
58
59+ @property
60+ def milestone_buglistings(self):
61+ """Return a buglisting for each milestone."""
62+ milestone_buglistings = []
63+ for series in self.series_list:
64+ for milestone in series.milestones:
65+ milestone_bug_count = milestone.open_bugtasks.count()
66+ if milestone_bug_count > 0:
67+ milestone_buglistings.append(
68+ dict(
69+ title=milestone.name,
70+ url=canonical_url(milestone),
71+ count=milestone_bug_count))
72+ return milestone_buglistings
73+
74
75 class BugCountDataItem:
76 """Data about bug count for a status."""
77
78=== modified file 'lib/lp/bugs/browser/configure.zcml'
79--- lib/lp/bugs/browser/configure.zcml 2009-09-14 12:19:55 +0000
80+++ lib/lp/bugs/browser/configure.zcml 2009-09-18 18:45:18 +0000
81@@ -342,6 +342,13 @@
82 template="../templates/bugtask-portlet-seriesbugs.pt"/>
83 <browser:page
84 for="lp.registry.interfaces.distroseries.IDistroSeries"
85+ class="lp.bugs.browser.bugtarget.BugTargetBugListingView"
86+ facet="bugs"
87+ permission="zope.Public"
88+ name="+portlet-bugtasklist-milestonebugs"
89+ template="../templates/bugtask-portlet-milestonebugs.pt"/>
90+ <browser:page
91+ for="lp.registry.interfaces.distroseries.IDistroSeries"
92 name="+nominations"
93 class="lp.bugs.browser.bugtask.BugNominationsView"
94 permission="zope.Public"
95@@ -369,6 +376,13 @@
96 name="+portlet-bugtasklist-seriesbugs"
97 template="../templates/bugtask-portlet-seriesbugs.pt"/>
98 <browser:page
99+ for="lp.registry.interfaces.product.IProduct"
100+ class="lp.bugs.browser.bugtarget.BugTargetBugListingView"
101+ facet="bugs"
102+ permission="zope.Public"
103+ name="+portlet-bugtasklist-milestonebugs"
104+ template="../templates/bugtask-portlet-milestonebugs.pt"/>
105+ <browser:page
106 for="lp.registry.interfaces.distribution.IDistribution"
107 class="lp.bugs.browser.bugtarget.BugTargetBugListingView"
108 facet="bugs"
109@@ -376,6 +390,13 @@
110 name="+portlet-bugtasklist-seriesbugs"
111 template="../templates/bugtask-portlet-seriesbugs.pt"/>
112 <browser:page
113+ for="lp.registry.interfaces.distribution.IDistribution"
114+ class="lp.bugs.browser.bugtarget.BugTargetBugListingView"
115+ facet="bugs"
116+ permission="zope.Public"
117+ name="+portlet-bugtasklist-milestonebugs"
118+ template="../templates/bugtask-portlet-milestonebugs.pt"/>
119+ <browser:page
120 name="+filebug"
121 for="lp.registry.interfaces.project.IProject"
122 class="lp.bugs.browser.bugtarget.ProjectFileBugGuidedView"
123@@ -408,6 +429,13 @@
124 template="../templates/bugtask-portlet-seriesbugs.pt"/>
125 <browser:page
126 for="lp.registry.interfaces.productseries.IProductSeries"
127+ class="lp.bugs.browser.bugtarget.BugTargetBugListingView"
128+ facet="bugs"
129+ permission="zope.Public"
130+ name="+portlet-bugtasklist-milestonebugs"
131+ template="../templates/bugtask-portlet-milestonebugs.pt"/>
132+ <browser:page
133+ for="lp.registry.interfaces.productseries.IProductSeries"
134 name="+nominations"
135 class="lp.bugs.browser.bugtask.BugNominationsView"
136 permission="zope.Public"
137
138=== added file 'lib/lp/bugs/stories/bugs/xx-portlets-bug-milestones.txt'
139--- lib/lp/bugs/stories/bugs/xx-portlets-bug-milestones.txt 1970-01-01 00:00:00 +0000
140+++ lib/lp/bugs/stories/bugs/xx-portlets-bug-milestones.txt 2009-09-18 18:41:39 +0000
141@@ -0,0 +1,76 @@
142+Milestone-targeted bugs portlet
143+===============================
144+
145+The milestone-targeted bugs portlet displays the number of bugs that have
146+been targeted to a specific milestone.
147+
148+This portlet is available from a distribution's bug page.
149+
150+ >>> anon_browser.open("http://bugs.launchpad.dev/debian/+bugs")
151+ >>> portlet = find_portlet(
152+ ... anon_browser.contents, "Milestone-targeted bugs")
153+ >>> print extract_text(portlet)
154+ Milestone-targeted bugs
155+ 3.1 1
156+
157+It is also available from the bug page for a series in the distribution.
158+
159+ >>> anon_browser.open("http://bugs.launchpad.dev/debian/sarge/+bugs")
160+ >>> portlet = find_portlet(
161+ ... anon_browser.contents, "Milestone-targeted bugs")
162+ >>> print extract_text(portlet)
163+ Milestone-targeted bugs
164+ 3.1 1
165+
166+The portlet is also available from a project's bugs home page. To demonstrate
167+this, a project has to first have one of its milestones associated with a bug.
168+If there are no milestones with bugs, then there is no milestone-targeted
169+portlet.
170+
171+ >>> anon_browser.open("http://bugs.launchpad.dev/firefox")
172+ >>> portlet = find_portlet(
173+ ... anon_browser.contents, "Milestone-targeted bugs")
174+ >>> portlet is None
175+ True
176+
177+To enable the portlet, a bugtask needs to have a milestone associated with it.
178+Bug 4 has a Firefox bugtask, which can be used once a milestone is selected.
179+
180+ >>> login('test@canonical.com')
181+ >>> from zope.component import getUtility
182+ >>> from lp.bugs.interfaces.bugtask import IBugTaskSet
183+ >>> ff_bugtask = getUtility(IBugTaskSet).get(13)
184+ >>> print ff_bugtask.bug.id
185+ 4
186+
187+ >>> from lp.registry.interfaces.product import IProductSet
188+ >>> from lp.registry.interfaces.milestone import IMilestoneSet
189+ >>> firefox = getUtility(IProductSet).getByName('firefox')
190+ >>> ff_milestone = getUtility(IMilestoneSet).getByNameAndProduct(
191+ ... "1.0", firefox)
192+ >>> print ff_milestone.name
193+ 1.0
194+
195+The bugtask milestone is set to the Firefox 1.0 milestone.
196+
197+ >>> ff_bugtask.milestone = ff_milestone.id
198+ >>> logout()
199+
200+Now Firefox has a milestone-targeted bugs portlet on the project's bugs home
201+page.
202+
203+ >>> anon_browser.open("http://bugs.launchpad.dev/firefox")
204+ >>> portlet = find_portlet(
205+ ... anon_browser.contents, "Milestone-targeted bugs")
206+ >>> print extract_text(portlet)
207+ Milestone-targeted bugs
208+ 1.0 1
209+
210+The portlet will also appear on a project's series bug page.
211+
212+ >>> anon_browser.open("http://launchpad.dev/firefox/trunk/+bugs")
213+ >>> portlet = find_portlet(
214+ ... anon_browser.contents, "Milestone-targeted bugs")
215+ >>> print extract_text(portlet)
216+ Milestone-targeted bugs
217+ 1.0 1
218
219=== modified file 'lib/lp/bugs/templates/buglisting-default.pt'
220--- lib/lp/bugs/templates/buglisting-default.pt 2009-09-11 16:33:22 +0000
221+++ lib/lp/bugs/templates/buglisting-default.pt 2009-09-16 17:05:13 +0000
222@@ -62,6 +62,9 @@
223 <tal:releasecriticalbugs
224 tal:condition="view/shouldShowReleaseCriticalPortlet"
225 tal:content="structure context/@@+portlet-bugtasklist-seriesbugs" />
226+ <tal:milestonecriticalbugs
227+ tal:condition="view/shouldShowReleaseCriticalPortlet"
228+ tal:content="structure context/@@+portlet-bugtasklist-milestonebugs" />
229 </tal:do_not_show_portlets_advanced_form>
230 </tal:side>
231 </body>
232
233=== modified file 'lib/lp/bugs/templates/bugtarget-bugs.pt'
234--- lib/lp/bugs/templates/bugtarget-bugs.pt 2009-07-18 00:05:49 +0000
235+++ lib/lp/bugs/templates/bugtarget-bugs.pt 2009-09-16 17:05:13 +0000
236@@ -19,6 +19,9 @@
237 <tal:releasecriticalbugs
238 tal:condition="view/shouldShowReleaseCriticalPortlet"
239 tal:content="structure context/@@+portlet-bugtasklist-seriesbugs" />
240+ <tal:milestonecriticalbugs
241+ tal:condition="view/shouldShowReleaseCriticalPortlet"
242+ tal:content="structure context/@@+portlet-bugtasklist-milestonebugs" />
243 </metal:portlets>
244 <body>
245 <div metal:fill-slot="main" class="tab-bugs"
246
247=== added file 'lib/lp/bugs/templates/bugtask-portlet-milestonebugs.pt'
248--- lib/lp/bugs/templates/bugtask-portlet-milestonebugs.pt 1970-01-01 00:00:00 +0000
249+++ lib/lp/bugs/templates/bugtask-portlet-milestonebugs.pt 2009-09-16 17:05:13 +0000
250@@ -0,0 +1,24 @@
251+<div
252+ xmlns:tal="http://xml.zope.org/namespaces/tal"
253+ xmlns:metal="http://xml.zope.org/namespaces/metal"
254+ xmlns:i18n="http://xml.zope.org/namespaces/i18n"
255+ class="portlet" id="portlet-milestone-critical-bugs"
256+ tal:define="milestone_buglistings view/milestone_buglistings"
257+ tal:condition="milestone_buglistings">
258+
259+ <h2>Milestone-targeted bugs</h2>
260+
261+ <div class="portletBody">
262+ <table width="100%">
263+ <tr tal:repeat="milestone_openbugs milestone_buglistings">
264+ <td>
265+ <a href=""
266+ tal:content="milestone_openbugs/title"
267+ tal:attributes="href milestone_openbugs/url">sid</a>
268+ </td>
269+ <td><span tal:replace="milestone_openbugs/count">2</span></td>
270+ </tr>
271+ </table>
272+ </div>
273+
274+</div>