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
=== 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
@@ -279,7 +279,8 @@
279 # The user is trying to file a new Ubuntu bug via the web279 # The user is trying to file a new Ubuntu bug via the web
280 # interface and without using apport. Redirect to a page280 # interface and without using apport. Redirect to a page
281 # explaining the preferred bug-filing procedure.281 # explaining the preferred bug-filing procedure.
282 self.request.response.redirect(config.malone.ubuntu_bug_filing_url)282 self.request.response.redirect(
283 config.malone.ubuntu_bug_filing_url)
283 if self.extra_data_token is not None:284 if self.extra_data_token is not None:
284 # self.extra_data has been initialized in publishTraverse().285 # self.extra_data has been initialized in publishTraverse().
285 if self.extra_data.initial_summary:286 if self.extra_data.initial_summary:
@@ -1125,14 +1126,7 @@
1125 """Helper methods for rendering bug listings."""1126 """Helper methods for rendering bug listings."""
11261127
1127 @property1128 @property
1128 def series_buglistings(self):1129 def series_list(self):
1129 """Return a buglisting for each series.
1130
1131 The list is sorted newest series to oldest.
1132
1133 The count only considers bugs that the user would actually be
1134 able to see in a listing.
1135 """
1136 if IDistribution(self.context, None):1130 if IDistribution(self.context, None):
1137 serieses = self.context.serieses1131 serieses = self.context.serieses
1138 elif IProduct(self.context, None):1132 elif IProduct(self.context, None):
@@ -1142,11 +1136,20 @@
1142 elif IProductSeries(self.context, None):1136 elif IProductSeries(self.context, None):
1143 serieses = self.context.product.serieses1137 serieses = self.context.product.serieses
1144 else:1138 else:
1145 raise AssertionError, ("series_bug_counts called with "1139 raise AssertionError, ("series_list called with illegal context")
1146 "illegal context")1140 return serieses
11471141
1142 @property
1143 def series_buglistings(self):
1144 """Return a buglisting for each series.
1145
1146 The list is sorted newest series to oldest.
1147
1148 The count only considers bugs that the user would actually be
1149 able to see in a listing.
1150 """
1148 series_buglistings = []1151 series_buglistings = []
1149 for series in serieses:1152 for series in self.series_list:
1150 series_bug_count = series.open_bugtasks.count()1153 series_bug_count = series.open_bugtasks.count()
1151 if series_bug_count > 0:1154 if series_bug_count > 0:
1152 series_buglistings.append(1155 series_buglistings.append(
@@ -1157,6 +1160,21 @@
11571160
1158 return series_buglistings1161 return series_buglistings
11591162
1163 @property
1164 def milestone_buglistings(self):
1165 """Return a buglisting for each milestone."""
1166 milestone_buglistings = []
1167 for series in self.series_list:
1168 for milestone in series.milestones:
1169 milestone_bug_count = milestone.open_bugtasks.count()
1170 if milestone_bug_count > 0:
1171 milestone_buglistings.append(
1172 dict(
1173 title=milestone.name,
1174 url=canonical_url(milestone),
1175 count=milestone_bug_count))
1176 return milestone_buglistings
1177
11601178
1161class BugCountDataItem:1179class BugCountDataItem:
1162 """Data about bug count for a status."""1180 """Data about bug count for a status."""
11631181
=== modified file 'lib/lp/bugs/browser/configure.zcml'
--- lib/lp/bugs/browser/configure.zcml 2009-09-14 12:19:55 +0000
+++ lib/lp/bugs/browser/configure.zcml 2009-09-18 18:45:18 +0000
@@ -342,6 +342,13 @@
342 template="../templates/bugtask-portlet-seriesbugs.pt"/>342 template="../templates/bugtask-portlet-seriesbugs.pt"/>
343 <browser:page343 <browser:page
344 for="lp.registry.interfaces.distroseries.IDistroSeries"344 for="lp.registry.interfaces.distroseries.IDistroSeries"
345 class="lp.bugs.browser.bugtarget.BugTargetBugListingView"
346 facet="bugs"
347 permission="zope.Public"
348 name="+portlet-bugtasklist-milestonebugs"
349 template="../templates/bugtask-portlet-milestonebugs.pt"/>
350 <browser:page
351 for="lp.registry.interfaces.distroseries.IDistroSeries"
345 name="+nominations"352 name="+nominations"
346 class="lp.bugs.browser.bugtask.BugNominationsView"353 class="lp.bugs.browser.bugtask.BugNominationsView"
347 permission="zope.Public"354 permission="zope.Public"
@@ -369,6 +376,13 @@
369 name="+portlet-bugtasklist-seriesbugs"376 name="+portlet-bugtasklist-seriesbugs"
370 template="../templates/bugtask-portlet-seriesbugs.pt"/>377 template="../templates/bugtask-portlet-seriesbugs.pt"/>
371 <browser:page378 <browser:page
379 for="lp.registry.interfaces.product.IProduct"
380 class="lp.bugs.browser.bugtarget.BugTargetBugListingView"
381 facet="bugs"
382 permission="zope.Public"
383 name="+portlet-bugtasklist-milestonebugs"
384 template="../templates/bugtask-portlet-milestonebugs.pt"/>
385 <browser:page
372 for="lp.registry.interfaces.distribution.IDistribution"386 for="lp.registry.interfaces.distribution.IDistribution"
373 class="lp.bugs.browser.bugtarget.BugTargetBugListingView"387 class="lp.bugs.browser.bugtarget.BugTargetBugListingView"
374 facet="bugs"388 facet="bugs"
@@ -376,6 +390,13 @@
376 name="+portlet-bugtasklist-seriesbugs"390 name="+portlet-bugtasklist-seriesbugs"
377 template="../templates/bugtask-portlet-seriesbugs.pt"/>391 template="../templates/bugtask-portlet-seriesbugs.pt"/>
378 <browser:page392 <browser:page
393 for="lp.registry.interfaces.distribution.IDistribution"
394 class="lp.bugs.browser.bugtarget.BugTargetBugListingView"
395 facet="bugs"
396 permission="zope.Public"
397 name="+portlet-bugtasklist-milestonebugs"
398 template="../templates/bugtask-portlet-milestonebugs.pt"/>
399 <browser:page
379 name="+filebug"400 name="+filebug"
380 for="lp.registry.interfaces.project.IProject"401 for="lp.registry.interfaces.project.IProject"
381 class="lp.bugs.browser.bugtarget.ProjectFileBugGuidedView"402 class="lp.bugs.browser.bugtarget.ProjectFileBugGuidedView"
@@ -408,6 +429,13 @@
408 template="../templates/bugtask-portlet-seriesbugs.pt"/>429 template="../templates/bugtask-portlet-seriesbugs.pt"/>
409 <browser:page430 <browser:page
410 for="lp.registry.interfaces.productseries.IProductSeries"431 for="lp.registry.interfaces.productseries.IProductSeries"
432 class="lp.bugs.browser.bugtarget.BugTargetBugListingView"
433 facet="bugs"
434 permission="zope.Public"
435 name="+portlet-bugtasklist-milestonebugs"
436 template="../templates/bugtask-portlet-milestonebugs.pt"/>
437 <browser:page
438 for="lp.registry.interfaces.productseries.IProductSeries"
411 name="+nominations"439 name="+nominations"
412 class="lp.bugs.browser.bugtask.BugNominationsView"440 class="lp.bugs.browser.bugtask.BugNominationsView"
413 permission="zope.Public"441 permission="zope.Public"
414442
=== 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 00:00:00 +0000
+++ lib/lp/bugs/stories/bugs/xx-portlets-bug-milestones.txt 2009-09-18 18:41:39 +0000
@@ -0,0 +1,76 @@
1Milestone-targeted bugs portlet
2===============================
3
4The milestone-targeted bugs portlet displays the number of bugs that have
5been targeted to a specific milestone.
6
7This portlet is available from a distribution's bug page.
8
9 >>> anon_browser.open("http://bugs.launchpad.dev/debian/+bugs")
10 >>> portlet = find_portlet(
11 ... anon_browser.contents, "Milestone-targeted bugs")
12 >>> print extract_text(portlet)
13 Milestone-targeted bugs
14 3.1 1
15
16It is also available from the bug page for a series in the distribution.
17
18 >>> anon_browser.open("http://bugs.launchpad.dev/debian/sarge/+bugs")
19 >>> portlet = find_portlet(
20 ... anon_browser.contents, "Milestone-targeted bugs")
21 >>> print extract_text(portlet)
22 Milestone-targeted bugs
23 3.1 1
24
25The portlet is also available from a project's bugs home page. To demonstrate
26this, a project has to first have one of its milestones associated with a bug.
27If there are no milestones with bugs, then there is no milestone-targeted
28portlet.
29
30 >>> anon_browser.open("http://bugs.launchpad.dev/firefox")
31 >>> portlet = find_portlet(
32 ... anon_browser.contents, "Milestone-targeted bugs")
33 >>> portlet is None
34 True
35
36To enable the portlet, a bugtask needs to have a milestone associated with it.
37Bug 4 has a Firefox bugtask, which can be used once a milestone is selected.
38
39 >>> login('test@canonical.com')
40 >>> from zope.component import getUtility
41 >>> from lp.bugs.interfaces.bugtask import IBugTaskSet
42 >>> ff_bugtask = getUtility(IBugTaskSet).get(13)
43 >>> print ff_bugtask.bug.id
44 4
45
46 >>> from lp.registry.interfaces.product import IProductSet
47 >>> from lp.registry.interfaces.milestone import IMilestoneSet
48 >>> firefox = getUtility(IProductSet).getByName('firefox')
49 >>> ff_milestone = getUtility(IMilestoneSet).getByNameAndProduct(
50 ... "1.0", firefox)
51 >>> print ff_milestone.name
52 1.0
53
54The bugtask milestone is set to the Firefox 1.0 milestone.
55
56 >>> ff_bugtask.milestone = ff_milestone.id
57 >>> logout()
58
59Now Firefox has a milestone-targeted bugs portlet on the project's bugs home
60page.
61
62 >>> anon_browser.open("http://bugs.launchpad.dev/firefox")
63 >>> portlet = find_portlet(
64 ... anon_browser.contents, "Milestone-targeted bugs")
65 >>> print extract_text(portlet)
66 Milestone-targeted bugs
67 1.0 1
68
69The portlet will also appear on a project's series bug page.
70
71 >>> anon_browser.open("http://launchpad.dev/firefox/trunk/+bugs")
72 >>> portlet = find_portlet(
73 ... anon_browser.contents, "Milestone-targeted bugs")
74 >>> print extract_text(portlet)
75 Milestone-targeted bugs
76 1.0 1
077
=== modified file 'lib/lp/bugs/templates/buglisting-default.pt'
--- lib/lp/bugs/templates/buglisting-default.pt 2009-09-11 16:33:22 +0000
+++ lib/lp/bugs/templates/buglisting-default.pt 2009-09-16 17:05:13 +0000
@@ -62,6 +62,9 @@
62 <tal:releasecriticalbugs62 <tal:releasecriticalbugs
63 tal:condition="view/shouldShowReleaseCriticalPortlet"63 tal:condition="view/shouldShowReleaseCriticalPortlet"
64 tal:content="structure context/@@+portlet-bugtasklist-seriesbugs" />64 tal:content="structure context/@@+portlet-bugtasklist-seriesbugs" />
65 <tal:milestonecriticalbugs
66 tal:condition="view/shouldShowReleaseCriticalPortlet"
67 tal:content="structure context/@@+portlet-bugtasklist-milestonebugs" />
65 </tal:do_not_show_portlets_advanced_form>68 </tal:do_not_show_portlets_advanced_form>
66 </tal:side>69 </tal:side>
67</body>70</body>
6871
=== modified file 'lib/lp/bugs/templates/bugtarget-bugs.pt'
--- lib/lp/bugs/templates/bugtarget-bugs.pt 2009-07-18 00:05:49 +0000
+++ lib/lp/bugs/templates/bugtarget-bugs.pt 2009-09-16 17:05:13 +0000
@@ -19,6 +19,9 @@
19 <tal:releasecriticalbugs19 <tal:releasecriticalbugs
20 tal:condition="view/shouldShowReleaseCriticalPortlet"20 tal:condition="view/shouldShowReleaseCriticalPortlet"
21 tal:content="structure context/@@+portlet-bugtasklist-seriesbugs" />21 tal:content="structure context/@@+portlet-bugtasklist-seriesbugs" />
22 <tal:milestonecriticalbugs
23 tal:condition="view/shouldShowReleaseCriticalPortlet"
24 tal:content="structure context/@@+portlet-bugtasklist-milestonebugs" />
22 </metal:portlets>25 </metal:portlets>
23 <body>26 <body>
24 <div metal:fill-slot="main" class="tab-bugs"27 <div metal:fill-slot="main" class="tab-bugs"
2528
=== added file 'lib/lp/bugs/templates/bugtask-portlet-milestonebugs.pt'
--- lib/lp/bugs/templates/bugtask-portlet-milestonebugs.pt 1970-01-01 00:00:00 +0000
+++ lib/lp/bugs/templates/bugtask-portlet-milestonebugs.pt 2009-09-16 17:05:13 +0000
@@ -0,0 +1,24 @@
1<div
2 xmlns:tal="http://xml.zope.org/namespaces/tal"
3 xmlns:metal="http://xml.zope.org/namespaces/metal"
4 xmlns:i18n="http://xml.zope.org/namespaces/i18n"
5 class="portlet" id="portlet-milestone-critical-bugs"
6 tal:define="milestone_buglistings view/milestone_buglistings"
7 tal:condition="milestone_buglistings">
8
9 <h2>Milestone-targeted bugs</h2>
10
11 <div class="portletBody">
12 <table width="100%">
13 <tr tal:repeat="milestone_openbugs milestone_buglistings">
14 <td>
15 <a href=""
16 tal:content="milestone_openbugs/title"
17 tal:attributes="href milestone_openbugs/url">sid</a>
18 </td>
19 <td><span tal:replace="milestone_openbugs/count">2</span></td>
20 </tr>
21 </table>
22 </div>
23
24</div>