Merge lp:~deryck/launchpad/lock-fix-released-status-126516 into lp:launchpad

Proposed by Deryck Hodge
Status: Merged
Approved by: Jelmer Vernooij
Approved revision: no longer in the source branch.
Merged at revision: 11785
Proposed branch: lp:~deryck/launchpad/lock-fix-released-status-126516
Merge into: lp:launchpad
Diff against target: 252 lines (+69/-21)
11 files modified
lib/lp/bugs/browser/tests/bugs-views.txt (+1/-1)
lib/lp/bugs/doc/bugtask.txt (+1/-1)
lib/lp/bugs/doc/displaying-bugs-and-tasks.txt (+1/-1)
lib/lp/bugs/doc/malone-karma.txt (+1/-1)
lib/lp/bugs/model/bugtask.py (+4/-3)
lib/lp/bugs/stories/bugs/xx-bug-text-pages.txt (+3/-2)
lib/lp/bugs/stories/bugs/xx-incomplete-bugs.txt (+10/-0)
lib/lp/bugs/tests/bugs-emailinterface.txt (+8/-8)
lib/lp/bugs/tests/test_bugtask_1.py (+4/-2)
lib/lp/bugs/tests/test_bugtask_status.py (+34/-0)
lib/lp/soyuz/doc/closing-bugs-from-changelogs.txt (+2/-2)
To merge this branch: bzr merge lp:~deryck/launchpad/lock-fix-released-status-126516
Reviewer Review Type Date Requested Status
Jelmer Vernooij (community) code Approve
Review via email: mp+38931@code.launchpad.net

Commit message

Lock FIXRELEASED bugtask status so that only project maintainers and bug supervisors can transition away from that status.

Description of the change

This branch locks the status FIXRELEASED so that only project
maintainers and bug supervisors can transition away from the status.
Status transitions are well tested.

./bin/test -cvvt test_bugtask_status

The widget which allows toggling status on the bug page uses
IBugTask.canTransitionToStatus to determine which statuses are
clickable. So no changes are needed to the UI.

Thanks for the review!

To post a comment you must log in.
Revision history for this message
Jelmer Vernooij (jelmer) wrote :

The line breaks for line 46 and 76 seem unnecessary, please consider removing them.

As pointed out on IRC, the linked bug report requests a slightly different change (transitioning to FIXRELEASED vs transitioning away from it).

review: Approve (code)
Revision history for this message
Deryck Hodge (deryck) wrote :

Hi, Jelmer.

I've got a new bug linked now. Thanks for catching that!

Also, I'd like to keep the line breaks. That phrasing is used throughout the tests, and longer status names require the line break. Even though these lines here don't require it, in the context of the entire test, I felt it was more readable to be consistent.

Thanks for the review!

