Merge lp:~sinzui/launchpad/peppermint-sticks into lp:launchpad

Proposed by Curtis Hovey on 2010-12-21
Status: Merged
Approved by: Leonard Richardson on 2010-12-21
Approved revision: no longer in the source branch.
Merged at revision: 12150
Proposed branch: lp:~sinzui/launchpad/peppermint-sticks
Merge into: lp:launchpad
Diff against target: 1149 lines (+196/-239)
22 files modified
cronscripts/buildd-queue-builder.py (+1/-7)
daemons/buildd-slave.tac (+5/-5)
doc/security.txt (+0/-3)
lib/canonical/buildd/__init__.py (+0/-2)
lib/canonical/buildd/debian/launchpad-buildd.init (+0/-2)
lib/canonical/buildd/generate-translation-templates (+0/-2)
lib/canonical/buildd/mount-chroot (+0/-2)
lib/canonical/buildd/override-sources-list (+0/-2)
lib/canonical/buildd/remove-build (+0/-2)
lib/canonical/buildd/scan-for-processes (+0/-2)
lib/canonical/buildd/umount-chroot (+0/-2)
lib/canonical/buildd/unpack-chroot (+0/-2)
lib/canonical/buildd/update-debian-chroot (+0/-2)
lib/canonical/launchpad/scripts/tests/__init__.py (+0/-9)
lib/lp/bugs/doc/bugs-email-affects-path.txt (+29/-13)
lib/lp/bugs/stories/guided-filebug/xx-project-guided-filebug.txt (+48/-68)
lib/lp/registry/browser/product.py (+0/-8)
lib/lp/registry/codesofconduct/README (+0/-3)
lib/lp/registry/doc/milestone.txt (+102/-94)
lib/lp/registry/doc/projectgroup.txt (+6/-5)
lib/lp/registry/model/projectgroup.py (+3/-2)
lib/lp/registry/stories/project/xx-project-index.txt (+2/-2)
To merge this branch: bzr merge lp:~sinzui/launchpad/peppermint-sticks
Reviewer Review Type Date Requested Status
Leonard Richardson (community) 2010-12-21 Approve on 2010-12-21
Review via email: mp+44378@code.launchpad.net

Description of the Change

Fix ProjectGroup.products sort order and remove Author: comments.

    Launchpad bug:
        https://bugs.launchpad.net/bugs/385711
        https://bugs.launchpad.net/bugs/398896
    Pre-implementation: no one
    Test command: ./bin/test -vv \
      -t doc/projectgroup -t doc/milestone \
      -t xx-project-index -t xx-project-guided-filebug

Bug #385711 [projectgroup sorts projects by their name instead of displayname]
    The project drop-down menu in the form for filing a new bug on a
    projectgroup shows the project displayname, but it sorts the list by the
    project name. The project group page is also sorted wrong

Bug #398896 [get rid of Author tags (etc) in Launchpad source code]
    Some files in the Launchpad source code have "Author:" tags. They
    shouldn't.

--------------------------------------------------------------------

RULES

Bug #385711 [projectgroup sorts projects by their name instead of displayname]
    * Change ProjectGroup.products to sort by displayname.
    * ADDENDUM Remove ProductView.projproducts because it is never used.

Bug #398896 [get rid of Author tags (etc) in Launchpad source code]
    * Delete the lines

QA

Bug #385711 [projectgroup sorts projects by their name instead of displayname]
    * Visit https://launchpad.net/launchpad-project
    * Verify the projects are listed in alphabetical order.

Bug #398896 [get rid of Author tags (etc) in Launchpad source code]
    None

LINT

  cronscripts/buildd-queue-builder.py
  daemons/buildd-slave.tac
  doc/security.txt
  lib/canonical/buildd/__init__.py
  lib/canonical/buildd/generate-translation-templates
  lib/canonical/buildd/mount-chroot
  lib/canonical/buildd/override-sources-list
  lib/canonical/buildd/remove-build
  lib/canonical/buildd/scan-for-processes
  lib/canonical/buildd/umount-chroot
  lib/canonical/buildd/unpack-chroot
  lib/canonical/buildd/update-debian-chroot
  lib/canonical/buildd/debian/launchpad-buildd.init
  lib/canonical/launchpad/scripts/tests/__init__.py
  lib/lp/bugs/stories/guided-filebug/xx-project-guided-filebug.txt
  lib/lp/registry/browser/product.py
  lib/lp/registry/codesofconduct/README
  lib/lp/registry/doc/milestone.txt
  lib/lp/registry/doc/projectgroup.txt
  lib/lp/registry/model/projectgroup.py
  lib/lp/registry/stories/project/xx-project-index.txt

^ Lint hates the txt files. I can clean these up before I land.

IMPLEMENTATION

Bug #385711 [projectgroup sorts projects by their name instead of displayname]
    Changed the sort on ProjectGroup.products to displayname. Removed unused
    method from ProductView.projproducts and duplicate test from
    xx-project-guided-filebug.
    lib/lp/bugs/stories/guided-filebug/xx-project-guided-filebug.txt
    lib/lp/registry/browser/product.py
    lib/lp/registry/doc/milestone.txt
    lib/lp/registry/doc/projectgroup.txt
    lib/lp/registry/model/projectgroup.py
    lib/lp/registry/stories/project/xx-project-index.txt

Bug #398896 [get rid of Author tags (etc) in Launchpad source code]
    Deleted the author comments from the files.
    cronscripts/buildd-queue-builder.py
    daemons/buildd-slave.tac
    doc/security.txt
    lib/canonical/buildd/__init__.py
    lib/canonical/buildd/debian/launchpad-buildd.init
    lib/canonical/buildd/generate-translation-templates
    lib/canonical/buildd/mount-chroot
    lib/canonical/buildd/override-sources-list
    lib/canonical/buildd/remove-build
    lib/canonical/buildd/scan-for-processes
    lib/canonical/buildd/umount-chroot
    lib/canonical/buildd/unpack-chroot
    lib/canonical/buildd/update-debian-chroot
    lib/canonical/launchpad/scripts/tests/__init__.py
    lib/lp/registry/codesofconduct/README

To post a comment you must log in.
Leonard Richardson (leonardr) wrote :

Starting on line 301, you should mention the "display names" instead of the "names". You should also show the display names--otherwise there's no way to verify that the projects are really in alphabetical order.

