Show More
@@ -145,28 +145,77 b' from mercurial.node import short' | |||||
145 | from mercurial import cmdutil, templater, util |
|
145 | from mercurial import cmdutil, templater, util | |
146 | import re, time |
|
146 | import re, time | |
147 |
|
147 | |||
148 | MySQLdb = None |
|
148 | class bzaccess(object): | |
149 |
|
149 | '''Base class for access to Bugzilla.''' | ||
150 | def buglist(ids): |
|
|||
151 | return '(' + ','.join(map(str, ids)) + ')' |
|
|||
152 |
|
||||
153 | class bugzilla_2_16(object): |
|
|||
154 | '''support for bugzilla version 2.16.''' |
|
|||
155 |
|
150 | |||
156 | def __init__(self, ui): |
|
151 | def __init__(self, ui): | |
157 | self.ui = ui |
|
152 | self.ui = ui | |
|
153 | usermap = self.ui.config('bugzilla', 'usermap') | |||
|
154 | if usermap: | |||
|
155 | self.ui.readconfig(usermap, sections=['usermap']) | |||
|
156 | ||||
|
157 | def map_committer(self, user): | |||
|
158 | '''map name of committer to Bugzilla user name.''' | |||
|
159 | for committer, bzuser in self.ui.configitems('usermap'): | |||
|
160 | if committer.lower() == user.lower(): | |||
|
161 | return bzuser | |||
|
162 | return user | |||
|
163 | ||||
|
164 | # Methods to be implemented by access classes. | |||
|
165 | def filter_real_bug_ids(self, ids): | |||
|
166 | '''remove bug IDs that do not exist in Bugzilla from set.''' | |||
|
167 | pass | |||
|
168 | ||||
|
169 | def filter_cset_known_bug_ids(self, node, ids): | |||
|
170 | '''remove bug IDs where node occurs in comment text from set.''' | |||
|
171 | pass | |||
|
172 | ||||
|
173 | def add_comment(self, bugid, text, committer): | |||
|
174 | '''add comment to bug. | |||
|
175 | ||||
|
176 | If possible add the comment as being from the committer of | |||
|
177 | the changeset. Otherwise use the default Bugzilla user. | |||
|
178 | ''' | |||
|
179 | pass | |||
|
180 | ||||
|
181 | def notify(self, ids, committer): | |||
|
182 | '''Force sending of Bugzilla notification emails.''' | |||
|
183 | pass | |||
|
184 | ||||
|
185 | # Bugzilla via direct access to MySQL database. | |||
|
186 | class bzmysql(bzaccess): | |||
|
187 | '''Support for direct MySQL access to Bugzilla. | |||
|
188 | ||||
|
189 | The earliest Bugzilla version this is tested with is version 2.16. | |||
|
190 | ''' | |||
|
191 | ||||
|
192 | @staticmethod | |||
|
193 | def sql_buglist(ids): | |||
|
194 | '''return SQL-friendly list of bug ids''' | |||
|
195 | return '(' + ','.join(map(str, ids)) + ')' | |||
|
196 | ||||
|
197 | _MySQLdb = None | |||
|
198 | ||||
|
199 | def __init__(self, ui): | |||
|
200 | try: | |||
|
201 | import MySQLdb as mysql | |||
|
202 | bzmysql._MySQLdb = mysql | |||
|
203 | except ImportError, err: | |||
|
204 | raise util.Abort(_('python mysql support not available: %s') % err) | |||
|
205 | ||||
|
206 | bzaccess.__init__(self, ui) | |||
|
207 | ||||
158 | host = self.ui.config('bugzilla', 'host', 'localhost') |
|
208 | host = self.ui.config('bugzilla', 'host', 'localhost') | |
159 | user = self.ui.config('bugzilla', 'user', 'bugs') |
|
209 | user = self.ui.config('bugzilla', 'user', 'bugs') | |
160 | passwd = self.ui.config('bugzilla', 'password') |
|
210 | passwd = self.ui.config('bugzilla', 'password') | |
161 | db = self.ui.config('bugzilla', 'db', 'bugs') |
|
211 | db = self.ui.config('bugzilla', 'db', 'bugs') | |
162 | timeout = int(self.ui.config('bugzilla', 'timeout', 5)) |
|
212 | timeout = int(self.ui.config('bugzilla', 'timeout', 5)) | |
163 | usermap = self.ui.config('bugzilla', 'usermap') |
|
|||
164 | if usermap: |
|
|||
165 | self.ui.readconfig(usermap, sections=['usermap']) |
|
|||
166 | self.ui.note(_('connecting to %s:%s as %s, password %s\n') % |
|
213 | self.ui.note(_('connecting to %s:%s as %s, password %s\n') % | |
167 | (host, db, user, '*' * len(passwd))) |
|
214 | (host, db, user, '*' * len(passwd))) | |
168 |
self.conn = MySQLdb.connect(host=host, |
|
215 | self.conn = bzmysql._MySQLdb.connect(host=host, | |
169 | db=db, connect_timeout=timeout) |
|
216 | user=user, passwd=passwd, | |
|
217 | db=db, | |||
|
218 | connect_timeout=timeout) | |||
170 | self.cursor = self.conn.cursor() |
|
219 | self.cursor = self.conn.cursor() | |
171 | self.longdesc_id = self.get_longdesc_id() |
|
220 | self.longdesc_id = self.get_longdesc_id() | |
172 | self.user_ids = {} |
|
221 | self.user_ids = {} | |
@@ -177,7 +226,7 b' class bugzilla_2_16(object):' | |||||
177 | self.ui.note(_('query: %s %s\n') % (args, kwargs)) |
|
226 | self.ui.note(_('query: %s %s\n') % (args, kwargs)) | |
178 | try: |
|
227 | try: | |
179 | self.cursor.execute(*args, **kwargs) |
|
228 | self.cursor.execute(*args, **kwargs) | |
180 | except MySQLdb.MySQLError: |
|
229 | except bzmysql._MySQLdb.MySQLError: | |
181 | self.ui.note(_('failed query: %s %s\n') % (args, kwargs)) |
|
230 | self.ui.note(_('failed query: %s %s\n') % (args, kwargs)) | |
182 | raise |
|
231 | raise | |
183 |
|
232 | |||
@@ -191,7 +240,8 b' class bugzilla_2_16(object):' | |||||
191 |
|
240 | |||
192 | def filter_real_bug_ids(self, ids): |
|
241 | def filter_real_bug_ids(self, ids): | |
193 | '''filter not-existing bug ids from set.''' |
|
242 | '''filter not-existing bug ids from set.''' | |
194 |
self.run('select bug_id from bugs where bug_id in %s' % |
|
243 | self.run('select bug_id from bugs where bug_id in %s' % | |
|
244 | bzmysql.sql_buglist(ids)) | |||
195 | return set([c[0] for c in self.cursor.fetchall()]) |
|
245 | return set([c[0] for c in self.cursor.fetchall()]) | |
196 |
|
246 | |||
197 | def filter_cset_known_bug_ids(self, node, ids): |
|
247 | def filter_cset_known_bug_ids(self, node, ids): | |
@@ -199,7 +249,7 b' class bugzilla_2_16(object):' | |||||
199 |
|
249 | |||
200 | self.run('''select bug_id from longdescs where |
|
250 | self.run('''select bug_id from longdescs where | |
201 | bug_id in %s and thetext like "%%%s%%"''' % |
|
251 | bug_id in %s and thetext like "%%%s%%"''' % | |
202 | (buglist(ids), short(node))) |
|
252 | (bzmysql.sql_buglist(ids), short(node))) | |
203 | for (id,) in self.cursor.fetchall(): |
|
253 | for (id,) in self.cursor.fetchall(): | |
204 | self.ui.status(_('bug %d already knows about changeset %s\n') % |
|
254 | self.ui.status(_('bug %d already knows about changeset %s\n') % | |
205 | (id, short(node))) |
|
255 | (id, short(node))) | |
@@ -250,13 +300,6 b' class bugzilla_2_16(object):' | |||||
250 | self.user_ids[user] = userid |
|
300 | self.user_ids[user] = userid | |
251 | return userid |
|
301 | return userid | |
252 |
|
302 | |||
253 | def map_committer(self, user): |
|
|||
254 | '''map name of committer to bugzilla user name.''' |
|
|||
255 | for committer, bzuser in self.ui.configitems('usermap'): |
|
|||
256 | if committer.lower() == user.lower(): |
|
|||
257 | return bzuser |
|
|||
258 | return user |
|
|||
259 |
|
||||
260 | def get_bugzilla_user(self, committer): |
|
303 | def get_bugzilla_user(self, committer): | |
261 | '''see if committer is a registered bugzilla user. Return |
|
304 | '''see if committer is a registered bugzilla user. Return | |
262 | bugzilla username and userid if so. If not, return default |
|
305 | bugzilla username and userid if so. If not, return default | |
@@ -291,19 +334,19 b' class bugzilla_2_16(object):' | |||||
291 | (bugid, userid, now, self.longdesc_id)) |
|
334 | (bugid, userid, now, self.longdesc_id)) | |
292 | self.conn.commit() |
|
335 | self.conn.commit() | |
293 |
|
336 | |||
294 |
class b |
|
337 | class bzmysql_2_18(bzmysql): | |
295 | '''support for bugzilla 2.18 series.''' |
|
338 | '''support for bugzilla 2.18 series.''' | |
296 |
|
339 | |||
297 | def __init__(self, ui): |
|
340 | def __init__(self, ui): | |
298 |
b |
|
341 | bzmysql.__init__(self, ui) | |
299 | self.default_notify = \ |
|
342 | self.default_notify = \ | |
300 | "cd %(bzdir)s && perl -T contrib/sendbugmail.pl %(id)s %(user)s" |
|
343 | "cd %(bzdir)s && perl -T contrib/sendbugmail.pl %(id)s %(user)s" | |
301 |
|
344 | |||
302 |
class b |
|
345 | class bzmysql_3_0(bzmysql_2_18): | |
303 | '''support for bugzilla 3.0 series.''' |
|
346 | '''support for bugzilla 3.0 series.''' | |
304 |
|
347 | |||
305 | def __init__(self, ui): |
|
348 | def __init__(self, ui): | |
306 |
b |
|
349 | bzmysql_2_18.__init__(self, ui) | |
307 |
|
350 | |||
308 | def get_longdesc_id(self): |
|
351 | def get_longdesc_id(self): | |
309 | '''get identity of longdesc field''' |
|
352 | '''get identity of longdesc field''' | |
@@ -317,9 +360,9 b' class bugzilla(object):' | |||||
317 | # supported versions of bugzilla. different versions have |
|
360 | # supported versions of bugzilla. different versions have | |
318 | # different schemas. |
|
361 | # different schemas. | |
319 | _versions = { |
|
362 | _versions = { | |
320 |
'2.16': b |
|
363 | '2.16': bzmysql, | |
321 |
'2.18': b |
|
364 | '2.18': bzmysql_2_18, | |
322 |
'3.0': b |
|
365 | '3.0': bzmysql_3_0 | |
323 | } |
|
366 | } | |
324 |
|
367 | |||
325 | _default_bug_re = (r'bugs?\s*,?\s*(?:#|nos?\.?|num(?:ber)?s?)?\s*' |
|
368 | _default_bug_re = (r'bugs?\s*,?\s*(?:#|nos?\.?|num(?:ber)?s?)?\s*' | |
@@ -419,13 +462,6 b' def hook(ui, repo, hooktype, node=None, ' | |||||
419 | '''add comment to bugzilla for each changeset that refers to a |
|
462 | '''add comment to bugzilla for each changeset that refers to a | |
420 | bugzilla bug id. only add a comment once per bug, so same change |
|
463 | bugzilla bug id. only add a comment once per bug, so same change | |
421 | seen multiple times does not fill bug with duplicate data.''' |
|
464 | seen multiple times does not fill bug with duplicate data.''' | |
422 | try: |
|
|||
423 | import MySQLdb as mysql |
|
|||
424 | global MySQLdb |
|
|||
425 | MySQLdb = mysql |
|
|||
426 | except ImportError, err: |
|
|||
427 | raise util.Abort(_('python mysql support not available: %s') % err) |
|
|||
428 |
|
||||
429 | if node is None: |
|
465 | if node is None: | |
430 | raise util.Abort(_('hook type %s does not pass a changeset id') % |
|
466 | raise util.Abort(_('hook type %s does not pass a changeset id') % | |
431 | hooktype) |
|
467 | hooktype) | |
@@ -437,6 +473,6 b' def hook(ui, repo, hooktype, node=None, ' | |||||
437 | for id in ids: |
|
473 | for id in ids: | |
438 | bz.update(id, ctx) |
|
474 | bz.update(id, ctx) | |
439 | bz.notify(ids, util.email(ctx.user())) |
|
475 | bz.notify(ids, util.email(ctx.user())) | |
440 | except MySQLdb.MySQLError, err: |
|
476 | except Exception, e: | |
441 |
raise util.Abort(_(' |
|
477 | raise util.Abort(_('Bugzilla error: %s') % e) | |
442 |
|
478 |
General Comments 0
You need to be logged in to leave comments.
Login now