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
=== modified file 'lib/lp/bugs/adapters/bugchange.py'
--- lib/lp/bugs/adapters/bugchange.py 2011-09-23 12:26:15 +0000
+++ lib/lp/bugs/adapters/bugchange.py 2011-10-19 23:52:28 +0000
@@ -27,6 +27,7 @@
27 'BugTaskAdded',27 'BugTaskAdded',
28 'BugTaskAssigneeChange',28 'BugTaskAssigneeChange',
29 'BugTaskBugWatchChange',29 'BugTaskBugWatchChange',
30 'BugTaskDeleted',
30 'BugTaskImportanceChange',31 'BugTaskImportanceChange',
31 'BugTaskMilestoneChange',32 'BugTaskMilestoneChange',
32 'BugTaskStatusChange',33 'BugTaskStatusChange',
@@ -260,6 +261,27 @@
260 }261 }
261262
262263
264class BugTaskDeleted(BugChangeBase):
265 """A bugtask was removed from the bug."""
266
267 def __init__(self, when, person, bugtask):
268 super(BugTaskDeleted, self).__init__(when, person)
269 self.targetname = bugtask.bugtargetname
270
271 def getBugActivity(self):
272 """See `IBugChange`."""
273 return dict(
274 whatchanged='bug task deleted',
275 oldvalue=self.targetname)
276
277 def getBugNotification(self):
278 """See `IBugChange`."""
279 return {
280 'text': (
281 "** No longer affects: %s" % self.targetname),
282 }
283
284
263class SeriesNominated(BugChangeBase):285class SeriesNominated(BugChangeBase):
264 """A user nominated the bug to be fixed in a series."""286 """A user nominated the bug to be fixed in a series."""
265287
266288
=== modified file 'lib/lp/bugs/configure.zcml'
--- lib/lp/bugs/configure.zcml 2011-10-19 23:52:27 +0000
+++ lib/lp/bugs/configure.zcml 2011-10-19 23:52:28 +0000
@@ -1080,6 +1080,9 @@
1080 for="lp.bugs.interfaces.bugtask.IBugTask lazr.lifecycle.interfaces.IObjectCreatedEvent"1080 for="lp.bugs.interfaces.bugtask.IBugTask lazr.lifecycle.interfaces.IObjectCreatedEvent"
1081 handler="lp.bugs.subscribers.bugactivity.notify_bugtask_added"/>1081 handler="lp.bugs.subscribers.bugactivity.notify_bugtask_added"/>
1082 <subscriber1082 <subscriber
1083 for="lp.bugs.interfaces.bugtask.IBugTask lazr.lifecycle.interfaces.IObjectDeletedEvent"
1084 handler="lp.bugs.subscribers.bugactivity.notify_bugtask_deleted"/>
1085 <subscriber
1083 for="lp.bugs.interfaces.bugtask.IBugTask zope.lifecycleevent.interfaces.IObjectCreatedEvent"1086 for="lp.bugs.interfaces.bugtask.IBugTask zope.lifecycleevent.interfaces.IObjectCreatedEvent"
1084 handler="canonical.launchpad.subscribers.karma.bugtask_created"/>1087 handler="canonical.launchpad.subscribers.karma.bugtask_created"/>
1085 <subscriber1088 <subscriber
10861089
=== added file 'lib/lp/bugs/mail/tests/test_bug_task_deletion.py'
--- lib/lp/bugs/mail/tests/test_bug_task_deletion.py 1970-01-01 00:00:00 +0000
+++ lib/lp/bugs/mail/tests/test_bug_task_deletion.py 2011-10-19 23:52:28 +0000
@@ -0,0 +1,42 @@
1# Copyright 2010 Canonical Ltd. This software is licensed under the
2# GNU Affero General Public License version 3 (see the file LICENSE).
3
4"""Test for emails sent after bug task deletion."""
5
6import transaction
7from zope.component import getUtility
8
9from lp.bugs.model.bugnotification import BugNotification
10from canonical.launchpad.webapp.interfaces import ILaunchBag
11from canonical.testing.layers import DatabaseFunctionalLayer
12from lp.bugs.scripts.bugnotification import construct_email_notifications
13from lp.services.features.testing import FeatureFixture
14from lp.testing import TestCaseWithFactory
15
16
17class TestDeletionNotification(TestCaseWithFactory):
18 """Test email notifications when a bug task is deleted."""
19
20 layer = DatabaseFunctionalLayer
21
22 def setUp(self):
23 # Run the tests as a logged-in user.
24 super(TestDeletionNotification, self).setUp(
25 user='test@canonical.com')
26 self.user = getUtility(ILaunchBag).user
27 product = self.factory.makeProduct(owner=self.user)
28 self.bug_task = self.factory.makeBugTask(target=product)
29
30 def test_for_bug_modifier_header(self):
31 """Test X-Launchpad-Bug-Modifier appears when a bugtask is deleted."""
32 flags = {u"disclosure.delete_bugtask.enabled": u"on"}
33 with FeatureFixture(flags):
34 self.bug_task.delete(self.user)
35 transaction.commit()
36 latest_notification = BugNotification.selectFirst(orderBy='-id')
37 notifications, omitted, messages = construct_email_notifications(
38 [latest_notification])
39 self.assertEqual(len(notifications), 1,
40 'email notification not created')
41 headers = [msg['X-Launchpad-Bug-Modifier'] for msg in messages]
42 self.assertEqual(len(headers), len(messages))
043
=== modified file 'lib/lp/bugs/model/bugtask.py'
--- lib/lp/bugs/model/bugtask.py 2011-10-19 23:52:27 +0000
+++ lib/lp/bugs/model/bugtask.py 2011-10-19 23:52:28 +0000
@@ -29,7 +29,10 @@
29import re29import re
3030
31from lazr.enum import BaseItem31from lazr.enum import BaseItem
32from lazr.lifecycle.event import ObjectModifiedEvent32from lazr.lifecycle.event import (
33 ObjectDeletedEvent,
34 ObjectModifiedEvent,
35 )
33from lazr.lifecycle.snapshot import Snapshot36from lazr.lifecycle.snapshot import Snapshot
34import pytz37import pytz
35from sqlobject import (38from sqlobject import (
@@ -637,6 +640,7 @@
637 "Cannot delete bugtask: %s" % self.title)640 "Cannot delete bugtask: %s" % self.title)
638 bug = self.bug641 bug = self.bug
639 target = self.target642 target = self.target
643 notify(ObjectDeletedEvent(self, who))
640 self.destroySelf()644 self.destroySelf()
641 del get_property_cache(bug).bugtasks645 del get_property_cache(bug).bugtasks
642646
643647
=== modified file 'lib/lp/bugs/model/tests/test_bugtask.py'
--- lib/lp/bugs/model/tests/test_bugtask.py 2011-10-19 23:52:27 +0000
+++ lib/lp/bugs/model/tests/test_bugtask.py 2011-10-19 23:52:28 +0000
@@ -9,11 +9,8 @@
99
10from lazr.lifecycle.event import ObjectModifiedEvent10from lazr.lifecycle.event import ObjectModifiedEvent
11from lazr.lifecycle.snapshot import Snapshot11from lazr.lifecycle.snapshot import Snapshot
12<<<<<<< TREE12from lazr.restfulclient.errors import Unauthorized
13from testtools.testcase import ExpectedException13from testtools.testcase import ExpectedException
14=======
15from lazr.restfulclient.errors import Unauthorized
16>>>>>>> MERGE-SOURCE
17from testtools.matchers import Equals14from testtools.matchers import Equals
18from zope.component import getUtility15from zope.component import getUtility
19from zope.event import notify16from zope.event import notify
2017
=== modified file 'lib/lp/bugs/subscribers/bugactivity.py'
--- lib/lp/bugs/subscribers/bugactivity.py 2011-02-11 22:04:25 +0000
+++ lib/lp/bugs/subscribers/bugactivity.py 2011-10-19 23:52:28 +0000
@@ -14,6 +14,7 @@
14from canonical.database.sqlbase import block_implicit_flushes14from canonical.database.sqlbase import block_implicit_flushes
15from lp.bugs.adapters.bugchange import (15from lp.bugs.adapters.bugchange import (
16 BugTaskAdded,16 BugTaskAdded,
17 BugTaskDeleted,
17 BugWatchAdded,18 BugWatchAdded,
18 BugWatchRemoved,19 BugWatchRemoved,
19 CveLinkedToBug,20 CveLinkedToBug,
@@ -96,11 +97,11 @@
96@block_implicit_flushes97@block_implicit_flushes
97def record_bug_added(bug, object_created_event):98def record_bug_added(bug, object_created_event):
98 activity = getUtility(IBugActivitySet).new(99 activity = getUtility(IBugActivitySet).new(
99 bug = bug.id,100 bug=bug.id,
100 datechanged = UTC_NOW,101 datechanged=UTC_NOW,
101 person = IPerson(object_created_event.user),102 person=IPerson(object_created_event.user),
102 whatchanged = "bug",103 whatchanged="bug",
103 message = "added bug")104 message="added bug")
104 bug.addCommentNotification(bug.initial_message, activity=activity)105 bug.addCommentNotification(bug.initial_message, activity=activity)
105106
106107
@@ -165,6 +166,16 @@
165166
166167
167@block_implicit_flushes168@block_implicit_flushes
169def notify_bugtask_deleted(bugtask, event):
170 """A bugtask has been deleted (removed from a bug).
171
172 bugtask must be in IBugTask. event must be anIObjectDeletedEvent.
173 """
174 bugtask.bug.addChange(
175 BugTaskDeleted(UTC_NOW, IPerson(event.user), bugtask))
176
177
178@block_implicit_flushes
168def notify_bug_watch_modified(modified_bug_watch, event):179def notify_bug_watch_modified(modified_bug_watch, event):
169 """Notify CC'd bug subscribers that a bug watch was edited.180 """Notify CC'd bug subscribers that a bug watch was edited.
170181
171182
=== modified file 'lib/lp/bugs/tests/test_bugchanges.py'
--- lib/lp/bugs/tests/test_bugchanges.py 2011-10-05 04:14:04 +0000
+++ lib/lp/bugs/tests/test_bugchanges.py 2011-10-19 23:52:28 +0000
@@ -25,7 +25,9 @@
25from lp.bugs.interfaces.cve import ICveSet25from lp.bugs.interfaces.cve import ICveSet
26from lp.bugs.model.bugnotification import BugNotification26from lp.bugs.model.bugnotification import BugNotification
27from lp.bugs.scripts.bugnotification import construct_email_notifications27from lp.bugs.scripts.bugnotification import construct_email_notifications
28from lp.services.features.testing import FeatureFixture
28from lp.testing import (29from lp.testing import (
30 login_person,
29 person_logged_in,31 person_logged_in,
30 TestCaseWithFactory,32 TestCaseWithFactory,
31 )33 )
@@ -1403,6 +1405,34 @@
1403 expected_activity=expected_activity,1405 expected_activity=expected_activity,
1404 expected_notification=expected_notification)1406 expected_notification=expected_notification)
14051407
1408 def test_bugtask_deleted(self):
1409 # Deleting a bug task adds entries in both BugActivity and
1410 # BugNotification.
1411 target = self.factory.makeProduct()
1412 task_to_delete = self.bug.addTask(self.user, target)
1413 self.saveOldChanges()
1414
1415 login_person(self.user)
1416 flags = {u"disclosure.delete_bugtask.enabled": u"on"}
1417 with FeatureFixture(flags):
1418 task_to_delete.delete()
1419
1420 task_deleted_activity = {
1421 'person': self.user,
1422 'whatchanged': 'bug task deleted',
1423 'oldvalue': target.bugtargetname,
1424 }
1425
1426 task_deleted_notification = {
1427 'person': self.user,
1428 'text': (
1429 "** No longer affects: %s" % target.bugtargetname),
1430 }
1431
1432 self.assertRecordedChange(
1433 expected_notification=task_deleted_notification,
1434 expected_activity=task_deleted_activity)
1435
1406 def test_product_series_nominated(self):1436 def test_product_series_nominated(self):
1407 # Nominating a bug to be fixed in a product series adds an item1437 # Nominating a bug to be fixed in a product series adds an item
1408 # to the activity log only.1438 # to the activity log only.