Merge lp:~gmb/launchpad/bugzilla3.4-see-also-bug-419134 into lp:launchpad

Proposed by Graham Binns
Status: Merged
Approved by: Graham Binns
Approved revision: not available
Merged at revision: not available
Proposed branch: lp:~gmb/launchpad/bugzilla3.4-see-also-bug-419134
Merge into: lp:launchpad
Diff against target: 431 lines (+217/-1)
6 files modified
lib/lp/bugs/doc/externalbugtracker-bugzilla-api.txt (+32/-0)
lib/lp/bugs/doc/externalbugtracker-bugzilla-lp-plugin.txt (+3/-0)
lib/lp/bugs/externalbugtracker/bugzilla.py (+34/-1)
lib/lp/bugs/tests/bugzilla-api-xmlrpc-transport.txt (+72/-0)
lib/lp/bugs/tests/bugzilla-xmlrpc-transport.txt (+6/-0)
lib/lp/bugs/tests/externalbugtracker.py (+70/-0)
To merge this branch: bzr merge lp:~gmb/launchpad/bugzilla3.4-see-also-bug-419134
Reviewer Review Type Date Requested Status
Guilherme Salgado (community) rc Abstain
Abel Deuring (community) code Approve
Review via email: mp+15404@code.launchpad.net

Commit message

Launchpad can now update the see_also link for bugs on Bugzilla 3.4 bug trackers.

To post a comment you must log in.
Revision history for this message
Graham Binns (gmb) wrote :

This branch fixes bug 419134 by making the BugzillaAPI ExternalBugTracker implement the ISupportsBackLinking interface.

I've added a test implementation of the Bugzilla API's Bug.update_see_also() method, which I've then used in the tests of BugzillaAPI.setLaunchpadBugId().

This branch is an rc candidate.

= Launchpad lint =

Note: I suspect that the lint notices about email.Utils are because lint runs using the system Python (2.6) rather than bin/py.

Checking for conflicts. and issues in doctests and templates.
Running jslint, xmllint, pyflakes, and pylint.
Using normal rules.

Linting changed files:
  lib/lp/bugs/doc/externalbugtracker-bugzilla-api.txt
  lib/lp/bugs/externalbugtracker/bugzilla.py
  lib/lp/bugs/tests/bugzilla-api-xmlrpc-transport.txt
  lib/lp/bugs/tests/externalbugtracker.py

== Pylint notices ==

lib/lp/bugs/externalbugtracker/bugzilla.py
    20: [F0401] Unable to import 'email.Utils' (No module named Utils)

lib/lp/bugs/tests/externalbugtracker.py
    1642: [W0108, Urlib2TransportTestHandler.default_open.<lambda>] Lambda may not be necessary
    1656: [W0108, Urlib2TransportTestHandler.default_open.<lambda>] Lambda may not be necessary

Revision history for this message
Abel Deuring (adeuring) wrote :

Looks good. Please add an "XXX" to the doc string of getLaunchpadBugId(), where you mention bug 490267.

review: Approve (code)
Revision history for this message
Guilherme Salgado (salgado) wrote :

Not yet ready for RC as can't be easily QAed on staging.

