Merge lp:~bac/launchpad/clarity into lp:launchpad

Proposed by Brad Crittenden
Status: Merged
Approved by: Jelmer Vernooij
Approved revision: no longer in the source branch.
Merged at revision: 11025
Proposed branch: lp:~bac/launchpad/clarity
Merge into: lp:launchpad
Diff against target: 785 lines (+249/-111)
26 files modified
lib/canonical/launchpad/interfaces/launchpad.py (+1/-1)
lib/canonical/launchpad/webapp/menu.py (+0/-1)
lib/lp/bugs/browser/bugrole.py (+0/-13)
lib/lp/bugs/browser/tests/test_bugsupervisor.py (+1/-10)
lib/lp/bugs/browser/tests/test_configure_bugtracker_links.py (+105/-0)
lib/lp/bugs/interfaces/bugsupervisor.py (+8/-1)
lib/lp/bugs/interfaces/bugtarget.py (+4/-3)
lib/lp/bugs/interfaces/securitycontact.py (+4/-1)
lib/lp/bugs/stories/bug-also-affects/xx-upstream-bugtracker-links.txt (+3/-2)
lib/lp/bugs/stories/bug-release-management/50-defer-distribution-bug.txt (+4/-1)
lib/lp/bugs/stories/bug-release-management/60-defer-product-bug.txt (+4/-1)
lib/lp/bugs/stories/bugtask-management/xx-bug-privileged-statuses.txt (+3/-4)
lib/lp/bugs/stories/guided-filebug/xx-bug-reporting-guidelines.txt (+9/-9)
lib/lp/bugs/templates/bugtarget-bugs.pt (+12/-2)
lib/lp/bugs/templates/bugtarget-macros-filebug.pt (+1/-1)
lib/lp/registry/browser/distribution.py (+2/-20)
lib/lp/registry/browser/distributionsourcepackage.py (+2/-5)
lib/lp/registry/browser/pillar.py (+31/-2)
lib/lp/registry/browser/product.py (+5/-18)
lib/lp/registry/help/driver.html (+26/-0)
lib/lp/registry/interfaces/product.py (+5/-4)
lib/lp/registry/stories/person/xx-person-home.txt (+4/-3)
lib/lp/registry/stories/product/xx-product-launchpad-usage.txt (+3/-3)
lib/lp/registry/templates/person-portlet-contact-details.pt (+2/-2)
lib/lp/registry/templates/pillar-involvement-portlet.pt (+0/-1)
lib/lp/registry/templates/product-index.pt (+10/-3)
To merge this branch: bzr merge lp:~bac/launchpad/clarity
Reviewer Review Type Date Requested Status
Jelmer Vernooij (community) code Approve
Matthew Revell (community) text Approve
Review via email: mp+27747@code.launchpad.net

Description of the change

= Summary =

This branch fixes a slew of bugs related to better wording for various
concepts and other small improvements. The bugs are:

* Bug #91905: Better text for: Product>Bugs>Change Bug Contact
* Bug #91911: Better text for: Product>Bugs>Change Security Contact

 - Simply change the wording in the interface.

* Bug #305482: <project/project-group/distro>/+edit page shows
  misleading instructions for bug reporting guidelines

 - Reword the instructions for entering bug reporting guidelines. Also
change the display to say "Ubuntu bug reporting guidelines" rather than
the older, terse "Ubuntu guidelines".

* Bug #419020: there's no help on the meaning of 'driver' or 'bug
  supervisor'

 - Add a pop-up help page with the definition of driver. Fix the
description of bug supervisor.

* Bug #240369: Editing bug-reporting guidelines should start from Bugs

 - Add a link on the bugs page in the involvement portlet for setting
the bug tracker. Required some refactoring of the bugs menus and the
introduction of a PillarBugsMenu superclass.

Before and after screenshot can be found at:
http://people.canonical.com/~bac/claritynow/

== Proposed fix ==

As above.

== Pre-implementation notes ==

Calls with Curtis.

== Implementation details ==

As above.

== Tests ==

So many tests are affected it is best just to run all registry and bugs
tests:

bin/test -vvm lp.registry
bin/test -vvm lp.bugs

== Demo and Q/A ==

Visit the following URLs and examine the new text:

https://launchpad.dev/applets/+configure-bugtracker
https://launchpad.dev/applets/+securitycontact
https://launchpad.dev/applets/+bugsupervisor
https://launchpad.dev/applets and click on the driver (?) link

= 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/browser/tests/test_configure_bugtracker_links.py
  lib/lp/bugs/browser/bugrole.py
  lib/lp/registry/templates/product-index.pt
  lib/canonical/launchpad/interfaces/launchpad.py
  lib/lp/bugs/templates/bugtarget-macros-filebug.pt
  lib/lp/bugs/stories/guided-filebug/xx-bug-reporting-guidelines.txt
  lib/lp/registry/browser/product.py
  lib/lp/registry/stories/person/xx-person-home.txt
  lib/lp/bugs/stories/bugtask-management/xx-bug-privileged-statuses.txt
  lib/lp/registry/browser/distributionsourcepackage.py
  lib/lp/registry/interfaces/product.py
  lib/lp/registry/templates/person-portlet-contact-details.pt
  lib/lp/bugs/stories/bug-release-management/50-defer-distribution-bug.txt
  lib/lp/registry/browser/pillar.py
  lib/lp/bugs/interfaces/securitycontact.py
  lib/lp/bugs/browser/tests/test_bugsupervisor.py
  lib/lp/bugs/stories/bug-release-management/60-defer-product-bug.txt
  lib/lp/registry/templates/pillar-involvement-portlet.pt
  lib/lp/registry/stories/product/xx-product-launchpad-usage.txt
  lib/lp/bugs/interfaces/bugtarget.py
  lib/lp/bugs/templates/bugtarget-bugs.pt
  lib/canonical/launchpad/webapp/menu.py
  lib/lp/bugs/interfaces/bugsupervisor.py
  lib/lp/registry/help/driver.html
  lib/lp/registry/browser/distribution.py
  lib/lp/bugs/stories/bug-also-affects/xx-upstream-bugtracker-links.txt

== Pyflakes notices ==

lib/lp/registry/browser/distribution.py
    9: undefined name 'DistributionLanguagePackAdminView' in __all__
    538: local variable 'more_than_five' is assigned to but never used

