Merge lp:~edwin-grubbs/launchpad/bug-669724-projectgroup-milestones-timeout into lp:launchpad

Proposed by Edwin Grubbs
Status: Merged
Approved by: Curtis Hovey
Approved revision: no longer in the source branch.
Merged at revision: 12238
Proposed branch: lp:~edwin-grubbs/launchpad/bug-669724-projectgroup-milestones-timeout
Merge into: lp:launchpad
Diff against target: 271 lines (+46/-31)
7 files modified
lib/lp/bugs/doc/official-bug-tags.txt (+10/-5)
lib/lp/registry/browser/configure.zcml (+2/-2)
lib/lp/registry/browser/milestone.py (+10/-6)
lib/lp/registry/browser/project.py (+9/-5)
lib/lp/registry/model/projectgroup.py (+9/-6)
lib/lp/registry/stories/milestone/object-milestones.txt (+1/-2)
lib/lp/registry/templates/object-milestones.pt (+5/-5)
To merge this branch: bzr merge lp:~edwin-grubbs/launchpad/bug-669724-projectgroup-milestones-timeout
Reviewer Review Type Date Requested Status
Curtis Hovey (community) code Approve
Review via email: mp+46837@code.launchpad.net

Commit message

[r=sinzui][ui=none][bug=669724] Fixed timeout on $projectgroup/+milestones page.

Description of the change

Summary
-------

This branch fixes timeouts on the $projectgroup/+milestones page by
removing the counts for bugs and blueprints, since that information has
already been removed for projects and distributions.
It would be possible to re-add the bug and blueprints counts by writing
a query that gets the counts for all the milestones at once. However,
this will require rewriting the templates or adding a decorator on the
milestone object with count data for the various types of milestone
targets.

Implementation details
----------------------

The +pillar-table-row for IProjectGroupMilestone was using MilestoneView
instead of MilestonesView, which has show_series_context=True, and that
caused should_show_bugs_and_blueprints to be false for projects and
distributions, but not for project groups. I made this more explicit. I
renamed MilestonesView to avoid confusing it with MilestoneView, and it
also wasn't a very accurate name. Cache the milestones as a list so
that it can be referenced multiple times in the template without
evaluating the storm result set multiple times.
    lib/lp/registry/browser/configure.zcml
    lib/lp/registry/browser/milestone.py
    lib/lp/registry/stories/milestone/object-milestones.txt
    lib/lp/registry/templates/object-milestones.pt

Reduced the number of queries in the page by preventing the menu from
querying whether the project group has projects for each menu item.
    lib/lp/registry/browser/project.py

Instead of one query per project, use one query to get all bug tags for
the project group.
    lib/lp/registry/model/projectgroup.py

Fixed test for attribute that now returns storm result set.
    lib/lp/bugs/doc/official-bug-tags.txt

Tests
-----

./bin/test -vv -t 'official-bug-tags.txt|object-milestones.txt'

Demo and Q/A
------------

* Open https://launchpad.net/openobject/+milestones
  * It should not timeout.

Lint
----

No lint.

To post a comment you must log in.
Revision history for this message
Curtis Hovey (sinzui) wrote :

Thank you for discovering my typo. The renaming and clean ups are very appreciated.

