diff --git a/Bugtracker/__init__.py b/Bugtracker/__init__.py index d7d0918..c651cbf 100644 --- a/Bugtracker/__init__.py +++ b/Bugtracker/__init__.py @@ -24,7 +24,7 @@ import supybot.world as world from imp import reload -__version__ = "3.0.0" +__version__ = "3.1.0" __author__ = supybot.Author("Krytarik Raido", "krytarik", "krytarik@tuxgarage.com") __contributors__ = { supybot.Author("Dennis Kaarsemaker", "Seveas", "dennis@kaarsemaker.net"): ['Original Author'], diff --git a/Bugtracker/plugin.py b/Bugtracker/plugin.py index 8176889..1090dec 100644 --- a/Bugtracker/plugin.py +++ b/Bugtracker/plugin.py @@ -151,8 +151,8 @@ class Bugtracker(callbacks.PluginRegexp): def add(self, irc, msg, args, name, trackertype, url, description): """ [] - Add a bugtracker to the list of defined bugtrackers. Currently supported - types are Launchpad, Debbugs, Bugzilla, SourceForge, Github, Mantis, and Trac. + Add a bugtracker to the list of defined bugtrackers. Currently supported types are + Launchpad, Debbugs, Bugzilla, SourceForge, Github, GitLab, Gitea, Mantis, and Trac. will be used to reference the bugtracker in all commands. Unambiguous abbreviations of it will also be accepted. will be used to reference the bugtracker in the @@ -323,7 +323,7 @@ class Bugtracker(callbacks.PluginRegexp): 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?/))(?P\d+)/?" + 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\d+)/?" channel = msg.args[0] if ircutils.isChannel(msg.args[0]) else None if checkAddressed(msg.args[1].strip(), channel): return @@ -334,13 +334,14 @@ class Bugtracker(callbacks.PluginRegexp): return msg.tag('nbugs', nbugs+1) url = match.group(0) + bugid = int(match.group('bug')) if '://' in url: url = url[url.rfind('://')+3:] try: - tracker = self.get_tracker(url) + tracker = self.get_tracker(url, bugid) if not tracker: return - report = self.get_bug(channel or msg.nick, tracker, int(match.group('bug')), self.registryValue('showassignee', channel), + report = self.get_bug(channel or msg.nick, tracker, bugid, self.registryValue('showassignee', channel), self.registryValue('extended', channel), do_url=False) except BugtrackerError as e: irc.error(str(e)) @@ -395,7 +396,7 @@ class Bugtracker(callbacks.PluginRegexp): irc.reply(cverr) #TODO: As we will depend on launchpadlib, we should consider using lazr.uri.URI to do URL parsing - def get_tracker(self, snarfurl): + def get_tracker(self, snarfurl, bugid): # SourceForge short domain snarfurl = snarfurl.replace('sf.net', 'sourceforge.net', 1) @@ -418,6 +419,10 @@ class Bugtracker(callbacks.PluginRegexp): tracker = SourceForge().get_tracker(snarfurl) elif 'github.com' in snarfurl: tracker = GitHub().get_tracker(snarfurl) + elif re.match(r'[^\s/]+/[^\s/]+/[^\s/]+/(issues|pulls|merge_requests)', snarfurl): + tracker = GitLab().get_tracker(snarfurl, bugid) + if not tracker: + tracker = Gitea().get_tracker(snarfurl, bugid) elif 'view.php' in snarfurl: tracker = Mantis().get_tracker(snarfurl) elif '/ticket/' in snarfurl: @@ -443,9 +448,9 @@ class Bugtracker(callbacks.PluginRegexp): if duplicate and not self.is_ok(channel, tracker, bid): return - bugtype = re.match(r'.*/(feature-)?(?Prequest|patch|todo|issue|pull|ticket)(e?s)?/[0-9]+/?$', url) - if do_tracker and tracker.trackertype != 'github': - if re.match(r'.*/(bugs|feature-requests|patches|todo|issues|pulls?|ticket)/?$', tracker.description): + bugtype = re.match(r'.*/(feature-)?(?Prequest|patch|todo|issue|pull|merge|ticket)(_requests)?(e?s)?/[0-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, bid) else: if bugtype: @@ -855,6 +860,74 @@ class GitHub(IBugtracker): except Exception as e: raise BugtrackerError(self.errparse % (self.description, e, url)) +class GitLab(IBugtracker): + def get_tracker(self, url, id): + try: + match = re.match(r'[^\s/]+/[^\s/]+/[^\s/]+/(issues|merge_requests)', url) + name = desc = match.group(0) + url = 'https://%s' % name + bugurl = '%s/%d.json' % (url, id) + bugjson = utils.web.getUrl(bugurl) + bug = json.loads(bugjson.decode('utf-8')) +# registerBugtracker(name, url, desc, 'gitlab') + return GitLab(name, url, desc, 'gitlab') + except: + pass + + def get_bug(self, id): + url = "%s/%d.json" % (self.url, id) + try: + bugjson = utils.web.getUrl(url) + bug = json.loads(bugjson.decode('utf-8')) + except Exception as e: + raise BugtrackerError(self.errget % (self.description, e, url)) + try: + product = '/'.join(url.split('/')[-4:-2]) + status = bug['state'] + if 'assignees' in bug and bug['assignees']: + assignee = bug['assignees'][0]['name'] + else: + assignee = '' + return (id, product, bug['title'], '', status, assignee, "%s/%d" % (self.url, id), [], []) + except Exception as e: + raise BugtrackerError(self.errparse % (self.description, e, url)) + +class Gitea(IBugtracker): + def get_tracker(self, url, id): + try: + match = re.match(r'[^\s/]+/[^\s/]+/[^\s/]+/(issues|pulls)', url) + name = desc = match.group(0) + url = 'https://%s' % name + bugurl = '%s/%d' % (re.sub(r'://[^\s/]+/', r'\g<0>api/v1/repos/', url), id) + bugjson = utils.web.getUrl(bugurl) + bug = json.loads(bugjson.decode('utf-8')) +# registerBugtracker(name, url, desc, 'gitea') + return Gitea(name, url, desc, 'gitea') + except: + pass + + def get_bug(self, id): + url = "%s/%d" % (re.sub(r'://[^\s/]+/', r'\g<0>api/v1/repos/', self.url), id) + try: + bugjson = utils.web.getUrl(url) + bug = json.loads(bugjson.decode('utf-8')) + except Exception as e: + raise BugtrackerError(self.errget % (self.description, e, url)) + try: + product = '/'.join(url.split('/')[-4:-2]) + if 'merged' in bug and bug['merged']: + status = 'Merged' + else: + status = bug['state'] + if bug['assignee']: + assignee = bug['assignee']['username'] + else: + assignee = '' + # Issues have no 'html_url', but pulls do + return (id, product, bug['title'], '', status, assignee, "%s/%d" % (self.url, id), [], []) + except Exception as e: + raise BugtrackerError(self.errparse % (self.description, e, url)) + class Mantis(IBugtracker): def __init__(self, *args, **kwargs): if not sys.version_info < (3,0):