hg_hooks/bugzilla/versiontobugzilla.py
changeset 22 f55ca49f7f44
child 42 ac3a70c9f81c
equal deleted inserted replaced
21:36e05c0da8f7 22:f55ca49f7f44
       
     1 '''Bugzilla integration for adding versions from tags
       
     2 
       
     3 The hook updates the Bugzilla database directly. Only Bugzilla installations
       
     4 using MySQL are supported.
       
     5 
       
     6 This hook uses the same .hgrc parameters as the default Bugzilla hook. There
       
     7 is no need for configuring the same stuff twice. (connection, etc.)
       
     8 
       
     9 Configuring the extension: (same as Bugzilla -hook)
       
    10 
       
    11     [bugzilla]
       
    12     host       Hostname of the MySQL server holding the Bugzilla database.
       
    13     db         Name of the Bugzilla database in MySQL. Default 'bugs'.
       
    14     user       Username to use to access MySQL server. Default 'bugs'.
       
    15     password   Password to use to access MySQL server.
       
    16     timeout    Database connection timeout (seconds). Default 5.
       
    17 
       
    18 Additional elements under Bugzilla -section: (new items)
       
    19     [bugzilla]
       
    20     product    The name on the Bugzilla product that is used for adding 
       
    21                the new versions.
       
    22 
       
    23 Activating the extension:
       
    24 
       
    25     [extensions]
       
    26     hgext.versiontobugzilla =
       
    27 
       
    28     [hooks]
       
    29     incoming.versiontobugzilla = python:hgext.versiontobugzilla.hook
       
    30 
       
    31 Example configuration in hgrc:
       
    32     [bugzilla]
       
    33     host = localhost
       
    34     user = bugs
       
    35     password = password
       
    36     product = my_product
       
    37 
       
    38     [extensions]
       
    39     hgext.versiontobugzilla =
       
    40 
       
    41     [hooks]
       
    42     incoming.versiontobugzilla = python:hgext.versiontobugzilla.hook
       
    43 '''
       
    44 
       
    45 from mercurial import util
       
    46 import re
       
    47 
       
    48 MySQLdb = None
       
    49 
       
    50 class BugzillaClient:
       
    51     
       
    52     def __init__(self, ui, repo, node):
       
    53         self.tag = None
       
    54         self.ui = ui
       
    55         self.repo = repo
       
    56         self.node = node
       
    57         self.product = ui.config('bugzilla', 'product')
       
    58         self.host = ui.config('bugzilla', 'host', 'localhost')
       
    59         self.user = ui.config('bugzilla', 'user', 'bugs')
       
    60         self.passwd = ui.config('bugzilla', 'password')
       
    61         self.db = ui.config('bugzilla', 'db', 'bugs')
       
    62         self.timeout = int(ui.config('bugzilla', 'timeout', 10))
       
    63         self.connection = MySQLdb.connect(host=self.host, user=self.user, passwd=self.passwd,
       
    64                                     db=self.db, connect_timeout=self.timeout)
       
    65         self.cursor = self.connection.cursor()
       
    66 
       
    67     def printMessageInVerboseMode(self, message):
       
    68         '''Prints a message to console if hg has been executed with -v option.'''
       
    69         self.ui.note(message)
       
    70 
       
    71     def executeDatabaseQuery(self, *args, **kwargs):
       
    72         self.printMessageInVerboseMode('Bugzilla: query: %s %s\n' % (args, kwargs))
       
    73         try:
       
    74             self.cursor.execute(*args, **kwargs)
       
    75         except MySQLdb.MySQLError:
       
    76             self.printMessageInVerboseMode('Bugzilla: failed query: %s %s\n' % (args, kwargs))
       
    77             raise
       
    78 
       
    79     def commitContainsTag(self):
       
    80         self.parseTagFromCommitMessage()
       
    81         if self.tag:
       
    82             return True
       
    83         else:
       
    84             return False
       
    85 
       
    86     def parseTagFromCommitMessage(self):
       
    87         ctx = self.repo[self.node]
       
    88         version_re = re.compile(('Added tag (.+) for changeset [0-9a-h]+'), re.IGNORECASE)
       
    89         m = version_re.search(ctx.description())
       
    90         if m:
       
    91             self.tag = m.group(1)
       
    92 
       
    93     def insertTagIntoDatabase(self):
       
    94         self.makeSureThatProductExists()
       
    95         if not self.doesVersionAlreadyExist():
       
    96             self.printMessageInVerboseMode("Bugzilla: adding version '%s' to product '%s' in database.\n" % (self.tag, self.product))
       
    97             self.insertNewVersionIntoDatabase()
       
    98         else:
       
    99             self.printMessageInVerboseMode("Bugzilla: product '%s' already has a version '%s' in database. Not trying to add it again." % (self.product, self.tag))
       
   100 
       
   101     def makeSureThatProductExists(self):
       
   102         self.executeDatabaseQuery('select id from products where name = %s', (self.product,))
       
   103         ids = self.cursor.fetchall()
       
   104         if len(ids) != 1:
       
   105             raise util.Abort("Product '%s' does not exist in database, please check the [bugzilla] -section in hgrc." % self.product)
       
   106 
       
   107     def doesVersionAlreadyExist(self):
       
   108         self.executeDatabaseQuery('select * from versions where value = %s and product_id in (select id from products where name=%s )', (self.tag, self.product))
       
   109         ids = self.cursor.fetchall()
       
   110         if len(ids) == 1:
       
   111             return True
       
   112         else:
       
   113             return False
       
   114 
       
   115     def insertNewVersionIntoDatabase(self):
       
   116         self.executeDatabaseQuery('insert into versions (value, product_id) values (%s, (select id from products where name=%s ))', (self.tag, self.product))
       
   117         self.connection.commit()
       
   118 
       
   119 def hook(ui, repo, hooktype, node=None, **kwargs):
       
   120 
       
   121     try:
       
   122         import MySQLdb as mysql
       
   123         global MySQLdb
       
   124         MySQLdb = mysql
       
   125     except ImportError, err:
       
   126         raise util.Abort('MySQL driver not installed: %s' % err)
       
   127 
       
   128     if node is None:
       
   129         raise util.Abort('Only hooks that have changesetid''s can be used.')
       
   130 
       
   131     try: 
       
   132         bzClient = BugzillaClient(ui, repo, node)
       
   133         if bzClient.commitContainsTag():
       
   134             bzClient.insertTagIntoDatabase()
       
   135     except MySQLdb.MySQLError, err:
       
   136         raise util.Abort('Database error: %s' % err[1])