review: Approve (code)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'lib/lp/bugs/doc/official-bug-tags.txt'
--- lib/lp/bugs/doc/official-bug-tags.txt 2010-10-20 19:41:34 +0000
+++ lib/lp/bugs/doc/official-bug-tags.txt 2011-01-19 21:51:20 +0000
@@ -1,4 +1,5 @@
1= Official Bug Tags =1Official Bug Tags
2=================
23
3Distributions and products can define official bug tags.4Distributions and products can define official bug tags.
45
@@ -49,7 +50,8 @@
49 >>> transaction.abort()50 >>> transaction.abort()
5051
5152
52== Targets of official bug tags ==53Targets of official bug tags
54----------------------------
5355
54Distribution owners and other persons with the permission launchpad.Edit56Distribution owners and other persons with the permission launchpad.Edit
55can add and remove offical bug tags by calling addOfficialBugTag()57can add and remove offical bug tags by calling addOfficialBugTag()
@@ -169,7 +171,8 @@
169 >>> ubuntu.official_bug_tags = [u'foo', u'bar']171 >>> ubuntu.official_bug_tags = [u'foo', u'bar']
170 Traceback (most recent call last):172 Traceback (most recent call last):
171 ...173 ...
172 Unauthorized: (<Distribution 'Ubuntu' (ubuntu)>, 'official_bug_tags', 'launchpad.BugSupervisor')174 Unauthorized: (<Distribution 'Ubuntu' (ubuntu)>,
175 'official_bug_tags', 'launchpad.BugSupervisor')
173176
174The same is available for products.177The same is available for products.
175178
@@ -180,7 +183,8 @@
180 [u'bar', u'foo']183 [u'bar', u'foo']
181184
182185
183== Official tags for additional bug targets ==186Official tags for additional bug targets
187----------------------------------------
184188
185All IHasBugs implementations provide an official_bug_tags property. They are189All IHasBugs implementations provide an official_bug_tags property. They are
186taken from the relevant distribution or product.190taken from the relevant distribution or product.
@@ -213,7 +217,8 @@
213 >>> thunderbird.official_bug_tags = [u'baz']217 >>> thunderbird.official_bug_tags = [u'baz']
214 >>> logout()218 >>> logout()
215 >>> login('no-priv@canonical.com')219 >>> login('no-priv@canonical.com')
216 >>> getUtility(IProjectGroupSet).getByName('mozilla').official_bug_tags220 >>> mozilla = getUtility(IProjectGroupSet).getByName('mozilla')
221 >>> list(mozilla.official_bug_tags)
217 [u'bar', u'baz', u'foo']222 [u'bar', u'baz', u'foo']
218 >>> logout()223 >>> logout()
219224
220225
=== modified file 'lib/lp/registry/browser/configure.zcml'
--- lib/lp/registry/browser/configure.zcml 2011-01-18 20:49:35 +0000
+++ lib/lp/registry/browser/configure.zcml 2011-01-19 21:51:20 +0000
@@ -1330,14 +1330,14 @@
1330 <browser:page1330 <browser:page
1331 name="+pillar-table-row"1331 name="+pillar-table-row"
1332 for="lp.registry.interfaces.milestone.IMilestone"1332 for="lp.registry.interfaces.milestone.IMilestone"
1333 class="lp.registry.browser.milestone.MilestonesView"1333 class="lp.registry.browser.milestone.MilestoneWithoutCountsView"
1334 facet="overview"1334 facet="overview"
1335 permission="zope.Public"1335 permission="zope.Public"
1336 template="../templates/productseries-milestone-table-row.pt"/>1336 template="../templates/productseries-milestone-table-row.pt"/>
1337 <browser:page1337 <browser:page
1338 name="+pillar-table-row"1338 name="+pillar-table-row"
1339 for="lp.registry.interfaces.milestone.IProjectGroupMilestone"1339 for="lp.registry.interfaces.milestone.IProjectGroupMilestone"
1340 class="lp.registry.browser.milestone.MilestoneView"1340 class="lp.registry.browser.milestone.MilestoneWithoutCountsView"
1341 facet="overview"1341 facet="overview"
1342 permission="zope.Public"1342 permission="zope.Public"
1343 template="../templates/productseries-milestone-table-row.pt"/>1343 template="../templates/productseries-milestone-table-row.pt"/>
13441344
=== modified file 'lib/lp/registry/browser/milestone.py'
--- lib/lp/registry/browser/milestone.py 2010-12-10 15:06:12 +0000
+++ lib/lp/registry/browser/milestone.py 2011-01-19 21:51:20 +0000
@@ -15,7 +15,7 @@
15 'MilestoneNavigation',15 'MilestoneNavigation',
16 'MilestoneOverviewNavigationMenu',16 'MilestoneOverviewNavigationMenu',
17 'MilestoneSetNavigation',17 'MilestoneSetNavigation',
18 'MilestonesView',18 'MilestoneWithoutCountsView',
19 'MilestoneView',19 'MilestoneView',
20 'ObjectMilestonesView',20 'ObjectMilestonesView',
21 ]21 ]
@@ -55,9 +55,7 @@
55 LaunchpadFormView,55 LaunchpadFormView,
56 )56 )
57from lp.bugs.browser.bugtask import BugTaskListingItem57from lp.bugs.browser.bugtask import BugTaskListingItem
58from lp.bugs.interfaces.bugtask import (58from lp.bugs.interfaces.bugtask import IBugTaskSet
59 IBugTaskSet,
60 )
61from lp.registry.browser import (59from lp.registry.browser import (
62 get_status_counts,60 get_status_counts,
63 RegistryDeleteViewMixin,61 RegistryDeleteViewMixin,
@@ -213,7 +211,7 @@
213 @property211 @property
214 def should_show_bugs_and_blueprints(self):212 def should_show_bugs_and_blueprints(self):
215 """Display the summary of bugs/blueprints for this milestone?"""213 """Display the summary of bugs/blueprints for this milestone?"""
216 return (not self.show_series_context) and self.milestone.active214 return self.milestone.active
217215
218 @property216 @property
219 def page_title(self):217 def page_title(self):
@@ -368,9 +366,11 @@
368 return len(self.bugtasks) > 0 or len(self.specifications) > 0366 return len(self.bugtasks) > 0 or len(self.specifications) > 0
369367
370368
371class MilestonesView(MilestoneView):369class MilestoneWithoutCountsView(MilestoneView):
372 """Show a milestone in a list of milestones."""370 """Show a milestone in a list of milestones."""
371
373 show_series_context = True372 show_series_context = True
373 should_show_bugs_and_blueprints = False
374374
375375
376class MilestoneAddView(LaunchpadFormView):376class MilestoneAddView(LaunchpadFormView):
@@ -516,3 +516,7 @@
516 """A view for listing the milestones for any `IHasMilestones` object"""516 """A view for listing the milestones for any `IHasMilestones` object"""
517517
518 label = 'Milestones'518 label = 'Milestones'
519
520 @cachedproperty
521 def milestones(self):
522 return list(self.context.all_milestones)
519523
=== modified file 'lib/lp/registry/browser/project.py'
--- lib/lp/registry/browser/project.py 2010-12-13 21:41:15 +0000
+++ lib/lp/registry/browser/project.py 2011-01-19 21:51:20 +0000
@@ -164,29 +164,33 @@
164 enable_only = ['overview', 'branches', 'bugs', 'specifications',164 enable_only = ['overview', 'branches', 'bugs', 'specifications',
165 'answers', 'translations']165 'answers', 'translations']
166166
167 @cachedproperty
168 def has_products(self):
169 return self.context.hasProducts()
170
167 def branches(self):171 def branches(self):
168 text = 'Code'172 text = 'Code'
169 return Link('', text, enabled=self.context.hasProducts())173 return Link('', text, enabled=self.has_products)
170174
171 def bugs(self):175 def bugs(self):
172 site = 'bugs'176 site = 'bugs'
173 text = 'Bugs'177 text = 'Bugs'
174 return Link('', text, enabled=self.context.hasProducts(), site=site)178 return Link('', text, enabled=self.has_products, site=site)
175179
176 def answers(self):180 def answers(self):
177 site = 'answers'181 site = 'answers'
178 text = 'Answers'182 text = 'Answers'
179 return Link('', text, enabled=self.context.hasProducts(), site=site)183 return Link('', text, enabled=self.has_products, site=site)
180184
181 def specifications(self):185 def specifications(self):
182 site = 'blueprints'186 site = 'blueprints'
183 text = 'Blueprints'187 text = 'Blueprints'
184 return Link('', text, enabled=self.context.hasProducts(), site=site)188 return Link('', text, enabled=self.has_products, site=site)
185189
186 def translations(self):190 def translations(self):
187 site = 'translations'191 site = 'translations'
188 text = 'Translations'192 text = 'Translations'
189 return Link('', text, enabled=self.context.hasProducts(), site=site)193 return Link('', text, enabled=self.has_products, site=site)
190194
191195
192class ProjectAdminMenuMixin:196class ProjectAdminMenuMixin:
193197
=== modified file 'lib/lp/registry/model/projectgroup.py'
--- lib/lp/registry/model/projectgroup.py 2010-12-25 21:28:14 +0000
+++ lib/lp/registry/model/projectgroup.py 2011-01-19 21:51:20 +0000
@@ -20,8 +20,8 @@
20 )20 )
21from storm.expr import (21from storm.expr import (
22 And,22 And,
23 Join,
23 SQL,24 SQL,
24 Join,
25 )25 )
26from storm.locals import Int26from storm.locals import Int
27from storm.store import Store27from storm.store import Store
@@ -91,6 +91,7 @@
91 IProjectGroupSet,91 IProjectGroupSet,
92 )92 )
93from lp.registry.model.announcement import MakesAnnouncements93from lp.registry.model.announcement import MakesAnnouncements
94from lp.registry.model.hasdrivers import HasDriversMixin
94from lp.registry.model.karma import KarmaContextMixin95from lp.registry.model.karma import KarmaContextMixin
95from lp.registry.model.milestone import (96from lp.registry.model.milestone import (
96 HasMilestonesMixin,97 HasMilestonesMixin,
@@ -100,7 +101,6 @@
100from lp.registry.model.pillar import HasAliasMixin101from lp.registry.model.pillar import HasAliasMixin
101from lp.registry.model.product import Product102from lp.registry.model.product import Product
102from lp.registry.model.productseries import ProductSeries103from lp.registry.model.productseries import ProductSeries
103from lp.registry.model.hasdrivers import HasDriversMixin
104from lp.registry.model.structuralsubscription import (104from lp.registry.model.structuralsubscription import (
105 StructuralSubscriptionTargetMixin,105 StructuralSubscriptionTargetMixin,
106 )106 )
@@ -327,10 +327,13 @@
327 @property327 @property
328 def official_bug_tags(self):328 def official_bug_tags(self):
329 """See `IHasBugs`."""329 """See `IHasBugs`."""
330 official_bug_tags = set()330 store = Store.of(self)
331 for product in self.products:331 result = store.find(
332 official_bug_tags.update(product.official_bug_tags)332 OfficialBugTag.tag,
333 return sorted(official_bug_tags)333 OfficialBugTag.product == Product.id,
334 Product.project == self.id).order_by(OfficialBugTag.tag)
335 result.config(distinct=True)
336 return result
334337
335 def getUsedBugTags(self):338 def getUsedBugTags(self):
336 """See `IHasBugs`."""339 """See `IHasBugs`."""
337340
=== modified file 'lib/lp/registry/stories/milestone/object-milestones.txt'
--- lib/lp/registry/stories/milestone/object-milestones.txt 2010-12-21 23:49:34 +0000
+++ lib/lp/registry/stories/milestone/object-milestones.txt 2011-01-19 21:51:20 +0000
@@ -129,8 +129,7 @@
129 GNOME 1.3 A date This is an inactive milestone129 GNOME 1.3 A date This is an inactive milestone
130 GNOME 1.2 A date not yet released130 GNOME 1.2 A date not yet released
131 GNOME 1.1. A date not yet released131 GNOME 1.1. A date not yet released
132 GNOME 1.1 A date not yet released Bugs targeted: 3 Confirmed132 GNOME 1.1 A date not yet released
133 Blueprints targeted: 2 Unknown
134133
135134
136Individual milestones135Individual milestones
137136
=== modified file 'lib/lp/registry/templates/object-milestones.pt'
--- lib/lp/registry/templates/object-milestones.pt 2010-08-20 04:14:22 +0000
+++ lib/lp/registry/templates/object-milestones.pt 2011-01-19 21:51:20 +0000
@@ -14,7 +14,7 @@
14 Milestones belong to a series and can be created from the series page14 Milestones belong to a series and can be created from the series page
15 by a project owner or series release manager.15 by a project owner or series release manager.
16 </p>16 </p>
17 17
18 <ul class="horizontal"18 <ul class="horizontal"
19 tal:condition="context/project|nothing">19 tal:condition="context/project|nothing">
20 <li>20 <li>
@@ -25,10 +25,10 @@
25 </ul>25 </ul>
26 </div>26 </div>
2727
28 <tal:milestones define="milestones context/all_milestones">28 <tal:milestones>
29 <table id="milestones" class="listing"29 <table id="milestones" class="listing"
30 tal:define="has_series context/series|nothing"30 tal:define="has_series context/series|nothing"
31 tal:condition="context/has_milestones">31 tal:condition="view/milestones">
32 <thead>32 <thead>
33 <tr>33 <tr>
34 <th>Version</th>34 <th>Version</th>
@@ -40,12 +40,12 @@
40 </thead>40 </thead>
41 <tbody>41 <tbody>
42 <tal:row42 <tal:row
43 repeat="milestone milestones"43 repeat="milestone view/milestones"
44 replace="structure milestone/@@+pillar-table-row" />44 replace="structure milestone/@@+pillar-table-row" />
45 </tbody>45 </tbody>
46 </table>46 </table>
4747
48 <tal:no-milestones condition="not: context/has_milestones">48 <tal:no-milestones condition="not: view/milestones">
49 <p>There are no milestones associated with49 <p>There are no milestones associated with
50 <span tal:replace="context/title" />50 <span tal:replace="context/title" />
51 </p>51 </p>