====== The Mercurial Bugzilla extension ====== The [[http://mercurial.selenic.com|Mercurial]] Distributed Version Control System comes as standard with an [[http://mercurial.selenic.com/wiki/BugzillaExtension|extension]] providing some integration with [[http://www.bugzilla.org|Bugzilla]] bug tracking. ===== Bugzilla 4.4.3 and later ===== The Mercurial extension uses the Bugzilla XML-RPC API to interact with Bugzilla. In 4.4.3, Bugzilla changes the way it authenticates use of the API. This breaks the Bugzilla extension distributed with Mercurial versions 3.0 and prior. For Mercurial 3.0, this patch will get things working again. It should be part of Mercurial 3.1 and later. --- a/hgext/bugzilla.py Mon May 05 16:54:15 2014 +0200 +++ b/hgext/bugzilla.py Wed May 21 22:51:16 2014 +0100 @@ -1,7 +1,7 @@ # bugzilla.py - bugzilla integration for mercurial # # Copyright 2006 Vadim Gelfer -# Copyright 2011-2 Jim Hague +# Copyright 2011-4 Jim Hague # # This software may be used and distributed according to the terms of the # GNU General Public License version 2 or any later version. @@ -232,7 +232,7 @@ bzurl=http://my-project.org/bugzilla user=bugmail@my-project.org password=plugh - version=xmlrpc + version=xmlrpc+email bzemail=bugzilla@my-project.org template=Changeset {node|short} in {root|basename}. {hgweb}/{webroot}/rev/{node|short}\\n @@ -523,7 +523,7 @@ The regular xmlrpclib transports ignore cookies. Which causes a bit of a problem when you need a cookie-based login, as with - the Bugzilla XMLRPC interface. + the Bugzilla XMLRPC interface prior to 4.4.3. So this is a helper for defining a Transport which looks for cookies being set in responses and saves them to add to all future @@ -620,7 +620,9 @@ ver = self.bzproxy.Bugzilla.version()['version'].split('.') self.bzvermajor = int(ver[0]) self.bzverminor = int(ver[1]) - self.bzproxy.User.login({'login': user, 'password': passwd}) + login = self.bzproxy.User.login({'login': user, 'password': passwd, + 'restrict_login': True}) + self.bztoken = login.get('token', '') def transport(self, uri): if urlparse.urlparse(uri, "http")[0] == "https": @@ -631,13 +633,15 @@ def get_bug_comments(self, id): """Return a string with all comment text for a bug.""" c = self.bzproxy.Bug.comments({'ids': [id], - 'include_fields': ['text']}) + 'include_fields': ['text'], + 'token': self.bztoken}) return ''.join([t['text'] for t in c['bugs'][str(id)]['comments']]) def filter_real_bug_ids(self, bugs): probe = self.bzproxy.Bug.get({'ids': sorted(bugs.keys()), 'include_fields': [], 'permissive': True, + 'token': self.bztoken, }) for badbug in probe['faults']: id = badbug['id'] @@ -662,6 +666,7 @@ if 'fix' in newstate: args['status'] = self.fixstatus args['resolution'] = self.fixresolution + args['token'] = self.bztoken self.bzproxy.Bug.update(args) else: if 'fix' in newstate: @@ -719,10 +724,12 @@ than the subject line, and leave a blank line after it. ''' user = self.map_committer(committer) - matches = self.bzproxy.User.get({'match': [user]}) + matches = self.bzproxy.User.get({'match': [user], + 'token': self.bztoken}) if not matches['users']: user = self.ui.config('bugzilla', 'user', 'bugs') - matches = self.bzproxy.User.get({'match': [user]}) + matches = self.bzproxy.User.get({'match': [user], + 'token': self.bztoken}) if not matches['users']: raise util.Abort(_("default bugzilla user %s email not found") % user) For older versions of Mercurial, this patch is equivalent, but will apply without errors. --- hgext/bugzilla.py.orig 2014-02-12 21:32:36.000000000 +0100 +++ hgext/bugzilla.py 2014-05-22 20:49:41.249870459 +0200 @@ -620,7 +620,9 @@ ver = self.bzproxy.Bugzilla.version()['version'].split('.') self.bzvermajor = int(ver[0]) self.bzverminor = int(ver[1]) - self.bzproxy.User.login(dict(login=user, password=passwd)) + login = self.bzproxy.User.login(dict(login=user, password=passwd, + restrict_login=True)) + self.bztoken = login.get('token', '') def transport(self, uri): if urlparse.urlparse(uri, "http")[0] == "https": @@ -630,12 +632,14 @@ def get_bug_comments(self, id): """Return a string with all comment text for a bug.""" - c = self.bzproxy.Bug.comments(dict(ids=[id], include_fields=['text'])) + c = self.bzproxy.Bug.comments(dict(ids=[id], include_fields=['text'], + token=self.bztoken)) return ''.join([t['text'] for t in c['bugs'][str(id)]['comments']]) def filter_real_bug_ids(self, bugs): probe = self.bzproxy.Bug.get(dict(ids=sorted(bugs.keys()), include_fields=[], + token=self.bztoken, permissive=True)) for badbug in probe['faults']: id = badbug['id'] @@ -660,6 +664,7 @@ if 'fix' in newstate: args['status'] = self.fixstatus args['resolution'] = self.fixresolution + args['token'] = self.bztoken self.bzproxy.Bug.update(args) else: if 'fix' in newstate: @@ -717,10 +722,10 @@ than the subject line, and leave a blank line after it. ''' user = self.map_committer(committer) - matches = self.bzproxy.User.get(dict(match=[user])) + matches = self.bzproxy.User.get(dict(match=[user], token=self.bztoken)) if not matches['users']: user = self.ui.config('bugzilla', 'user', 'bugs') - matches = self.bzproxy.User.get(dict(match=[user])) + matches = self.bzproxy.User.get(dict(match=[user], token=self.bztoken)) if not matches['users']: raise util.Abort(_("default bugzilla user %s email not found") % user)