277 Changeset commit comment. Bug 1234. |
277 Changeset commit comment. Bug 1234. |
278 ''' |
278 ''' |
279 |
279 |
280 from mercurial.i18n import _ |
280 from mercurial.i18n import _ |
281 from mercurial.node import short |
281 from mercurial.node import short |
282 from mercurial import cmdutil, mail, util |
282 from mercurial import cmdutil, mail, util, error |
283 import re, time, urlparse, xmlrpclib |
283 import re, time, urlparse, xmlrpclib |
284 |
284 |
285 # Note for extension authors: ONLY specify testedwith = 'internal' for |
285 # Note for extension authors: ONLY specify testedwith = 'internal' for |
286 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should |
286 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should |
287 # be specifying the version(s) of Mercurial they are tested with, or |
287 # be specifying the version(s) of Mercurial they are tested with, or |
356 def __init__(self, ui): |
356 def __init__(self, ui): |
357 try: |
357 try: |
358 import MySQLdb as mysql |
358 import MySQLdb as mysql |
359 bzmysql._MySQLdb = mysql |
359 bzmysql._MySQLdb = mysql |
360 except ImportError as err: |
360 except ImportError as err: |
361 raise util.Abort(_('python mysql support not available: %s') % err) |
361 raise error.Abort(_('python mysql support not available: %s') % err) |
362 |
362 |
363 bzaccess.__init__(self, ui) |
363 bzaccess.__init__(self, ui) |
364 |
364 |
365 host = self.ui.config('bugzilla', 'host', 'localhost') |
365 host = self.ui.config('bugzilla', 'host', 'localhost') |
366 user = self.ui.config('bugzilla', 'user', 'bugs') |
366 user = self.ui.config('bugzilla', 'user', 'bugs') |
390 def get_longdesc_id(self): |
390 def get_longdesc_id(self): |
391 '''get identity of longdesc field''' |
391 '''get identity of longdesc field''' |
392 self.run('select fieldid from fielddefs where name = "longdesc"') |
392 self.run('select fieldid from fielddefs where name = "longdesc"') |
393 ids = self.cursor.fetchall() |
393 ids = self.cursor.fetchall() |
394 if len(ids) != 1: |
394 if len(ids) != 1: |
395 raise util.Abort(_('unknown database schema')) |
395 raise error.Abort(_('unknown database schema')) |
396 return ids[0][0] |
396 return ids[0][0] |
397 |
397 |
398 def filter_real_bug_ids(self, bugs): |
398 def filter_real_bug_ids(self, bugs): |
399 '''filter not-existing bugs from set.''' |
399 '''filter not-existing bugs from set.''' |
400 self.run('select bug_id from bugs where bug_id in %s' % |
400 self.run('select bug_id from bugs where bug_id in %s' % |
435 fp = util.popen('(%s) 2>&1' % cmd) |
435 fp = util.popen('(%s) 2>&1' % cmd) |
436 out = fp.read() |
436 out = fp.read() |
437 ret = fp.close() |
437 ret = fp.close() |
438 if ret: |
438 if ret: |
439 self.ui.warn(out) |
439 self.ui.warn(out) |
440 raise util.Abort(_('bugzilla notify command %s') % |
440 raise error.Abort(_('bugzilla notify command %s') % |
441 util.explainexit(ret)[0]) |
441 util.explainexit(ret)[0]) |
442 self.ui.status(_('done\n')) |
442 self.ui.status(_('done\n')) |
443 |
443 |
444 def get_user_id(self, user): |
444 def get_user_id(self, user): |
445 '''look up numeric bugzilla user id.''' |
445 '''look up numeric bugzilla user id.''' |
468 userid = self.get_user_id(user) |
468 userid = self.get_user_id(user) |
469 except KeyError: |
469 except KeyError: |
470 try: |
470 try: |
471 defaultuser = self.ui.config('bugzilla', 'bzuser') |
471 defaultuser = self.ui.config('bugzilla', 'bzuser') |
472 if not defaultuser: |
472 if not defaultuser: |
473 raise util.Abort(_('cannot find bugzilla user id for %s') % |
473 raise error.Abort(_('cannot find bugzilla user id for %s') % |
474 user) |
474 user) |
475 userid = self.get_user_id(defaultuser) |
475 userid = self.get_user_id(defaultuser) |
476 user = defaultuser |
476 user = defaultuser |
477 except KeyError: |
477 except KeyError: |
478 raise util.Abort(_('cannot find bugzilla user id for %s or %s') |
478 raise error.Abort(_('cannot find bugzilla user id for %s or %s') |
479 % (user, defaultuser)) |
479 % (user, defaultuser)) |
480 return (user, userid) |
480 return (user, userid) |
481 |
481 |
482 def updatebug(self, bugid, newstate, text, committer): |
482 def updatebug(self, bugid, newstate, text, committer): |
483 '''update bug state with comment text. |
483 '''update bug state with comment text. |
515 def get_longdesc_id(self): |
515 def get_longdesc_id(self): |
516 '''get identity of longdesc field''' |
516 '''get identity of longdesc field''' |
517 self.run('select id from fielddefs where name = "longdesc"') |
517 self.run('select id from fielddefs where name = "longdesc"') |
518 ids = self.cursor.fetchall() |
518 ids = self.cursor.fetchall() |
519 if len(ids) != 1: |
519 if len(ids) != 1: |
520 raise util.Abort(_('unknown database schema')) |
520 raise error.Abort(_('unknown database schema')) |
521 return ids[0][0] |
521 return ids[0][0] |
522 |
522 |
523 # Bugzilla via XMLRPC interface. |
523 # Bugzilla via XMLRPC interface. |
524 |
524 |
525 class cookietransportrequest(object): |
525 class cookietransportrequest(object): |
703 def __init__(self, ui): |
703 def __init__(self, ui): |
704 bzxmlrpc.__init__(self, ui) |
704 bzxmlrpc.__init__(self, ui) |
705 |
705 |
706 self.bzemail = self.ui.config('bugzilla', 'bzemail') |
706 self.bzemail = self.ui.config('bugzilla', 'bzemail') |
707 if not self.bzemail: |
707 if not self.bzemail: |
708 raise util.Abort(_("configuration 'bzemail' missing")) |
708 raise error.Abort(_("configuration 'bzemail' missing")) |
709 mail.validateconfig(self.ui) |
709 mail.validateconfig(self.ui) |
710 |
710 |
711 def makecommandline(self, fieldname, value): |
711 def makecommandline(self, fieldname, value): |
712 if self.bzvermajor >= 4: |
712 if self.bzvermajor >= 4: |
713 return "@%s %s" % (fieldname, str(value)) |
713 return "@%s %s" % (fieldname, str(value)) |
733 if not matches['users']: |
733 if not matches['users']: |
734 user = self.ui.config('bugzilla', 'user', 'bugs') |
734 user = self.ui.config('bugzilla', 'user', 'bugs') |
735 matches = self.bzproxy.User.get({'match': [user], |
735 matches = self.bzproxy.User.get({'match': [user], |
736 'token': self.bztoken}) |
736 'token': self.bztoken}) |
737 if not matches['users']: |
737 if not matches['users']: |
738 raise util.Abort(_("default bugzilla user %s email not found") % |
738 raise error.Abort(_("default bugzilla user %s email not found") |
739 user) |
739 % user) |
740 user = matches['users'][0]['email'] |
740 user = matches['users'][0]['email'] |
741 commands.append(self.makecommandline("id", bugid)) |
741 commands.append(self.makecommandline("id", bugid)) |
742 |
742 |
743 text = "\n".join(commands) + "\n\n" + comment |
743 text = "\n".join(commands) + "\n\n" + comment |
744 |
744 |
787 |
787 |
788 bzversion = self.ui.config('bugzilla', 'version') |
788 bzversion = self.ui.config('bugzilla', 'version') |
789 try: |
789 try: |
790 bzclass = bugzilla._versions[bzversion] |
790 bzclass = bugzilla._versions[bzversion] |
791 except KeyError: |
791 except KeyError: |
792 raise util.Abort(_('bugzilla version %s not supported') % |
792 raise error.Abort(_('bugzilla version %s not supported') % |
793 bzversion) |
793 bzversion) |
794 self.bzdriver = bzclass(self.ui) |
794 self.bzdriver = bzclass(self.ui) |
795 |
795 |
796 self.bug_re = re.compile( |
796 self.bug_re = re.compile( |
797 self.ui.config('bugzilla', 'regexp', |
797 self.ui.config('bugzilla', 'regexp', |
898 def hook(ui, repo, hooktype, node=None, **kwargs): |
898 def hook(ui, repo, hooktype, node=None, **kwargs): |
899 '''add comment to bugzilla for each changeset that refers to a |
899 '''add comment to bugzilla for each changeset that refers to a |
900 bugzilla bug id. only add a comment once per bug, so same change |
900 bugzilla bug id. only add a comment once per bug, so same change |
901 seen multiple times does not fill bug with duplicate data.''' |
901 seen multiple times does not fill bug with duplicate data.''' |
902 if node is None: |
902 if node is None: |
903 raise util.Abort(_('hook type %s does not pass a changeset id') % |
903 raise error.Abort(_('hook type %s does not pass a changeset id') % |
904 hooktype) |
904 hooktype) |
905 try: |
905 try: |
906 bz = bugzilla(ui, repo) |
906 bz = bugzilla(ui, repo) |
907 ctx = repo[node] |
907 ctx = repo[node] |
908 bugs = bz.find_bugs(ctx) |
908 bugs = bz.find_bugs(ctx) |
909 if bugs: |
909 if bugs: |
910 for bug in bugs: |
910 for bug in bugs: |
911 bz.update(bug, bugs[bug], ctx) |
911 bz.update(bug, bugs[bug], ctx) |
912 bz.notify(bugs, util.email(ctx.user())) |
912 bz.notify(bugs, util.email(ctx.user())) |
913 except Exception as e: |
913 except Exception as e: |
914 raise util.Abort(_('Bugzilla error: %s') % e) |
914 raise error.Abort(_('Bugzilla error: %s') % e) |