bugzilla: add modified XMLRPC mode that uses email to send bug comments.
authorJim Hague <jim.hague@acm.org>
Wed, 30 Mar 2011 09:49:45 +0100
changeset 13802 49b5a1aaf726
parent 13801 60256f7f30c1
child 13803 e380964d53f8
bugzilla: add modified XMLRPC mode that uses email to send bug comments. If Bugzilla has its email interface configured, an email can be used to update bugs. If the From: address in the email matches a valid user email, Bugzillas make the update as that user. So comments attached to a bug appear under the name of the user making the change, and the user does not receive email about the change, exactly as if they had made the change via the web interface. So add a modified XMLRPC mode that uses email to modify bugs. The format of the mails is documented in the Bugzilla email_in.pl specification. Briefly, initial non-blank lines in the message body starting '@<field> = <value> modify bug fields. A blank line signals the end of the command lines, and the rest of the message is used as bug comment. Invoke the same Mercurial user to Bugzilla user email mapping currently used in the MySQL mode. All other processing - checking the bug numbers, checking user ids, etc. continues to be done via XMLRPC.
hgext/bugzilla.py
--- a/hgext/bugzilla.py	Wed Mar 30 09:49:45 2011 +0100
+++ b/hgext/bugzilla.py	Wed Mar 30 09:49:45 2011 +0100
@@ -14,9 +14,12 @@
 
 The hook does not change bug status.
 
-Two basic modes of access to Bugzilla are provided:
+Three basic modes of access to Bugzilla are provided:
 
-1. Access via the Bugzilla XMLRPC interface (requires Bugzilla 3.4 or later).
+1. Access via the Bugzilla XMLRPC interface. Requires Bugzilla 3.4 or later.
+
+2. Check data via the Bugzilla XMLRPC interface and submit bug change
+   via email to Bugzilla email interface. Requires Bugzilla 3.4 or later.
 
 2. Writing directly to the Bugzilla database. Only Bugzilla installations
    using MySQL are supported. Requires Python MySQLdb.
@@ -37,15 +40,24 @@
 that the rights of that user are restricted in Bugzilla to the minimum
 necessary to add comments.
 
-Configuration items common to both access modes:
+Access via XMLRPC/email behaves uses XMLRPC to query Bugzilla, but sends
+email to the Bugzilla email interface to submit comments to bugs.
+The From: address in the email is set to the email address of the Mercurial
+user, so the comment appears to come from the Mercurial user. In the event
+that the Mercurial user email is not recognised by Bugzilla as a Bugzilla
+user, the Bugzilla username and password used to log into Bugzilla are
+used instead as the source of the comment.
+
+Configuration items common to all access modes:
 
 [bugzilla]
 version
   This access type to use. Values recognised are:
-  xmlrpc  Bugzilla XMLRPC interface.
-  3.0     MySQL access, Bugzilla 3.0 and later.
-  2.18    MySQL access, Bugzilla 2.18 and up to but not including 3.0.
-  2.16    MySQL access, Bugzilla 2.16 and up to but not including 2.18.
+  xmlrpc       Bugzilla XMLRPC interface.
+  xmlrpc+email Bugzilla XMLRPC and email interfaces.
+  3.0          MySQL access, Bugzilla 3.0 and later.
+  2.18         MySQL access, Bugzilla 2.18 and up to but not including 3.0.
+  2.16         MySQL access, Bugzilla 2.16 and up to but not including 2.18.
 
 regexp
   Regular expression to match bug IDs in changeset commit message.
@@ -80,6 +92,18 @@
   Base URL for browsing Mercurial repositories. Referenced from
   templates as {hgweb}.
 
+Configuration items common to XMLRPC+email and MySQL access modes:
+
+usermap
+  Path of file containing Mercurial committer email to Bugzilla user email
+  mappings. If specified, the file should contain one mapping per
+  line, "committer"="Bugzilla user". See also the [usermap] section.
+
+[usermap]
+The [usermap] section is used to specify mappings of Mercurial
+committer email to Bugzilla user email. See also [bugzilla].usermap.
+Contains entries of the form "committer"="Bugzilla user".
+
 XMLRPC access mode configuration:
 
 [bugzilla]
@@ -93,6 +117,16 @@
 password
   The password for Bugzilla login.
 
+XMLRPC+email access mode uses the XMLRPC access mode configuration items,
+and also:
+
+[bugzilla]
+bzemail
+  The Bugzilla email address.
+
+In addition, the Mercurial email settings must be configured. See the
+documentation for 'hgrc', sections '[email]' and '[smtp]'.
+
 MySQL access mode configuration:
 
 [bugzilla]
@@ -127,16 +161,6 @@
   from 2.18 it is "cd %(bzdir)s && perl -T contrib/sendbugmail.pl
   %(id)s %(user)s".
 
