Merge lp:~stevenk/launchpad/deal-with-unsynched-bugwatch-comments into lp:launchpad

Proposed by Steve Kowalik
Status: Merged
Approved by: Steve Kowalik
Approved revision: no longer in the source branch.
Merged at revision: 16189
Proposed branch: lp:~stevenk/launchpad/deal-with-unsynched-bugwatch-comments
Merge into: lp:launchpad
Diff against target: 205 lines (+40/-61)
7 files modified
Makefile (+0/-3)
lib/lp/bugs/browser/bugwatch.py (+4/-4)
lib/lp/bugs/browser/tests/test_bugwatch_views.py (+23/-9)
lib/lp/bugs/configure.zcml (+1/-0)
lib/lp/bugs/interfaces/bugwatch.py (+6/-0)
lib/lp/bugs/model/bugwatch.py (+6/-11)
lib/lp/bugs/stories/bugwatches/xx-delete-bugwatch.txt (+0/-34)
To merge this branch: bzr merge lp:~stevenk/launchpad/deal-with-unsynched-bugwatch-comments
Reviewer Review Type Date Requested Status
Ian Booth (community) Approve
Review via email: mp+131293@code.launchpad.net

Commit message

Also check for unsynchronized messages when checking if the Delete Bug Watch button can be displayed in the UI.

Description of the change

When deleting a bugwatch that has a message which does not contain a remote ID, it is shown in the UI as unsynchronized, and if it is the only bugmessage that references that bugwatch when that bugwatch is deleted, an OOPS will result due to a foreign key violation. I have dealt with that by adding a new method onto IBugWatch, and making use of it in the view.

This branch does not close the linked bug entirely, but it destroys the cause of the OOPS, so it can drop from Critical to Low.

I have destroyed an evil doctest for LoC credit, as well as refactoring the current method on IBugWatch.