review: Abstain (rc)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'lib/lp/bugs/doc/externalbugtracker-bugzilla-api.txt'
--- lib/lp/bugs/doc/externalbugtracker-bugzilla-api.txt 2009-08-28 12:54:58 +0000
+++ lib/lp/bugs/doc/externalbugtracker-bugzilla-api.txt 2009-12-13 01:14:17 +0000
@@ -145,6 +145,7 @@
145 priority: P1145 priority: P1
146 product: Marvin146 product: Marvin
147 resolution: FIXED147 resolution: FIXED
148 see_also: []
148 severity: normal149 severity: normal
149 status: RESOLVED150 status: RESOLVED
150 summary: That bloody robot still exists.151 summary: That bloody robot still exists.
@@ -161,6 +162,7 @@
161 priority: P1162 priority: P1
162 product: HeartOfGold163 product: HeartOfGold
163 resolution:164 resolution:
165 see_also: []
164 severity: high166 severity: high
165 status: NEW167 status: NEW
166 summary: Collect unknown persons in docking bay 2.168 summary: Collect unknown persons in docking bay 2.
@@ -198,6 +200,7 @@
198 priority: P1200 priority: P1
199 product: HeartOfGold201 product: HeartOfGold
200 resolution:202 resolution:
203 see_also: []
201 severity: high204 severity: high
202 status: NEW205 status: NEW
203 summary: Collect unknown persons in docking bay 2.206 summary: Collect unknown persons in docking bay 2.
@@ -560,3 +563,32 @@
560 This is a new remote comment.563 This is a new remote comment.
561 <BLANKLINE>564 <BLANKLINE>
562565
566
567Linking a Launchpad bug to a remote bug
568---------------------------------------
569
570BugzillaAPI implements the ISupportsBackLinking interface, which means
571that it can be used to tell the remote bug tracker that a given remote
572bug is linked to a Launchpad bug.
573
574 >>> from canonical.launchpad.interfaces import ISupportsBackLinking
575 >>> verifyObject(ISupportsBackLinking, bugzilla)
576 True
577
578BugzillaAPI.setLaunchpadBugId() can be used to set the Launchpad bug ID
579for a given bug.
580
581setLaunchpadBugId() requires the user to be logged in.
582
583 >>> bugzilla.xmlrpc_transport.expireCookie(
584 ... bugzilla.xmlrpc_transport.auth_cookie)
585
586 >>> bugzilla.xmlrpc_transport.print_method_calls = True
587 >>> bugzilla.setLaunchpadBugId(bug_watch.remotebug, bug_watch.bug.id)
588 CALLED Bug.update_see_also({'add':
589 ['http://bugs.launchpad.dev/bugs...'], 'ids': [1]})
590
591BugzillaAPI.getLaunchpadBugId() will currently always return None due to
592bug 490267.
593
594 >>> bugzilla.getLaunchpadBugId(bug_watch.remotebug)
563595
=== modified file 'lib/lp/bugs/doc/externalbugtracker-bugzilla-lp-plugin.txt'
--- lib/lp/bugs/doc/externalbugtracker-bugzilla-lp-plugin.txt 2009-08-26 00:17:29 +0000
+++ lib/lp/bugs/doc/externalbugtracker-bugzilla-lp-plugin.txt 2009-12-13 01:14:17 +0000
@@ -210,6 +210,7 @@
210 priority: P1210 priority: P1
211 product: Marvin211 product: Marvin
212 resolution: FIXED212 resolution: FIXED
213 see_also:...
213 severity: normal214 severity: normal
214 status: RESOLVED215 status: RESOLVED
215 summary: That bloody robot still exists.216 summary: That bloody robot still exists.
@@ -226,6 +227,7 @@
226 priority: P1227 priority: P1
227 product: HeartOfGold228 product: HeartOfGold
228 resolution:229 resolution:
230 see_also:...
229 severity: high231 severity: high
230 status: NEW232 status: NEW
231 summary: Collect unknown persons in docking bay 2.233 summary: Collect unknown persons in docking bay 2.
@@ -555,6 +557,7 @@
555 priority: P1557 priority: P1
556 product: HeartOfGold558 product: HeartOfGold
557 resolution:559 resolution:
560 see_also: []
558 severity: high561 severity: high
559 status: NEW562 status: NEW
560 summary: Collect unknown persons in docking bay 2.563 summary: Collect unknown persons in docking bay 2.
561564
=== modified file 'lib/lp/bugs/externalbugtracker/bugzilla.py'
--- lib/lp/bugs/externalbugtracker/bugzilla.py 2009-09-23 12:24:10 +0000
+++ lib/lp/bugs/externalbugtracker/bugzilla.py 2009-12-13 01:14:17 +0000
@@ -27,6 +27,7 @@
27from canonical.config import config27from canonical.config import config
28from canonical.launchpad.interfaces.message import IMessageSet28from canonical.launchpad.interfaces.message import IMessageSet
29from canonical.launchpad.webapp.url import urlappend, urlparse29from canonical.launchpad.webapp.url import urlappend, urlparse
30from canonical.launchpad.webapp.publisher import canonical_url
3031
31from lp.bugs.externalbugtracker.base import (32from lp.bugs.externalbugtracker.base import (
32 BugNotFound, BugTrackerAuthenticationError, BugTrackerConnectError,33 BugNotFound, BugTrackerAuthenticationError, BugTrackerConnectError,
@@ -35,6 +36,7 @@
35 UnparseableBugTrackerVersion)36 UnparseableBugTrackerVersion)
36from lp.bugs.externalbugtracker.xmlrpc import (37from lp.bugs.externalbugtracker.xmlrpc import (
37 UrlLib2Transport)38 UrlLib2Transport)
39from lp.bugs.interfaces.bug import IBugSet
38from lp.bugs.interfaces.bugtask import BugTaskImportance, BugTaskStatus40from lp.bugs.interfaces.bugtask import BugTaskImportance, BugTaskStatus
39from lp.bugs.interfaces.externalbugtracker import UNKNOWN_REMOTE_IMPORTANCE41from lp.bugs.interfaces.externalbugtracker import UNKNOWN_REMOTE_IMPORTANCE
40from lp.bugs.interfaces.externalbugtracker import (42from lp.bugs.interfaces.externalbugtracker import (
@@ -425,7 +427,8 @@
425class BugzillaAPI(Bugzilla):427class BugzillaAPI(Bugzilla):
426 """An `ExternalBugTracker` to handle Bugzillas that offer an API."""428 """An `ExternalBugTracker` to handle Bugzillas that offer an API."""
427429
428 implements(ISupportsCommentImport, ISupportsCommentPushing)430 implements(
431 ISupportsBackLinking, ISupportsCommentImport, ISupportsCommentPushing)
429432
430 def __init__(self, baseurl, xmlrpc_transport=None,433 def __init__(self, baseurl, xmlrpc_transport=None,
431 internal_xmlrpc_transport=None):434 internal_xmlrpc_transport=None):
@@ -756,6 +759,36 @@
756 # BugWatchUpdater will expect (see bug 248938).759 # BugWatchUpdater will expect (see bug 248938).
757 return str(return_dict['id'])760 return str(return_dict['id'])
758761
762 def getLaunchpadBugId(self, remote_bug):
763 """Return the Launchpad bug ID for the remote bug.
764
765 See `ISupportsBackLinking`.
766 """
767 # XXX gmb 2009-11-30 bug=490267
768 # In fact, this method always returns None due to bug
769 # 490267. Once the bug is fixed in Bugzilla we should update
770 # this method.
771 return None
772
773 @needs_authentication
774 def setLaunchpadBugId(self, remote_bug, launchpad_bug_id):
775 """Set the Launchpad bug for a given remote bug.
776
777 See `ISupportsBackLinking`.
778 """
779 actual_bug_id = self._getActualBugId(remote_bug)
780
781 # Grab the bug from the database and get its canonical URL.
782 launchpad_bug = getUtility(IBugSet).get(launchpad_bug_id)
783 launchpad_bug_url = canonical_url(launchpad_bug)
784
785 request_params = {
786 'ids': [actual_bug_id],
787 'add': [launchpad_bug_url],
788 }
789
790 self.xmlrpc_proxy.Bug.update_see_also(request_params)
791
759792
760class BugzillaLPPlugin(BugzillaAPI):793class BugzillaLPPlugin(BugzillaAPI):
761 """An `ExternalBugTracker` to handle Bugzillas using the LP Plugin."""794 """An `ExternalBugTracker` to handle Bugzillas using the LP Plugin."""
762795
=== modified file 'lib/lp/bugs/tests/bugzilla-api-xmlrpc-transport.txt'
--- lib/lp/bugs/tests/bugzilla-api-xmlrpc-transport.txt 2009-09-02 09:18:14 +0000
+++ lib/lp/bugs/tests/bugzilla-api-xmlrpc-transport.txt 2009-12-13 01:14:17 +0000
@@ -113,6 +113,7 @@
113 priority: P1113 priority: P1
114 product: Marvin114 product: Marvin
115 resolution: FIXED115 resolution: FIXED
116 see_also: []
116 severity: normal117 severity: normal
117 status: RESOLVED118 status: RESOLVED
118 summary: That bloody robot still exists.119 summary: That bloody robot still exists.
@@ -165,6 +166,7 @@
165 priority: P1166 priority: P1
166 product: HeartOfGold167 product: HeartOfGold
167 resolution: 168 resolution:
169 see_also: []
168 severity: high170 severity: high
169 status: NEW171 status: NEW
170 summary: Collect unknown persons in docking bay 2.172 summary: Collect unknown persons in docking bay 2.
@@ -194,6 +196,7 @@
194 priority: P1196 priority: P1
195 product: Marvin197 product: Marvin
196 resolution: FIXED198 resolution: FIXED
199 see_also: []
197 severity: normal200 severity: normal
198 status: RESOLVED201 status: RESOLVED
199 summary: That bloody robot still exists.202 summary: That bloody robot still exists.
@@ -237,6 +240,7 @@
237 priority: P1240 priority: P1
238 product: HeartOfGold241 product: HeartOfGold
239 resolution: 242 resolution:
243 see_also: []
240 severity: high244 severity: high
241 status: NEW245 status: NEW
242 summary: Collect unknown persons in docking bay 2.246 summary: Collect unknown persons in docking bay 2.
@@ -261,6 +265,7 @@
261 priority: P1265 priority: P1
262 product: Marvin266 product: Marvin
263 resolution: FIXED267 resolution: FIXED
268 see_also: []
264 severity: normal269 severity: normal
265 status: RESOLVED270 status: RESOLVED
266 summary: That bloody robot still exists.271 summary: That bloody robot still exists.
@@ -275,6 +280,7 @@
275 priority: P1280 priority: P1
276 product: HeartOfGold281 product: HeartOfGold
277 resolution: 282 resolution:
283 see_also: []
278 severity: high284 severity: high
279 status: NEW285 status: NEW
280 summary: Collect unknown persons in docking bay 2.286 summary: Collect unknown persons in docking bay 2.
@@ -469,3 +475,69 @@
469 Fault: <Fault 101: 'Bug #42 does not exist.'>475 Fault: <Fault 101: 'Bug #42 does not exist.'>
470476
471477
478Updating the "See also" links on a bug
479--------------------------------------
480
481It's possible to alter the list of bugs linked to a bug in a Bugzilla
482instance by calling the Bug.update_see_also() method.
483
484URLs can be added to the list of "See also" links by passing them in the
485`add` parameter.
486
487 >>> server.Bug.update_see_also({
488 ... 'ids': [1], 'add': ['https://launchpad.net/bugs/15']})
489 {'changes': {1: {'see_also':
490 {'added': ['https://launchpad.net/bugs/15']}}}}
491
492The URL will now have been added to the bug's see_also list.
493
494 >>> return_value = server.Bug.get(
495 ... {'ids': [1], 'permissive': True})
496 >>> bug_dict = return_value['bugs'][0]
497 >>> for key in sorted(bug_dict):
498 ... print "%s: %s" % (key, bug_dict.get(key))
499 alias:
500 assigned_to: test@canonical.com
501 component: GPPSystems
502 creation_time: 20080610T16:19:53
503 id: 1
504 internals:...
505 is_open: True
506 last_change_time: 20080610T16:19:53
507 priority: P1
508 product: Marvin
509 resolution: FIXED
510 see_also: ['https://launchpad.net/bugs/15']
511 severity: normal
512 status: RESOLVED
513 summary: That bloody robot still exists.
514
515Any attempt to add the same URL again will simply be ignored.
516
517 >>> server.Bug.update_see_also({
518 ... 'ids': [1], 'add': ['https://launchpad.net/bugs/15']})
519 {'changes': {}}
520
521Trying to add a non Bugzilla or Launchpad URL will raise a Fault.
522
523 >>> server.Bug.update_see_also({
524 ... 'ids': [1], 'add': ['http://example.com/fail']});
525 Traceback (most recent call last):
526 ...
527 Fault: <Fault 112: 'Bug URL http://example.com/fail is invalid.'>
528
529It's also possible to remove items from a bug's see_also list.
530
531 >>> server.Bug.update_see_also({
532 ... 'ids': [1], 'remove': ['https://launchpad.net/bugs/15']})
533 {'changes': {1: {'see_also':
534 {'removed': ['https://launchpad.net/bugs/15']}}}}
535
536If a URL is passed in both the `add` and `remove` argument, it will be
537added (i.e. `add` overrides `remove`).
538
539 >>> server.Bug.update_see_also({
540 ... 'ids': [1], 'add': ['https://launchpad.net/bugs/14'],
541 ... 'remove': ['https://launchpad.dev/bugs/14']})
542 {'changes': {1: {'see_also':
543 {'added': ['https://launchpad.net/bugs/14']}}}}
472544
=== modified file 'lib/lp/bugs/tests/bugzilla-xmlrpc-transport.txt'
--- lib/lp/bugs/tests/bugzilla-xmlrpc-transport.txt 2009-08-21 13:13:56 +0000
+++ lib/lp/bugs/tests/bugzilla-xmlrpc-transport.txt 2009-12-13 01:14:17 +0000
@@ -152,6 +152,7 @@
152 priority: P1152 priority: P1
153 product: Marvin153 product: Marvin
154 resolution: FIXED154 resolution: FIXED
155 see_also: []
155 severity: normal156 severity: normal
156 status: RESOLVED157 status: RESOLVED
157 summary: That bloody robot still exists.158 summary: That bloody robot still exists.
@@ -177,6 +178,7 @@
177 priority: P1178 priority: P1
178 product: Marvin179 product: Marvin
179 resolution: FIXED180 resolution: FIXED
181 see_also: []
180 severity: normal182 severity: normal
181 status: RESOLVED183 status: RESOLVED
182 summary: That bloody robot still exists.184 summary: That bloody robot still exists.
@@ -192,6 +194,7 @@
192 priority: P1194 priority: P1
193 product: HeartOfGold195 product: HeartOfGold
194 resolution:196 resolution:
197 see_also: []
195 severity: high198 severity: high
196 status: NEW199 status: NEW
197 summary: Collect unknown persons in docking bay 2.200 summary: Collect unknown persons in docking bay 2.
@@ -214,6 +217,7 @@
214 priority: P1217 priority: P1
215 product: HeartOfGold218 product: HeartOfGold
216 resolution: 219 resolution:
220 see_also: []
217 severity: high221 severity: high
218 status: NEW222 status: NEW
219 summary: Collect unknown persons in docking bay 2.223 summary: Collect unknown persons in docking bay 2.
@@ -258,6 +262,7 @@
258 priority: P1262 priority: P1
259 product: HeartOfGold263 product: HeartOfGold
260 resolution: 264 resolution:
265 see_also: []
261 severity: high266 severity: high
262 status: NEW267 status: NEW
263 summary: Collect unknown persons in docking bay 2.268 summary: Collect unknown persons in docking bay 2.
@@ -307,6 +312,7 @@
307 priority: P1312 priority: P1
308 product: HeartOfGold313 product: HeartOfGold
309 resolution: 314 resolution:
315 see_also: []
310 severity: high316 severity: high
311 status: NEW317 status: NEW
312 summary: Collect unknown persons in docking bay 2.318 summary: Collect unknown persons in docking bay 2.
313319
=== modified file 'lib/lp/bugs/tests/externalbugtracker.py'
--- lib/lp/bugs/tests/externalbugtracker.py 2009-09-02 08:32:27 +0000
+++ lib/lp/bugs/tests/externalbugtracker.py 2009-12-13 01:14:17 +0000
@@ -379,6 +379,7 @@
379 'priority': 'P1',379 'priority': 'P1',
380 'product': 'Marvin',380 'product': 'Marvin',
381 'resolution': 'FIXED',381 'resolution': 'FIXED',
382 'see_also': [],
382 'severity': 'normal',383 'severity': 'normal',
383 'status': 'RESOLVED',384 'status': 'RESOLVED',
384 'summary': "That bloody robot still exists.",385 'summary': "That bloody robot still exists.",
@@ -394,6 +395,7 @@
394 'priority': 'P1',395 'priority': 'P1',
395 'product': 'HeartOfGold',396 'product': 'HeartOfGold',
396 'resolution': '',397 'resolution': '',
398 'see_also': [],
397 'severity': 'high',399 'severity': 'high',
398 'status': 'NEW',400 'status': 'NEW',
399 'summary': 'Collect unknown persons in docking bay 2.',401 'summary': 'Collect unknown persons in docking bay 2.',
@@ -773,6 +775,7 @@
773 'comments',775 'comments',
774 'get',776 'get',
775 'search',777 'search',
778 'update_see_also',
776 ],779 ],
777 'Bugzilla': [780 'Bugzilla': [
778 'time',781 'time',
@@ -992,6 +995,73 @@
992 # cause it to explode.995 # cause it to explode.
993 return [{'id': comment_id}]996 return [{'id': comment_id}]
994997
998 def update_see_also(self, arguments):
999 """Update the see_also references for a bug."""
1000 assert 'ids' in arguments, (
1001 "You must specify a set of IDs with which to work.")
1002 assert ('add' in arguments or 'remove' in arguments), (
1003 "You must specify a list of links to add or remove.")
1004
1005 changes = {}
1006
1007 for bug_id in arguments['ids']:
1008 bug_id = int(bug_id)
1009
1010 # If the bug ID doesn't exist, raise a Fault.
1011 if bug_id not in self.bugs:
1012 raise xmlrpclib.Fault(101, "Bug #%s does not exist." % bug_id)
1013
1014 see_also_list = self.bugs[bug_id].get('see_also', [])
1015
1016 # Remove any items first. That way, if they're also in the
1017 # 'add' section they'll get re-added.
1018 for url in arguments.get('remove', []):
1019 if url not in see_also_list:
1020 continue
1021
1022 if changes.get(bug_id) is None:
1023 changes[bug_id] = {}
1024
1025 if changes[bug_id].get('see_also') is None:
1026 changes[bug_id]['see_also'] = {}
1027
1028 if changes[bug_id]['see_also'].get('removed') is None:
1029 changes[bug_id]['see_also']['removed'] = []
1030
1031 see_also_list.remove(url)
1032 changes[bug_id]['see_also']['removed'].append(url)
1033
1034 # Add any items to the list.
1035 for url in arguments.get('add', []):
1036 if url in see_also_list:
1037 # Ignore existing urls.
1038 continue
1039
1040 if ('launchpad' not in url and
1041 'show_bug.cgi' not in url):
1042 raise xmlrpclib.Fault(
1043 112, "Bug URL %s is invalid." % url)
1044
1045 if changes.get(bug_id) is None:
1046 changes[bug_id] = {}
1047
1048 if changes[bug_id].get('see_also') is None:
1049 changes[bug_id]['see_also'] = {}
1050
1051 if changes[bug_id]['see_also'].get('added') is None:
1052 changes[bug_id]['see_also']['added'] = []
1053
1054 see_also_list.append(url)
1055 changes[bug_id]['see_also']['added'].append(url)
1056
1057 # Replace the bug's existing see_also list.
1058 self.bugs[bug_id]['see_also'] = see_also_list
1059
1060 # We have to return a list here because xmlrpclib will try to
1061 # expand sequences of length 1. Trying to do that on a dict will
1062 # cause it to explode.
1063 return [{'changes': changes}]
1064
9951065
996class TestMantis(Mantis):1066class TestMantis(Mantis):
997 """Mantis ExternalSystem for use in tests.1067 """Mantis ExternalSystem for use in tests.