== Pylint notices ==

lib/lp/registry/interfaces/product.py
    796: [C0322, IProductSet.createProduct] Operator not preceded by a space
    freshmeatproject='freshmeat_project', wikiurl='wiki_url',
    ^
    downloadurl='download_url',
    sourceforgeproject='sourceforge_project',
    programminglang='programming_lang')
    @export_factory_operation(
    IProduct, ['name', 'displayname', 'title', 'summary', 'description',
    'project', 'homepageurl', 'screenshotsurl',
    'downloadurl', 'freshmeatproject', 'wikiurl',
    'sourceforgeproject', 'programminglang',
    'license_reviewed', 'licenses', 'license_info',
    'registrant'])
    @export_operation_as('new_project')
    def createProduct(owner, name, displayname, title, summary,
    description=None, project=None, homepageurl=None,
    screenshotsurl=None, wikiurl=None,
    downloadurl=None, freshmeatproject=None,
    sourceforgeproject=None, programminglang=None,
    license_reviewed=False, mugshot=None, logo=None,
    icon=None, licenses=None, license_info=None,
    registrant=None):

lib/lp/bugs/interfaces/bugtarget.py
    69: [C0322, IHasBugs.searchTasks] Operator not preceded by a space
    value_type=Text(),
    ^
    required=False),
    search_text=copy_field(IBugTaskSearch['searchtext']),
    status=copy_field(IBugTaskSearch['status']),
    importance=copy_field(IBugTaskSearch['importance']),
    assignee=Reference(schema=Interface),
    bug_reporter=Reference(schema=Interface),
    bug_supervisor=Reference(schema=Interface),
    bug_commenter=Reference(schema=Interface),
    bug_subscriber=Reference(schema=Interface),
    structural_subscriber=Reference(schema=Interface),
    owner=Reference(schema=Interface),
    affected_user=Reference(schema=Interface),
    has_patch=copy_field(IBugTaskSearch['has_patch']),
    has_cve=copy_field(IBugTaskSearch['has_cve']),
    tags=copy_field(IBugTaskSearch['tag']),
    tags_combinator=copy_field(IBugTaskSearch['tags_combinator']),
    omit_duplicates=copy_field(IBugTaskSearch['omit_dupes']),
    omit_targeted=copy_field(IBugTaskSearch['omit_targeted']),
    status_upstream=copy_field(IBugTaskSearch['status_upstream']),
    milestone_assignment=copy_field(
    IBugTaskSearch['milestone_assignment']),
    milestone=copy_field(IBugTaskSearch['milestone']),
    component=copy_field(IBugTaskSearch['component']),
    nominated_for=Reference(schema=Interface),
    has_no_package=copy_field(IBugTaskSearch['has_no_package']),
    hardware_bus=Choice(
    title=u'The bus of a hardware device related to a bug',

    vocabulary=DBEnumeratedType, required=False),
    hardware_vendor_id=TextLine(
    title=(
    u"The vendor ID of a hardware device related to a bug."),
    description=(
    u"Allowed values of the vendor ID depend on the bus of the "
    "device.nn"
    "Vendor IDs of PCI, PCCard and USB devices are hexadecimal "
    "string representations of 16 bit integers in the format "
    "'0x01ab': The prefix '0x', followed by exactly 4 digits; "
    "where a digit is one of the characters 0..9, a..f. The "
    "characters A..F are not allowed.nn"
    "SCSI vendor IDs are strings with exactly 8 characters. "
    "Shorter names are right-padded with space (0x20) characters."
    "nn"
    "IDs for other buses may be arbitrary strings."),
    required=False),
    hardware_product_id=TextLine(
    title=(
    u"The product ID of a hardware device related to a bug."),
    description=(
    u"Allowed values of the product ID depend on the bus of the "
    "device.nn"
    "Product IDs of PCI, PCCard and USB devices are hexadecimal "
    "string representations of 16 bit integers in the format "
    "'0x01ab': The prefix '0x', followed by exactly 4 digits; "
    "where a digit is one of the characters 0..9, a..f. The "
    "characters A..F are not allowed.nn"
    "SCSI product IDs are strings with exactly 16 characters. "
    "Shorter names are right-padded with space (0x20) characters."
    "nn"
    "IDs for other buses may be arbitrary strings."),
    required=False),
    hardware_driver_name=TextLine(
    title=(
    u"The driver controlling a hardware device related to a "
    "bug."),
    required=False),
    hardware_driver_package_name=TextLine(
    title=(
    u"The package of the driver which controls a hardware "
    "device related to a bug."),
    required=False),
    hardware_owner_is_bug_reporter=Bool(
    title=(
    u"Search for bugs reported by people who own the given "
    "device or who use the given hardware driver."),
    required=False),
    hardware_owner_is_affected_by_bug=Bool(
    title=(
    u"Search for bugs where people affected by a bug own the "
    "given device or use the given hardware driver."),
    required=False),
    hardware_owner_is_subscribed_to_bug=Bool(
    title=(
    u"Search for bugs where a bug subscriber owns the "
    "given device or uses the given hardware driver."),
    required=False),
    hardware_is_linked_to_bug=Bool(
    title=(
    u"Search for bugs which are linked to hardware reports "
    "which contain the given device or whcih contain a device"
    "controlled by the given driver."),
    required=False),
    linked_branches=Choice(
    title=(
    u"Search for bugs that are linked to branches or for bugs "
    "that are not linked to branches."),
    vocabulary=BugBranchSearch, required=False))
    @operation_returns_collection_of(IBugTask)
    @export_read_operation()
    def searchTasks(search_params, user=None,
    order_by=None, search_text=None,
    status=None, importance=None,
    assignee=None, bug_reporter=None, bug_supervisor=None,
    bug_commenter=None, bug_subscriber=None, owner=None,
    affected_user=None, has_patch=None, has_cve=None,
    distribution=None, tags=None,
    tags_combinator=BugTagsSearchCombinator.ALL,
    omit_duplicates=True, omit_targeted=None,
    status_upstream=None, milestone_assignment=None,
    milestone=None, component=None, nominated_for=None,
    sourcepackagename=None, has_no_package=None,
    hardware_bus=None, hardware_vendor_id=None,
    hardware_product_id=None, hardware_driver_name=None,
    hardware_driver_package_name=None,
    hardware_owner_is_bug_reporter=None,
    hardware_owner_is_affected_by_bug=False,
    hardware_owner_is_subscribed_to_bug=False,
    hardware_is_linked_to_bug=False, linked_branches=None,
    structural_subscriber=None):