Everything else looks good.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'cronscripts/buildd-queue-builder.py'
2--- cronscripts/buildd-queue-builder.py 2010-04-27 19:48:39 +0000
3+++ cronscripts/buildd-queue-builder.py 2010-12-24 16:44:20 +0000
4@@ -2,13 +2,8 @@
5 #
6 # Copyright 2009 Canonical Ltd. This software is licensed under the
7 # GNU Affero General Public License version 3 (see the file LICENSE).
8+"""Build Jobs initialisation."""
9
10-# pylint: disable-msg=C0103,W0403
11-# Author: Daniel Silverstone <daniel.silverstone@canonical.com>
12-# Celso Providelo <celso.providelo@canonical.com>
13-#
14-# Build Jobs initialisation
15-#
16 __metaclass__ = type
17
18 import _pythonpath
19@@ -23,4 +18,3 @@
20 script.run()
21 finally:
22 script.unlock()
23-
24
25=== modified file 'daemons/buildd-slave.tac'
26--- daemons/buildd-slave.tac 2010-10-20 18:43:29 +0000
27+++ daemons/buildd-slave.tac 2010-12-24 16:44:20 +0000
28@@ -1,8 +1,6 @@
29 # Copyright 2009, 2010 Canonical Ltd. This software is licensed under the
30 # GNU Affero General Public License version 3 (see the file LICENSE).
31
32-# Author: Daniel Silverstone <daniel.silverstone@canonical.com>
33-
34 # Buildd Slave implementation
35 # XXX: dsilvers: 2005/01/21: Currently everything logged in the slave gets
36 # passed through to the twistd log too. this could get dangerous/big
37@@ -12,7 +10,8 @@
38 from canonical.buildd.binarypackage import BinaryPackageBuildManager
39 from canonical.buildd.sourcepackagerecipe import (
40 SourcePackageRecipeBuildManager)
41-from canonical.buildd.translationtemplates import TranslationTemplatesBuildManager
42+from canonical.buildd.translationtemplates import (
43+ TranslationTemplatesBuildManager)
44 from canonical.launchpad.daemons import readyservice
45
46 from twisted.web import server, resource, static
47@@ -30,7 +29,8 @@
48 slave.registerBuilder(BinaryPackageBuildManager, "debian")
49 slave.registerBuilder(BinaryPackageBuildManager, "binarypackage")
50 slave.registerBuilder(SourcePackageRecipeBuildManager, "sourcepackagerecipe")
51-slave.registerBuilder(TranslationTemplatesBuildManager, 'translation-templates')
52+slave.registerBuilder(
53+ TranslationTemplatesBuildManager, 'translation-templates')
54
55 application = service.Application('BuildDSlave')
56 builddslaveService = service.IServiceCollection(application)
57@@ -43,7 +43,7 @@
58 root.putChild('filecache', static.File(conf.get('slave', 'filecache')))
59 slavesite = server.Site(root)
60
61-strports.service(slave.slave._config.get("slave","bindport"),
62+strports.service(slave.slave._config.get("slave","bindport"),
63 slavesite).setServiceParent(builddslaveService)
64
65 # You can interact with a running slave like this:
66
67=== modified file 'doc/security.txt'
68--- doc/security.txt 2010-12-18 03:05:44 +0000
69+++ doc/security.txt 2010-12-24 16:44:20 +0000
70@@ -1,9 +1,6 @@
71 Security Policy in Launchpad
72 ============================
73
74-Author: Brad Bollenbach
75-Date: 2005-01-26
76-
77 Zope 3 is a security-aware framework that makes it possible to develop complex
78 applications with security policies that closely resemble the reality that the
79 system is trying to model.
80
81=== modified file 'lib/canonical/buildd/__init__.py'
82--- lib/canonical/buildd/__init__.py 2009-06-25 05:39:50 +0000
83+++ lib/canonical/buildd/__init__.py 2010-12-24 16:44:20 +0000
84@@ -1,7 +1,5 @@
85 # Copyright 2009 Canonical Ltd. This software is licensed under the
86 # GNU Affero General Public License version 3 (see the file LICENSE).
87
88-# Author: Daniel Silverstone <daniel.silverstone@canonical.com>
89-
90 from canonical.buildd.slave import XMLRPCBuildDSlave
91 from canonical.buildd.debian import DebianBuildManager
92
93=== modified file 'lib/canonical/buildd/debian/launchpad-buildd.init'
94--- lib/canonical/buildd/debian/launchpad-buildd.init 2010-07-22 16:12:39 +0000
95+++ lib/canonical/buildd/debian/launchpad-buildd.init 2010-12-24 16:44:20 +0000
96@@ -5,8 +5,6 @@
97 #
98 # launchpad-buildd
99 # This file is used to start and stop launchpad buildds
100-#
101-# Author: Daniel Silverstone <daniel.silverstone@canonical.com>
102
103 ### BEGIN INIT INFO
104 # Provides: launchpad_buildd
105
106=== modified file 'lib/canonical/buildd/generate-translation-templates'
107--- lib/canonical/buildd/generate-translation-templates 2010-05-19 15:32:21 +0000
108+++ lib/canonical/buildd/generate-translation-templates 2010-12-24 16:44:20 +0000
109@@ -2,8 +2,6 @@
110 #
111 # Copyright 2010 Canonical Ltd. This software is licensed under the
112 # GNU Affero General Public License version 3 (see the file LICENSE).
113-#
114-# Author: Henning Eggers <henning@canonical.com>
115
116 # Buildd Slave tool to generate translation templates. Boiler plate code
117 # copied from sbuild-package.
118
119=== modified file 'lib/canonical/buildd/mount-chroot'
120--- lib/canonical/buildd/mount-chroot 2010-11-23 13:19:18 +0000
121+++ lib/canonical/buildd/mount-chroot 2010-12-24 16:44:20 +0000
122@@ -2,8 +2,6 @@
123 #
124 # Copyright 2009 Canonical Ltd. This software is licensed under the
125 # GNU Affero General Public License version 3 (see the file LICENSE).
126-#
127-# Author: Daniel Silverstone <daniel.silverstone@canonical.com>
128
129 # Buildd Slave tool to mount a chroot
130
131
132=== modified file 'lib/canonical/buildd/override-sources-list'
133--- lib/canonical/buildd/override-sources-list 2009-06-30 21:06:27 +0000
134+++ lib/canonical/buildd/override-sources-list 2010-12-24 16:44:20 +0000
135@@ -2,8 +2,6 @@
136 #
137 # Copyright 2009 Canonical Ltd. This software is licensed under the
138 # GNU Affero General Public License version 3 (see the file LICENSE).
139-#
140-# Author: Colin Watson <cjwatson@canonical.com>
141
142 # Buildd Slave tool to override sources.list in the chroot with a list of
143 # archives
144
145=== modified file 'lib/canonical/buildd/remove-build'
146--- lib/canonical/buildd/remove-build 2009-06-30 21:06:27 +0000
147+++ lib/canonical/buildd/remove-build 2010-12-24 16:44:20 +0000
148@@ -2,8 +2,6 @@
149 #
150 # Copyright 2009 Canonical Ltd. This software is licensed under the
151 # GNU Affero General Public License version 3 (see the file LICENSE).
152-#
153-# Author: Daniel Silverstone <daniel.silverstone@canonical.com>
154
155 # Buildd Slave tool to remove an unmounted chroot
156
157
158=== modified file 'lib/canonical/buildd/scan-for-processes'
159--- lib/canonical/buildd/scan-for-processes 2009-08-15 12:05:11 +0000
160+++ lib/canonical/buildd/scan-for-processes 2010-12-24 16:44:20 +0000
161@@ -2,8 +2,6 @@
162 #
163 # Copyright 2009 Canonical Ltd. This software is licensed under the
164 # GNU Affero General Public License version 3 (see the file LICENSE).
165-#
166-# Author: Daniel Silverstone <daniel.silverstone@canonical.com>
167
168 # Buildd Slave tool to scan a chroot in case any processes are underneath it
169
170
171=== modified file 'lib/canonical/buildd/umount-chroot'
172--- lib/canonical/buildd/umount-chroot 2010-11-23 13:19:18 +0000
173+++ lib/canonical/buildd/umount-chroot 2010-12-24 16:44:20 +0000
174@@ -2,8 +2,6 @@
175 #
176 # Copyright 2009 Canonical Ltd. This software is licensed under the
177 # GNU Affero General Public License version 3 (see the file LICENSE).
178-#
179-# Author: Daniel Silverstone <daniel.silverstone@canonical.com>
180
181 # Buildd Slave tool to mount a chroot
182
183
184=== modified file 'lib/canonical/buildd/unpack-chroot'
185--- lib/canonical/buildd/unpack-chroot 2009-06-30 21:06:27 +0000
186+++ lib/canonical/buildd/unpack-chroot 2010-12-24 16:44:20 +0000
187@@ -2,8 +2,6 @@
188 #
189 # Copyright 2009 Canonical Ltd. This software is licensed under the
190 # GNU Affero General Public License version 3 (see the file LICENSE).
191-#
192-# Author: Daniel Silverstone <daniel.silverstone@canonical.com>
193
194 # Buildd Slave tool to unpack a chroot tarball
195
196
197=== modified file 'lib/canonical/buildd/update-debian-chroot'
198--- lib/canonical/buildd/update-debian-chroot 2010-07-13 10:57:06 +0000
199+++ lib/canonical/buildd/update-debian-chroot 2010-12-24 16:44:20 +0000
200@@ -2,8 +2,6 @@
201 #
202 # Copyright 2009 Canonical Ltd. This software is licensed under the
203 # GNU Affero General Public License version 3 (see the file LICENSE).
204-#
205-# Author: Daniel Silverstone <daniel.silverstone@canonical.com>
206
207 # Buildd Slave tool to update a debian chroot
208
209
210=== modified file 'lib/canonical/launchpad/scripts/tests/__init__.py'
211--- lib/canonical/launchpad/scripts/tests/__init__.py 2010-09-29 16:20:36 +0000
212+++ lib/canonical/launchpad/scripts/tests/__init__.py 2010-12-24 16:44:20 +0000
213@@ -1,15 +1,6 @@
214 # Copyright 2009 Canonical Ltd. This software is licensed under the
215 # GNU Affero General Public License version 3 (see the file LICENSE).
216
217-# Author: Carlos Perello Marin <carlos.perello@canonical.com>
218-# David Allouche <david.allouche@canonical.com>
219-
220-# Make this a package.
221-
222-# Note: by adding one's name to the copyright section, one is arguably making
223-# a substantial modification.
224-
225-
226 import os.path
227 import subprocess
228
229
230=== modified file 'lib/lp/bugs/doc/bugs-email-affects-path.txt'
231--- lib/lp/bugs/doc/bugs-email-affects-path.txt 2010-10-09 16:36:22 +0000
232+++ lib/lp/bugs/doc/bugs-email-affects-path.txt 2010-12-24 16:44:20 +0000
233@@ -1,4 +1,5 @@
234-= The 'affects' path in the Bugs e-mail interface =
235+The 'affects' path in the Bugs e-mail interface
236+===============================================
237
238 When choosing which bugtask certain e-mail commands should modify, the
239 'affects' command is used. It accepts a single argument, the name of the
240@@ -33,10 +34,12 @@
241 ...
242 BugTargetNotFound: gnome is a group of projects. To report a bug,
243 you need to specify which of these projects the
244- bug applies to: applets, evolution,
245- gnome-terminal, gnomebaker, netapplet
246-
247-== Getting a product ==
248+ bug applies to: evolution, gnome-terminal, applets,
249+ netapplet, gnomebaker
250+
251+
252+Getting a product
253+-----------------
254
255 Getting a product is done by specifying the name of the product.
256
257@@ -59,7 +62,9 @@
258 BugTargetNotFound: There is no project named 'unassigned'
259 registered in Launchpad.
260
261-== Getting a product series ==
262+
263+Getting a product series
264+------------------------
265
266 A product series is a part of a product, so both the product and series
267 name have to be given, separated with a slash.
268@@ -89,7 +94,9 @@
269 ...
270 BugTargetNotFound: Unexpected path components: foo
271
272-== Getting a distribution ==
273+
274+Getting a distribution
275+----------------------
276
277 Getting a distribution is done by specifying the name of the
278 distribution.
279@@ -101,14 +108,18 @@
280 >>> ubuntu.name
281 u'ubuntu'
282
283-=== Getting a source package in a distribution ===
284+
285+Getting a source package in a distribution
286+..........................................
287
288 A distribution source package is a part of a distribution, so both the
289 distribution and package name has to be specified when getting such a
290 package.
291
292- >>> from lp.registry.interfaces.distributionsourcepackage import IDistributionSourcePackage
293- >>> ubuntu_evolution = AffectsEmailCommand.getBugTarget('ubuntu/evolution')
294+ >>> from lp.registry.interfaces.distributionsourcepackage import (
295+ ... IDistributionSourcePackage)
296+ >>> ubuntu_evolution = AffectsEmailCommand.getBugTarget(
297+ ... 'ubuntu/evolution')
298 >>> IDistributionSourcePackage.providedBy(ubuntu_evolution)
299 True
300 >>> ubuntu_evolution.name
301@@ -133,7 +144,9 @@
302 ...
303 BugTargetNotFound: Unexpected path components: foo
304
305-== Getting a distribution series ==
306+
307+Getting a distribution series
308+-----------------------------
309
310 A distribution series is a part of a distribution, so both the
311 distribution and series has to be specified.
312@@ -152,7 +165,8 @@
313 both.
314
315
316-== Getting a source package in a distribution series ==
317+Getting a source package in a distribution series
318+-------------------------------------------------
319
320 When getting a source package within a distribution series, the source
321 package is given after the distribution series.
322@@ -186,7 +200,9 @@
323 ...
324 BugTargetNotFound: Unexpected path components: foo
325
326-== Error correction ==
327+
328+Error correction
329+----------------
330
331 Previously the affects path was resolved in the same way, except that
332 either /distros/ or /products/ was needed in the front. Since people are
333
334=== modified file 'lib/lp/bugs/stories/guided-filebug/xx-project-guided-filebug.txt'
335--- lib/lp/bugs/stories/guided-filebug/xx-project-guided-filebug.txt 2010-06-16 15:28:35 +0000
336+++ lib/lp/bugs/stories/guided-filebug/xx-project-guided-filebug.txt 2010-12-24 16:44:20 +0000
337@@ -1,4 +1,5 @@
338-= Filing bugs on ProjectGroups =
339+Filing bugs on ProjectGroups
340+============================
341
342 Even though it's not possible to file bugs against projects directly,
343 it's still possible to file a bug from a project's main page.
344@@ -8,8 +9,8 @@
345 >>> user_browser.url
346 'http://bugs.launchpad.dev/gnome/+filebug'
347
348-The ProjectGroup filebug page is like a Product's filebug page, except that
349-it also asks for a Product. Only Products that are using Bugs are
350+The ProjectGroup filebug page is like a Product's filebug page, except
351+that it also asks for a Product. Only Products that are using Bugs are
352 shown in the list of options.
353
354 >>> user_browser.getControl('Project').options
355@@ -33,15 +34,17 @@
356 >>> user_browser.getControl('Submit Bug Report').click()
357 >>> user_browser.url
358 'http://bugs.launchpad.dev/evolution/+bug/...'
359+
360 >>> user_browser.title
361 'Bug #... in Evolution: ...Evolution crashes...'
362
363
364-== Subscribing to a similar bug ==
365+Subscribing to a similar bug
366+----------------------------
367
368 If our bug is described by one of the suggested similar bugs, we can
369-subscribe to it instead of filing a new bug. This also loosely implies
370-a "me too" vote.
371+subscribe to it instead of filing a new bug. This also loosely implies a
372+"me too" vote.
373
374 >>> user_browser.open("http://bugs.launchpad.dev/gnome/+filebug")
375 >>> user_browser.getControl('Project').value = ['evolution']
376@@ -71,7 +74,8 @@
377 This bug is already marked as affecting you.
378
379
380-== Filing a bug when there are none similar ==
381+Filing a bug when there are none similar
382+----------------------------------------
383
384 When no similar bugs are found the form works the same but appears
385 different in the user agent.
386@@ -93,22 +97,25 @@
387 >>> print similar_bugs_list
388 None
389
390-But, as before, entering a description and submitting the bug takes
391-the user to the bug page.
392+But, as before, entering a description and submitting the bug takes the
393+user to the bug page.
394
395 >>> user_browser.getControl('Further information').value = (
396 ... 'Faznambutron is a plugin designed to ...')
397 >>> user_browser.getControl('Submit Bug Report').click()
398 >>> user_browser.url
399 'http://bugs.launchpad.dev/evolution/+bug/...'
400+
401 >>> user_browser.title
402 'Bug #... in Evolution: ...Faznambutron dumps core...'
403
404
405-== Empty ProjectGroups ==
406+Empty ProjectGroups
407+-------------------
408
409-It isn't possible to file a bug against an empty project. However, we give the
410-user some feedback in this regard. We need to create a new project first.
411+It isn't possible to file a bug against an empty project. However, we
412+give the user some feedback in this regard. We need to create a new
413+project first.
414
415 >>> admin_browser.open('http://launchpad.dev/projectgroups/+new')
416 >>> admin_browser.getControl('Name:', index=0).value = 'test-group'
417@@ -121,10 +128,11 @@
418 >>> admin_browser.url
419 'http://launchpad.dev/test-group'
420
421-A user navigating to the filebug page will see an information message. The
422-user can only get to the filebug page by entering its URL directly because all
423-links to the page are disabled for empty project groups. Since there are users
424-who would navigate to the page in that manner we test it here.
425+A user navigating to the filebug page will see an information message.
426+The user can only get to the filebug page by entering its URL directly
427+because all links to the page are disabled for empty project groups.
428+Since there are users who would navigate to the page in that manner we
429+test it here.
430
431 >>> user_browser.open('http://launchpad.dev/test-group/+filebug')
432 >>> user_browser.url
433@@ -136,8 +144,8 @@
434 There are no projects registered for Test Group that use Launchpad to
435 track bugs.
436
437-If the project registrant visits the filebug page they will see an additional
438-message:
439+If the project registrant visits the filebug page they will see an
440+additional message:
441
442 >>> admin_browser.open('http://launchpad.dev/test-group/+filebug')
443
444@@ -150,17 +158,21 @@
445 it.
446
447
448-== ProjectGroups With no Products Using Launchpad Bugs ==
449+ProjectGroups With no Products Using Launchpad Bugs
450+---------------------------------------------------
451
452-If we add a new product to our test project (specifically one that doesn't use
453-Launchpad for bug tracking) information about that product will also be
454-displayed.
455+If we add a new product to our test project (specifically one that
456+doesn't use Launchpad for bug tracking) information about that product
457+will also be displayed.
458
459 >>> admin_browser.open('http://launchpad.dev/test-group/+newproduct')
460 >>> admin_browser.getControl(name='field.name', index=0).value = 'testy'
461- >>> admin_browser.getControl(name='field.displayname').value = 'Testy Product'
462- >>> admin_browser.getControl(name='field.title').value = 'A Product for Testing'
463- >>> admin_browser.getControl(name='field.summary').value = 'Used for testing'
464+ >>> admin_browser.getControl(name='field.displayname').value = (
465+ ... 'Testy Product')
466+ >>> admin_browser.getControl(name='field.title').value = (
467+ ... 'A Product for Testing')
468+ >>> admin_browser.getControl(name='field.summary').value = (
469+ ... 'Used for testing')
470 >>> admin_browser.getControl('Continue').click()
471 >>> print admin_browser.url
472 http://launchpad.dev/test-group/+newproduct
473@@ -170,8 +182,8 @@
474 >>> admin_browser.url
475 'http://launchpad.dev/testy'
476
477-The user will now see the new product on the project's +filebug page, but will
478-not be able to file a bug against it.
479+The user will now see the new product on the project's +filebug page,
480+but will not be able to file a bug against it.
481
482 >>> user_browser.reload()
483 >>> for message in find_tags_by_class(user_browser.contents,
484@@ -180,8 +192,8 @@
485 There are no projects registered for Test Group that use Launchpad to
486 track bugs.
487
488-Testy Product doesn't use define an external bug tracker and isn't registered
489-in any source packages and the user is told this.
490+Testy Product doesn't use define an external bug tracker and isn't
491+registered in any source packages and the user is told this.
492
493 >>> print extract_text(find_tag_by_id(user_browser.contents,
494 ... 'product-list-summary'))
495@@ -197,13 +209,14 @@
496 Testy Product is not registered with any source packages. You can help by
497 linking them for us.
498
499-The user will also be presented with a link to the product's overview page:
500+The user will also be presented with a link to the product's overview
501+page:
502
503 >>> user_browser.getLink('Testy Product').url
504 'http://launchpad.dev/testy'
505
506-If we set up an external bug tracker for Testy Product, this will be reflected
507-in the Test Group's filebug page.
508+If we set up an external bug tracker for Testy Product, this will be
509+reflected in the Test Group's filebug page.
510
511 >>> from zope.component import getUtility
512 >>> from canonical.launchpad.interfaces.launchpad import (
513@@ -261,44 +274,11 @@
514 External bug tracker: Debian Bug tracker.
515 Source package: Ubuntu thunderbird (File a bug here)
516
517-We should be able to follow the link to the Ubuntu thunderbird source package
518-to file a bug:
519+We should be able to follow the link to the Ubuntu thunderbird source
520+package to file a bug:
521
522 >>> user_browser.getLink('File a bug here').click()
523 >>> user_browser.url
524 'http://launchpad.dev/ubuntu/+source/thunderbird/+filebug'
525
526-If we add a second product to the project, this too will be shown on the
527-filebug page:
528-
529- >>> admin_browser.open('http://launchpad.dev/test-group/+newproduct')
530- >>> admin_browser.getControl(name='field.name', index=0).value = 'second-test'
531- >>> admin_browser.getControl(name='field.displayname').value = 'Another product'
532- >>> admin_browser.getControl(name='field.title').value = 'For Testing'
533- >>> admin_browser.getControl(name='field.summary').value = 'Used for testing'
534- >>> admin_browser.getControl('Continue').click()
535- >>> print admin_browser.url
536- http://launchpad.dev/test-group/+newproduct
537-
538- >>> admin_browser.getControl(name='field.licenses').value = ['GNU_GPL_V2']
539- >>> admin_browser.getControl('Complete Registration').click()
540- >>> admin_browser.url
541- 'http://launchpad.dev/second-test'
542-
543- >>> user_browser.open('http://launchpad.dev/test-group/+filebug')
544- >>> print extract_text(find_tag_by_id(user_browser.contents,
545- ... 'product-list-summary'))
546- There are 2 projects registered as part of Test Group but none of them use
547- Launchpad as their bug tracker.
548-
549- >>> for tag in find_tags_by_class(
550- ... user_browser.contents, 'product-bug-options'):
551- ... print extract_text(tag)
552- Another product
553- Another product does not use an external bug tracker or has not registered
554- it with launchpad.
555- Another product is not registered with any source packages. You can help
556- by linking them for us.
557- Testy Product
558- External bug tracker: Debian Bug tracker.
559- Source package: Ubuntu thunderbird (File a bug here)
560+
561
562=== modified file 'lib/lp/registry/browser/product.py'
563--- lib/lp/registry/browser/product.py 2010-12-16 19:59:20 +0000
564+++ lib/lp/registry/browser/product.py 2010-12-24 16:44:20 +0000
565@@ -1070,14 +1070,6 @@
566 def browserLanguages(self):
567 return helpers.browserLanguages(self.request)
568
569- def projproducts(self):
570- """Return a list of other products from the same project as this
571- product, excluding this product"""
572- if self.context.project is None:
573- return []
574- return [product for product in self.context.project.products
575- if product.id != self.context.id]
576-
577 def getClosedBugsURL(self, series):
578 status = [status.title for status in RESOLVED_BUGTASK_STATUSES]
579 url = canonical_url(series) + '/+bugs'
580
581=== modified file 'lib/lp/registry/codesofconduct/README'
582--- lib/lp/registry/codesofconduct/README 2005-10-31 18:29:12 +0000
583+++ lib/lp/registry/codesofconduct/README 2010-12-24 16:44:20 +0000
584@@ -1,8 +1,5 @@
585 = Code of Conducts Directory =
586
587-Author: CelsoProvidelo
588-Date: 20050217
589-
590 This directory should store all the CoC (Code of Conducts) releases for
591 within the launchpad System.
592
593
594=== modified file 'lib/lp/registry/doc/milestone.txt'
595--- lib/lp/registry/doc/milestone.txt 2010-10-18 22:24:59 +0000
596+++ lib/lp/registry/doc/milestone.txt 2010-12-24 16:44:20 +0000
597@@ -1,12 +1,15 @@
598-= Milestones =
599+Milestones
600+==========
601
602-A milestone is a significant event in a project. In Malone, milestones can be
603-defined to assign bug fixes to a specific release of some software.
604+A milestone is a significant event in a project. In Malone, milestones
605+can be defined to assign bug fixes to a specific release of some
606+software.
607
608 This document is about milestones in Malone.
609
610
611-== Working with Milestones in Malone ==
612+Working with Milestones in Malone
613+---------------------------------
614
615 All Milestone creation and retrieval is done through IMilestoneSet.
616 IMilestoneSet can be accessed as a utility.
617@@ -19,8 +22,8 @@
618 >>> sorted(ms.id for ms in milestoneset)
619 [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
620
621-To create a new Milestone, use the .newMilestone(name, dateexpected=None)
622-method of a ProductSeries or DistroSeries:
623+To create a new Milestone, use the .newMilestone(name,
624+dateexpected=None) method of a ProductSeries or DistroSeries:
625
626 >>> from lp.registry.interfaces.product import IProductSet
627 >>> productset = getUtility(IProductSet)
628@@ -28,6 +31,7 @@
629 >>> ff_onedotzero = upstream_firefox.getSeries('1.0')
630
631 # Only owners, experts, or admins can create a milestone.
632+
633 >>> login('test@canonical.com')
634 >>> firefox_ms = ff_onedotzero.newMilestone(
635 ... name="1.0rc1", code_name="Candidate One",
636@@ -40,10 +44,13 @@
637
638 >>> print firefox_ms.name
639 1.0rc1
640+
641 >>> print firefox_ms.code_name
642 Candidate One
643+
644 >>> print firefox_ms.displayname
645 Mozilla Firefox 1.0rc1
646+
647 >>> print firefox_ms.title
648 Mozilla Firefox 1.0rc1 "Candidate One"
649
650@@ -56,6 +63,7 @@
651
652 >>> print firefox_ms.target.displayname
653 Mozilla Firefox
654+
655 >>> print firefox_ms.series_target.name
656 1.0
657
658@@ -64,11 +72,12 @@
659 >>> firefox_ms_1_0 = milestoneset.get(1)
660 >>> print firefox_ms_1_0.name
661 1.0
662+
663 >>> print firefox_ms_1_0.displayname
664 Mozilla Firefox 1.0
665
666-Of course, you can also get them off a Product or Distribution using
667-the getMilestone() method:
668+Of course, you can also get them off a Product or Distribution using the
669+getMilestone() method:
670
671 >>> ms = upstream_firefox.getMilestone('1.0rc1')
672 >>> print ms.name
673@@ -88,22 +97,30 @@
674 >>> krunch = kubuntu.getSeries('krunch')
675
676 # Only owners, experts, or admins can create a milestone.
677+
678 >>> login('mark@example.com')
679 >>> new_ms = krunch.newMilestone('1.3rc2')
680 >>> print new_ms.name
681 1.3rc2
682+
683 >>> print new_ms.code_name
684 None
685+
686 >>> print new_ms.displayname
687 Kubuntu 1.3rc2
688+
689 >>> print new_ms.title
690 Kubuntu 1.3rc2
691+
692 >>> print new_ms.target.name
693 kubuntu
694+
695 >>> print new_ms.series_target.name
696 krunch
697+
698 >>> print kubuntu.getMilestone('foo2.3')
699 None
700+
701 >>> print kubuntu.getMilestone('1.3rc2').dateexpected
702 None
703
704@@ -116,20 +133,21 @@
705 NotFoundError: 'Milestone with ID -1 does not exist'
706
707
708-== ProjectGroup Milestones ==
709+ProjectGroup Milestones
710+-----------------------
711
712 The database associates milestones only with products and distroseries.
713-The interface IProjectGroupMilestone provides a virtual view of milestones
714-that are related to a project by collecting all milestones that are
715-associated with products that belong to a project.
716-
717-The class ProjectMilestone collects the milestone names from products that
718-belong to one project and creates virtual milestones for each distinct
719-name.
720-
721-project.all_milestones returns all milestones for this project. No product
722-belonging to the Gnome project has any milestones, hence Gnome itself has
723-neither any milestones.
724+The interface IProjectGroupMilestone provides a virtual view of
725+milestones that are related to a project by collecting all milestones
726+that are associated with products that belong to a project.
727+
728+The class ProjectMilestone collects the milestone names from products
729+that belong to one project and creates virtual milestones for each
730+distinct name.
731+
732+project.all_milestones returns all milestones for this project. No
733+product belonging to the Gnome project has any milestones, hence Gnome
734+itself has neither any milestones.
735
736 >>> from lp.registry.interfaces.projectgroup import IProjectGroupSet
737 >>> gnome = getUtility(IProjectGroupSet)['gnome']
738@@ -137,11 +155,12 @@
739 ... print '%s %s' % (
740 ... product.name,
741 ... [milestone.title for milestone in product.all_milestones])
742- applets []
743 evolution [u'Evolution 2.1.6']
744 gnome-terminal []
745- gnomebaker []
746+ applets []
747 netapplet [u'NetApplet 1.0']
748+ gnomebaker []
749+
750 >>> print [milestone.title for milestone in gnome.all_milestones]
751 [u'GNOME 2.1.6', u'GNOME 1.0']
752
753@@ -156,6 +175,7 @@
754 >>> evolution = productset['evolution']
755 >>> print [milestone.name for milestone in evolution.all_milestones]
756 [u'2.1.6', u'1.1']
757+
758 >>> print [milestone.name for milestone in gnome.all_milestones]
759 [u'2.1.6', u'1.1', u'1.0']
760
761@@ -167,6 +187,7 @@
762 >>> applets = productset['applets']
763 >>> print [milestone.name for milestone in applets.all_milestones]
764 [u'1.1']
765+
766 >>> print [milestone.name for milestone in gnome.all_milestones]
767 [u'2.1.6', u'1.1', u'1.0']
768
769@@ -179,50 +200,61 @@
770 >>> netapplet = productset['netapplet']
771 >>> print [milestone.name for milestone in netapplet.all_milestones]
772 [u'1.1.', u'1.0']
773+
774 >>> print [milestone.name for milestone in gnome.all_milestones]
775 [u'2.1.6', u'1.1.', u'1.1', u'1.0']
776
777 A project milestone has the same attributes as product and distribution
778-milestones, but most are None because project milestones are aggregations.
779-The code_name and series attributes are always none.
780+milestones, but most are None because project milestones are
781+aggregations. The code_name and series attributes are always none.
782
783 >>> project_milestone = gnome.all_milestones[0]
784 >>> print project_milestone.name
785 2.1.6
786+
787 >>> print project_milestone.code_name
788 None
789+
790 >>> print project_milestone.displayname
791 GNOME 2.1.6
792+
793 >>> print project_milestone.title
794 GNOME 2.1.6
795+
796 >>> print project_milestone.target.name
797 gnome
798+
799 >>> print project_milestone.series_target
800 None
801
802-A project milestone is active, if at least one product milestone with the
803-same name is active.
804+A project milestone is active, if at least one product milestone with
805+the same name is active.
806
807 >>> from canonical.launchpad.ftests import syncUpdate
808 >>> print applets_1_1.active, evolution_1_1.active
809 True True
810+
811 >>> print gnome.getMilestone('1.1').active
812 True
813+
814 >>> applets_1_1.active = False
815 >>> syncUpdate(applets_1_1)
816 >>> print gnome.getMilestone('1.1').active
817 True
818+
819 >>> evolution_1_1.active = False
820 >>> syncUpdate(evolution_1_1)
821 >>> print gnome.getMilestone('1.1').active
822 False
823
824-A project milestone is not shown for active milestones from inactive products.
825+A project milestone is not shown for active milestones from inactive
826+products.
827
828 >>> print [milestone.name for milestone in gnome.milestones]
829 [u'1.1.']
830
831 # Unlink the source packages so the project can be deactivated.
832+
833 >>> from lp.testing import unlink_source_packages
834 >>> unlink_source_packages(netapplet)
835 >>> netapplet.active = False
836@@ -231,42 +263,46 @@
837 []
838
839 # Reset the product back to original status so future tests pass.
840+
841 >>> netapplet.active = True
842 >>> syncUpdate(netapplet)
843
844-
845-The dateexpected attribute is set to the minimum of the dateexpected values
846-of the product milestones.
847+The dateexpected attribute is set to the minimum of the dateexpected
848+values of the product milestones.
849
850 >>> print applets_1_1.dateexpected, evolution_1_1.dateexpected
851 None None
852+
853 >>> print gnome.getMilestone('1.1').dateexpected
854 None
855+
856 >>> from datetime import datetime
857 >>> applets_1_1.dateexpected = datetime(2007, 4, 2)
858 >>> syncUpdate(applets_1_1)
859 >>> print gnome.getMilestone('1.1').dateexpected
860 2007-04-02 00:00:00
861+
862 >>> evolution_1_1.dateexpected = datetime(2007, 4, 1)
863 >>> syncUpdate(evolution_1_1)
864 >>> print gnome.getMilestone('1.1').dateexpected
865 2007-04-01 00:00:00
866
867-All bugtasks that are associated with a product milestone are also associated
868-with the project milestone of the same name. For details, see
869+All bugtasks that are associated with a product milestone are also
870+associated with the project milestone of the same name. For details, see
871 bugtask-search.txt
872
873 All specifications that are associated with a product milestone are also
874-associated with the project milestone of the same name. No product of the
875-Gnome project has yet any specifications.
876+associated with the project milestone of the same name. No product of
877+the Gnome project has yet any specifications.
878
879 >>> for product in gnome.products:
880 ... print product.name, list(product.all_specifications)
881- applets []
882 evolution []
883 gnome-terminal []
884- gnomebaker []
885+ applets []
886 netapplet []
887+ gnomebaker []
888+
889 >>> print list(gnome.getMilestone('1.1').specifications)
890 []
891
892@@ -276,11 +312,13 @@
893 >>> spec = test_helper.createSpecification('1.1', 'applets')
894 >>> [spec.name for spec in applets.all_specifications]
895 [u'applets-specification']
896+
897 >>> [spec.name for spec in gnome.getMilestone('1.1').specifications]
898 [u'applets-specification']
899
900
901-== Target change notifications ==
902+Target change notifications
903+---------------------------
904
905 When we change the milestone for a bug task, subscribers to both the old
906 milestone and the new one are notified.
907@@ -311,6 +349,7 @@
908 >>> ddaa = getUtility(IPersonSet).getByName('ddaa')
909 >>> milestone_one.addBugSubscription(cprov, cprov)
910 <StructuralSubscription at ...>
911+
912 >>> milestone_two.addBugSubscription(ddaa, ddaa)
913 <StructuralSubscription at ...>
914
915@@ -333,6 +372,7 @@
916 >>> print notification.message.chunks[0].content
917 ** Changed in: firefox
918 Milestone: 1.0 => 2.0
919+
920 >>> for recipient in notification.recipients:
921 ... print recipient.person.name, recipient.reason_header
922 cprov Subscriber (Mozilla Firefox 1.0)
923@@ -340,23 +380,27 @@
924 ...
925
926
927-== Editing milestones ==
928+Editing milestones
929+------------------
930
931-Persons with launchpad.Edit permissions for milestones may create and edit
932-them. These users play the roles of owners, drivers or Launchpad admins.
933-The name, dateexpected, summary, and active, attributes are editable.
934+Persons with launchpad.Edit permissions for milestones may create and
935+edit them. These users play the roles of owners, drivers or Launchpad
936+admins. The name, dateexpected, summary, and active, attributes are
937+editable.
938
939 >>> login_person(upstream_firefox.owner)
940 >>> fizzy_milestone = ff_onedotzero.newMilestone('fuzzy')
941
942 >>> print fizzy_milestone.name
943 fuzzy
944+
945 >>> fizzy_milestone.name = 'fizzy'
946 >>> print fizzy_milestone.name
947 fizzy
948
949 >>> print fizzy_milestone.code_name
950 None
951+
952 >>> fizzy_milestone.code_name = 'dizzy'
953 >>> print fizzy_milestone.code_name
954 dizzy
955@@ -372,12 +416,13 @@
956
957 >>> fizzy_milestone.active
958 True
959+
960 >>> fizzy_milestone.active = False
961 >>> fizzy_milestone.active
962 False
963
964-The productseries attribute can be edited if the milestones belongs to
965-a product.
966+The productseries attribute can be edited if the milestones belongs to a
967+product.
968
969 >>> print fizzy_milestone.productseries.name
970 1.0
971@@ -388,8 +433,8 @@
972 >>> print fizzy_milestone.productseries.name
973 2.0
974
975-The driver for a milestone's target cannot change a milestone, but the driver
976-of the series_target is a release manager can can make changes.
977+The driver for a milestone's target cannot change a milestone, but the
978+driver of the series_target is a release manager can can make changes.
979
980 >>> from canonical.launchpad.webapp.authorization import check_permission
981
982@@ -407,65 +452,26 @@
983 >>> check_permission('launchpad.Edit', fizzy_milestone)
984 True
985
986-# XXX sinzui 2009-07-18 bug=40978: There are milestones in the database
987-# that are missing their series_target. The project owner can edit the
988-# milestone to fix the issue. It is not possible in this scenario for the
989-# milestone to have a driver.
990-
991- >>> login_person(upstream_firefox.owner)
992-
993-Hack the milestone to put it in an invalid state.
994- >>> fizzy_milestone.productseries = None
995- >>> check_permission('launchpad.Edit', fizzy_milestone)
996- True
997- >>> login_person(driver)
998- >>> check_permission('launchpad.Edit', fizzy_milestone)
999- False
1000-
1001-The distroseries attribute can be edited if the milestone belongs to
1002-a distribution.
1003-
1004- >>> from lp.registry.interfaces.distribution import (
1005- ... IDistributionSet)
1006-
1007- # The factory makes the right kind of generic object for this test,
1008- # but the test needs to use getUtility to get a security proxied object.
1009- >>> bell_distro = factory.makeDistribution('bell')
1010- >>> transaction.commit()
1011- >>> bell_distro = getUtility(IDistributionSet).getByName('bell')
1012- >>> login_person(bell_distro.owner)
1013- >>> book_series = bell_distro.newSeries(
1014- ... 'book', 'Book', 'title', 'summary', 'description',
1015- ... '1.n', None, bell_distro.owner)
1016- >>> ink_milestone = book_series.newMilestone('ink')
1017- >>> print ink_milestone.distroseries.name
1018- book
1019-
1020- >>> candle_series = bell_distro.newSeries(
1021- ... 'candle', 'candle', 'title', 'summary', 'description',
1022- ... '2.n', book_series, bell_distro.owner)
1023- >>> ink_milestone.distroseries = candle_series
1024- >>> print ink_milestone.distroseries.name
1025- candle
1026-
1027-
1028-== Deleting a milestone ==
1029+
1030+Deleting a milestone
1031+--------------------
1032
1033 A milestone can be deleted using its destroySelf() method, as long as it
1034-doesn't have an IProductRelease associated with it, nor any bugtasks
1035-or specifications targeted to it.
1036+doesn't have an IProductRelease associated with it, nor any bugtasks or
1037+specifications targeted to it.
1038
1039 >>> owner = getUtility(IPersonSet).getByName('name12')
1040 >>> login_person(owner)
1041 >>> milestone = ff_onedotzero.newMilestone('1.0.10')
1042 >>> print milestone.product_release
1043 None
1044+
1045 >>> milestone.destroySelf()
1046 >>> print upstream_firefox.getMilestone('1.0.10')
1047 None
1048
1049-If a milestone has a product release associated with it though, it can not be
1050-deleted.
1051+If a milestone has a product release associated with it though, it can
1052+not be deleted.
1053
1054 >>> from datetime import datetime
1055 >>> from pytz import UTC
1056@@ -516,8 +522,8 @@
1057 Closing milestone targeted bugs
1058 -------------------------------
1059
1060-When a milestone with bug tasks creates a release, those bug tasks in fix
1061-committed status are updated to fix released. An ObjectModifiedEvent
1062+When a milestone with bug tasks creates a release, those bug tasks in
1063+fix committed status are updated to fix released. An ObjectModifiedEvent
1064 event is signaled for each changed bug task.
1065
1066 >>> from canonical.launchpad.ftests.event import TestEventListener
1067@@ -550,3 +556,5 @@
1068 <DBItem BugTaskStatus.TRIAGED, (21) Triaged>
1069
1070 >>> bugtask_event_listener.unregister()
1071+
1072+
1073
1074=== modified file 'lib/lp/registry/doc/projectgroup.txt'
1075--- lib/lp/registry/doc/projectgroup.txt 2010-11-16 22:39:59 +0000
1076+++ lib/lp/registry/doc/projectgroup.txt 2010-12-24 16:44:20 +0000
1077@@ -23,7 +23,7 @@
1078 >>> evolution.translations_usage = ServiceUsage.LAUNCHPAD
1079 >>> logout()
1080 >>> login('test@canonical.com')
1081- >>> transaction.commit()
1082+ >>> transaction.commit()
1083
1084 Creating new projects
1085 ---------------------
1086@@ -121,8 +121,9 @@
1087 .products property. Note that only active products are included and they're
1088 ordered by their names.
1089
1090- >>> [product.name for product in gnome.products]
1091- [u'applets', u'evolution', u'gnome-terminal', u'gnomebaker', u'netapplet']
1092+ >>> [product.displayname for product in gnome.products]
1093+ [u'Evolution', u'GNOME Terminal', u'Gnome Applets', u'NetApplet',
1094+ u'gnomebaker']
1095
1096 >>> netapplet = gnome.getProduct('netapplet')
1097
1098@@ -131,8 +132,8 @@
1099 >>> unlink_source_packages(netapplet)
1100 >>> netapplet.active = False
1101 >>> flush_database_updates()
1102- >>> [product.name for product in gnome.products]
1103- [u'applets', u'evolution', u'gnome-terminal', u'gnomebaker']
1104+ >>> [product.displayname for product in gnome.products]
1105+ [u'Evolution', u'GNOME Terminal', u'Gnome Applets', u'gnomebaker']
1106
1107 # Re-activate netapplet so that we don't interfere in other tests below.
1108 >>> netapplet.active = True
1109
1110=== modified file 'lib/lp/registry/model/projectgroup.py'
1111--- lib/lp/registry/model/projectgroup.py 2010-12-01 20:53:19 +0000
1112+++ lib/lp/registry/model/projectgroup.py 2010-12-24 16:44:20 +0000
1113@@ -169,7 +169,8 @@
1114
1115 @property
1116 def products(self):
1117- return Product.selectBy(project=self, active=True, orderBy='name')
1118+ return Product.selectBy(
1119+ project=self, active=True, orderBy='displayname')
1120
1121 def getProduct(self, name):
1122 return Product.selectOneBy(project=self, name=name)
1123@@ -193,7 +194,7 @@
1124 Join(ProductSeries, Product.id == ProductSeries.productID),
1125 Join(POTemplate, ProductSeries.id == POTemplate.productseriesID),
1126 ]
1127- # XXX j.c.sackett 2010-11-19 bug=677532 It's less than ideal that
1128+ # XXX j.c.sackett 2010-11-19 bug=677532 It's less than ideal that
1129 # this query is using _translations_usage, but there's no cleaner
1130 # way to deal with it. Once the bug above is resolved, this should
1131 # should be fixed to use translations_usage.
1132
1133=== modified file 'lib/lp/registry/stories/project/xx-project-index.txt'
1134--- lib/lp/registry/stories/project/xx-project-index.txt 2010-09-28 00:07:37 +0000
1135+++ lib/lp/registry/stories/project/xx-project-index.txt 2010-12-24 16:44:20 +0000
1136@@ -29,11 +29,11 @@
1137
1138 >>> print extract_text(find_tag_by_id(anon_browser.contents, 'products'))
1139 Projects
1140- Gnome Applets
1141 Evolution
1142 GNOME Terminal
1143+ Gnome Applets
1144+ NetApplet
1145 gnomebaker
1146- NetApplet
1147 ...
1148
1149 The projects are linked.