##// END OF EJS Templates
bugzilla: allow change comment to mark bugs fixed...
Jim Hague -
r16223:ac4fd323 default
parent child Browse files
Show More
@@ -13,7 +13,7 b' that refer to bugs by Bugzilla ID are se'
13 13 the Mercurial template mechanism.
14 14
15 15 The bug references can optionally include an update for Bugzilla of the
16 hours spent working on the bug.
16 hours spent working on the bug. Bugs can also be marked fixed.
17 17
18 18 Three basic modes of access to Bugzilla are provided:
19 19
@@ -39,7 +39,7 b' Access via XMLRPC needs a Bugzilla usern'
39 39 in the configuration. Comments are added under that username. Since the
40 40 configuration must be readable by all Mercurial users, it is recommended
41 41 that the rights of that user are restricted in Bugzilla to the minimum
42 necessary to add comments.
42 necessary to add comments. Marking bugs fixed requires Bugzilla 4.0 and later.
43 43
44 44 Access via XMLRPC/email uses XMLRPC to query Bugzilla, but sends
45 45 email to the Bugzilla email interface to submit comments to bugs.
@@ -47,7 +47,8 b' The From: address in the email is set to'
47 47 user, so the comment appears to come from the Mercurial user. In the event
48 48 that the Mercurial user email is not recognised by Bugzilla as a Bugzilla
49 49 user, the email associated with the Bugzilla username used to log into
50 Bugzilla is used instead as the source of the comment.
50 Bugzilla is used instead as the source of the comment. Marking bugs fixed
51 works on all supported Bugzilla versions.
51 52
52 53 Configuration items common to all access modes:
53 54
@@ -63,7 +64,7 b' bugzilla.version'
63 64 including 2.18.
64 65
65 66 bugzilla.regexp
66 Regular expression to match bug IDs in changeset commit message.
67 Regular expression to match bug IDs for update in changeset commit message.
67 68 It must contain one "()" named group ``<ids>`` containing the bug
68 69 IDs separated by non-digit characters. It may also contain
69 70 a named group ``<hours>`` with a floating-point number giving the
@@ -74,6 +75,24 b' bugzilla.regexp'
74 75 variations thereof, followed by an hours number prefixed by ``h`` or
75 76 ``hours``, e.g. ``hours 1.5``. Matching is case insensitive.
76 77
78 bugzilla.fixregexp
79 Regular expression to match bug IDs for marking fixed in changeset
80 commit message. This must contain a "()" named group ``<ids>` containing
81 the bug IDs separated by non-digit characters. It may also contain
82 a named group ``<hours>`` with a floating-point number giving the
83 hours worked on the bug. If no named groups are present, the first
84 "()" group is assumed to contain the bug IDs, and work time is not
85 updated. The default expression matches ``Fixes 1234``, ``Fixes bug 1234``,
86 ``Fixes bugs 1234,5678``, ``Fixes 1234 and 5678`` and
87 variations thereof, followed by an hours number prefixed by ``h`` or
88 ``hours``, e.g. ``hours 1.5``. Matching is case insensitive.
89
90 bugzilla.fixstatus
91 The status to set a bug to when marking fixed. Default ``RESOLVED``.
92
93 bugzilla.fixresolution
94 The resolution to set a bug to when marking fixed. Default ``FIXED``.
95
77 96 bugzilla.style
78 97 The style file to use when formatting comments.
79 98
@@ -285,6 +304,7 b' class bzaccess(object):'
285 304 # updates to bug state. Recognised dict keys are:
286 305 #
287 306 # 'hours': Value, float containing work hours to be updated.
307 # 'fix': If key present, bug is to be marked fixed. Value ignored.
288 308
289 309 def filter_real_bug_ids(self, bugs):
290 310 '''remove bug IDs that do not exist in Bugzilla from bugs.'''
@@ -587,6 +607,10 b' class bzxmlrpc(bzaccess):'
587 607 user = self.ui.config('bugzilla', 'user', 'bugs')
588 608 passwd = self.ui.config('bugzilla', 'password')
589 609
610 self.fixstatus = self.ui.config('bugzilla', 'fixstatus', 'RESOLVED')
611 self.fixresolution = self.ui.config('bugzilla', 'fixresolution',
612 'FIXED')
613
590 614 self.bzproxy = xmlrpclib.ServerProxy(bzweb, self.transport(bzweb))
591 615 self.bzproxy.User.login(dict(login=user, password=passwd))
592 616
@@ -618,9 +642,22 b' class bzxmlrpc(bzaccess):'
618 642 del bugs[id]
619 643
620 644 def updatebug(self, bugid, newstate, text, committer):
621 args = dict(id=bugid, comment=text)
645 args = {}
622 646 if 'hours' in newstate:
623 647 args['work_time'] = newstate['hours']
648
649 if self.bzvermajor >= 4:
650 args['ids'] = [bugid]
651 args['comment'] = {'body' : text}
652 args['status'] = self.fixstatus
653 args['resolution'] = self.fixresolution
654 self.bzproxy.Bug.update(args)
655 else:
656 if 'fix' in newstate:
657 self.ui.warn(_("Bugzilla/XMLRPC needs Bugzilla 4.0 or later "
658 "to mark bugs fixed\n"))
659 args['id'] = bugid
660 args['comment'] = text
624 661 self.bzproxy.Bug.add_comment(args)
625 662
626 663 class bzxmlrpcemail(bzxmlrpc):
@@ -631,8 +668,9 b' class bzxmlrpcemail(bzxmlrpc):'
631 668 2. Bug statuses or other fields not accessible via XMLRPC can
632 669 potentially be updated.
633 670
634 Currently all status updates recognised can be done via XMLRPC, so
635 item 1 is the only actual advantage.
671 There is no XMLRPC function to change bug status before Bugzilla
672 4.0, so bugs cannot be marked fixed via XMLRPC before Bugzilla 4.0.
673 But bugs can be marked fixed via email from 3.4 onwards.
636 674 """
637 675
638 676 def __init__(self, ui):
@@ -680,6 +718,9 b' class bzxmlrpcemail(bzxmlrpc):'
680 718 cmds = []
681 719 if 'hours' in newstate:
682 720 cmds.append(self.makecommandline("work_time", newstate['hours']))
721 if 'fix' in newstate:
722 cmds.append(self.makecommandline("bug_status", self.fixstatus))
723 cmds.append(self.makecommandline("resolution", self.fixresolution))
683 724 self.send_bug_modify_email(bugid, cmds, text, committer)
684 725
685 726 class bugzilla(object):
@@ -697,6 +738,11 b' class bugzilla(object):'
697 738 r'(?P<ids>(?:\d+\s*(?:,?\s*(?:and)?)?\s*)+)'
698 739 r'\.?\s*(?:h(?:ours?)?\s*(?P<hours>\d*(?:\.\d+)?))?')
699 740
741 _default_fix_re = (r'fix(?:es)?\s*(?:bugs?\s*)?,?\s*'
742 r'(?:nos?\.?|num(?:ber)?s?)?\s*'
743 r'(?P<ids>(?:#?\d+\s*(?:,?\s*(?:and)?)?\s*)+)'
744 r'\.?\s*(?:h(?:ours?)?\s*(?P<hours>\d*(?:\.\d+)?))?')
745
700 746 _bz = None
701 747
702 748 def __init__(self, ui, repo):
@@ -721,6 +767,7 b' class bugzilla(object):'
721 767 return getattr(self.bz(), key)
722 768
723 769 _bug_re = None
770 _fix_re = None
724 771 _split_re = None
725 772
726 773 def find_bugs(self, ctx):
@@ -732,18 +779,39 b' class bugzilla(object):'
732 779 '''
733 780 if bugzilla._bug_re is None:
734 781 bugzilla._bug_re = re.compile(
735 self.ui.config('bugzilla', 'regexp', bugzilla._default_bug_re),
736 re.IGNORECASE)
782 self.ui.config('bugzilla', 'regexp',
783 bugzilla._default_bug_re), re.IGNORECASE)
784 bugzilla._fix_re = re.compile(
785 self.ui.config('bugzilla', 'fixregexp',
786 bugzilla._default_fix_re), re.IGNORECASE)
737 787 bugzilla._split_re = re.compile(r'\D+')
738 788 start = 0
739 789 hours = 0.0
740 790 bugs = {}
791 bugmatch = bugzilla._bug_re.search(ctx.description(), start)
792 fixmatch = bugzilla._fix_re.search(ctx.description(), start)
741 793 while True:
742 794 bugattribs = {}
743 m = bugzilla._bug_re.search(ctx.description(), start)
744 if not m:
795 if not bugmatch and not fixmatch:
745 796 break
797 if not bugmatch:
798 m = fixmatch
799 elif not fixmatch:
800 m = bugmatch
801 else:
802 if bugmatch.start() < fixmatch.start():
803 m = bugmatch
804 else:
805 m = fixmatch
746 806 start = m.end()
807 if m is bugmatch:
808 bugmatch = bugzilla._bug_re.search(ctx.description(), start)
809 if 'fix' in bugattribs:
810 del bugattribs['fix']
811 else:
812 fixmatch = bugzilla._fix_re.search(ctx.description(), start)
813 bugattribs['fix'] = None
814
747 815 try:
748 816 ids = m.group('ids')
749 817 except IndexError:
General Comments 0
You need to be logged in to leave comments. Login now