Cheers,
deryck

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/lp/bugs/browser/tests/bugs-views.txt'
2--- lib/lp/bugs/browser/tests/bugs-views.txt 2010-10-18 22:24:59 +0000
3+++ lib/lp/bugs/browser/tests/bugs-views.txt 2010-10-21 20:54:52 +0000
4@@ -37,7 +37,7 @@
5 >>> len(bug_eight.bugtasks)
6 1
7 >>> bug_eight.bugtasks[0].transitionToStatus(
8- ... BugTaskStatus.CONFIRMED, getUtility(ILaunchBag).user)
9+ ... BugTaskStatus.CONFIRMED, bug_eight.bugtasks[0].distribution.owner)
10 >>> def fix_bug(bug_id, bugtask_index=0):
11 ... bugtask = getUtility(IBugSet).get(bug_id).bugtasks[bugtask_index]
12 ... bugtask.transitionToStatus(
13
14=== modified file 'lib/lp/bugs/doc/bugtask.txt'
15--- lib/lp/bugs/doc/bugtask.txt 2010-10-19 18:44:31 +0000
16+++ lib/lp/bugs/doc/bugtask.txt 2010-10-21 20:54:52 +0000
17@@ -1022,7 +1022,7 @@
18 And attribute setting:
19
20 >>> bug_upstream_firefox_no_svg_support.transitionToStatus(
21- ... BugTaskStatus.FIXRELEASED, getUtility(ILaunchBag).user)
22+ ... BugTaskStatus.CONFIRMED, getUtility(ILaunchBag).user)
23 >>> bug_upstream_firefox_no_svg_support.transitionToStatus(
24 ... BugTaskStatus.NEW, getUtility(ILaunchBag).user)
25
26
27=== modified file 'lib/lp/bugs/doc/displaying-bugs-and-tasks.txt'
28--- lib/lp/bugs/doc/displaying-bugs-and-tasks.txt 2010-10-19 18:44:31 +0000
29+++ lib/lp/bugs/doc/displaying-bugs-and-tasks.txt 2010-10-21 20:54:52 +0000
30@@ -164,7 +164,7 @@
31 Lastly, some cleanup:
32
33 >>> test_task.transitionToStatus(
34- ... ORIGINAL_STATUS, getUtility(ILaunchBag).user)
35+ ... ORIGINAL_STATUS, test_task.distribution.owner)
36 >>> test_task.transitionToAssignee(ORIGINAL_ASSIGNEE)
37
38
39
40=== modified file 'lib/lp/bugs/doc/malone-karma.txt'
41--- lib/lp/bugs/doc/malone-karma.txt 2010-10-19 18:44:31 +0000
42+++ lib/lp/bugs/doc/malone-karma.txt 2010-10-21 20:54:52 +0000
43@@ -105,7 +105,7 @@
44
45 >>> old_bugtask = Snapshot(bugtask, providing=IDistroBugTask)
46 >>> bugtask.transitionToStatus(
47- ... BugTaskStatus.INVALID, getUtility(ILaunchBag).user)
48+ ... BugTaskStatus.INVALID, bugtask.target.owner)
49 >>> notify(ObjectModifiedEvent(bugtask, old_bugtask, ['status']))
50 Karma added: action=bugrejected, distribution=debian
51
52
53=== modified file 'lib/lp/bugs/model/bugtask.py'
54--- lib/lp/bugs/model/bugtask.py 2010-09-23 10:27:11 +0000
55+++ lib/lp/bugs/model/bugtask.py 2010-10-21 20:54:52 +0000
56@@ -891,12 +891,13 @@
57 user.id == celebrities.janitor.id):
58 return True
59 else:
60- return (self.status is not BugTaskStatus.WONTFIX and
61- new_status not in BUG_SUPERVISOR_BUGTASK_STATUSES)
62+ return (self.status not in (
63+ BugTaskStatus.WONTFIX, BugTaskStatus.FIXRELEASED)
64+ and new_status not in BUG_SUPERVISOR_BUGTASK_STATUSES)
65
66 def transitionToStatus(self, new_status, user, when=None):
67 """See `IBugTask`."""
68- if not new_status:
69+ if not new_status or user is None:
70 # This is mainly to facilitate tests which, unlike the
71 # normal status form, don't always submit a status when
72 # testing the edit form.
73
74=== modified file 'lib/lp/bugs/stories/bugs/xx-bug-text-pages.txt'
75--- lib/lp/bugs/stories/bugs/xx-bug-text-pages.txt 2010-10-09 16:36:22 +0000
76+++ lib/lp/bugs/stories/bugs/xx-bug-text-pages.txt 2010-10-21 20:54:52 +0000
77@@ -28,7 +28,8 @@
78 ... "bug-patch.diff", is_patch=True, content_type='text/plain',
79 ... description="a patch")
80
81-Next, we'll cycle through all statuses so the dates are present:
82+Next, we'll cycle through all statuses so the dates are present (to
83+toggle away from Fix Released we must be the target owner):
84
85 >>> from lp.bugs.interfaces.bugtask import BugTaskStatus
86 >>> t0 = bug.bugtasks[0]
87@@ -36,7 +37,7 @@
88 >>> t0.transitionToStatus(BugTaskStatus.CONFIRMED, mark)
89 >>> t0.transitionToStatus(BugTaskStatus.INPROGRESS, mark)
90 >>> t0.transitionToStatus(BugTaskStatus.FIXRELEASED, mark)
91- >>> t0.transitionToStatus(BugTaskStatus.NEW, mark)
92+ >>> t0.transitionToStatus(BugTaskStatus.NEW, t0.target.owner)
93 >>> t0.transitionToStatus(BugTaskStatus.FIXRELEASED, mark)
94 >>> logout()
95 >>> flush_database_updates()
96
97=== modified file 'lib/lp/bugs/stories/bugs/xx-incomplete-bugs.txt'
98--- lib/lp/bugs/stories/bugs/xx-incomplete-bugs.txt 2010-10-18 22:24:59 +0000
99+++ lib/lp/bugs/stories/bugs/xx-incomplete-bugs.txt 2010-10-21 20:54:52 +0000
100@@ -234,6 +234,16 @@
101 cannot expire. No Privileges Person sets a Debian bug to Incomplete,
102 and does not see the expiration notice.
103
104+In order for this to work, the bug cannot be FIXRELEASED, which
105+it is by default. So we set the bug back to NEW.
106+
107+ >>> from lp.bugs.interfaces.bugtask import BugTaskStatus
108+ >>> login('foo.bar@canonical.com')
109+ >>> bug_8 = getUtility(IBugSet).get(8)
110+ >>> bug_8.bugtasks[0].transitionToStatus(
111+ ... BugTaskStatus.NEW, bug_8.bugtasks[0].distribution.owner)
112+ >>> logout()
113+
114 >>> user_browser.open(
115 ... 'http://bugs.launchpad.dev/debian/+source/mozilla-firefox/+bug/8')
116 >>> user_browser.getControl('Status').value = ['Incomplete']
117
118=== modified file 'lib/lp/bugs/tests/bugs-emailinterface.txt'
119--- lib/lp/bugs/tests/bugs-emailinterface.txt 2010-10-21 01:42:14 +0000
120+++ lib/lp/bugs/tests/bugs-emailinterface.txt 2010-10-21 20:54:52 +0000
121@@ -1620,20 +1620,20 @@
122 edited:
123
124 >>> login('foo.bar@canonical.com')
125- >>> bug_eigth = getUtility(IBugSet).get(8)
126- >>> len(bug_eigth.bugtasks)
127+ >>> bug_ten = getUtility(IBugSet).get(10)
128+ >>> len(bug_ten.bugtasks)
129 1
130- >>> submit_commands(bug_eigth, 'status confirmed')
131- >>> mozilla_task = bug_eigth.bugtasks[0]
132- >>> print mozilla_task.status.name
133+ >>> submit_commands(bug_ten, 'status confirmed')
134+ >>> linux_task = bug_ten.bugtasks[0]
135+ >>> print linux_task.status.name
136 CONFIRMED
137
138 >>> bug_notification = BugNotification.selectFirst(orderBy='-id')
139 >>> print bug_notification.bug.id
140- 8
141+ 10
142 >>> print bug_notification.message.text_contents
143- ** Changed in: mozilla-firefox (Debian)
144- Status: Fix Released => Confirmed
145+ ** Changed in: linux-source-2.6.15 (Ubuntu)
146+ Status: New => Confirmed
147
148 If the bug has more than one bug task, we try to guess which bug task
149 the user wanted to edit. We apply the following heuristics for choosing
150
151=== modified file 'lib/lp/bugs/tests/test_bugtask_1.py'
152--- lib/lp/bugs/tests/test_bugtask_1.py 2010-10-04 19:50:45 +0000
153+++ lib/lp/bugs/tests/test_bugtask_1.py 2010-10-21 20:54:52 +0000
154@@ -116,9 +116,11 @@
155 def tearDownBugsElsewhereTests(self):
156 """Resets the modified bugtasks to their original statuses."""
157 self.firefox_upstream.transitionToStatus(
158- self.old_firefox_status, getUtility(ILaunchBag).user)
159+ self.old_firefox_status,
160+ self.firefox_upstream.target.bug_supervisor)
161 self.thunderbird_upstream.transitionToStatus(
162- self.old_thunderbird_status, getUtility(ILaunchBag).user)
163+ self.old_thunderbird_status,
164+ self.firefox_upstream.target.bug_supervisor)
165 flush_database_updates()
166
167 def assertBugTaskIsPendingBugWatchElsewhere(self, bugtask):
168
169=== modified file 'lib/lp/bugs/tests/test_bugtask_status.py'
170--- lib/lp/bugs/tests/test_bugtask_status.py 2010-10-18 17:29:49 +0000
171+++ lib/lp/bugs/tests/test_bugtask_status.py 2010-10-21 20:54:52 +0000
172@@ -73,6 +73,15 @@
173 UserCannotEditBugTaskStatus, self.task.transitionToStatus,
174 BugTaskStatus.CONFIRMED, self.user)
175
176+ def test_user_cannot_unset_fix_released_status(self):
177+ # A regular user should not be able to transition a bug away
178+ # from Fix Released.
179+ removeSecurityProxy(self.task).status = BugTaskStatus.FIXRELEASED
180+ with person_logged_in(self.user):
181+ self.assertRaises(
182+ UserCannotEditBugTaskStatus, self.task.transitionToStatus,
183+ BugTaskStatus.FIXRELEASED, self.user)
184+
185 def test_user_canTransitionToStatus(self):
186 # Regular user cannot transition to BUG_SUPERVISOR_BUGTASK_STATUSES,
187 # but can transition to any other status.
188@@ -129,6 +138,15 @@
189 BugTaskStatus.NEW, self.user),
190 False)
191
192+ def test_user_canTransitionToStatus_from_fixreleased(self):
193+ # A regular user cannot transition away from Fix Released,
194+ # so canTransitionToStatus should return False.
195+ removeSecurityProxy(self.task).status = BugTaskStatus.FIXRELEASED
196+ self.assertEqual(
197+ self.task.canTransitionToStatus(
198+ BugTaskStatus.NEW, self.user),
199+ False)
200+
201
202 class TestBugTaskStatusTransitionForPrivilegedUserBase:
203 """Base class used to test privileged users and status transitions."""
204@@ -188,6 +206,13 @@
205 self.task.transitionToStatus(BugTaskStatus.CONFIRMED, self.person)
206 self.assertEqual(self.task.status, BugTaskStatus.CONFIRMED)
207
208+ def test_privileged_user_can_unset_wont_fix_released(self):
209+ # Privileged users can transition away from Fix Released.
210+ removeSecurityProxy(self.task).status = BugTaskStatus.FIXRELEASED
211+ with person_logged_in(self.person):
212+ self.task.transitionToStatus(BugTaskStatus.CONFIRMED, self.person)
213+ self.assertEqual(self.task.status, BugTaskStatus.CONFIRMED)
214+
215 def test_privileged_user_canTransitionToStatus(self):
216 # Privileged users (like owner or bug supervisor) should
217 # be able to set any status, so canTransitionToStatus should
218@@ -246,6 +271,15 @@
219 BugTaskStatus.NEW, self.person),
220 True)
221
222+ def test_privileged_user_canTransitionToStatus_from_fixreleased(self):
223+ # A privileged user can transition away from Fix Released, so
224+ # canTransitionToStatus should return True.
225+ removeSecurityProxy(self.task).status = BugTaskStatus.FIXRELEASED
226+ self.assertEqual(
227+ self.task.canTransitionToStatus(
228+ BugTaskStatus.NEW, self.person),
229+ True)
230+
231
232 class TestBugTaskStatusTransitionOwnerPerson(
233 TestBugTaskStatusTransitionForPrivilegedUserBase, TestCaseWithFactory):
234
235=== modified file 'lib/lp/soyuz/doc/closing-bugs-from-changelogs.txt'
236--- lib/lp/soyuz/doc/closing-bugs-from-changelogs.txt 2010-10-17 15:44:08 +0000
237+++ lib/lp/soyuz/doc/closing-bugs-from-changelogs.txt 2010-10-21 20:54:52 +0000
238@@ -300,12 +300,12 @@
239 >>> pmount_bug = getUtility(IBugSet).get(pmount_bug_id)
240 >>> [pmount_task] = pmount_bug.bugtasks
241 >>> pmount_task.transitionToStatus(
242- ... BugTaskStatus.CONFIRMED, getUtility(ILaunchBag).user)
243+ ... BugTaskStatus.CONFIRMED, pmount_task.distribution.owner)
244
245 >>> another_pmount_bug = getUtility(IBugSet).get(another_pmount_bug_id)
246 >>> [another_pmount_task] = another_pmount_bug.bugtasks
247 >>> another_pmount_task.transitionToStatus(
248- ... BugTaskStatus.CONFIRMED, getUtility(ILaunchBag).user)
249+ ... BugTaskStatus.CONFIRMED, another_pmount_task.distribution.owner)
250
251
252 >>> print_single_task_status(pmount_bug_id)