Merge lp:~wallyworld/launchpad/delete-bugtask-log-activity-1324 into lp:launchpad

Proposed by Ian Booth
Status: Merged
Approved by: Aaron Bentley
Approved revision: no longer in the source branch.
Merged at revision: 14176
Proposed branch: lp:~wallyworld/launchpad/delete-bugtask-log-activity-1324
Merge into: lp:launchpad
Prerequisite: lp:~wallyworld/launchpad/delete-bugtasks-1324
Diff against target: 236 lines (+119/-10)
7 files modified
lib/lp/bugs/adapters/bugchange.py (+22/-0)
lib/lp/bugs/configure.zcml (+3/-0)
lib/lp/bugs/mail/tests/test_bug_task_deletion.py (+42/-0)
lib/lp/bugs/model/bugtask.py (+5/-1)
lib/lp/bugs/model/tests/test_bugtask.py (+1/-4)
lib/lp/bugs/subscribers/bugactivity.py (+16/-5)
lib/lp/bugs/tests/test_bugchanges.py (+30/-0)
To merge this branch: bzr merge lp:~wallyworld/launchpad/delete-bugtask-log-activity-1324
Reviewer Review Type Date Requested Status
Curtis Hovey (community) code Approve
Aaron Bentley (community) Approve
Review via email: mp+79779@code.launchpad.net

Commit message

[r=abentley,sinzui][bug=1342] Record bug activity and send email when bug task is deleted.

Description of the change

Record bug activity and send email when bug task is deleted.

== Implementation ==

Provide a new bug change class: BugTaskDeleted
Provide an event subscriber for bugtask delete events. Record the bug change activity in the subscriber.

== Tests ==

Add a new test to TestBugChanges:
  - test_bugtask_deleted

Add a new test case similar to test_bug_task_modification.TestModificationNotification"
  - test_bug_task_deletion.TestModificationNotification
(check that email is generated and correct header is present)

== Lint ==

Checking for conflicts and issues in changed files.

Linting changed files:
  lib/lp/bugs/configure.zcml
  lib/lp/bugs/adapters/bugchange.py
  lib/lp/bugs/mail/tests/test_bug_task_deletion.py
  lib/lp/bugs/model/bugtask.py
  lib/lp/bugs/subscribers/bugactivit

To post a comment you must log in.
Revision history for this message
Aaron Bentley (abentley) wrote :

Why the @block_implicit_flushes ?
If you plan on landing this branch separately from lp:~wallyworld/launchpad/delete-bugtasks-1324, I recommend creating a separate bug for it. It was a bit surprising that the linked bug was "Can't delete spurious "Affects" lines (bugtasks) from bug reports"

review: Approve
Revision history for this message
Curtis Hovey (sinzui) wrote :

This looks good to land after you fix the copyright date in test_bug_task_deletion.py.

We need to note that in when we create private projects, the bugtask.target.name may not be readable. Since this is serialised data, we will probably use <hidden name>.

review: Approve (code)
Revision history for this message
Ian Booth (wallyworld) wrote :

> Why the @block_implicit_flushes ?

I copied the existing notify_bugtask_added() method which used this.

> If you plan on landing this branch separately from lp:~wallyworld/launchpad
> /delete-bugtasks-1324, I recommend creating a separate bug for it. It was a
> bit surprising that the linked bug was "Can't delete spurious "Affects" lines
> (bugtasks) from bug reports"

