Merge lp:~wgrant/launchpad/nomination-limitation into lp:launchpad

Proposed by William Grant
Status: Merged
Merged at revision: 18228
Proposed branch: lp:~wgrant/launchpad/nomination-limitation
Merge into: lp:launchpad
Diff against target: 208 lines (+61/-14)
6 files modified
lib/lp/bugs/browser/bug.py (+5/-2)
lib/lp/bugs/browser/bugnomination.py (+13/-8)
lib/lp/bugs/browser/tests/test_bugnomination.py (+11/-0)
lib/lp/bugs/model/bugnomination.py (+8/-1)
lib/lp/bugs/templates/bug-nominate-for-series.pt (+2/-2)
lib/lp/bugs/tests/test_bugnomination.py (+22/-1)
To merge this branch: bzr merge lp:~wgrant/launchpad/nomination-limitation
Reviewer Review Type Date Requested Status
Colin Watson (community) Approve
Review via email: mp+307672@code.launchpad.net

Commit message

Add a feature flag to open up bug targeting to bug supervisors.

Description of the change

Add a feature flag to open up bug targeting to bug supervisors.

In the beginning, bug nomination was open to everyone, and targeting was
restricted to drivers. Over time, targeting was opened up to uploaders,
and nomination locked down to bug supervisors.

Now we have requests to open targeting up further, but it would be
lovely to avoid adding yet another hardcoded role. Since the vast
majority of recent nominations are approved, let's try opening targeting
up to the (usually semi-vetted) bug supervisor and see what happens.

Setting this feature flag effectively disables the creation of new
unapproved nominations by extending targeting privileges to everyone who
can nominate.