lib/lp/bugs/interfaces/bugsupervisor.py
    31: [C0301] Line too long (79/78)

I'll take care of this last lint issue.

To post a comment you must log in.
Revision history for this message
Matthew Revell (matthew.revell) wrote :

Thank you for doing this work, Brad. This will greatly help.

I have one small suggestion and it is not a show-stopper: I wonder if "Incomplete" in lib/canonical/launchpad/interfaces/launchpad.py should link to https://help.launchpad.net/Bugs/Statuses ... I'm not certain it should, I'm just offering it for your consideration.

review: Approve (text)
Revision history for this message
Jelmer Vernooij (jelmer) wrote :

Nice work, another step towards a less overwhelming project page for new users.

I don't see any issues, though I noticed two small formatting glitches:

There doesn't appear to be a (trivial) docstring in lib/lp/bugs/browser/tests/test_configure_bugtracker_links.py

There appears to be a missing whileline above the definition of PillarBugsMenu in lib/lp/registry/browser/pillar.py.

review: Approve (code)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/canonical/launchpad/interfaces/launchpad.py'
2--- lib/canonical/launchpad/interfaces/launchpad.py 2010-05-18 23:19:36 +0000
3+++ lib/canonical/launchpad/interfaces/launchpad.py 2010-06-17 15:28:31 +0000
4@@ -636,5 +636,5 @@
5 official_anything = Bool (
6 title=_('Uses Launchpad for something'),)
7 enable_bug_expiration = Bool(
8- title=_('Expire Incomplete bug reports when they become inactive'),
9+ title=_('Expire "Incomplete" bug reports when they become inactive'),
10 required=True)
11
12=== modified file 'lib/canonical/launchpad/webapp/menu.py'
13--- lib/canonical/launchpad/webapp/menu.py 2010-01-21 23:50:03 +0000
14+++ lib/canonical/launchpad/webapp/menu.py 2010-06-17 15:28:31 +0000
15@@ -10,7 +10,6 @@
16 'get_current_view',
17 'get_facet',
18 'structured',
19- 'translate_if_msgid',
20 'FacetMenu',
21 'ApplicationMenu',
22 'ContextMenu',
23
24=== modified file 'lib/lp/bugs/browser/bugrole.py'
25--- lib/lp/bugs/browser/bugrole.py 2010-05-25 20:36:49 +0000
26+++ lib/lp/bugs/browser/bugrole.py 2010-06-17 15:28:31 +0000
27@@ -79,19 +79,6 @@
28
29 def changeBugSupervisor(self, bug_supervisor):
30 self.context.setBugSupervisor(bug_supervisor, self.user)
31- if bug_supervisor is not None:
32- self.request.response.addNotification(structured(
33- 'Successfully changed the bug supervisor to '
34- '<a href="%(supervisor_url)s">%(displayname)s</a>.'
35- '<br /><a href="%(supervisor_url)s">%(displayname)s</a> '
36- 'has also been subscribed to bug notifications for '
37- '%(targetname)s.<br />You can '
38- '<a href="%(targeturl)s/+subscribe">change the '
39- 'subscriptions</a> for %(targetname)s at any time.',
40- supervisor_url=canonical_url(bug_supervisor),
41- displayname=bug_supervisor.displayname,
42- targetname=self.context.displayname,
43- targeturl=canonical_url(self.context)))
44
45 def validateSecurityContact(self, data):
46 """Validates the new security contact.
47
48=== modified file 'lib/lp/bugs/browser/tests/test_bugsupervisor.py'
49--- lib/lp/bugs/browser/tests/test_bugsupervisor.py 2010-06-08 20:42:35 +0000
50+++ lib/lp/bugs/browser/tests/test_bugsupervisor.py 2010-06-17 15:28:31 +0000
51@@ -65,16 +65,7 @@
52 self.assertEqual([], view.errors)
53 self.assertEqual(self.product.bug_supervisor, self.owner)
54 notifications = view.request.response.notifications
55- self.assertEqual(1, len(notifications))
56- expected = (
57- 'Successfully changed the bug supervisor to '
58- '<a href="http://launchpad.dev/~splat">&lt;splat /&gt;</a>.'
59- '<br /><a href="http://launchpad.dev/~splat">&lt;splat /&gt;</a> '
60- 'has also been subscribed to bug notifications for '
61- '&lt;boing /&gt;.<br />You can '
62- '<a href="http://launchpad.dev/boing/+subscribe">change '
63- 'the subscriptions</a> for &lt;boing /&gt; at any time.')
64- self.assertEqual(expected, notifications.pop().message)
65+ self.assertEqual(0, len(notifications))
66
67 def test_owner_appoint_self_from_another(self):
68 self.product.setBugSupervisor(self.team, self.owner)
69
70=== added file 'lib/lp/bugs/browser/tests/test_configure_bugtracker_links.py'
71--- lib/lp/bugs/browser/tests/test_configure_bugtracker_links.py 1970-01-01 00:00:00 +0000
72+++ lib/lp/bugs/browser/tests/test_configure_bugtracker_links.py 2010-06-17 15:28:31 +0000
73@@ -0,0 +1,105 @@
74+# Copyright 2010 Canonical Ltd. This software is licensed under the
75+# GNU Affero General Public License version 3 (see the file LICENSE).
76+
77+"""Unit tests for bug tracker configuration link visibility."""
78+
79+__metaclass__ = type
80+
81+import unittest
82+
83+from canonical.launchpad.ftests import ANONYMOUS, login
84+from canonical.launchpad.layers import BugsLayer
85+from canonical.testing import LaunchpadFunctionalLayer
86+
87+from lp.testing import login_person, TestCaseWithFactory
88+from lp.testing.views import create_initialized_view
89+
90+from lp.registry.browser.product import ProductBugsMenu
91+from lp.registry.browser.distribution import DistributionBugsMenu
92+from lp.registry.browser.distributionsourcepackage import (
93+ DistributionSourcePackageBugsMenu)
94+
95+
96+class TestConfigureBugTrackerBase(TestCaseWithFactory):
97+
98+ layer = LaunchpadFunctionalLayer
99+
100+ def setUp(self):
101+ super(TestConfigureBugTrackerBase, self).setUp()
102+ login('test@canonical.com')
103+ self.target = self.makeTarget()
104+ self.menu = self.getMenu()
105+ self.view = create_initialized_view(self.target, name="+index",
106+ layer=BugsLayer)
107+
108+ def makeTarget(self):
109+ raise NotImplementedError
110+
111+ def getOwner(self):
112+ return self.target.owner
113+
114+
115+class TestConfigureBugTrackerProduct(TestConfigureBugTrackerBase):
116+
117+ def makeTarget(self):
118+ return self.factory.makeProduct(name="vuvuzela")
119+
120+ def getMenu(self):
121+ return ProductBugsMenu(self.target)
122+
123+ def test_link_visible_to_owner(self):
124+ login_person(self.getOwner())
125+ link = self.menu.configure_bugtracker()
126+ self.assertTrue(link.enabled, "Link not enabled")
127+
128+ def test_link_visible_to_admin(self):
129+ login('foo.bar@canonical.com')
130+ link = self.menu.configure_bugtracker()
131+ self.assertTrue(link.enabled, "Link not enabled")
132+
133+ def test_not_visible_to_regular_user(self):
134+ login('no-priv@canonical.com')
135+ link = self.menu.configure_bugtracker()
136+ self.assertFalse(link.enabled, "Link enabled")
137+
138+ def test_not_visible_to_anon(self):
139+ login(ANONYMOUS)
140+ link = self.menu.configure_bugtracker()
141+ self.assertFalse(link.enabled, "Link enabled")
142+
143+
144+class TestConfigureBugTrackerDistro(TestConfigureBugTrackerBase):
145+
146+ def makeTarget(self):
147+ return self.factory.makeDistribution()
148+
149+ def getMenu(self):
150+ return DistributionBugsMenu(self.target)
151+
152+ def test_link_not_present(self):
153+ login_person(self.getOwner())
154+ self.assertFalse(hasattr(self.menu, 'configure_bugtracker'))
155+
156+
157+class TestConfigureBugTrackerDSP(TestConfigureBugTrackerDistro):
158+
159+ def makeTarget(self):
160+ return self.factory.makeDistributionSourcePackage()
161+
162+ def getMenu(self):
163+ return DistributionSourcePackageBugsMenu(self.target)
164+
165+ def getOwner(self):
166+ return self.target.distribution.owner
167+
168+
169+def test_suite():
170+ suite = unittest.TestSuite()
171+ suite.addTest(unittest.makeSuite(TestConfigureBugTrackerProduct))
172+ suite.addTest(unittest.makeSuite(TestConfigureBugTrackerDistro))
173+ suite.addTest(unittest.makeSuite(TestConfigureBugTrackerDSP))
174+ return suite
175+
176+
177+if __name__ == '__main__':
178+ unittest.TextTestRunner().run(test_suite())
179
180=== modified file 'lib/lp/bugs/interfaces/bugsupervisor.py'
181--- lib/lp/bugs/interfaces/bugsupervisor.py 2010-06-08 20:42:35 +0000
182+++ lib/lp/bugs/interfaces/bugsupervisor.py 2010-06-17 15:28:31 +0000
183@@ -27,7 +27,14 @@
184 bug_supervisor = exported(ParticipatingPersonChoice(
185 title=_("Bug Supervisor"),
186 description=_(
187- "The person or team responsible for bug management."),
188+ "The Launchpad id of the person or team (preferred) responsible "
189+ "for bug management. The bug supervisor will be subscribed to "
190+ "all bugs and will receive email about all activity on all bugs "
191+ "for this project, so that should be a factor in your decision. "
192+ "The bug supervisor will also have access to all private bugs."),
193+
194+
195+
196 required=False, vocabulary='ValidPersonOrTeam', readonly=True))
197
198 @mutator_for(bug_supervisor)
199
200=== modified file 'lib/lp/bugs/interfaces/bugtarget.py'
201--- lib/lp/bugs/interfaces/bugtarget.py 2010-06-09 08:26:26 +0000
202+++ lib/lp/bugs/interfaces/bugtarget.py 2010-06-17 15:28:31 +0000
203@@ -231,11 +231,12 @@
204 bug_reporting_guidelines = exported(
205 Text(
206 title=(
207- u"If I\N{right single quotation mark}m reporting a bug, "
208- u"I should include, if possible"),
209+ u"Helpful guidelines for reporting a bug"),
210 description=(
211 u"These guidelines will be shown to "
212- "anyone reporting a bug."),
213+ "everyone reporting a bug and should be "
214+ "text or a bulleted list with your particular "
215+ "requirements, if any."),
216 required=False,
217 max_length=50000))
218
219
220=== modified file 'lib/lp/bugs/interfaces/securitycontact.py'
221--- lib/lp/bugs/interfaces/securitycontact.py 2010-05-18 21:24:27 +0000
222+++ lib/lp/bugs/interfaces/securitycontact.py 2010-06-17 15:28:31 +0000
223@@ -25,5 +25,8 @@
224 security_contact = exported(PublicPersonChoice(
225 title=_("Security Contact"),
226 description=_(
227- "The person or team who handles security-related bug reports"),
228+ "The Launchpad id of the person or team (preferred) who handles "
229+ "security-related bug reports. The security contact will be "
230+ "subscribed to all bugs marked as a security vulnerability and "
231+ "will receive email about all activity on all security bugs."),
232 required=False, vocabulary='ValidPersonOrTeam'))
233
234=== modified file 'lib/lp/bugs/stories/bug-also-affects/xx-upstream-bugtracker-links.txt'
235--- lib/lp/bugs/stories/bug-also-affects/xx-upstream-bugtracker-links.txt 2010-05-19 21:22:00 +0000
236+++ lib/lp/bugs/stories/bug-also-affects/xx-upstream-bugtracker-links.txt 2010-06-17 15:28:31 +0000
237@@ -122,10 +122,11 @@
238
239 >>> admin_browser.open(
240 ... 'http://launchpad.dev/thunderbird/+configure-bugtracker')
241- >>> admin_browser.getControl('Remote project').value = 'Thunderbird'
242+ >>> admin_browser.getControl('Remote bug tracker project id').value = (
243+ ... 'Thunderbird')
244 >>> admin_browser.getControl('Change').click()
245
246 >>> admin_browser.open(
247 ... 'http://launchpad.dev/thunderbird/+configure-bugtracker')
248- >>> print admin_browser.getControl('Remote project').value
249+ >>> print admin_browser.getControl('Remote bug tracker project id').value
250 Thunderbird
251
252=== modified file 'lib/lp/bugs/stories/bug-release-management/50-defer-distribution-bug.txt'
253--- lib/lp/bugs/stories/bug-release-management/50-defer-distribution-bug.txt 2009-06-12 16:36:02 +0000
254+++ lib/lp/bugs/stories/bug-release-management/50-defer-distribution-bug.txt 2010-06-17 15:28:31 +0000
255@@ -25,7 +25,10 @@
256
257 >>> for tag in find_tags_by_class(admin_browser.contents, 'message'):
258 ... print tag.renderContents()
259- Successfully changed the bug supervisor to...No Privileges Person...
260+
261+ >>> print extract_text(find_tag_by_id(admin_browser.contents, 'bug-supervisor'))
262+ Bug supervisor:
263+ No Privileges Person
264
265 >>> user_browser.reload()
266
267
268=== modified file 'lib/lp/bugs/stories/bug-release-management/60-defer-product-bug.txt'
269--- lib/lp/bugs/stories/bug-release-management/60-defer-product-bug.txt 2009-06-12 16:36:02 +0000
270+++ lib/lp/bugs/stories/bug-release-management/60-defer-product-bug.txt 2010-06-17 15:28:31 +0000
271@@ -25,7 +25,10 @@
272
273 >>> for tag in find_tags_by_class(admin_browser.contents, 'message'):
274 ... print tag.renderContents()
275- Successfully changed the bug supervisor to...No Privileges Person...
276+
277+ >>> print extract_text(find_tag_by_id(admin_browser.contents, 'bug-supervisor'))
278+ Bug supervisor:
279+ No Privileges Person
280
281 >>> user_browser.reload()
282
283
284=== modified file 'lib/lp/bugs/stories/bugtask-management/xx-bug-privileged-statuses.txt'
285--- lib/lp/bugs/stories/bugtask-management/xx-bug-privileged-statuses.txt 2009-09-02 22:13:06 +0000
286+++ lib/lp/bugs/stories/bugtask-management/xx-bug-privileged-statuses.txt 2010-06-17 15:28:31 +0000
287@@ -57,9 +57,9 @@
288 ... 'test@canonical.com')
289 >>> admin_browser.getControl('Change').click()
290
291- >>> for tag in find_tags_by_class(admin_browser.contents, 'message'):
292- ... print tag.renderContents()
293- Successfully changed the bug supervisor to...Sample Person...
294+ >>> print extract_text(find_tag_by_id(admin_browser.contents, 'bug-supervisor'))
295+ Bug supervisor:
296+ Sample Person
297
298 The new Bug Supervisor for Ubuntu can change the status to Won't Fix:
299
300@@ -124,4 +124,3 @@
301 http://bugs.launchpad.dev/ubuntu/+source/iceweasel/+bug/1
302 >>> print_highlighted_bugtask(bug_supervisor_browser)
303 iceweasel (Ubuntu) ... Triaged Medium Unassigned ...
304-
305
306=== modified file 'lib/lp/bugs/stories/guided-filebug/xx-bug-reporting-guidelines.txt'
307--- lib/lp/bugs/stories/guided-filebug/xx-bug-reporting-guidelines.txt 2010-06-14 15:52:41 +0000
308+++ lib/lp/bugs/stories/guided-filebug/xx-bug-reporting-guidelines.txt 2010-06-17 15:28:31 +0000
309@@ -65,32 +65,32 @@
310 *
311 Ubuntu
312 <http://launchpad.dev/ubuntu/+filebug>
313- Ubuntu guidelines:
314+ Ubuntu bug reporting guidelines:
315 The version of Ubuntu you're using.
316 Thank you for filing a bug for Ubuntu
317 *
318 Mozilla
319 <http://launchpad.dev/mozilla/+filebug>
320- The Mozilla Project guidelines:
321+ The Mozilla Project bug reporting guidelines:
322 The version of Mozilla you're using.
323 Thank you for filing a bug for Mozilla
324 *
325 Firefox
326 <http://launchpad.dev/firefox/+filebug>
327- Mozilla Firefox guidelines:
328+ Mozilla Firefox bug reporting guidelines:
329 The version of Firefox you're using.
330 Thank you for filing a bug for Firefox
331 *
332 alsa-utils in Ubuntu
333 <http://launchpad.dev/ubuntu/+source/alsa-utils/+filebug>
334- alsa-utils (Ubuntu) guidelines:
335+ alsa-utils (Ubuntu) bug reporting guidelines:
336 The version of alsa-utils in Ubuntu you're using.
337- Ubuntu guidelines:
338+ Ubuntu bug reporting guidelines:
339 The version of Ubuntu you're using.
340 Thank you for filing a bug for alsa-utils in Ubuntu
341
342 Note how the alsa-utils in Ubuntu specific guidelines were displayed
343-followed by the general Ubuntu guidelines.
344+followed by the general Ubuntu bug reporting guidelines.
345
346 Bugs can also be reported directly against a distribution series, for
347 which the guidelines are taken from the respective distribution.
348@@ -101,7 +101,7 @@
349 >>> user_browser.getControl('Continue').click()
350 >>> print extract_text(find_tag_by_id(
351 ... user_browser.contents, 'bug-reporting-guidelines'))
352- Ubuntu guidelines:
353+ Ubuntu bug reporting guidelines:
354 The version of Ubuntu you're using.
355
356
357@@ -127,7 +127,7 @@
358 >>> user_browser.getControl('Continue').click()
359 >>> print extract_text(find_tag_by_id(
360 ... user_browser.contents, 'bug-reporting-guidelines'))
361- Ubuntu guidelines:
362+ Ubuntu bug reporting guidelines:
363 The version of Ubuntu you're using.
364
365 Changing the package to alsa-utils does not make the alsa-utils
366@@ -139,7 +139,7 @@
367 ... name='field.packagename').value = "alsa-utils"
368 >>> print extract_text(find_tag_by_id(
369 ... user_browser.contents, 'bug-reporting-guidelines'))
370- Ubuntu guidelines:
371+ Ubuntu bug reporting guidelines:
372 The version of Ubuntu you're using.
373
374 XXX: allenap 2008-11-14 bug=297743: These limitations have been filed
375
376=== modified file 'lib/lp/bugs/templates/bugtarget-bugs.pt'
377--- lib/lp/bugs/templates/bugtarget-bugs.pt 2010-06-09 13:58:08 +0000
378+++ lib/lp/bugs/templates/bugtarget-bugs.pt 2010-06-17 15:28:31 +0000
379@@ -16,8 +16,8 @@
380 </metal:block>
381 <body>
382 <tal:side metal:fill-slot="side" condition="view/uses_launchpad_bugtracker">
383- <div id="involvement" class="portlet involvement">
384- <ul>
385+ <div id="involvement" class="portlet">
386+ <ul class="involvement">
387 <li style="border: none">
388 <a href="+filebug" class="menu-link-filebug sprite bugs">
389 Report a bug
390@@ -32,6 +32,16 @@
391 </a>
392 </li>
393 </ul>
394+ <tal:bugtracker
395+ define="link context/menu:bugs/configure_bugtracker|nothing"
396+ condition="link">
397+ <ul tal:condition="link/enabled"
398+ style="padding-top: 1em">
399+ <li>
400+ <a tal:replace="structure link/fmt:link" />
401+ </li>
402+ </ul>
403+ </tal:bugtracker>
404 </div>
405 <div class="portlet">
406 <dl tal:define="bug_supervisor context/bug_supervisor"
407
408=== modified file 'lib/lp/bugs/templates/bugtarget-macros-filebug.pt'
409--- lib/lp/bugs/templates/bugtarget-macros-filebug.pt 2010-06-14 13:54:39 +0000
410+++ lib/lp/bugs/templates/bugtarget-macros-filebug.pt 2010-06-17 15:28:31 +0000
411@@ -353,7 +353,7 @@
412 tal:condition="guidelines">
413 <td colspan="2" id="bug-reporting-guidelines">
414 <tal:guidelines repeat="guideline guidelines">
415- <h3><span tal:replace="guideline/source" /> guidelines:</h3>
416+ <h3><span tal:replace="guideline/source" /> bug reporting guidelines:</h3>
417 <div tal:content="structure guideline/content/fmt:text-to-html" />
418 </tal:guidelines>
419 </td>
420
421=== modified file 'lib/lp/registry/browser/distribution.py'
422--- lib/lp/registry/browser/distribution.py 2010-06-14 15:52:41 +0000
423+++ lib/lp/registry/browser/distribution.py 2010-06-17 15:28:31 +0000
424@@ -51,6 +51,7 @@
425 from lp.registry.browser.announcement import HasAnnouncementsView
426 from lp.registry.browser.menu import (
427 IRegistryCollectionNavigationMenu, RegistryCollectionActionMenuBase)
428+from lp.registry.browser.pillar import PillarBugsMenu
429 from lp.bugs.browser.bugtask import BugTargetTraversalMixin
430 from lp.answers.browser.faqtarget import FAQTargetNavigationMixin
431 from canonical.launchpad.browser.feeds import FeedsMixin
432@@ -73,7 +74,6 @@
433 from lp.soyuz.interfaces.publishedpackage import (
434 IPublishedPackageSet)
435 from lp.registry.browser.structuralsubscription import (
436- StructuralSubscriptionMenuMixin,
437 StructuralSubscriptionTargetTraversalMixin)
438 from canonical.launchpad.webapp import (
439 action, ApplicationMenu, canonical_url, ContextMenu, custom_widget,
440@@ -415,7 +415,7 @@
441 return Link('+addseries', text, icon='add')
442
443
444-class DistributionBugsMenu(ApplicationMenu, StructuralSubscriptionMenuMixin):
445+class DistributionBugsMenu(PillarBugsMenu):
446
447 usedfor = IDistribution
448 facet = 'bugs'
449@@ -427,24 +427,6 @@
450 'subscribe',
451 )
452
453- def cve(self):
454- text = 'CVE reports'
455- return Link('+cve', text, icon='cve')
456-
457- @enabled_with_permission('launchpad.Edit')
458- def bugsupervisor(self):
459- text = 'Change bug supervisor'
460- return Link('+bugsupervisor', text, icon='edit')
461-
462- @enabled_with_permission('launchpad.Edit')
463- def securitycontact(self):
464- text = 'Change security contact'
465- return Link('+securitycontact', text, icon='edit')
466-
467- def filebug(self):
468- text = 'Report a bug'
469- return Link('+filebug', text, icon='bug')
470-
471
472 class DistributionSpecificationsMenu(NavigationMenu,
473 HasSpecificationsMenuMixin):
474
475=== modified file 'lib/lp/registry/browser/distributionsourcepackage.py'
476--- lib/lp/registry/browser/distributionsourcepackage.py 2010-06-14 15:52:41 +0000
477+++ lib/lp/registry/browser/distributionsourcepackage.py 2010-06-17 15:28:31 +0000
478@@ -41,6 +41,7 @@
479 QuestionTargetFacetMixin, QuestionTargetTraversalMixin)
480 from lp.answers.interfaces.questionenums import QuestionStatus
481 from lp.bugs.browser.bugtask import BugTargetTraversalMixin
482+from lp.registry.browser.pillar import PillarBugsMenu
483 from lp.soyuz.browser.sourcepackagerelease import (
484 extract_bug_numbers, extract_email_addresses, linkify_changelog)
485 from lp.soyuz.interfaces.archive import IArchiveSet
486@@ -107,16 +108,12 @@
487
488
489 class DistributionSourcePackageBugsMenu(
490- DistributionSourcePackageOverviewMenu):
491+ PillarBugsMenu, DistributionSourcePackageLinksMixin):
492
493 usedfor = IDistributionSourcePackage
494 facet = 'bugs'
495 links = ['filebug', 'subscribe']
496
497- def filebug(self):
498- text = 'Report a bug'
499- return Link('+filebug', text, icon='bug')
500-
501
502 class DistributionSourcePackageNavigation(Navigation,
503 BugTargetTraversalMixin, HasCustomLanguageCodesTraversalMixin,
504
505=== modified file 'lib/lp/registry/browser/pillar.py'
506--- lib/lp/registry/browser/pillar.py 2010-05-03 18:28:16 +0000
507+++ lib/lp/registry/browser/pillar.py 2010-06-17 15:28:31 +0000
508@@ -1,4 +1,4 @@
509-# Copyright 2009 Canonical Ltd. This software is licensed under the
510+# Copyright 2009-2010 Canonical Ltd. This software is licensed under the
511 # GNU Affero General Public License version 3 (see the file LICENSE).
512
513 """Common views for objects that implement `IPillar`."""
514@@ -8,6 +8,7 @@
515 __all__ = [
516 'InvolvedMenu',
517 'PillarView',
518+ 'PillarBugsMenu',
519 ]
520
521
522@@ -16,10 +17,13 @@
523 from zope.interface import implements, Interface
524
525 from canonical.cachedproperty import cachedproperty
526-from canonical.launchpad.webapp.menu import Link, NavigationMenu
527+from canonical.launchpad.webapp.menu import (
528+ ApplicationMenu, enabled_with_permission, Link, NavigationMenu)
529 from canonical.launchpad.webapp.publisher import LaunchpadView, nearest
530 from canonical.launchpad.webapp.tales import MenuAPI
531
532+from lp.registry.browser.structuralsubscription import (
533+ StructuralSubscriptionMenuMixin)
534 from lp.registry.interfaces.distroseries import IDistroSeries
535 from lp.registry.interfaces.distributionsourcepackage import (
536 IDistributionSourcePackage)
537@@ -149,3 +153,28 @@
538 return sorted([
539 link for link in important_links if not link.enabled],
540 key=attrgetter('sort_key'))
541+
542+
543+class PillarBugsMenu(ApplicationMenu, StructuralSubscriptionMenuMixin):
544+ """Base class for pillar bugs menus."""
545+
546+ facet = 'bugs'
547+ configurable_bugtracker = False
548+
549+ @enabled_with_permission('launchpad.Edit')
550+ def bugsupervisor(self):
551+ text = 'Change bug supervisor'
552+ return Link('+bugsupervisor', text, icon='edit')
553+
554+ def cve(self):
555+ text = 'CVE reports'
556+ return Link('+cve', text, icon='cve')
557+
558+ def filebug(self):
559+ text = 'Report a bug'
560+ return Link('+filebug', text, icon='bug')
561+
562+ @enabled_with_permission('launchpad.Edit')
563+ def securitycontact(self):
564+ text = 'Change security contact'
565+ return Link('+securitycontact', text, icon='edit')
566
567=== modified file 'lib/lp/registry/browser/product.py'
568--- lib/lp/registry/browser/product.py 2010-06-11 04:02:27 +0000
569+++ lib/lp/registry/browser/product.py 2010-06-17 15:28:31 +0000
570@@ -95,6 +95,7 @@
571 from lp.registry.browser.distribution import UsesLaunchpadMixin
572 from lp.registry.browser.menu import (
573 IRegistryCollectionNavigationMenu, RegistryCollectionActionMenuBase)
574+from lp.registry.browser.pillar import PillarBugsMenu
575 from lp.answers.browser.faqtarget import FAQTargetNavigationMixin
576 from canonical.launchpad.browser.feeds import FeedsMixin
577 from lp.registry.browser.pillar import PillarView
578@@ -555,7 +556,8 @@
579 return Link('+addbranch', text, summary, icon='add')
580
581
582-class ProductBugsMenu(ApplicationMenu, StructuralSubscriptionMenuMixin):
583+class ProductBugsMenu(PillarBugsMenu,
584+ ProductEditLinksMixin):
585
586 usedfor = IProduct
587 facet = 'bugs'
588@@ -565,24 +567,9 @@
589 'securitycontact',
590 'cve',
591 'subscribe',
592+ 'configure_bugtracker',
593 )
594-
595- def filebug(self):
596- text = 'Report a bug'
597- return Link('+filebug', text, icon='bug')
598-
599- def cve(self):
600- return Link('+cve', 'CVE reports', icon='cve')
601-
602- @enabled_with_permission('launchpad.Edit')
603- def bugsupervisor(self):
604- text = 'Change bug supervisor'
605- return Link('+bugsupervisor', text, icon='edit')
606-
607- @enabled_with_permission('launchpad.Edit')
608- def securitycontact(self):
609- text = 'Change security contact'
610- return Link('+securitycontact', text, icon='edit')
611+ configurable_bugtracker = True
612
613
614 class ProductSpecificationsMenu(NavigationMenu, ProductEditLinksMixin,
615
616=== added file 'lib/lp/registry/help/driver.html'
617--- lib/lp/registry/help/driver.html 1970-01-01 00:00:00 +0000
618+++ lib/lp/registry/help/driver.html 2010-06-17 15:28:31 +0000
619@@ -0,0 +1,26 @@
620+<html>
621+ <head>
622+ <title>What is a project driver?</title>
623+ <link rel="stylesheet" type="text/css"
624+ href="/+icing/yui/cssreset/reset.css" />
625+ <link rel="stylesheet" type="text/css"
626+ href="/+icing/yui/cssfonts/fonts.css" />
627+ <link rel="stylesheet" type="text/css"
628+ href="/+icing/yui/cssbase/base.css" />
629+ </head>
630+ <body>
631+ <h1>What is a project driver?</h1>
632+
633+ <p>
634+ The project driver is a person or team who is responsible for setting
635+ the direction for the project. The driver can set goals, approve bug
636+ targeting, or set backporting for <b>any</b> major series in the
637+ project.
638+ </p>
639+ <p>
640+ Alternatively, you can chose to leave the project driver unset and
641+ appoint a team for each series.
642+ </p>
643+
644+ </body>
645+</html>
646
647=== modified file 'lib/lp/registry/interfaces/product.py'
648--- lib/lp/registry/interfaces/product.py 2010-05-24 21:39:43 +0000
649+++ lib/lp/registry/interfaces/product.py 2010-06-17 15:28:31 +0000
650@@ -663,9 +663,10 @@
651
652 remote_product = exported(
653 TextLine(
654- title=_('Remote project'), required=False,
655+ title=_('Remote bug tracker project id'), required=False,
656 description=_(
657- "The ID of this project on its remote bug tracker.")))
658+ "Some bug trackers host multiple projects at the same URL "
659+ "and require an identifier for the specific project.")))
660
661 def redeemSubscriptionVoucher(voucher, registrant, purchaser,
662 subscription_months, whiteboard=None,
663@@ -731,8 +732,8 @@
664
665
666 class IProduct(
667- IHasBugSupervisor, IProductEditRestricted,
668- IProductProjectReviewRestricted, IProductDriverRestricted,
669+ IHasBugSupervisor, IProductEditRestricted,
670+ IProductProjectReviewRestricted, IProductDriverRestricted,
671 IProductPublic, IRootContext, IStructuralSubscriptionTarget):
672 """A Product.
673
674
675=== modified file 'lib/lp/registry/stories/person/xx-person-home.txt'
676--- lib/lp/registry/stories/person/xx-person-home.txt 2010-03-23 21:59:13 +0000
677+++ lib/lp/registry/stories/person/xx-person-home.txt 2010-06-17 15:28:31 +0000
678@@ -58,11 +58,12 @@
679 >>> user_browser.open('http://launchpad.dev/~no-priv')
680 >>> print extract_text(
681 ... find_tag_by_id(user_browser.contents, 'openid-info'))
682- OpenID login: http://launchpad.dev/~no-priv ...
683+ OpenID login:
684+ http://launchpad.dev/~no-priv
685
686 The URL is followed by a helpful link.
687
688- >>> print user_browser.getLink('(What\xe2\x80\x99s\xc2\xa0this?)').url
689+ >>> print user_browser.getLink('openid help').url
690 http://launchpad.dev/+help/openid.html
691
692 However, when the user visits someone else's page, they see no such URL.
693@@ -73,7 +74,7 @@
694
695 And there is no helpful link.
696
697- >>> print user_browser.getLink(u"What&#8217;s\xa0this?").url
698+ >>> print user_browser.getLink('openid help').url
699 Traceback (most recent call last):
700 ...
701 LinkNotFoundError
702
703=== modified file 'lib/lp/registry/stories/product/xx-product-launchpad-usage.txt'
704--- lib/lp/registry/stories/product/xx-product-launchpad-usage.txt 2010-04-09 02:25:21 +0000
705+++ lib/lp/registry/stories/product/xx-product-launchpad-usage.txt 2010-06-17 15:28:31 +0000
706@@ -39,7 +39,7 @@
707 ... 'In Launchpad').selected
708 True
709 >>> registrant_browser.getControl(
710- ... 'Expire Incomplete bug reports when they '
711+ ... 'Expire "Incomplete" bug reports when they '
712 ... 'become inactive').selected
713 False
714 >>> registrant_browser.getControl('Somewhere else').selected = True
715@@ -152,7 +152,7 @@
716 True
717
718 >>> registrant_browser.getControl(
719- ... 'Expire Incomplete bug reports when they '
720+ ... 'Expire "Incomplete" bug reports when they '
721 ... 'become inactive').selected
722 True
723
724@@ -173,6 +173,6 @@
725 False
726
727 >>> registrant_browser.getControl(
728- ... 'Expire Incomplete bug reports when they '
729+ ... 'Expire "Incomplete" bug reports when they '
730 ... 'become inactive').selected
731 False
732
733=== modified file 'lib/lp/registry/templates/person-portlet-contact-details.pt'
734--- lib/lp/registry/templates/person-portlet-contact-details.pt 2010-04-19 02:45:43 +0000
735+++ lib/lp/registry/templates/person-portlet-contact-details.pt 2010-06-17 15:28:31 +0000
736@@ -67,8 +67,8 @@
737 <dd>
738 <img src="/@@/private" alt="" />
739 <tal:openid-login content="view/openid_identity_url" />
740- <a target="help" href="/+help/openid.html"
741- >(What&rsquo;s&nbsp;this?)</a>
742+ <a target="help" href="/+help/openid.html" class="icon">
743+ <img src="/@@/maybe" alt="openid help" /></a>
744 </dd>
745 </dl>
746
747
748=== modified file 'lib/lp/registry/templates/pillar-involvement-portlet.pt'
749--- lib/lp/registry/templates/pillar-involvement-portlet.pt 2010-03-19 16:06:30 +0000
750+++ lib/lp/registry/templates/pillar-involvement-portlet.pt 2010-06-17 15:28:31 +0000
751@@ -10,7 +10,6 @@
752 <li tal:repeat="link view/enabled_links">
753 <a tal:replace="structure link/fmt:link" />
754 </li>
755-
756 <tal:disabled repeat="link view/visible_disabled_links">
757 <li tal:condition="not: link/enabled"
758 tal:attributes="title string:Launchpad needs to know where the user can ${link/text/lower}"
759
760=== modified file 'lib/lp/registry/templates/product-index.pt'
761--- lib/lp/registry/templates/product-index.pt 2010-04-19 22:36:58 +0000
762+++ lib/lp/registry/templates/product-index.pt 2010-06-17 15:28:31 +0000
763@@ -79,13 +79,20 @@
764
765 <dl id="driver">
766 <dt>Driver:</dt>
767- <dd tal:condition="view/effective_driver">
768+ <dd>
769+
770+ <tal:driver_set condition="view/effective_driver">
771 <a tal:replace="structure view/effective_driver/fmt:link" />
772 <a tal:replace="structure overview_menu/reassign/fmt:icon" />
773- </dd>
774- <dd tal:condition="not: view/effective_driver">
775+ </tal:driver_set>
776+
777+ <tal:driver_unset condition="not: view/effective_driver">
778 Not yet appointed.
779 <a tal:replace="structure overview_menu/reassign/fmt:icon" />
780+ </tal:driver_unset>
781+
782+ <a target="help" href="/+help/driver.html" class="icon">
783+ <img src="/@@/maybe" alt="help" /></a>
784 </dd>
785 </dl>
786