-usermap
-  Path of file containing Mercurial committer ID to Bugzilla user ID
-  mappings. If specified, the file should contain one mapping per
-  line, "committer"="Bugzilla user". See also the [usermap] section.
-
-[usermap]
-The [usermap] section is used to specify mappings of Mercurial
-committer email to Bugzilla user email. See also [bugzilla].usermap.
-Contains entries of the form "committer"="Bugzilla user".
-
 Activating the extension::
 
     [extensions]
@@ -162,6 +186,22 @@
     [web]
     baseurl=http://my-project.org/hg
 
+XMLRPC+email example configuration. This uses the Bugzilla at
+'http://my-project.org/bugzilla', logging in as user 'bugmail@my-project.org'
+wityh password 'plugh'. It is used with a collection of Mercurial
+repositories in '/var/local/hg/repos/'. Bug comments are sent to the
+Bugzilla email address 'buzilla@my-project.org'. ::
+
+    [bugzilla]
+    user=bugmail@my-project.org
+    password=plugh
+    version=xmlrpc
+    bzemail=bugzilla@my-project.org
+
+    [web]
+    baseurl=https://dev.laicatc.com/hg
+    bugzillaurl=https://dev.laicatc.com/bugzilla
+
 MySQL example configuration. This is for a collection of Mercurial
 repositories in '/var/local/hg/repos/' used with a local Bugzilla 3.2
 installation in /opt/bugzilla-3.2. The MySQL database is on 'localhost',
@@ -185,7 +225,7 @@
     [usermap]
     user@emaildomain.com=user.name@bugzilladomain.com
 
-Both the above add a comment to the Bugzilla bug record of the form::
+All the above add a comment to the Bugzilla bug record of the form::
 
     Changeset 3b16791d6642 in repository-name.
     http://dev.domain.com/hg/repository-name/rev/3b16791d6642
@@ -195,7 +235,7 @@
 
 from mercurial.i18n import _
 from mercurial.node import short
-from mercurial import cmdutil, templater, util
+from mercurial import cmdutil, mail, templater, util
 import re, time, xmlrpclib
 
 class bzaccess(object):
@@ -520,6 +560,59 @@
     def add_comment(self, bugid, text, committer):
         self.bzproxy.Bug.add_comment(dict(id=bugid, comment=text))
 
+class bzxmlrpcemail(bzxmlrpc):
+    """Read data from Bugzilla via XMLRPC, send updates via email.
+
+    Advantages of sending updates via email:
+      1. Comments can be added as any user, not just logged in user.
+      2. Bug statuses and other fields not accessible via XMLRPC can
+        be updated. This is not currently used.
+    """
+
+    def __init__(self, ui):
+        bzxmlrpc.__init__(self, ui)
+
+        self.bzemail = self.ui.config('bugzilla', 'bzemail')
+        if not self.bzemail:
+            raise util.Abort(_("configuration 'bzemail' missing"))
+        mail.validateconfig(self.ui)
+
+    def send_bug_modify_email(self, bugid, commands, comment, committer):
+        '''send modification message to Bugzilla bug via email.
+
+        The message format is documented in the Bugzilla email_in.pl
+        specification. commands is a list of command lines, comment is the
+        comment text.
+
+        To stop users from crafting commit comments with
+        Bugzilla commands, specify the bug ID via the message body, rather
+        than the subject line, and leave a blank line after it.
+        '''
+        user = self.map_committer(committer)
+        matches = self.bzproxy.User.get(dict(match=[user]))
+        if not matches['users']:
+            user = self.ui.config('bugzilla', 'user', 'bugs')
+            matches = self.bzproxy.User.get(dict(match=[user]))
+            if not matches['users']:
+                raise util.Abort(_("default bugzilla user %s email not found") %
+                                 user)
+        user = matches['users'][0]['email']
+
+        text = "\n".join(commands) + "\n@bug_id = %d\n\n" % bugid + comment
+
+        _charsets = mail._charsets(self.ui)
+        user = mail.addressencode(self.ui, user, _charsets)
+        bzemail = mail.addressencode(self.ui, self.bzemail, _charsets)
+        msg = mail.mimeencode(self.ui, text, _charsets)
+        msg['From'] = user
+        msg['To'] = bzemail
+        msg['Subject'] = mail.headencode(self.ui, "Bug modification", _charsets)
+        sendmail = mail.connect(self.ui)
+        sendmail(user, bzemail, msg.as_string())
+
+    def add_comment(self, bugid, text, committer):
+        self.send_bug_modify_email(bugid, [], text, committer)
+
 class bugzilla(object):
     # supported versions of bugzilla. different versions have
     # different schemas.
@@ -527,7 +620,8 @@
         '2.16': bzmysql,
         '2.18': bzmysql_2_18,
         '3.0':  bzmysql_3_0,
-        'xmlrpc': bzxmlrpc
+        'xmlrpc': bzxmlrpc,
+        'xmlrpc+email': bzxmlrpcemail
         }
 
     _default_bug_re = (r'bugs?\s*,?\s*(?:#|nos?\.?|num(?:ber)?s?)?\s*'