Mercurial > hg
comparison hgext/bugzilla.py @ 45942:89a2afe31e82
formating: upgrade to black 20.8b1
This required a couple of small tweaks to un-confuse black, but now it
works. Big formatting changes come from:
* Dramatically improved collection-splitting logic upstream
* Black having a strong (correct IMO) opinion that """ is better than '''
Differential Revision: https://phab.mercurial-scm.org/D9430
author | Augie Fackler <raf@durin42.com> |
---|---|
date | Fri, 27 Nov 2020 17:03:29 -0500 |
parents | 3194cc8c8de0 |
children | d6afa9c149c3 |
comparison
equal
deleted
inserted
replaced
45941:346af7687c6f | 45942:89a2afe31e82 |
---|---|
323 | 323 |
324 configtable = {} | 324 configtable = {} |
325 configitem = registrar.configitem(configtable) | 325 configitem = registrar.configitem(configtable) |
326 | 326 |
327 configitem( | 327 configitem( |
328 b'bugzilla', b'apikey', default=b'', | 328 b'bugzilla', |
329 ) | 329 b'apikey', |
330 configitem( | 330 default=b'', |
331 b'bugzilla', b'bzdir', default=b'/var/www/html/bugzilla', | 331 ) |
332 ) | 332 configitem( |
333 configitem( | 333 b'bugzilla', |
334 b'bugzilla', b'bzemail', default=None, | 334 b'bzdir', |
335 ) | 335 default=b'/var/www/html/bugzilla', |
336 configitem( | 336 ) |
337 b'bugzilla', b'bzurl', default=b'http://localhost/bugzilla/', | 337 configitem( |
338 ) | 338 b'bugzilla', |
339 configitem( | 339 b'bzemail', |
340 b'bugzilla', b'bzuser', default=None, | 340 default=None, |
341 ) | 341 ) |
342 configitem( | 342 configitem( |
343 b'bugzilla', b'db', default=b'bugs', | 343 b'bugzilla', |
344 b'bzurl', | |
345 default=b'http://localhost/bugzilla/', | |
346 ) | |
347 configitem( | |
348 b'bugzilla', | |
349 b'bzuser', | |
350 default=None, | |
351 ) | |
352 configitem( | |
353 b'bugzilla', | |
354 b'db', | |
355 default=b'bugs', | |
344 ) | 356 ) |
345 configitem( | 357 configitem( |
346 b'bugzilla', | 358 b'bugzilla', |
347 b'fixregexp', | 359 b'fixregexp', |
348 default=( | 360 default=( |
351 br'(?P<ids>(?:#?\d+\s*(?:,?\s*(?:and)?)?\s*)+)' | 363 br'(?P<ids>(?:#?\d+\s*(?:,?\s*(?:and)?)?\s*)+)' |
352 br'\.?\s*(?:h(?:ours?)?\s*(?P<hours>\d*(?:\.\d+)?))?' | 364 br'\.?\s*(?:h(?:ours?)?\s*(?P<hours>\d*(?:\.\d+)?))?' |
353 ), | 365 ), |
354 ) | 366 ) |
355 configitem( | 367 configitem( |
356 b'bugzilla', b'fixresolution', default=b'FIXED', | 368 b'bugzilla', |
357 ) | 369 b'fixresolution', |
358 configitem( | 370 default=b'FIXED', |
359 b'bugzilla', b'fixstatus', default=b'RESOLVED', | 371 ) |
360 ) | 372 configitem( |
361 configitem( | 373 b'bugzilla', |
362 b'bugzilla', b'host', default=b'localhost', | 374 b'fixstatus', |
363 ) | 375 default=b'RESOLVED', |
364 configitem( | 376 ) |
365 b'bugzilla', b'notify', default=configitem.dynamicdefault, | 377 configitem( |
366 ) | 378 b'bugzilla', |
367 configitem( | 379 b'host', |
368 b'bugzilla', b'password', default=None, | 380 default=b'localhost', |
381 ) | |
382 configitem( | |
383 b'bugzilla', | |
384 b'notify', | |
385 default=configitem.dynamicdefault, | |
386 ) | |
387 configitem( | |
388 b'bugzilla', | |
389 b'password', | |
390 default=None, | |
369 ) | 391 ) |
370 configitem( | 392 configitem( |
371 b'bugzilla', | 393 b'bugzilla', |
372 b'regexp', | 394 b'regexp', |
373 default=( | 395 default=( |
375 br'(?P<ids>(?:\d+\s*(?:,?\s*(?:and)?)?\s*)+)' | 397 br'(?P<ids>(?:\d+\s*(?:,?\s*(?:and)?)?\s*)+)' |
376 br'\.?\s*(?:h(?:ours?)?\s*(?P<hours>\d*(?:\.\d+)?))?' | 398 br'\.?\s*(?:h(?:ours?)?\s*(?P<hours>\d*(?:\.\d+)?))?' |
377 ), | 399 ), |
378 ) | 400 ) |
379 configitem( | 401 configitem( |
380 b'bugzilla', b'strip', default=0, | 402 b'bugzilla', |
381 ) | 403 b'strip', |
382 configitem( | 404 default=0, |
383 b'bugzilla', b'style', default=None, | 405 ) |
384 ) | 406 configitem( |
385 configitem( | 407 b'bugzilla', |
386 b'bugzilla', b'template', default=None, | 408 b'style', |
387 ) | 409 default=None, |
388 configitem( | 410 ) |
389 b'bugzilla', b'timeout', default=5, | 411 configitem( |
390 ) | 412 b'bugzilla', |
391 configitem( | 413 b'template', |
392 b'bugzilla', b'user', default=b'bugs', | 414 default=None, |
393 ) | 415 ) |
394 configitem( | 416 configitem( |
395 b'bugzilla', b'usermap', default=None, | 417 b'bugzilla', |
396 ) | 418 b'timeout', |
397 configitem( | 419 default=5, |
398 b'bugzilla', b'version', default=None, | 420 ) |
421 configitem( | |
422 b'bugzilla', | |
423 b'user', | |
424 default=b'bugs', | |
425 ) | |
426 configitem( | |
427 b'bugzilla', | |
428 b'usermap', | |
429 default=None, | |
430 ) | |
431 configitem( | |
432 b'bugzilla', | |
433 b'version', | |
434 default=None, | |
399 ) | 435 ) |
400 | 436 |
401 | 437 |
402 class bzaccess(object): | 438 class bzaccess(object): |
403 '''Base class for access to Bugzilla.''' | 439 '''Base class for access to Bugzilla.''' |
428 | 464 |
429 def filter_cset_known_bug_ids(self, node, bugs): | 465 def filter_cset_known_bug_ids(self, node, bugs): |
430 '''remove bug IDs where node occurs in comment text from bugs.''' | 466 '''remove bug IDs where node occurs in comment text from bugs.''' |
431 | 467 |
432 def updatebug(self, bugid, newstate, text, committer): | 468 def updatebug(self, bugid, newstate, text, committer): |
433 '''update the specified bug. Add comment text and set new states. | 469 """update the specified bug. Add comment text and set new states. |
434 | 470 |
435 If possible add the comment as being from the committer of | 471 If possible add the comment as being from the committer of |
436 the changeset. Otherwise use the default Bugzilla user. | 472 the changeset. Otherwise use the default Bugzilla user. |
437 ''' | 473 """ |
438 | 474 |
439 def notify(self, bugs, committer): | 475 def notify(self, bugs, committer): |
440 '''Force sending of Bugzilla notification emails. | 476 """Force sending of Bugzilla notification emails. |
441 | 477 |
442 Only required if the access method does not trigger notification | 478 Only required if the access method does not trigger notification |
443 emails automatically. | 479 emails automatically. |
444 ''' | 480 """ |
445 | 481 |
446 | 482 |
447 # Bugzilla via direct access to MySQL database. | 483 # Bugzilla via direct access to MySQL database. |
448 class bzmysql(bzaccess): | 484 class bzmysql(bzaccess): |
449 '''Support for direct MySQL access to Bugzilla. | 485 """Support for direct MySQL access to Bugzilla. |
450 | 486 |
451 The earliest Bugzilla version this is tested with is version 2.16. | 487 The earliest Bugzilla version this is tested with is version 2.16. |
452 | 488 |
453 If your Bugzilla is version 3.4 or above, you are strongly | 489 If your Bugzilla is version 3.4 or above, you are strongly |
454 recommended to use the XMLRPC access method instead. | 490 recommended to use the XMLRPC access method instead. |
455 ''' | 491 """ |
456 | 492 |
457 @staticmethod | 493 @staticmethod |
458 def sql_buglist(ids): | 494 def sql_buglist(ids): |
459 '''return SQL-friendly list of bug ids''' | 495 '''return SQL-friendly list of bug ids''' |
460 return b'(' + b','.join(map(str, ids)) + b')' | 496 return b'(' + b','.join(map(str, ids)) + b')' |
579 userid = int(all[0][0]) | 615 userid = int(all[0][0]) |
580 self.user_ids[user] = userid | 616 self.user_ids[user] = userid |
581 return userid | 617 return userid |
582 | 618 |
583 def get_bugzilla_user(self, committer): | 619 def get_bugzilla_user(self, committer): |
584 '''See if committer is a registered bugzilla user. Return | 620 """See if committer is a registered bugzilla user. Return |
585 bugzilla username and userid if so. If not, return default | 621 bugzilla username and userid if so. If not, return default |
586 bugzilla username and userid.''' | 622 bugzilla username and userid.""" |
587 user = self.map_committer(committer) | 623 user = self.map_committer(committer) |
588 try: | 624 try: |
589 userid = self.get_user_id(user) | 625 userid = self.get_user_id(user) |
590 except KeyError: | 626 except KeyError: |
591 try: | 627 try: |
602 % (user, defaultuser) | 638 % (user, defaultuser) |
603 ) | 639 ) |
604 return (user, userid) | 640 return (user, userid) |
605 | 641 |
606 def updatebug(self, bugid, newstate, text, committer): | 642 def updatebug(self, bugid, newstate, text, committer): |
607 '''update bug state with comment text. | 643 """update bug state with comment text. |
608 | 644 |
609 Try adding comment as committer of changeset, otherwise as | 645 Try adding comment as committer of changeset, otherwise as |
610 default bugzilla user.''' | 646 default bugzilla user.""" |
611 if len(newstate) > 0: | 647 if len(newstate) > 0: |
612 self.ui.warn(_(b"Bugzilla/MySQL cannot update bug state\n")) | 648 self.ui.warn(_(b"Bugzilla/MySQL cannot update bug state\n")) |
613 | 649 |
614 (user, userid) = self.get_bugzilla_user(committer) | 650 (user, userid) = self.get_bugzilla_user(committer) |
615 now = time.strftime('%Y-%m-%d %H:%M:%S') | 651 now = time.strftime('%Y-%m-%d %H:%M:%S') |
867 if fieldname == b"id": | 903 if fieldname == b"id": |
868 fieldname = b"bug_id" | 904 fieldname = b"bug_id" |
869 return b"@%s = %s" % (fieldname, pycompat.bytestr(value)) | 905 return b"@%s = %s" % (fieldname, pycompat.bytestr(value)) |
870 | 906 |
871 def send_bug_modify_email(self, bugid, commands, comment, committer): | 907 def send_bug_modify_email(self, bugid, commands, comment, committer): |
872 '''send modification message to Bugzilla bug via email. | 908 """send modification message to Bugzilla bug via email. |
873 | 909 |
874 The message format is documented in the Bugzilla email_in.pl | 910 The message format is documented in the Bugzilla email_in.pl |
875 specification. commands is a list of command lines, comment is the | 911 specification. commands is a list of command lines, comment is the |
876 comment text. | 912 comment text. |
877 | 913 |
878 To stop users from crafting commit comments with | 914 To stop users from crafting commit comments with |
879 Bugzilla commands, specify the bug ID via the message body, rather | 915 Bugzilla commands, specify the bug ID via the message body, rather |
880 than the subject line, and leave a blank line after it. | 916 than the subject line, and leave a blank line after it. |
881 ''' | 917 """ |
882 user = self.map_committer(committer) | 918 user = self.map_committer(committer) |
883 matches = self.bzproxy.User.get( | 919 matches = self.bzproxy.User.get( |
884 {b'match': [user], b'token': self.bztoken} | 920 {b'match': [user], b'token': self.bztoken} |
885 ) | 921 ) |
886 if not matches[b'users']: | 922 if not matches[b'users']: |
1014 % (bugid, sn) | 1050 % (bugid, sn) |
1015 ) | 1051 ) |
1016 del bugs[bugid] | 1052 del bugs[bugid] |
1017 | 1053 |
1018 def updatebug(self, bugid, newstate, text, committer): | 1054 def updatebug(self, bugid, newstate, text, committer): |
1019 '''update the specified bug. Add comment text and set new states. | 1055 """update the specified bug. Add comment text and set new states. |
1020 | 1056 |
1021 If possible add the comment as being from the committer of | 1057 If possible add the comment as being from the committer of |
1022 the changeset. Otherwise use the default Bugzilla user. | 1058 the changeset. Otherwise use the default Bugzilla user. |
1023 ''' | 1059 """ |
1024 bugmod = {} | 1060 bugmod = {} |
1025 if b'hours' in newstate: | 1061 if b'hours' in newstate: |
1026 bugmod[b'work_time'] = newstate[b'hours'] | 1062 bugmod[b'work_time'] = newstate[b'hours'] |
1027 if b'fix' in newstate: | 1063 if b'fix' in newstate: |
1028 bugmod[b'status'] = self.fixstatus | 1064 bugmod[b'status'] = self.fixstatus |
1048 }, | 1084 }, |
1049 ) | 1085 ) |
1050 self.ui.debug(b'added comment to bug %s\n' % bugid) | 1086 self.ui.debug(b'added comment to bug %s\n' % bugid) |
1051 | 1087 |
1052 def notify(self, bugs, committer): | 1088 def notify(self, bugs, committer): |
1053 '''Force sending of Bugzilla notification emails. | 1089 """Force sending of Bugzilla notification emails. |
1054 | 1090 |
1055 Only required if the access method does not trigger notification | 1091 Only required if the access method does not trigger notification |
1056 emails automatically. | 1092 emails automatically. |
1057 ''' | 1093 """ |
1058 pass | 1094 pass |
1059 | 1095 |
1060 | 1096 |
1061 class bugzilla(object): | 1097 class bugzilla(object): |
1062 # supported versions of bugzilla. different versions have | 1098 # supported versions of bugzilla. different versions have |
1090 self.ui.config(b'bugzilla', b'fixregexp'), re.IGNORECASE | 1126 self.ui.config(b'bugzilla', b'fixregexp'), re.IGNORECASE |
1091 ) | 1127 ) |
1092 self.split_re = re.compile(br'\D+') | 1128 self.split_re = re.compile(br'\D+') |
1093 | 1129 |
1094 def find_bugs(self, ctx): | 1130 def find_bugs(self, ctx): |
1095 '''return bugs dictionary created from commit comment. | 1131 """return bugs dictionary created from commit comment. |
1096 | 1132 |
1097 Extract bug info from changeset comments. Filter out any that are | 1133 Extract bug info from changeset comments. Filter out any that are |
1098 not known to Bugzilla, and any that already have a reference to | 1134 not known to Bugzilla, and any that already have a reference to |
1099 the given changeset in their comments. | 1135 the given changeset in their comments. |
1100 ''' | 1136 """ |
1101 start = 0 | 1137 start = 0 |
1102 bugs = {} | 1138 bugs = {} |
1103 bugmatch = self.bug_re.search(ctx.description(), start) | 1139 bugmatch = self.bug_re.search(ctx.description(), start) |
1104 fixmatch = self.fix_re.search(ctx.description(), start) | 1140 fixmatch = self.fix_re.search(ctx.description(), start) |
1105 while True: | 1141 while True: |
1150 | 1186 |
1151 def update(self, bugid, newstate, ctx): | 1187 def update(self, bugid, newstate, ctx): |
1152 '''update bugzilla bug with reference to changeset.''' | 1188 '''update bugzilla bug with reference to changeset.''' |
1153 | 1189 |
1154 def webroot(root): | 1190 def webroot(root): |
1155 '''strip leading prefix of repo root and turn into | 1191 """strip leading prefix of repo root and turn into |
1156 url-safe path.''' | 1192 url-safe path.""" |
1157 count = int(self.ui.config(b'bugzilla', b'strip')) | 1193 count = int(self.ui.config(b'bugzilla', b'strip')) |
1158 root = util.pconvert(root) | 1194 root = util.pconvert(root) |
1159 while count > 0: | 1195 while count > 0: |
1160 c = root.find(b'/') | 1196 c = root.find(b'/') |
1161 if c == -1: | 1197 if c == -1: |
1193 '''ensure Bugzilla users are notified of bug change.''' | 1229 '''ensure Bugzilla users are notified of bug change.''' |
1194 self.bzdriver.notify(bugs, committer) | 1230 self.bzdriver.notify(bugs, committer) |
1195 | 1231 |
1196 | 1232 |
1197 def hook(ui, repo, hooktype, node=None, **kwargs): | 1233 def hook(ui, repo, hooktype, node=None, **kwargs): |
1198 '''add comment to bugzilla for each changeset that refers to a | 1234 """add comment to bugzilla for each changeset that refers to a |
1199 bugzilla bug id. only add a comment once per bug, so same change | 1235 bugzilla bug id. only add a comment once per bug, so same change |
1200 seen multiple times does not fill bug with duplicate data.''' | 1236 seen multiple times does not fill bug with duplicate data.""" |
1201 if node is None: | 1237 if node is None: |
1202 raise error.Abort( | 1238 raise error.Abort( |
1203 _(b'hook type %s does not pass a changeset id') % hooktype | 1239 _(b'hook type %s does not pass a changeset id') % hooktype |
1204 ) | 1240 ) |
1205 try: | 1241 try: |