To post a comment you must log in.
Revision history for this message
Ian Booth (wallyworld) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'Makefile'
2--- Makefile 2012-09-24 17:14:32 +0000
3+++ Makefile 2012-10-25 00:28:22 +0000
4@@ -132,9 +132,6 @@
5 logs:
6 mkdir logs
7
8-xxxreport: $(PY)
9- ${PY} -t ./utilities/xxxreport.py -f csv -o xxx-report.csv ./
10-
11 codehosting-dir:
12 mkdir -p $(CODEHOSTING_ROOT)/mirrors
13 mkdir -p $(CODEHOSTING_ROOT)/config
14
15=== modified file 'lib/lp/bugs/browser/bugwatch.py'
16--- lib/lp/bugs/browser/bugwatch.py 2011-12-30 06:14:56 +0000
17+++ lib/lp/bugs/browser/bugwatch.py 2012-10-25 00:28:22 +0000
18@@ -1,4 +1,4 @@
19-# Copyright 2009-2011 Canonical Ltd. This software is licensed under the
20+# Copyright 2009-2012 Canonical Ltd. This software is licensed under the
21 # GNU Affero General Public License version 3 (see the file LICENSE).
22
23 """IBugWatch-related browser views."""
24@@ -8,8 +8,8 @@
25 'BugWatchSetNavigation',
26 'BugWatchActivityPortletView',
27 'BugWatchEditView',
28- 'BugWatchView']
29-
30+ 'BugWatchView'
31+ ]
32
33 from zope.component import getUtility
34 from zope.interface import Interface
35@@ -133,7 +133,7 @@
36 """Return whether the bug watch is unlinked."""
37 return (
38 len(self.context.bugtasks) == 0 and
39- self.context.getImportedBugMessages().is_empty())
40+ self.context.getBugMessages().is_empty())
41
42 @action('Delete Bug Watch', name='delete', condition=bugWatchIsUnlinked)
43 def delete_action(self, action, data):
44
45=== modified file 'lib/lp/bugs/browser/tests/test_bugwatch_views.py'
46--- lib/lp/bugs/browser/tests/test_bugwatch_views.py 2012-01-01 02:58:52 +0000
47+++ lib/lp/bugs/browser/tests/test_bugwatch_views.py 2012-10-25 00:28:22 +0000
48@@ -1,4 +1,4 @@
49-# Copyright 2010-2011 Canonical Ltd. This software is licensed under the
50+# Copyright 2010-2012 Canonical Ltd. This software is licensed under the
51 # GNU Affero General Public License version 3 (see the file LICENSE).
52
53 """Tests for BugWatch views."""
54@@ -7,7 +7,10 @@
55
56 from zope.component import getUtility
57
58+from lp.app.errors import NotFoundError
59+from lp.bugs.interfaces.bugwatch import IBugWatchSet
60 from lp.services.messages.interfaces.message import IMessageSet
61+from lp.services.webapp.interfaces import ILaunchBag
62 from lp.testing import (
63 login,
64 login_person,
65@@ -32,15 +35,29 @@
66 self.bug_watch = self.factory.makeBugWatch(
67 bug=self.bug_task.bug)
68
69+ def test_can_delete_watch(self):
70+ # An unlinked bugwatch can be deleted.
71+ bwid = self.bug_watch.id
72+ form = {'field.actions.delete': 'Delete Bug Watch'}
73+ getUtility(ILaunchBag).add(self.bug_task.bug)
74+ view = create_initialized_view(self.bug_watch, '+edit', form=form)
75+ self.assertContentEqual([], view.errors)
76+ self.assertRaises(NotFoundError, getUtility(IBugWatchSet).get, bwid)
77+
78+ def test_can_not_delete_unlinked_watch_with_unsynched_comments(self):
79+ # If a bugwatch is unlinked, but has imported comments that are
80+ # awaiting synch, it can not be deleted.
81+ self.factory.makeBugComment(
82+ bug=self.bug_task.bug.id, bug_watch=self.bug_watch)
83+ view = create_initialized_view(self.bug_watch, '+edit')
84+ self.assertFalse(view.bugWatchIsUnlinked(None))
85+
86 def test_cannot_delete_watch_if_linked_to_task(self):
87 # It isn't possible to delete a bug watch that's linked to a bug
88 # task.
89 self.bug_task.bugwatch = self.bug_watch
90 view = create_initialized_view(self.bug_watch, '+edit')
91- self.assertFalse(
92- view.bugWatchIsUnlinked(None),
93- "bugWatchIsUnlinked() returned True though there is a task "
94- "linked to the watch.")
95+ self.assertFalse(view.bugWatchIsUnlinked(None))
96
97 def test_cannot_delete_watch_if_linked_to_comment(self):
98 # It isn't possible to delete a bug watch that's linked to a bug
99@@ -54,7 +71,4 @@
100 self.bug_watch.addComment('comment-id', message)
101 login_person(self.person)
102 view = create_initialized_view(self.bug_watch, '+edit')
103- self.assertFalse(
104- view.bugWatchIsUnlinked(None),
105- "bugWatchIsUnlinked() returned True though there is a comment "
106- "linked to the watch.")
107+ self.assertFalse(view.bugWatchIsUnlinked(None))
108
109=== modified file 'lib/lp/bugs/configure.zcml'
110--- lib/lp/bugs/configure.zcml 2012-10-15 02:32:30 +0000
111+++ lib/lp/bugs/configure.zcml 2012-10-25 00:28:22 +0000
112@@ -879,6 +879,7 @@
113 remotestatus
114 title
115 url
116+ getBugMessages
117 getImportedBugMessages"/>
118 <require
119 permission="launchpad.AnyPerson"
120
121=== modified file 'lib/lp/bugs/interfaces/bugwatch.py'
122--- lib/lp/bugs/interfaces/bugwatch.py 2012-10-09 05:48:57 +0000
123+++ lib/lp/bugs/interfaces/bugwatch.py 2012-10-25 00:28:22 +0000
124@@ -263,6 +263,12 @@
125 :param message: The imported comment as a Launchpad Message object.
126 """
127
128+ def getBugMessages(clauses):
129+ """Return all the `IBugMessage`s that reference this BugWatch.
130+
131+ :param clauses: A iterable of Storm clauses to limit the messages.
132+ """
133+
134 def getImportedBugMessages():
135 """Return all the `IBugMessage`s that have been imported."""
136
137
138=== modified file 'lib/lp/bugs/model/bugwatch.py'
139--- lib/lp/bugs/model/bugwatch.py 2012-10-09 04:47:36 +0000
140+++ lib/lp/bugs/model/bugwatch.py 2012-10-25 00:28:22 +0000
141@@ -283,19 +283,14 @@
142 remote_comment_id=comment_id)
143 return bug_message
144
145+ def getBugMessages(self, clauses=[]):
146+ return Store.of(self).find(
147+ BugMessage, BugMessage.bug == self.bug.id,
148+ BugMessage.bugwatch == self.id, *clauses)
149+
150 def getImportedBugMessages(self):
151 """See `IBugWatch`."""
152- store = Store.of(self)
153- # If a comment is linked to a bug watch and has a
154- # remote_comment_id, it means it's imported.
155- # XXX gmb 2008-12-09 bug 244768:
156- # The Not() needs to be in this find() call due to bug
157- # 244768; we should remove it once that is solved.
158- return store.find(
159- BugMessage,
160- BugMessage.bug == self.bug.id,
161- BugMessage.bugwatch == self.id,
162- Not(BugMessage.remote_comment_id == None))
163+ return self.getBugMessages([BugMessage.remote_comment_id != None])
164
165 def addActivity(self, result=None, message=None, oops_id=None):
166 """See `IBugWatch`."""
167
168=== removed file 'lib/lp/bugs/stories/bugwatches/xx-delete-bugwatch.txt'
169--- lib/lp/bugs/stories/bugwatches/xx-delete-bugwatch.txt 2010-09-29 11:07:13 +0000
170+++ lib/lp/bugs/stories/bugwatches/xx-delete-bugwatch.txt 1970-01-01 00:00:00 +0000
171@@ -1,34 +0,0 @@
172-= Delete a Bug Watch =
173-
174-If a bug watch isn't linked to a bug task and no comments have been
175-imported for it, it's possible to delete from the bug watch edit page.
176-
177- >>> user_browser.open('http://launchpad.dev/bugs/1')
178- >>> bug_watches = find_portlet(user_browser.contents, 'Remote bug watches')
179- >>> for li in bug_watches('li'):
180- ... print li.findAll('a')[0].renderContents()
181- mozilla.org #123543
182- mozilla.org #2000
183- mozilla.org #42
184- debbugs #304014
185-
186- >>> user_browser.getLink(url='/+watch/3').click()
187- >>> user_browser.title
188- 'Edit bug watch for bug 123543 in The Mozilla.org Bug Tracker on bug #1'
189- >>> print find_portlet(
190- ... user_browser.contents, 'Bug watch links').span.renderContents()
191- There are currently no links to this bug watch.
192-
193- >>> user_browser.getControl('Delete Bug Watch').click()
194-
195- >>> for message in find_tags_by_class(user_browser.contents, 'message'):
196- ... print message.renderContents()
197- The <a href="https://bugzilla.mozilla.org/...123543">mozilla.org #123543</a>
198- bug watch has been deleted.
199-
200- >>> bug_watches = find_portlet(user_browser.contents, 'Remote bug watches')
201- >>> for li in bug_watches('li'):
202- ... print li.findAll('a')[0].renderContents()
203- mozilla.org #2000
204- mozilla.org #42
205- debbugs #304014