Bugtracker: Add support for commits.
This commit is contained in:
@ -24,7 +24,7 @@ import supybot.world as world
|
||||
|
||||
from imp import reload
|
||||
|
||||
__version__ = "4.2.0"
|
||||
__version__ = "4.3.0"
|
||||
__author__ = supybot.Author("Krytarik Raido", "krytarik", "krytarik@tuxgarage.com")
|
||||
__contributors__ = {
|
||||
supybot.Author("Dennis Kaarsemaker", "Seveas", "dennis@kaarsemaker.net"): ['Original Author'],
|
||||
|
@ -49,8 +49,9 @@ def configure(advanced):
|
||||
else:
|
||||
return repeatdelay
|
||||
|
||||
output("Each of the next 3 questions can be set per-channel with the '@config channel' command.")
|
||||
output("Each of the next 4 questions can be set per-channel with the '@config channel' command.")
|
||||
bugSnarfer = yn("Enable detecting bug numbers and URLs in all channels?", default=Bugtracker.bugSnarfer._default)
|
||||
commitSnarfer = yn("Enable detecting commit hashes and URLs in all channels?", default=Bugtracker.commitSnarfer._default)
|
||||
cveSnarfer = yn("Enable detecting CVE numbers and URLs in all channels?", default=Bugtracker.cveSnarfer._default)
|
||||
oopsSnarfer = yn("Enable detecting Launchpad OOPS IDs in all channels?", default=Bugtracker.oopsSnarfer._default)
|
||||
if advanced:
|
||||
@ -72,6 +73,7 @@ def configure(advanced):
|
||||
saveDiscoveredTrackers = yn("Save automatically discovered trackers to configuration?", default=Bugtracker.saveDiscoveredTrackers._default)
|
||||
|
||||
Bugtracker.bugSnarfer.setValue(bugSnarfer)
|
||||
Bugtracker.commitSnarfer.setValue(commitSnarfer)
|
||||
Bugtracker.cveSnarfer.setValue(cveSnarfer)
|
||||
Bugtracker.oopsSnarfer.setValue(oopsSnarfer)
|
||||
Bugtracker.replyNoBugtracker.setValue(replyNoBugtracker)
|
||||
@ -90,6 +92,11 @@ conf.registerChannelValue(Bugtracker, 'bugSnarfer',
|
||||
enabled, such that any bugtracker URLs and bug ### seen in the channel
|
||||
will have their information reported into the channel."""))
|
||||
|
||||
conf.registerChannelValue(Bugtracker, 'commitSnarfer',
|
||||
registry.Boolean(False, """Determines whether the commit snarfer will be
|
||||
enabled, such that any commit URLs and commit ### seen in the channel
|
||||
will have their information reported into the channel."""))
|
||||
|
||||
conf.registerChannelValue(Bugtracker, 'cveSnarfer',
|
||||
registry.Boolean(False, """Determines whether the CVE snarfer will be
|
||||
enabled, such that any CVE URLs and CVE-????-???? seen in the channel
|
||||
|
@ -71,7 +71,7 @@ class Bugtracker(callbacks.PluginRegexp):
|
||||
"""Show a link to a bug report with a brief description"""
|
||||
threaded = True
|
||||
callBefore = ('URL')
|
||||
regexps = ('turlSnarfer', 'bugSnarfer', 'cveSnarfer', 'oopsSnarfer')
|
||||
regexps = ('bugSnarfer', 'bugUrlSnarfer', 'commitSnarfer', 'commitUrlSnarfer', 'cveSnarfer', 'oopsSnarfer')
|
||||
|
||||
def __init__(self, irc):
|
||||
self.__parent = super(Bugtracker, self)
|
||||
@ -97,14 +97,14 @@ class Bugtracker(callbacks.PluginRegexp):
|
||||
supylog.warning("Bugtracker: Unknown trackertype '%s' (%s)" % (trackers[name].trackertype(), name))
|
||||
self.shorthand = utils.abbrev(list(self.db.keys()))
|
||||
|
||||
def is_ok(self, channel, tracker, bug):
|
||||
def is_ok(self, channel, tracker, bugid):
|
||||
"""Flood/repeat protection"""
|
||||
now = time.time()
|
||||
for k in list(self.shown.keys()):
|
||||
if self.shown[k] < now - self.registryValue('repeatdelay', channel):
|
||||
self.shown.pop(k)
|
||||
if (channel, tracker, bug) not in self.shown:
|
||||
self.shown[(channel, tracker, bug)] = now
|
||||
if (channel, tracker, bugid) not in self.shown:
|
||||
self.shown[(channel, tracker, bugid)] = now
|
||||
return True
|
||||
return False
|
||||
|
||||
@ -308,26 +308,39 @@ class Bugtracker(callbacks.PluginRegexp):
|
||||
|
||||
def bugSnarfer(self, irc, msg, match):
|
||||
r"(?P<bt>[a-z][^\s:]*(\s+(bug|ticket|issue|pull|pr|merge|mr)('?s)?)?):*\s+#?(?P<bug>\d+(?!\d*[-.]\d+)(\s*([,\s]+|[,\s]*(and|und|en|et|ir|[&+]+))\s*#?\d+(?!\d*[-.]\d+))*)"
|
||||
self.termSnarfer(irc, msg, match, 'bug')
|
||||
|
||||
def commitSnarfer(self, irc, msg, match):
|
||||
r"(?P<bt>[a-z][^\s:]*(\s+(commit)('?s)?)?):*\s+#?(?P<bug>[a-f0-9]{7,}(?![a-f0-9]*[-.][a-f0-9]{7,})(\s*([,\s]+|[,\s]*(and|und|en|et|ir|[&+]+))\s*#?[a-f0-9]{7,}(?![a-f0-9]*[-.][a-f0-9]{7,}))*)"
|
||||
self.termSnarfer(irc, msg, match, 'commit')
|
||||
|
||||
def termSnarfer(self, irc, msg, match, termtype):
|
||||
channel = msg.args[0] if ircutils.isChannel(msg.args[0]) else None
|
||||
if checkAddressed(msg.args[1].strip(), channel):
|
||||
return
|
||||
if not self.registryValue('bugSnarfer', channel):
|
||||
if not self.registryValue('{}Snarfer'.format(termtype), channel):
|
||||
return
|
||||
nbugs = msg.tagged('nbugs') or 0
|
||||
if nbugs >= 5:
|
||||
return
|
||||
|
||||
bugids = re.split(r'[^\d]+', match.group('bug'))[:5-nbugs]
|
||||
if termtype != 'commit':
|
||||
bugids = re.findall(r'[0-9]+', match.group('bug'))[:5-nbugs]
|
||||
else:
|
||||
bugids = re.findall(r'[a-f0-9]{7,}', match.group('bug'))[:5-nbugs]
|
||||
|
||||
# Begin HACK
|
||||
# Strings like "Ubuntu 1004" and "Ubuntu 1610" are false triggers for us
|
||||
if match.group('bt').lower() == 'ubuntu':
|
||||
if match.group('bt').lower() == 'ubuntu' and termtype == 'bug':
|
||||
bugids = [x for x in bugids if not re.match(r'^([4-9]|[12][0-9])(04|10)$', x)]
|
||||
# End HACK
|
||||
|
||||
# Get tracker name
|
||||
bt = [x.lower() for x in match.group('bt').split()]
|
||||
sure_bug = re.match(r"^(?P<type>bug|ticket|issue|pull|pr|merge|mr)('?s)?$", bt[-1])
|
||||
if termtype != 'commit':
|
||||
sure_bug = re.match(r"^(?P<type>bug|ticket|issue|pull|pr|merge|mr)('?s)?$", bt[-1])
|
||||
else:
|
||||
sure_bug = re.match(r"^(?P<type>commit)('?s)?$", bt[-1])
|
||||
|
||||
# Get bug type
|
||||
if sure_bug:
|
||||
@ -337,7 +350,7 @@ class Bugtracker(callbacks.PluginRegexp):
|
||||
|
||||
bugids = list(set(bugids)) # remove dupes
|
||||
|
||||
if not sure_bug:
|
||||
if not sure_bug and termtype == 'bug':
|
||||
bugids = [x for x in bugids if int(x) > 100]
|
||||
|
||||
msg.tag('nbugs', nbugs + len(bugids))
|
||||
@ -376,13 +389,12 @@ class Bugtracker(callbacks.PluginRegexp):
|
||||
return
|
||||
|
||||
for bugid in bugids:
|
||||
bugid = int(bugid)
|
||||
try:
|
||||
report = self.get_bug(channel or msg.nick, tracker, bugtype, bugid, self.registryValue('showassignee', channel),
|
||||
self.registryValue('extended', channel), do_tracker=showTracker)
|
||||
except trackers.BugNotFoundError:
|
||||
if self.registryValue('replyWhenNotFound'):
|
||||
irc.error("Could not find %s bug %d" % (tracker.description, bugid))
|
||||
irc.error("Could not find %s %s %s" % (tracker.description, termtype, bugid))
|
||||
except trackers.BugtrackerError as e:
|
||||
if self.registryValue('replyWhenError') and sure_bug:
|
||||
irc.error(str(e))
|
||||
@ -390,19 +402,26 @@ class Bugtracker(callbacks.PluginRegexp):
|
||||
if report:
|
||||
irc.reply(report)
|
||||
|
||||
def turlSnarfer(self, irc, msg, match):
|
||||
r"(https?://)?((bugs\.debian\.org|pad\.lv)/|\S+/(show_bug\.cgi\?id=|bugreport\.cgi\?bug=|view\.php\?id=|bug=|bugs/|\+bug/|ticket/|feature-requests/|patches/|todo/|issues/|pulls?/|merge_requests/))(?P<bug>\d+)/?"
|
||||
def bugUrlSnarfer(self, irc, msg, match):
|
||||
r"(https?://)?((bugs\.debian\.org|pad\.lv)/|\S+/(show_bug\.cgi\?id=|bugreport\.cgi\?bug=|view\.php\?id=|bug=|bugs/|\+bug/|ticket/|feature-requests/|patches/|todo/|issues/|pulls?/|merge_requests/))(?P<bug>\d+)"
|
||||
self.urlSnarfer(irc, msg, match, 'bug')
|
||||
|
||||
def commitUrlSnarfer(self, irc, msg, match):
|
||||
r"(https?://)?\S+/commits?/(?P<bug>[a-f0-9]{7,})"
|
||||
self.urlSnarfer(irc, msg, match, 'commit')
|
||||
|
||||
def urlSnarfer(self, irc, msg, match, urltype):
|
||||
channel = msg.args[0] if ircutils.isChannel(msg.args[0]) else None
|
||||
if checkAddressed(msg.args[1].strip(), channel):
|
||||
return
|
||||
if not self.registryValue('bugSnarfer', channel):
|
||||
if not self.registryValue('{}Snarfer'.format(urltype), channel):
|
||||
return
|
||||
nbugs = msg.tagged('nbugs') or 0
|
||||
if nbugs >= 5:
|
||||
return
|
||||
msg.tag('nbugs', nbugs+1)
|
||||
url = match.group(0)
|
||||
bugid = int(match.group('bug'))
|
||||
bugid = match.group('bug')
|
||||
if '://' in url:
|
||||
url = url[url.rfind('://')+3:]
|
||||
try:
|
||||
@ -413,7 +432,7 @@ class Bugtracker(callbacks.PluginRegexp):
|
||||
self.registryValue('extended', channel), do_url=False)
|
||||
except trackers.BugNotFoundError:
|
||||
if self.registryValue('replyWhenNotFound'):
|
||||
irc.error("Could not find %s bug %s" % (tracker.description, match.group('bug')))
|
||||
irc.error("Could not find %s %s %s" % (tracker.description, urltype, match.group('bug')))
|
||||
except trackers.BugtrackerError as e:
|
||||
if self.registryValue('replyWhenError'):
|
||||
irc.error(str(e))
|
||||
@ -423,7 +442,7 @@ class Bugtracker(callbacks.PluginRegexp):
|
||||
|
||||
# Only useful to Launchpad developers
|
||||
def oopsSnarfer(self, irc, msg, match):
|
||||
r"(https?://\S+[=/])?OOPS-(?P<oopsid>[\dA-Za-z]{6,})"
|
||||
r"(https?://\S+[=/])?OOPS-(?P<oopsid>[a-f0-9]{6,})"
|
||||
channel = msg.args[0] if ircutils.isChannel(msg.args[0]) else None
|
||||
if checkAddressed(msg.args[1].strip(), channel):
|
||||
return
|
||||
@ -482,11 +501,11 @@ class Bugtracker(callbacks.PluginRegexp):
|
||||
tracker = trackers.SourceForge().get_tracker(snarfurl)
|
||||
elif 'github.com' in snarfurl:
|
||||
tracker = trackers.GitHub().get_tracker(snarfurl)
|
||||
elif re.match(r'[^\s/]+/[^\s/]+(/[^\s/]+)+/-/(issues|merge_requests)', snarfurl) \
|
||||
elif re.match(r'[^\s/]+/[^\s/]+(/[^\s/]+)+/-/(issues|merge_requests|commits?)', snarfurl) \
|
||||
or re.match(r'[^\s/]+/[^\s/]+(/[^\s/]+)+/merge_requests', snarfurl) \
|
||||
or re.match(r'[^\s/]+/[^\s/]+(/[^\s/]+){2,}/issues', snarfurl):
|
||||
or re.match(r'[^\s/]+/[^\s/]+(/[^\s/]+){2,}/(issues|commits?)', snarfurl):
|
||||
tracker = trackers.GitLab().get_tracker(snarfurl, bugid)
|
||||
elif re.match(r'[^\s/]+/[^\s/]+/[^\s/]+/issues', snarfurl):
|
||||
elif re.match(r'[^\s/]+/[^\s/]+/[^\s/]+/(issues|commits?)', snarfurl):
|
||||
tracker = trackers.GitLab().get_tracker(snarfurl, bugid)
|
||||
if not tracker:
|
||||
tracker = trackers.Gitea().get_tracker(snarfurl, bugid)
|
||||
@ -519,20 +538,20 @@ class Bugtracker(callbacks.PluginRegexp):
|
||||
if duplicate and not self.is_ok(channel, tracker, bugid):
|
||||
return
|
||||
|
||||
bugtype = re.match(r'.*/(feature-)?(?P<type>request|patch|todo|issue|pull|merge|ticket)(_requests)?(e?s)?/[0-9]+/?$', url)
|
||||
bugtype = re.match(r'.*/(feature-)?(?P<type>request|patch|todo|issue|pull|merge|ticket|commit)(_requests)?(e?s)?/[a-f0-9]+$', url)
|
||||
if do_tracker and tracker.trackertype not in ('github', 'gitlab', 'gitea'):
|
||||
if re.match(r'.*/(bugs|feature-requests|patches|todo|issues|pulls?|merge_requests|ticket)/?$', tracker.description):
|
||||
report = '%s %d' % (tracker.description, bugid)
|
||||
if re.match(r'.*/(bugs|feature-requests|patches|todo|issues|pulls?|merge_requests|ticket|commits?)$', tracker.description):
|
||||
report = '%s %s' % (tracker.description, bugid)
|
||||
else:
|
||||
if bugtype:
|
||||
report = '%s %s %d' % (tracker.description, bugtype.group('type'), bugid)
|
||||
report = '%s %s %s' % (tracker.description, bugtype.group('type'), bugid)
|
||||
else:
|
||||
report = '%s bug %d' % (tracker.description, bugid)
|
||||
report = '%s bug %s' % (tracker.description, bugid)
|
||||
else:
|
||||
if bugtype:
|
||||
report = '%s %d' % (bugtype.group('type').title(), bugid)
|
||||
report = '%s %s' % (bugtype.group('type').title(), bugid)
|
||||
else:
|
||||
report = 'Bug %d' % bugid
|
||||
report = 'Bug %s' % bugid
|
||||
|
||||
if product:
|
||||
report += ' in %s' % product
|
||||
@ -548,8 +567,10 @@ class Bugtracker(callbacks.PluginRegexp):
|
||||
severity_status = []
|
||||
if severity:
|
||||
severity_status.append(' '.join(word[0].upper() + word[1:].lower() for word in severity.split()))
|
||||
severity_status.append(' '.join(word[0].upper() + word[1:].lower() for word in status.split()))
|
||||
report += ' [%s]' % ', '.join(severity_status)
|
||||
if status:
|
||||
severity_status.append(' '.join(word[0].upper() + word[1:].lower() for word in status.split()))
|
||||
if severity_status:
|
||||
report += ' [%s]' % ', '.join(severity_status)
|
||||
|
||||
if duplicate:
|
||||
report += ' [duplicate: %s]' % duplicate[0]
|
||||
|
@ -114,7 +114,7 @@ class Bugzilla(IBugtracker):
|
||||
pass
|
||||
|
||||
def get_bug(self, bugtype, bugid):
|
||||
url = "%s/rest/bug/%d" % (self.url, bugid)
|
||||
url = "%s/rest/bug/%s" % (self.url, bugid)
|
||||
try:
|
||||
bugjson = utils.web.getUrl(url)
|
||||
bug = json.loads(bugjson.decode('utf-8'))['bugs'][0]
|
||||
@ -134,12 +134,12 @@ class Bugzilla(IBugtracker):
|
||||
else:
|
||||
assignee = ''
|
||||
return (bugid, bug['product'], bug['summary'], bug['severity'], status, assignee,
|
||||
"%s/show_bug.cgi?id=%d" % (self.url, bugid), [], [])
|
||||
"%s/show_bug.cgi?id=%s" % (self.url, bugid), [], [])
|
||||
except Exception as e:
|
||||
raise BugtrackerError(self.errparse % (self.description, e, url))
|
||||
|
||||
def get_bug_old(self, bugtype, bugid): # Deprecated
|
||||
url = "%s/show_bug.cgi?id=%d&ctype=xml" % (self.url, bugid)
|
||||
url = "%s/show_bug.cgi?id=%s&ctype=xml" % (self.url, bugid)
|
||||
try:
|
||||
bugxml = utils.web.getUrl(url)
|
||||
zilladom = minidom.parseString(bugxml)
|
||||
@ -150,7 +150,7 @@ class Bugzilla(IBugtracker):
|
||||
errtxt = bug_n.getAttribute('error')
|
||||
if errtxt in ('NotFound', 'InvalidBugId'):
|
||||
raise BugNotFoundError
|
||||
s = 'Could not get %s bug #%d: %s' % (self.description, bugid, errtxt)
|
||||
s = 'Could not get %s bug #%s: %s' % (self.description, bugid, errtxt)
|
||||
raise BugtrackerError(s)
|
||||
try:
|
||||
title = _getnodetxt(bug_n.getElementsByTagName('short_desc')[0])
|
||||
@ -170,7 +170,7 @@ class Bugzilla(IBugtracker):
|
||||
assignee = ''
|
||||
except Exception as e:
|
||||
raise BugtrackerError(self.errparse % (self.description, e, url))
|
||||
return (bugid, product, title, severity, status, assignee, "%s/show_bug.cgi?id=%d" % (self.url, bugid), [], [])
|
||||
return (bugid, product, title, severity, status, assignee, "%s/show_bug.cgi?id=%s" % (self.url, bugid), [], [])
|
||||
|
||||
class Launchpad(IBugtracker):
|
||||
statuses = ("Unknown", "Invalid", "Opinion", "Won't Fix", "Fix Released", "Fix Committed", "New",
|
||||
@ -259,7 +259,7 @@ class Launchpad(IBugtracker):
|
||||
|
||||
def get_bug_new(self, bugtype, bugid): #TODO: Rename this method to 'get_bug'
|
||||
try:
|
||||
bugdata = self.lp.bugs[bugid]
|
||||
bugdata = self.lp.bugs[int(bugid)]
|
||||
if bugdata.private:
|
||||
raise BugtrackerError("This bug is private")
|
||||
duplicate = []
|
||||
@ -287,27 +287,27 @@ class Launchpad(IBugtracker):
|
||||
if type(e).__name__ == 'HTTPError': # messy, but saves trying to import lazr.restfulclient.errors.HTPError
|
||||
if e.response.status == 404:
|
||||
bugNo = e.content.split()[-1][2:-1] # extract the real bug number
|
||||
if bugNo != str(bugid): # A duplicate of a private bug, at least we know it exists
|
||||
raise BugtrackerError('Bug #%d is a duplicate of bug #%s, but it is private (%s/bugs/%s)' % (bugid, bugNo, self.url, bugNo))
|
||||
raise BugtrackerError("Bug #%d is private or does not exist (%s/bugs/%d)" % (bugid, self.url, bugid)) # Could be private, could just not exist
|
||||
raise BugtrackerError(self.errget % (self.description, e, '%s/bugs/%d' % (self.url, bugid)))
|
||||
if bugNo != bugid: # A duplicate of a private bug, at least we know it exists
|
||||
raise BugtrackerError('Bug #%s is a duplicate of bug #%s, but it is private (%s/bugs/%s)' % (bugid, bugNo, self.url, bugNo))
|
||||
raise BugtrackerError("Bug #%s is private or does not exist (%s/bugs/%s)" % (bugid, self.url, bugid)) # Could be private, could just not exist
|
||||
raise BugtrackerError(self.errget % (self.description, e, '%s/bugs/%s' % (self.url, bugid)))
|
||||
elif isinstance(e, KeyError):
|
||||
raise BugNotFoundError
|
||||
raise BugtrackerError(self.errget % (self.description, e, '%s/bugs/%d' % (self.url, bugid)))
|
||||
raise BugtrackerError(self.errget % (self.description, e, '%s/bugs/%s' % (self.url, bugid)))
|
||||
|
||||
return (bugdata.id, taskdata.bug_target_display_name, bugdata.title, taskdata.importance, taskdata.status,
|
||||
assignee, "%s/bugs/%d" % (self.url, bugdata.id), extinfo, duplicate)
|
||||
assignee, "%s/bugs/%s" % (self.url, bugdata.id), extinfo, duplicate)
|
||||
|
||||
def get_bug_old(self, bugtype, bugid, duplicate=None): # Deprecated
|
||||
try:
|
||||
bugdata = utils.web.getUrl("%s/bugs/%d/+text" % (self.url, bugid)).decode('utf-8')
|
||||
bugdata = utils.web.getUrl("%s/bugs/%s/+text" % (self.url, bugid)).decode('utf-8')
|
||||
except Exception as e:
|
||||
if 'HTTP Error 404' in str(e):
|
||||
if duplicate:
|
||||
raise BugtrackerError('Bug #%d is a duplicate of bug #%d, but it is private (%s/bugs/%d)' % (duplicate, bugid, self.url, bugid))
|
||||
raise BugtrackerError('Bug #%s is a duplicate of bug #%s, but it is private (%s/bugs/%s)' % (duplicate, bugid, self.url, bugid))
|
||||
else:
|
||||
raise BugNotFoundError
|
||||
raise BugtrackerError(self.errget % (self.description, e, '%s/bugs/%d' % (self.url, bugid)))
|
||||
raise BugtrackerError(self.errget % (self.description, e, '%s/bugs/%s' % (self.url, bugid)))
|
||||
|
||||
try:
|
||||
# Split bug data into separate pieces (bug data, task data)
|
||||
@ -324,16 +324,16 @@ class Launchpad(IBugtracker):
|
||||
else:
|
||||
assignee = ''
|
||||
except Exception as e:
|
||||
raise BugtrackerError(self.errparse % (self.description, e, '%s/bugs/%d' % (self.url, bugid)))
|
||||
raise BugtrackerError(self.errparse % (self.description, e, '%s/bugs/%s' % (self.url, bugid)))
|
||||
|
||||
# Try and find duplicates
|
||||
if bugdata['duplicate-of']:
|
||||
data = self.get_bug_old(bugtype, int(bugdata['duplicate-of']), duplicate or bugid)
|
||||
data = self.get_bug_old(bugtype, bugdata['duplicate-of'], duplicate or bugid)
|
||||
data[8].append(bugdata['bug'])
|
||||
return data
|
||||
|
||||
return (bugid, taskdata['task'], bugdata['title'], taskdata['importance'], taskdata['status'],
|
||||
assignee, "%s/bugs/%d" % (self.url, bugid), [], [])
|
||||
assignee, "%s/bugs/%s" % (self.url, bugid), [], [])
|
||||
|
||||
# <rant>
|
||||
# Debbugs sucks donkeyballs
|
||||
@ -351,7 +351,7 @@ class Debbugs(IBugtracker):
|
||||
self.soap_client = SoapClient("%s/cgi-bin/soap.cgi" % self.url, namespace="Debbugs/SOAP")
|
||||
|
||||
def get_bug(self, bugtype, bugid):
|
||||
url = "%s/cgi-bin/bugreport.cgi?bug=%d" % (self.url, bugid)
|
||||
url = "%s/cgi-bin/bugreport.cgi?bug=%s" % (self.url, bugid)
|
||||
try:
|
||||
raw = self.soap_client.get_status(bugs=bugid)
|
||||
except Exception as e:
|
||||
@ -364,7 +364,7 @@ class Debbugs(IBugtracker):
|
||||
status = 'Fixed'
|
||||
else:
|
||||
status = 'Open'
|
||||
return (bugid, str(raw.package), str(raw.subject), str(raw.severity), status, '', "%s/%d" % (self.url, bugid), [], [])
|
||||
return (bugid, str(raw.package), str(raw.subject), str(raw.severity), status, '', "%s/%s" % (self.url, bugid), [], [])
|
||||
except Exception as e:
|
||||
raise BugtrackerError(self.errparse % (self.description, e, url))
|
||||
|
||||
@ -380,7 +380,7 @@ class SourceForge(IBugtracker):
|
||||
pass
|
||||
|
||||
def get_bug(self, bugtype, bugid):
|
||||
url = "%s/%d/" % (self.url.replace('sourceforge.net', 'sourceforge.net/rest'), bugid)
|
||||
url = "%s/%s/" % (self.url.replace('sourceforge.net', 'sourceforge.net/rest'), bugid)
|
||||
try:
|
||||
bugjson = utils.web.getUrl(url)
|
||||
bug = json.loads(bugjson.decode('utf-8'))['ticket']
|
||||
@ -393,31 +393,40 @@ class SourceForge(IBugtracker):
|
||||
if '_priority' in bug['custom_fields']:
|
||||
severity = 'Pri: %s' % bug['custom_fields']['_priority']
|
||||
return (bugid, product, bug['summary'], severity, ': '.join(bug['status'].split('-')),
|
||||
bug['assigned_to'], "%s/%d/" % (self.url, bugid), [], [])
|
||||
bug['assigned_to'], "%s/%s/" % (self.url, bugid), [], [])
|
||||
except Exception as e:
|
||||
raise BugtrackerError(self.errparse % (self.description, e, url))
|
||||
|
||||
class GitHub(IBugtracker):
|
||||
def get_tracker(self, url):
|
||||
try:
|
||||
match = re.match(r'github\.com/[^\s/]+/[^\s/]+/(issues|pulls?)', url)
|
||||
match = re.match(r'github\.com/[^\s/]+/[^\s/]+/(issues|pulls?|commits?)', url)
|
||||
desc = match.group(0)
|
||||
url = 'https://%s' % desc
|
||||
# Pulls are inconsistent in main and single page URLs
|
||||
desc = re.sub(r'/pull$', r'/pulls', desc)
|
||||
# Commits are inconsistent in main and single page URLs
|
||||
desc = re.sub(r'/commit$', r'/commits', desc)
|
||||
name = desc.lower()
|
||||
return GitHub(name, url, desc, 'github')
|
||||
except:
|
||||
pass
|
||||
|
||||
def get_bug(self, bugtype, bugid):
|
||||
url = "%s/%d" % (self.url.replace('github.com', 'api.github.com/repos'), bugid)
|
||||
url = "%s/%s" % (self.url.replace('github.com', 'api.github.com/repos'), bugid)
|
||||
# Pulls are inconsistent in web and API URLs
|
||||
url = url.replace('/pull/', '/pulls/')
|
||||
# Commits are inconsistent in web and API URLs
|
||||
url = url.replace('/commit/', '/commits/')
|
||||
if bugtype in ('issue', 'bug'):
|
||||
url = url.replace('/pulls/', '/issues/')
|
||||
url = url.replace('/commits/', '/issues/')
|
||||
elif bugtype in ('pull', 'pr', 'merge', 'mr'):
|
||||
url = url.replace('/issues/', '/pulls/')
|
||||
url = url.replace('/commits/', '/pulls/')
|
||||
elif bugtype == 'commit':
|
||||
url = url.replace('/issues/', '/commits/')
|
||||
url = url.replace('/pulls/', '/commits/')
|
||||
try:
|
||||
bugjson = utils.web.getUrl(url)
|
||||
bug = json.loads(bugjson.decode('utf-8'))
|
||||
@ -425,27 +434,40 @@ class GitHub(IBugtracker):
|
||||
raise BugtrackerError(self.errget % (self.description, e, url))
|
||||
try:
|
||||
product = '/'.join(self.url.split('/')[-3:-1])
|
||||
if 'merged' in bug and bug['merged']:
|
||||
status = 'Merged'
|
||||
else:
|
||||
status = bug['state']
|
||||
if bug['assignee']:
|
||||
assignee = bug['assignee']['login']
|
||||
if '/commits/' not in url:
|
||||
title = bug['title']
|
||||
if 'merged' in bug and bug['merged']:
|
||||
status = 'Merged'
|
||||
else:
|
||||
status = bug['state']
|
||||
if bug['assignee']:
|
||||
assignee = bug['assignee']['login']
|
||||
else:
|
||||
assignee = ''
|
||||
else:
|
||||
bugid = bug['sha'][:7]
|
||||
title = bug['commit']['message'].split('\n', 1)[0]
|
||||
status = ''
|
||||
assignee = ''
|
||||
return (bugid, product, bug['title'], '', status, assignee, bug['html_url'], [], [])
|
||||
return (bugid, product, title, '', status, assignee, bug['html_url'], [], [])
|
||||
except Exception as e:
|
||||
raise BugtrackerError(self.errparse % (self.description, e, url))
|
||||
|
||||
class GitLab(IBugtracker):
|
||||
def get_tracker(self, url, bugid):
|
||||
try:
|
||||
match = re.match(r'[^\s/]+/(?P<project>[^\s/]+/[^\s/]+(/[^\s/]+)*?)/(-/)?(issues|merge_requests)', url)
|
||||
match = re.match(r'[^\s/]+/(?P<project>[^\s/]+/[^\s/]+(/[^\s/]+)*?)/(-/)?(issues|merge_requests|commits?)', url)
|
||||
desc = match.group(0)
|
||||
name = desc.lower()
|
||||
url = 'https://%s' % desc
|
||||
bugurl = "%s/%d" % (re.sub(r'(://[^\s/]+)/[^\s/]+(/[^\s/]+)+/(-/)?',
|
||||
# Commits are inconsistent in main and single page URLs
|
||||
desc = re.sub(r'/commit$', r'/commits', desc)
|
||||
name = desc.lower()
|
||||
bugurl = "%s/%s" % (re.sub(r'(://[^\s/]+)/[^\s/]+(/[^\s/]+)+/(-/)?',
|
||||
r'\g<1>/api/v4/projects/%s/' % match.group('project').replace('/', '%2F'), url), bugid)
|
||||
# Commits are inconsistent in web and API URLs
|
||||
bugurl = bugurl.replace('/commit/', '/commits/')
|
||||
# Commits need an extra bit on API URLs
|
||||
bugurl = bugurl.replace('/commits/', '/repository/commits/')
|
||||
bugjson = utils.web.getUrl(bugurl)
|
||||
bug = json.loads(bugjson.decode('utf-8'))
|
||||
return GitLab(name, url, desc, 'gitlab')
|
||||
@ -453,13 +475,22 @@ class GitLab(IBugtracker):
|
||||
pass
|
||||
|
||||
def get_bug(self, bugtype, bugid):
|
||||
match = re.match(r'[^\s:]+://[^\s/]+/(?P<project>[^\s/]+/[^\s/]+(/[^\s/]+)*?)/(-/)?(issues|merge_requests)', self.url)
|
||||
url = "%s/%d" % (re.sub(r'(://[^\s/]+)/[^\s/]+(/[^\s/]+)+/(-/)?',
|
||||
match = re.match(r'[^\s:]+://[^\s/]+/(?P<project>[^\s/]+/[^\s/]+(/[^\s/]+)*?)/(-/)?(issues|merge_requests|commits?)', self.url)
|
||||
url = "%s/%s" % (re.sub(r'(://[^\s/]+)/[^\s/]+(/[^\s/]+)+/(-/)?',
|
||||
r'\g<1>/api/v4/projects/%s/' % match.group('project').replace('/', '%2F'), self.url), bugid)
|
||||
# Commits are inconsistent in web and API URLs
|
||||
url = url.replace('/commit/', '/commits/')
|
||||
if bugtype in ('issue', 'bug'):
|
||||
url = url.replace('/merge_requests/', '/issues/')
|
||||
url = url.replace('/commits/', '/issues/')
|
||||
elif bugtype in ('merge', 'mr', 'pull', 'pr'):
|
||||
url = url.replace('/issues/', '/merge_requests/')
|
||||
url = url.replace('/commits/', '/merge_requests/')
|
||||
elif bugtype == 'commit':
|
||||
url = url.replace('/issues/', '/commits/')
|
||||
url = url.replace('/merge_requests/', '/commits/')
|
||||
# Commits need an extra bit on API URLs
|
||||
url = url.replace('/commits/', '/repository/commits/')
|
||||
try:
|
||||
bugjson = utils.web.getUrl(url)
|
||||
bug = json.loads(bugjson.decode('utf-8'))
|
||||
@ -467,27 +498,40 @@ class GitLab(IBugtracker):
|
||||
raise BugtrackerError(self.errget % (self.description, e, url))
|
||||
try:
|
||||
product = match.group('project')
|
||||
status = bug['state']
|
||||
if bug['assignees']:
|
||||
assino = len(bug['assignees'])
|
||||
if assino == 1:
|
||||
assignee = bug['assignees'][0]['name']
|
||||
if '/commits/' not in url:
|
||||
title = bug['title']
|
||||
status = bug['state']
|
||||
if bug['assignees']:
|
||||
assino = len(bug['assignees'])
|
||||
if assino == 1:
|
||||
assignee = bug['assignees'][0]['name']
|
||||
else:
|
||||
assignee = '%d people' % assino
|
||||
else:
|
||||
assignee = '%d people' % assino
|
||||
assignee = ''
|
||||
else:
|
||||
bugid = bug['id'][:7]
|
||||
title = bug['message'].split('\n', 1)[0]
|
||||
status = ''
|
||||
assignee = ''
|
||||
return (bugid, product, bug['title'], '', status, assignee, bug['web_url'], [], [])
|
||||
return (bugid, product, title, '', status, assignee, bug['web_url'], [], [])
|
||||
except Exception as e:
|
||||
raise BugtrackerError(self.errparse % (self.description, e, url))
|
||||
|
||||
class Gitea(IBugtracker):
|
||||
def get_tracker(self, url, bugid):
|
||||
try:
|
||||
match = re.match(r'[^\s/]+/[^\s/]+/[^\s/]+/(issues|pulls)', url)
|
||||
match = re.match(r'[^\s/]+/[^\s/]+/[^\s/]+/(issues|pulls|commits?)', url)
|
||||
desc = match.group(0)
|
||||
name = desc.lower()
|
||||
url = 'https://%s' % desc
|
||||
bugurl = '%s/%d' % (re.sub(r'(://[^\s/]+)/', r'\g<1>/api/v1/repos/', url), bugid)
|
||||
# Commits are inconsistent in main and single page URLs
|
||||
desc = re.sub(r'/commit$', r'/commits', desc)
|
||||
name = desc.lower()
|
||||
bugurl = '%s/%s' % (re.sub(r'(://[^\s/]+)/', r'\g<1>/api/v1/repos/', url), bugid)
|
||||
# Commits are inconsistent in web and API URLs
|
||||
bugurl = bugurl.replace('/commit/', '/commits/')
|
||||
# Commits need an extra bit on API URLs
|
||||
bugurl = bugurl.replace('/commits/', '/git/commits/')
|
||||
bugjson = utils.web.getUrl(bugurl)
|
||||
bug = json.loads(bugjson.decode('utf-8'))
|
||||
return Gitea(name, url, desc, 'gitea')
|
||||
@ -495,11 +539,20 @@ class Gitea(IBugtracker):
|
||||
pass
|
||||
|
||||
def get_bug(self, bugtype, bugid):
|
||||
url = "%s/%d" % (re.sub(r'(://[^\s/]+)/', r'\g<1>/api/v1/repos/', self.url), bugid)
|
||||
url = "%s/%s" % (re.sub(r'(://[^\s/]+)/', r'\g<1>/api/v1/repos/', self.url), bugid)
|
||||
# Commits are inconsistent in web and API URLs
|
||||
url = url.replace('/commit/', '/commits/')
|
||||
if bugtype in ('issue', 'bug'):
|
||||
url = url.replace('/pulls/', '/issues/')
|
||||
url = url.replace('/commits/', '/issues/')
|
||||
elif bugtype in ('pull', 'pr', 'merge', 'mr'):
|
||||
url = url.replace('/issues/', '/pulls/')
|
||||
url = url.replace('/commits/', '/pulls/')
|
||||
elif bugtype == 'commit':
|
||||
url = url.replace('/issues/', '/commits/')
|
||||
url = url.replace('/pulls/', '/commits/')
|
||||
# Commits need an extra bit on API URLs
|
||||
url = url.replace('/commits/', '/git/commits/')
|
||||
try:
|
||||
bugjson = utils.web.getUrl(url)
|
||||
bug = json.loads(bugjson.decode('utf-8'))
|
||||
@ -507,20 +560,27 @@ class Gitea(IBugtracker):
|
||||
raise BugtrackerError(self.errget % (self.description, e, url))
|
||||
try:
|
||||
product = '/'.join(self.url.split('/')[-3:-1])
|
||||
if 'merged' in bug and bug['merged']:
|
||||
status = 'Merged'
|
||||
else:
|
||||
status = bug['state']
|
||||
if bug['assignee']:
|
||||
assignee = bug['assignee']['username']
|
||||
if '/commits/' not in url:
|
||||
title = bug['title']
|
||||
if 'merged' in bug and bug['merged']:
|
||||
status = 'Merged'
|
||||
else:
|
||||
status = bug['state']
|
||||
if bug['assignee']:
|
||||
assignee = bug['assignee']['username']
|
||||
else:
|
||||
assignee = ''
|
||||
else:
|
||||
bugid = bug['sha'][:7]
|
||||
title = bug['commit']['message'].split('\n', 1)[0]
|
||||
status = ''
|
||||
assignee = ''
|
||||
# Issues have no 'html_url', but pulls do
|
||||
# Issues have no 'html_url', but pulls and commits do
|
||||
if 'html_url' in bug:
|
||||
htmlurl = bug['html_url']
|
||||
else:
|
||||
htmlurl = url.replace('/api/v1/repos/', '/')
|
||||
return (bugid, product, bug['title'], '', status, assignee, htmlurl, [], [])
|
||||
return (bugid, product, title, '', status, assignee, htmlurl, [], [])
|
||||
except Exception as e:
|
||||
raise BugtrackerError(self.errparse % (self.description, e, url))
|
||||
|
||||
@ -540,7 +600,7 @@ class Mantis(IBugtracker):
|
||||
pass
|
||||
|
||||
def get_bug(self, bugtype, bugid):
|
||||
url = "%s/api/rest/issues/%d" % (self.url, bugid)
|
||||
url = "%s/api/rest/issues/%s" % (self.url, bugid)
|
||||
try:
|
||||
bugjson = utils.web.getUrl(url)
|
||||
bug = json.loads(bugjson.decode('utf-8'))['issues'][0]
|
||||
@ -555,11 +615,11 @@ class Mantis(IBugtracker):
|
||||
raise BugtrackerError(self.errparse % (self.description, e, url))
|
||||
|
||||
def get_bug_old(self, bugtype, bugid): # Deprecated
|
||||
url = "%s/view.php?id=%d" % (self.url, bugid)
|
||||
url = "%s/view.php?id=%s" % (self.url, bugid)
|
||||
try:
|
||||
raw = self.soap_client.mc_issue_get(username='', password='', issue_id=bugid)
|
||||
except Exception as e:
|
||||
if 'Issue #%d not found' % bugid in str(e):
|
||||
if 'Issue #%s not found' % bugid in str(e):
|
||||
raise BugNotFoundError
|
||||
# Often SOAP is not enabled
|
||||
if '.' in self.name:
|
||||
@ -589,7 +649,7 @@ class Trac(IBugtracker):
|
||||
pass
|
||||
|
||||
def get_bug(self, bugtype, bugid): # This is still a little rough, but it works :)
|
||||
url = "%s/%d" % (self.url, bugid)
|
||||
url = "%s/%s" % (self.url, bugid)
|
||||
try:
|
||||
raw = utils.web.getUrl("%s?format=tab" % url).decode('utf-8')
|
||||
except Exception as e:
|
||||
|
Reference in New Issue
Block a user