Show More
@@ -13,7 +13,7 b' that refer to bugs by Bugzilla ID are se' | |||||
13 | the Mercurial template mechanism. |
|
13 | the Mercurial template mechanism. | |
14 |
|
14 | |||
15 | The bug references can optionally include an update for Bugzilla of the |
|
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 | Three basic modes of access to Bugzilla are provided: |
|
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 | in the configuration. Comments are added under that username. Since the |
|
39 | in the configuration. Comments are added under that username. Since the | |
40 | configuration must be readable by all Mercurial users, it is recommended |
|
40 | configuration must be readable by all Mercurial users, it is recommended | |
41 | that the rights of that user are restricted in Bugzilla to the minimum |
|
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 | Access via XMLRPC/email uses XMLRPC to query Bugzilla, but sends |
|
44 | Access via XMLRPC/email uses XMLRPC to query Bugzilla, but sends | |
45 | email to the Bugzilla email interface to submit comments to bugs. |
|
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 | user, so the comment appears to come from the Mercurial user. In the event |
|
47 | user, so the comment appears to come from the Mercurial user. In the event | |
48 | that the Mercurial user email is not recognised by Bugzilla as a Bugzilla |
|
48 | that the Mercurial user email is not recognised by Bugzilla as a Bugzilla | |
49 | user, the email associated with the Bugzilla username used to log into |
|
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 | Configuration items common to all access modes: |
|
53 | Configuration items common to all access modes: | |
53 |
|
54 | |||
@@ -63,7 +64,7 b' bugzilla.version' | |||||
63 | including 2.18. |
|
64 | including 2.18. | |
64 |
|
65 | |||
65 | bugzilla.regexp |
|
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 | It must contain one "()" named group ``<ids>`` containing the bug |
|
68 | It must contain one "()" named group ``<ids>`` containing the bug | |
68 | IDs separated by non-digit characters. It may also contain |
|
69 | IDs separated by non-digit characters. It may also contain | |
69 | a named group ``<hours>`` with a floating-point number giving the |
|
70 | a named group ``<hours>`` with a floating-point number giving the | |
@@ -74,6 +75,24 b' bugzilla.regexp' | |||||
74 | variations thereof, followed by an hours number prefixed by ``h`` or |
|
75 | variations thereof, followed by an hours number prefixed by ``h`` or | |
75 | ``hours``, e.g. ``hours 1.5``. Matching is case insensitive. |
|
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 | bugzilla.style |
|
96 | bugzilla.style | |
78 | The style file to use when formatting comments. |
|
97 | The style file to use when formatting comments. | |
79 |
|
98 | |||
@@ -285,6 +304,7 b' class bzaccess(object):' | |||||
285 | # updates to bug state. Recognised dict keys are: |
|
304 | # updates to bug state. Recognised dict keys are: | |
286 | # |
|
305 | # | |
287 | # 'hours': Value, float containing work hours to be updated. |
|
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 | def filter_real_bug_ids(self, bugs): |
|
309 | def filter_real_bug_ids(self, bugs): | |
290 | '''remove bug IDs that do not exist in Bugzilla from bugs.''' |
|
310 | '''remove bug IDs that do not exist in Bugzilla from bugs.''' | |
@@ -587,6 +607,10 b' class bzxmlrpc(bzaccess):' | |||||
587 | user = self.ui.config('bugzilla', 'user', 'bugs') |
|
607 | user = self.ui.config('bugzilla', 'user', 'bugs') | |
588 | passwd = self.ui.config('bugzilla', 'password') |
|
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 | self.bzproxy = xmlrpclib.ServerProxy(bzweb, self.transport(bzweb)) |
|
614 | self.bzproxy = xmlrpclib.ServerProxy(bzweb, self.transport(bzweb)) | |
591 | self.bzproxy.User.login(dict(login=user, password=passwd)) |
|
615 | self.bzproxy.User.login(dict(login=user, password=passwd)) | |
592 |
|
616 | |||
@@ -618,10 +642,23 b' class bzxmlrpc(bzaccess):' | |||||
618 | del bugs[id] |
|
642 | del bugs[id] | |
619 |
|
643 | |||
620 | def updatebug(self, bugid, newstate, text, committer): |
|
644 | def updatebug(self, bugid, newstate, text, committer): | |
621 | args = dict(id=bugid, comment=text) |
|
645 | args = {} | |
622 | if 'hours' in newstate: |
|
646 | if 'hours' in newstate: | |
623 | args['work_time'] = newstate['hours'] |
|
647 | args['work_time'] = newstate['hours'] | |
624 | self.bzproxy.Bug.add_comment(args) |
|
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 | |||
|
661 | self.bzproxy.Bug.add_comment(args) | |||
625 |
|
662 | |||
626 | class bzxmlrpcemail(bzxmlrpc): |
|
663 | class bzxmlrpcemail(bzxmlrpc): | |
627 | """Read data from Bugzilla via XMLRPC, send updates via email. |
|
664 | """Read data from Bugzilla via XMLRPC, send updates via email. | |
@@ -631,8 +668,9 b' class bzxmlrpcemail(bzxmlrpc):' | |||||
631 | 2. Bug statuses or other fields not accessible via XMLRPC can |
|
668 | 2. Bug statuses or other fields not accessible via XMLRPC can | |
632 | potentially be updated. |
|
669 | potentially be updated. | |
633 |
|
670 | |||
634 | Currently all status updates recognised can be done via XMLRPC, so |
|
671 | There is no XMLRPC function to change bug status before Bugzilla | |
635 | item 1 is the only actual advantage. |
|
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 | def __init__(self, ui): |
|
676 | def __init__(self, ui): | |
@@ -680,6 +718,9 b' class bzxmlrpcemail(bzxmlrpc):' | |||||
680 | cmds = [] |
|
718 | cmds = [] | |
681 | if 'hours' in newstate: |
|
719 | if 'hours' in newstate: | |
682 | cmds.append(self.makecommandline("work_time", newstate['hours'])) |
|
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 | self.send_bug_modify_email(bugid, cmds, text, committer) |
|
724 | self.send_bug_modify_email(bugid, cmds, text, committer) | |
684 |
|
725 | |||
685 | class bugzilla(object): |
|
726 | class bugzilla(object): | |
@@ -697,6 +738,11 b' class bugzilla(object):' | |||||
697 | r'(?P<ids>(?:\d+\s*(?:,?\s*(?:and)?)?\s*)+)' |
|
738 | r'(?P<ids>(?:\d+\s*(?:,?\s*(?:and)?)?\s*)+)' | |
698 | r'\.?\s*(?:h(?:ours?)?\s*(?P<hours>\d*(?:\.\d+)?))?') |
|
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 | _bz = None |
|
746 | _bz = None | |
701 |
|
747 | |||
702 | def __init__(self, ui, repo): |
|
748 | def __init__(self, ui, repo): | |
@@ -721,6 +767,7 b' class bugzilla(object):' | |||||
721 | return getattr(self.bz(), key) |
|
767 | return getattr(self.bz(), key) | |
722 |
|
768 | |||
723 | _bug_re = None |
|
769 | _bug_re = None | |
|
770 | _fix_re = None | |||
724 | _split_re = None |
|
771 | _split_re = None | |
725 |
|
772 | |||
726 | def find_bugs(self, ctx): |
|
773 | def find_bugs(self, ctx): | |
@@ -732,18 +779,39 b' class bugzilla(object):' | |||||
732 | ''' |
|
779 | ''' | |
733 | if bugzilla._bug_re is None: |
|
780 | if bugzilla._bug_re is None: | |
734 | bugzilla._bug_re = re.compile( |
|
781 | bugzilla._bug_re = re.compile( | |
735 |
self.ui.config('bugzilla', 'regexp', |
|
782 | self.ui.config('bugzilla', 'regexp', | |
736 | re.IGNORECASE) |
|
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 | bugzilla._split_re = re.compile(r'\D+') |
|
787 | bugzilla._split_re = re.compile(r'\D+') | |
738 | start = 0 |
|
788 | start = 0 | |
739 | hours = 0.0 |
|
789 | hours = 0.0 | |
740 | bugs = {} |
|
790 | bugs = {} | |
|
791 | bugmatch = bugzilla._bug_re.search(ctx.description(), start) | |||
|
792 | fixmatch = bugzilla._fix_re.search(ctx.description(), start) | |||
741 | while True: |
|
793 | while True: | |
742 | bugattribs = {} |
|
794 | bugattribs = {} | |
743 | m = bugzilla._bug_re.search(ctx.description(), start) |
|
795 | if not bugmatch and not fixmatch: | |
744 | if not m: |
|
|||
745 | break |
|
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 | start = m.end() |
|
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 | try: |
|
815 | try: | |
748 | ids = m.group('ids') |
|
816 | ids = m.group('ids') | |
749 | except IndexError: |
|
817 | except IndexError: |
General Comments 0
You need to be logged in to leave comments.
Login now