To post a comment you must log in.
Revision history for this message
Colin Watson (cjwatson) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/lp/bugs/browser/bug.py'
2--- lib/lp/bugs/browser/bug.py 2015-10-15 14:09:50 +0000
3+++ lib/lp/bugs/browser/bug.py 2016-10-05 09:04:15 +0000
4@@ -1,4 +1,4 @@
5-# Copyright 2009-2013 Canonical Ltd. This software is licensed under the
6+# Copyright 2009-2016 Canonical Ltd. This software is licensed under the
7 # GNU Affero General Public License version 3 (see the file LICENSE).
8
9 """IBug related view classes."""
10@@ -104,6 +104,7 @@
11 get_structural_subscriptions_for_bug,
12 )
13 from lp.registry.interfaces.person import IPersonSet
14+from lp.services.features import getFeatureFlag
15 from lp.services.fields import DuplicateBug
16 from lp.services.librarian.browser import ProxiedLibraryFileAlias
17 from lp.services.mail.mailwrapper import MailWrapper
18@@ -304,7 +305,9 @@
19 """Return the 'Target/Nominate for series' Link."""
20 launchbag = getUtility(ILaunchBag)
21 target = launchbag.product or launchbag.distribution
22- if check_permission("launchpad.Driver", target):
23+ if check_permission("launchpad.Driver", target) or (
24+ getFeatureFlag('bugs.nominations.bug_supervisors_can_target')
25+ and check_permission("launchpad.BugSupervisor", target)):
26 text = "Target to series"
27 return Link('+nominate', text, icon='milestone')
28 elif (check_permission("launchpad.BugSupervisor", target) or
29
30=== modified file 'lib/lp/bugs/browser/bugnomination.py'
31--- lib/lp/bugs/browser/bugnomination.py 2014-11-28 22:07:05 +0000
32+++ lib/lp/bugs/browser/bugnomination.py 2016-10-05 09:04:15 +0000
33@@ -30,6 +30,7 @@
34 IBugNominationForm,
35 )
36 from lp.bugs.interfaces.cve import ICveSet
37+from lp.services.features import getFeatureFlag
38 from lp.services.webapp import (
39 canonical_url,
40 LaunchpadView,
41@@ -52,9 +53,9 @@
42 LaunchpadFormView.initialize(self)
43 # Update the submit label based on the user's permission.
44 submit_action = self.__class__.actions.byname['actions.submit']
45- if self.userIsReleaseManager():
46+ if self.userCanTarget():
47 submit_action.label = _("Target")
48- elif self.userIsBugSupervisor():
49+ elif self.userCanNominate():
50 submit_action.label = _("Nominate")
51 else:
52 self.request.response.addErrorNotification(
53@@ -68,19 +69,23 @@
54
55 The label returned depends on the user's privileges.
56 """
57- if self.userIsReleaseManager():
58+ if self.userCanTarget():
59 return "Target bug #%d to series" % self.context.bug.id
60 else:
61 return "Nominate bug #%d for series" % self.context.bug.id
62
63 page_title = label
64
65- def userIsReleaseManager(self):
66- """Does the current user have release management privileges?"""
67- return self.current_bugtask.userHasDriverPrivileges(self.user)
68+ def userCanTarget(self):
69+ """Can the current user target the bug to a series?"""
70+ return (
71+ self.current_bugtask.userHasDriverPrivileges(self.user)
72+ or (getFeatureFlag('bugs.nominations.bug_supervisors_can_target')
73+ and self.current_bugtask.userHasBugSupervisorPrivileges(
74+ self.user)))
75
76- def userIsBugSupervisor(self):
77- """Is the current user the bug supervisor?"""
78+ def userCanNominate(self):
79+ """Can the current user nominate the bug for a series?"""
80 return self.current_bugtask.userHasBugSupervisorPrivileges(
81 self.user)
82
83
84=== modified file 'lib/lp/bugs/browser/tests/test_bugnomination.py'
85--- lib/lp/bugs/browser/tests/test_bugnomination.py 2012-10-11 14:57:32 +0000
86+++ lib/lp/bugs/browser/tests/test_bugnomination.py 2016-10-05 09:04:15 +0000
87@@ -12,6 +12,7 @@
88 from zope.component import getUtility
89
90 from lp.registry.interfaces.series import SeriesStatus
91+from lp.services.features.testing import FeatureFixture
92 from lp.services.webapp.interaction import get_current_principal
93 from lp.services.webapp.interfaces import (
94 BrowserNotificationLevel,
95@@ -63,6 +64,16 @@
96 action = view.__class__.actions.byname['actions.submit']
97 self.assertEqual('Nominate', action.label)
98
99+ def test_submit_action_bug_supervisor_feature_flag(self):
100+ # A bug supervisor sees the Target action label when the feature
101+ # flag is enabled.
102+ self.useFixture(FeatureFixture(
103+ {'bugs.nominations.bug_supervisors_can_target': 'on'}))
104+ login_person(self.bug_worker)
105+ view = create_initialized_view(self.bug_task, name='+nominate')
106+ action = view.__class__.actions.byname['actions.submit']
107+ self.assertEqual('Target', action.label)
108+
109 def test_submit_action_driver(self):
110 # A driver sees the Target action label.
111 login_person(self.distribution.driver)
112
113=== modified file 'lib/lp/bugs/model/bugnomination.py'
114--- lib/lp/bugs/model/bugnomination.py 2015-07-08 16:05:11 +0000
115+++ lib/lp/bugs/model/bugnomination.py 2016-10-05 09:04:15 +0000
116@@ -1,4 +1,4 @@
117-# Copyright 2009 Canonical Ltd. This software is licensed under the
118+# Copyright 2009-2016 Canonical Ltd. This software is licensed under the
119 # GNU Affero General Public License version 3 (see the file LICENSE).
120
121 """Database classes related to bug nomination.
122@@ -37,6 +37,7 @@
123 from lp.services.database.datetimecol import UtcDateTimeCol
124 from lp.services.database.enumcol import EnumCol
125 from lp.services.database.sqlbase import SQLBase
126+from lp.services.features import getFeatureFlag
127
128
129 @implementer(IBugNomination)
130@@ -122,6 +123,12 @@
131 # Use the class method to check permissions because there is not
132 # yet a bugtask instance with the this target.
133 BugTask = self.bug.bugtasks[0].__class__
134+
135+ if (getFeatureFlag('bugs.nominations.bug_supervisors_can_target') and
136+ BugTask.userHasBugSupervisorPrivilegesContext(
137+ self.target, person)):
138+ return True
139+
140 if BugTask.userHasDriverPrivilegesContext(self.target, person):
141 return True
142
143
144=== modified file 'lib/lp/bugs/templates/bug-nominate-for-series.pt'
145--- lib/lp/bugs/templates/bug-nominate-for-series.pt 2010-12-21 19:11:49 +0000
146+++ lib/lp/bugs/templates/bug-nominate-for-series.pt 2016-10-05 09:04:15 +0000
147@@ -14,14 +14,14 @@
148 <div metal:use-macro="context/@@launchpad_form/form">
149
150 <div metal:fill-slot="extra_info">
151- <tal:targeting-mode condition="view/userIsReleaseManager">
152+ <tal:targeting-mode condition="view/userCanTarget">
153 <p>
154 Series targeting allows you to track the status, assignee, and
155 importance of a bug in one or more official series.
156 </p>
157 </tal:targeting-mode>
158
159- <tal:nomination-mode condition="not:view/userIsReleaseManager">
160+ <tal:nomination-mode condition="not:view/userCanTarget">
161 <p>
162 Bug nominations are evaluated by release managers and accepted
163 or declined for fixing in a series.
164
165=== modified file 'lib/lp/bugs/tests/test_bugnomination.py'
166--- lib/lp/bugs/tests/test_bugnomination.py 2012-11-26 08:33:03 +0000
167+++ lib/lp/bugs/tests/test_bugnomination.py 2016-10-05 09:04:15 +0000
168@@ -1,4 +1,4 @@
169-# Copyright 2009-2011 Canonical Ltd. This software is licensed under the
170+# Copyright 2009-2016 Canonical Ltd. This software is licensed under the
171 # GNU Affero General Public License version 3 (see the file LICENSE).
172
173 """Tests related to bug nominations."""
174@@ -14,6 +14,7 @@
175 IBugNomination,
176 IBugNominationSet,
177 )
178+from lp.services.features.testing import FeatureFixture
179 from lp.soyuz.interfaces.publishing import PackagePublishingStatus
180 from lp.testing import (
181 celebrity_logged_in,
182@@ -308,6 +309,26 @@
183 self.assertTrue(nomination.canApprove(product.driver))
184 self.assertTrue(nomination.canApprove(series.driver))
185
186+ def test_bug_supervisors_can_approve_with_feature_flag(self):
187+ product = self.factory.makeProduct(driver=self.factory.makePerson())
188+ series = self.factory.makeProductSeries(product=product)
189+ with celebrity_logged_in('admin'):
190+ product.bug_supervisor = self.factory.makePerson()
191+ product.driver = self.factory.makePerson()
192+ series.driver = self.factory.makePerson()
193+
194+ nomination = self.factory.makeBugNomination(target=series)
195+
196+ self.assertFalse(nomination.canApprove(product.bug_supervisor))
197+ self.assertTrue(nomination.canApprove(product.driver))
198+ self.assertTrue(nomination.canApprove(series.driver))
199+
200+ with FeatureFixture({
201+ 'bugs.nominations.bug_supervisors_can_target': 'on'}):
202+ self.assertTrue(nomination.canApprove(product.bug_supervisor))
203+ self.assertTrue(nomination.canApprove(product.driver))
204+ self.assertTrue(nomination.canApprove(series.driver))
205+
206 def publishSource(self, series, sourcepackagename, component):
207 return self.factory.makeSourcePackagePublishingHistory(
208 archive=series.main_archive,