This branch is part 2 of the work to fix that bug. The first branch did the core work, this one adds the activity recording. I am going to land both together.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/lp/bugs/adapters/bugchange.py'
2--- lib/lp/bugs/adapters/bugchange.py 2011-09-23 12:26:15 +0000
3+++ lib/lp/bugs/adapters/bugchange.py 2011-10-19 23:52:28 +0000
4@@ -27,6 +27,7 @@
5 'BugTaskAdded',
6 'BugTaskAssigneeChange',
7 'BugTaskBugWatchChange',
8+ 'BugTaskDeleted',
9 'BugTaskImportanceChange',
10 'BugTaskMilestoneChange',
11 'BugTaskStatusChange',
12@@ -260,6 +261,27 @@
13 }
14
15
16+class BugTaskDeleted(BugChangeBase):
17+ """A bugtask was removed from the bug."""
18+
19+ def __init__(self, when, person, bugtask):
20+ super(BugTaskDeleted, self).__init__(when, person)
21+ self.targetname = bugtask.bugtargetname
22+
23+ def getBugActivity(self):
24+ """See `IBugChange`."""
25+ return dict(
26+ whatchanged='bug task deleted',
27+ oldvalue=self.targetname)
28+
29+ def getBugNotification(self):
30+ """See `IBugChange`."""
31+ return {
32+ 'text': (
33+ "** No longer affects: %s" % self.targetname),
34+ }
35+
36+
37 class SeriesNominated(BugChangeBase):
38 """A user nominated the bug to be fixed in a series."""
39
40
41=== modified file 'lib/lp/bugs/configure.zcml'
42--- lib/lp/bugs/configure.zcml 2011-10-19 23:52:27 +0000
43+++ lib/lp/bugs/configure.zcml 2011-10-19 23:52:28 +0000
44@@ -1080,6 +1080,9 @@
45 for="lp.bugs.interfaces.bugtask.IBugTask lazr.lifecycle.interfaces.IObjectCreatedEvent"
46 handler="lp.bugs.subscribers.bugactivity.notify_bugtask_added"/>
47 <subscriber
48+ for="lp.bugs.interfaces.bugtask.IBugTask lazr.lifecycle.interfaces.IObjectDeletedEvent"
49+ handler="lp.bugs.subscribers.bugactivity.notify_bugtask_deleted"/>
50+ <subscriber
51 for="lp.bugs.interfaces.bugtask.IBugTask zope.lifecycleevent.interfaces.IObjectCreatedEvent"
52 handler="canonical.launchpad.subscribers.karma.bugtask_created"/>
53 <subscriber
54
55=== added file 'lib/lp/bugs/mail/tests/test_bug_task_deletion.py'
56--- lib/lp/bugs/mail/tests/test_bug_task_deletion.py 1970-01-01 00:00:00 +0000
57+++ lib/lp/bugs/mail/tests/test_bug_task_deletion.py 2011-10-19 23:52:28 +0000
58@@ -0,0 +1,42 @@
59+# Copyright 2010 Canonical Ltd. This software is licensed under the
60+# GNU Affero General Public License version 3 (see the file LICENSE).
61+
62+"""Test for emails sent after bug task deletion."""
63+
64+import transaction
65+from zope.component import getUtility
66+
67+from lp.bugs.model.bugnotification import BugNotification
68+from canonical.launchpad.webapp.interfaces import ILaunchBag
69+from canonical.testing.layers import DatabaseFunctionalLayer
70+from lp.bugs.scripts.bugnotification import construct_email_notifications
71+from lp.services.features.testing import FeatureFixture
72+from lp.testing import TestCaseWithFactory
73+
74+
75+class TestDeletionNotification(TestCaseWithFactory):
76+ """Test email notifications when a bug task is deleted."""
77+
78+ layer = DatabaseFunctionalLayer
79+
80+ def setUp(self):
81+ # Run the tests as a logged-in user.
82+ super(TestDeletionNotification, self).setUp(
83+ user='test@canonical.com')
84+ self.user = getUtility(ILaunchBag).user
85+ product = self.factory.makeProduct(owner=self.user)
86+ self.bug_task = self.factory.makeBugTask(target=product)
87+
88+ def test_for_bug_modifier_header(self):
89+ """Test X-Launchpad-Bug-Modifier appears when a bugtask is deleted."""
90+ flags = {u"disclosure.delete_bugtask.enabled": u"on"}
91+ with FeatureFixture(flags):
92+ self.bug_task.delete(self.user)
93+ transaction.commit()
94+ latest_notification = BugNotification.selectFirst(orderBy='-id')
95+ notifications, omitted, messages = construct_email_notifications(
96+ [latest_notification])
97+ self.assertEqual(len(notifications), 1,
98+ 'email notification not created')
99+ headers = [msg['X-Launchpad-Bug-Modifier'] for msg in messages]
100+ self.assertEqual(len(headers), len(messages))
101
102=== modified file 'lib/lp/bugs/model/bugtask.py'
103--- lib/lp/bugs/model/bugtask.py 2011-10-19 23:52:27 +0000
104+++ lib/lp/bugs/model/bugtask.py 2011-10-19 23:52:28 +0000
105@@ -29,7 +29,10 @@
106 import re
107
108 from lazr.enum import BaseItem
109-from lazr.lifecycle.event import ObjectModifiedEvent
110+from lazr.lifecycle.event import (
111+ ObjectDeletedEvent,
112+ ObjectModifiedEvent,
113+ )
114 from lazr.lifecycle.snapshot import Snapshot
115 import pytz
116 from sqlobject import (
117@@ -637,6 +640,7 @@
118 "Cannot delete bugtask: %s" % self.title)
119 bug = self.bug
120 target = self.target
121+ notify(ObjectDeletedEvent(self, who))
122 self.destroySelf()
123 del get_property_cache(bug).bugtasks
124
125
126=== modified file 'lib/lp/bugs/model/tests/test_bugtask.py'
127--- lib/lp/bugs/model/tests/test_bugtask.py 2011-10-19 23:52:27 +0000
128+++ lib/lp/bugs/model/tests/test_bugtask.py 2011-10-19 23:52:28 +0000
129@@ -9,11 +9,8 @@
130
131 from lazr.lifecycle.event import ObjectModifiedEvent
132 from lazr.lifecycle.snapshot import Snapshot
133-<<<<<<< TREE
134+from lazr.restfulclient.errors import Unauthorized
135 from testtools.testcase import ExpectedException
136-=======
137-from lazr.restfulclient.errors import Unauthorized
138->>>>>>> MERGE-SOURCE
139 from testtools.matchers import Equals
140 from zope.component import getUtility
141 from zope.event import notify
142
143=== modified file 'lib/lp/bugs/subscribers/bugactivity.py'
144--- lib/lp/bugs/subscribers/bugactivity.py 2011-02-11 22:04:25 +0000
145+++ lib/lp/bugs/subscribers/bugactivity.py 2011-10-19 23:52:28 +0000
146@@ -14,6 +14,7 @@
147 from canonical.database.sqlbase import block_implicit_flushes
148 from lp.bugs.adapters.bugchange import (
149 BugTaskAdded,
150+ BugTaskDeleted,
151 BugWatchAdded,
152 BugWatchRemoved,
153 CveLinkedToBug,
154@@ -96,11 +97,11 @@
155 @block_implicit_flushes
156 def record_bug_added(bug, object_created_event):
157 activity = getUtility(IBugActivitySet).new(
158- bug = bug.id,
159- datechanged = UTC_NOW,
160- person = IPerson(object_created_event.user),
161- whatchanged = "bug",
162- message = "added bug")
163+ bug=bug.id,
164+ datechanged=UTC_NOW,
165+ person=IPerson(object_created_event.user),
166+ whatchanged="bug",
167+ message="added bug")
168 bug.addCommentNotification(bug.initial_message, activity=activity)
169
170
171@@ -165,6 +166,16 @@
172
173
174 @block_implicit_flushes
175+def notify_bugtask_deleted(bugtask, event):
176+ """A bugtask has been deleted (removed from a bug).
177+
178+ bugtask must be in IBugTask. event must be anIObjectDeletedEvent.
179+ """
180+ bugtask.bug.addChange(
181+ BugTaskDeleted(UTC_NOW, IPerson(event.user), bugtask))
182+
183+
184+@block_implicit_flushes
185 def notify_bug_watch_modified(modified_bug_watch, event):
186 """Notify CC'd bug subscribers that a bug watch was edited.
187
188
189=== modified file 'lib/lp/bugs/tests/test_bugchanges.py'
190--- lib/lp/bugs/tests/test_bugchanges.py 2011-10-05 04:14:04 +0000
191+++ lib/lp/bugs/tests/test_bugchanges.py 2011-10-19 23:52:28 +0000
192@@ -25,7 +25,9 @@
193 from lp.bugs.interfaces.cve import ICveSet
194 from lp.bugs.model.bugnotification import BugNotification
195 from lp.bugs.scripts.bugnotification import construct_email_notifications
196+from lp.services.features.testing import FeatureFixture
197 from lp.testing import (
198+ login_person,
199 person_logged_in,
200 TestCaseWithFactory,
201 )
202@@ -1403,6 +1405,34 @@
203 expected_activity=expected_activity,
204 expected_notification=expected_notification)
205
206+ def test_bugtask_deleted(self):
207+ # Deleting a bug task adds entries in both BugActivity and
208+ # BugNotification.
209+ target = self.factory.makeProduct()
210+ task_to_delete = self.bug.addTask(self.user, target)
211+ self.saveOldChanges()
212+
213+ login_person(self.user)
214+ flags = {u"disclosure.delete_bugtask.enabled": u"on"}
215+ with FeatureFixture(flags):
216+ task_to_delete.delete()
217+
218+ task_deleted_activity = {
219+ 'person': self.user,
220+ 'whatchanged': 'bug task deleted',
221+ 'oldvalue': target.bugtargetname,
222+ }
223+
224+ task_deleted_notification = {
225+ 'person': self.user,
226+ 'text': (
227+ "** No longer affects: %s" % target.bugtargetname),
228+ }
229+
230+ self.assertRecordedChange(
231+ expected_notification=task_deleted_notification,
232+ expected_activity=task_deleted_activity)
233+
234 def test_product_series_nominated(self):
235 # Nominating a bug to be fixed in a product series adds an item
236 # to the activity log only.