340 ) |
341 ) |
341 configitem('bugzilla', 'db', |
342 configitem('bugzilla', 'db', |
342 default='bugs', |
343 default='bugs', |
343 ) |
344 ) |
344 configitem('bugzilla', 'fixregexp', |
345 configitem('bugzilla', 'fixregexp', |
345 default=(r'fix(?:es)?\s*(?:bugs?\s*)?,?\s*' |
346 default=(br'fix(?:es)?\s*(?:bugs?\s*)?,?\s*' |
346 r'(?:nos?\.?|num(?:ber)?s?)?\s*' |
347 br'(?:nos?\.?|num(?:ber)?s?)?\s*' |
347 r'(?P<ids>(?:#?\d+\s*(?:,?\s*(?:and)?)?\s*)+)' |
348 br'(?P<ids>(?:#?\d+\s*(?:,?\s*(?:and)?)?\s*)+)' |
348 r'\.?\s*(?:h(?:ours?)?\s*(?P<hours>\d*(?:\.\d+)?))?') |
349 br'\.?\s*(?:h(?:ours?)?\s*(?P<hours>\d*(?:\.\d+)?))?') |
349 ) |
350 ) |
350 configitem('bugzilla', 'fixresolution', |
351 configitem('bugzilla', 'fixresolution', |
351 default='FIXED', |
352 default='FIXED', |
352 ) |
353 ) |
353 configitem('bugzilla', 'fixstatus', |
354 configitem('bugzilla', 'fixstatus', |
361 ) |
362 ) |
362 configitem('bugzilla', 'password', |
363 configitem('bugzilla', 'password', |
363 default=None, |
364 default=None, |
364 ) |
365 ) |
365 configitem('bugzilla', 'regexp', |
366 configitem('bugzilla', 'regexp', |
366 default=(r'bugs?\s*,?\s*(?:#|nos?\.?|num(?:ber)?s?)?\s*' |
367 default=(br'bugs?\s*,?\s*(?:#|nos?\.?|num(?:ber)?s?)?\s*' |
367 r'(?P<ids>(?:\d+\s*(?:,?\s*(?:and)?)?\s*)+)' |
368 br'(?P<ids>(?:\d+\s*(?:,?\s*(?:and)?)?\s*)+)' |
368 r'\.?\s*(?:h(?:ours?)?\s*(?P<hours>\d*(?:\.\d+)?))?') |
369 br'\.?\s*(?:h(?:ours?)?\s*(?P<hours>\d*(?:\.\d+)?))?') |
369 ) |
370 ) |
370 configitem('bugzilla', 'strip', |
371 configitem('bugzilla', 'strip', |
371 default=0, |
372 default=0, |
372 ) |
373 ) |
373 configitem('bugzilla', 'style', |
374 configitem('bugzilla', 'style', |
731 def get_bug_comments(self, id): |
732 def get_bug_comments(self, id): |
732 """Return a string with all comment text for a bug.""" |
733 """Return a string with all comment text for a bug.""" |
733 c = self.bzproxy.Bug.comments({'ids': [id], |
734 c = self.bzproxy.Bug.comments({'ids': [id], |
734 'include_fields': ['text'], |
735 'include_fields': ['text'], |
735 'token': self.bztoken}) |
736 'token': self.bztoken}) |
736 return ''.join([t['text'] for t in c['bugs'][str(id)]['comments']]) |
737 return ''.join([t['text'] for t in c['bugs']['%d' % id]['comments']]) |
737 |
738 |
738 def filter_real_bug_ids(self, bugs): |
739 def filter_real_bug_ids(self, bugs): |
739 probe = self.bzproxy.Bug.get({'ids': sorted(bugs.keys()), |
740 probe = self.bzproxy.Bug.get({'ids': sorted(bugs.keys()), |
740 'include_fields': [], |
741 'include_fields': [], |
741 'permissive': True, |
742 'permissive': True, |
802 raise error.Abort(_("configuration 'bzemail' missing")) |
803 raise error.Abort(_("configuration 'bzemail' missing")) |
803 mail.validateconfig(self.ui) |
804 mail.validateconfig(self.ui) |
804 |
805 |
805 def makecommandline(self, fieldname, value): |
806 def makecommandline(self, fieldname, value): |
806 if self.bzvermajor >= 4: |
807 if self.bzvermajor >= 4: |
807 return "@%s %s" % (fieldname, str(value)) |
808 return "@%s %s" % (fieldname, pycompat.bytestr(value)) |
808 else: |
809 else: |
809 if fieldname == "id": |
810 if fieldname == "id": |
810 fieldname = "bug_id" |
811 fieldname = "bug_id" |
811 return "@%s = %s" % (fieldname, str(value)) |
812 return "@%s = %s" % (fieldname, pycompat.bytestr(value)) |
812 |
813 |
813 def send_bug_modify_email(self, bugid, commands, comment, committer): |
814 def send_bug_modify_email(self, bugid, commands, comment, committer): |
814 '''send modification message to Bugzilla bug via email. |
815 '''send modification message to Bugzilla bug via email. |
815 |
816 |
816 The message format is documented in the Bugzilla email_in.pl |
817 The message format is documented in the Bugzilla email_in.pl |
871 self.passwd = self.ui.config('bugzilla', 'password') |
872 self.passwd = self.ui.config('bugzilla', 'password') |
872 self.fixstatus = self.ui.config('bugzilla', 'fixstatus') |
873 self.fixstatus = self.ui.config('bugzilla', 'fixstatus') |
873 self.fixresolution = self.ui.config('bugzilla', 'fixresolution') |
874 self.fixresolution = self.ui.config('bugzilla', 'fixresolution') |
874 |
875 |
875 def apiurl(self, targets, include_fields=None): |
876 def apiurl(self, targets, include_fields=None): |
876 url = '/'.join([self.bzroot] + [str(t) for t in targets]) |
877 url = '/'.join([self.bzroot] + [pycompat.bytestr(t) for t in targets]) |
877 qv = {} |
878 qv = {} |
878 if self.apikey: |
879 if self.apikey: |
879 qv['api_key'] = self.apikey |
880 qv['api_key'] = self.apikey |
880 elif self.user and self.passwd: |
881 elif self.user and self.passwd: |
881 qv['login'] = self.user |
882 qv['login'] = self.user |
936 '''remove bug IDs where node occurs in comment text from bugs.''' |
937 '''remove bug IDs where node occurs in comment text from bugs.''' |
937 sn = short(node) |
938 sn = short(node) |
938 for bugid in bugs.keys(): |
939 for bugid in bugs.keys(): |
939 burl = self.apiurl(('bug', bugid, 'comment'), include_fields='text') |
940 burl = self.apiurl(('bug', bugid, 'comment'), include_fields='text') |
940 result = self._fetch(burl) |
941 result = self._fetch(burl) |
941 comments = result['bugs'][str(bugid)]['comments'] |
942 comments = result['bugs'][pycompat.bytestr(bugid)]['comments'] |
942 if any(sn in c['text'] for c in comments): |
943 if any(sn in c['text'] for c in comments): |
943 self.ui.status(_('bug %d already knows about changeset %s\n') % |
944 self.ui.status(_('bug %d already knows about changeset %s\n') % |
944 (bugid, sn)) |
945 (bugid, sn)) |
945 del bugs[bugid] |
946 del bugs[bugid] |
946 |
947 |
1009 |
1010 |
1010 self.bug_re = re.compile( |
1011 self.bug_re = re.compile( |
1011 self.ui.config('bugzilla', 'regexp'), re.IGNORECASE) |
1012 self.ui.config('bugzilla', 'regexp'), re.IGNORECASE) |
1012 self.fix_re = re.compile( |
1013 self.fix_re = re.compile( |
1013 self.ui.config('bugzilla', 'fixregexp'), re.IGNORECASE) |
1014 self.ui.config('bugzilla', 'fixregexp'), re.IGNORECASE) |
1014 self.split_re = re.compile(r'\D+') |
1015 self.split_re = re.compile(br'\D+') |
1015 |
1016 |
1016 def find_bugs(self, ctx): |
1017 def find_bugs(self, ctx): |
1017 '''return bugs dictionary created from commit comment. |
1018 '''return bugs dictionary created from commit comment. |
1018 |
1019 |
1019 Extract bug info from changeset comments. Filter out any that are |
1020 Extract bug info from changeset comments. Filter out any that are |
1096 'to bug {bug}.\ndetails:\n\t{desc|tabindent}') |
1097 'to bug {bug}.\ndetails:\n\t{desc|tabindent}') |
1097 spec = logcmdutil.templatespec(tmpl, mapfile) |
1098 spec = logcmdutil.templatespec(tmpl, mapfile) |
1098 t = logcmdutil.changesettemplater(self.ui, self.repo, spec) |
1099 t = logcmdutil.changesettemplater(self.ui, self.repo, spec) |
1099 self.ui.pushbuffer() |
1100 self.ui.pushbuffer() |
1100 t.show(ctx, changes=ctx.changeset(), |
1101 t.show(ctx, changes=ctx.changeset(), |
1101 bug=str(bugid), |
1102 bug=pycompat.bytestr(bugid), |
1102 hgweb=self.ui.config('web', 'baseurl'), |
1103 hgweb=self.ui.config('web', 'baseurl'), |
1103 root=self.repo.root, |
1104 root=self.repo.root, |
1104 webroot=webroot(self.repo.root)) |
1105 webroot=webroot(self.repo.root)) |
1105 data = self.ui.popbuffer() |
1106 data = self.ui.popbuffer() |
1106 self.bzdriver.updatebug(bugid, newstate, data, |
1107 self.bzdriver.updatebug(bugid, newstate, data, |