diff --git a/ChangeLog b/ChangeLog index eff3fd2da..c32a17bc8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ + * Replaced Sourceforge.{rfe,bug} with Sourceforge.tracker, which + can query any tracker type (not just RFEs and bugs) and responds + with more information, a la trackerSnarfer. + * Added supybot.log.individualPluginLogfiles, which determines whether plugin logs will be logged to their individual logfiles in addition to the misc.log logfile. diff --git a/plugins/Sourceforge.py b/plugins/Sourceforge.py index 69a6845ec..cb5255499 100644 --- a/plugins/Sourceforge.py +++ b/plugins/Sourceforge.py @@ -108,13 +108,15 @@ class Sourceforge(callbacks.PrivmsgCommandAndRegexp): '&_group=100&order=artifact_id&sort=DESC' _resolution=re.compile(r'(Resolution): (.+?)',_reopts) _assigned=re.compile(r'(Assigned To): (.+?)', _reopts) - _submitted = re.compile(r'(Submitted By):
([^<]+)', _reopts) + _submitted = re.compile(r'(Submitted By):
([^-]+) - ' + r'(?:nobody|(Priority): (.+?)', _reopts) _status = re.compile(r'(Status): (.+?)', _reopts) _regexps =(_resolution, _assigned, _submitted, _priority, _status) _statusOpt = {'any':100, 'open':1, 'closed':2, 'deleted':3, 'pending':4} _projectURL = 'http://sourceforge.net/projects/' + _trackerURL = 'https://sourceforge.net/support/tracker.php?aid=' def __init__(self): callbacks.PrivmsgCommandAndRegexp.__init__(self) self.__class__.sf = self.__class__.sourceforge @@ -159,16 +161,49 @@ class Sourceforge(callbacks.PrivmsgCommandAndRegexp): except webutils.WebError, e: raise callbacks.Error, str(e) - def _getTrackerInfo(self, irc, msg, url, num): + _bold = lambda self, m: (ircutils.bold(m[0]),) + m[1:] + _sfTitle = re.compile(r'Detail:(\d+) - ([^<]+)', re.I) + _linkType = re.compile(r'(\w+ \w+|\w+): Tracker Detailed View', re.I) + def _getTrackerInfo(self, url): try: - text = webutils.getUrl(url) - head = '%s ' - resp = [head % match for match in self._formatResp(text,num)] - if resp: - irc.reply(resp[0]) - return - irc.errorPossibleBug('No Trackers were found.') + s = webutils.getUrl(url) + self.log.warning(s) + resp = [] + head = '' + m = self._linkType.search(s) + n = self._sfTitle.search(s) + if m and n: + linktype = m.group(1) + linktype = utils.depluralize(linktype) + (num, desc) = n.groups() + head = '%s #%s:' % (ircutils.bold(linktype), num) + resp.append(desc) + else: + return None + for r in self._regexps: + m = r.search(s) + if m: + resp.append('%s: %s' % self._bold(m.groups())) + return '%s #%s: %s' % (ircutils.bold(linktype), ircutils.bold(num), + '; '.join(resp)) except webutils.WebError, e: + raise TrackerError, str(e) + + def tracker(self, irc, msg, args): + """ + + Returns a description of the tracker with Tracker id and the + corresponding Tracker url. + """ + num = privmsgs.getArgs(args) + try: + url = '%s%s' % (self._trackerURL, num) + resp = self._getTrackerInfo(url) + if resp is None: + irc.error('Invalid Tracker page snarfed: %s' % url) + else: + irc.reply(resp) + except TrackerError, e: irc.error(str(e)) _bugLink = re.compile(r'"([^"]+)">Bugs') @@ -225,38 +260,6 @@ class Sourceforge(callbacks.PrivmsgCommandAndRegexp): else: irc.error('Could not find bug statistics.') - def bug(self, irc, msg, args): - """[--{any,open,closed,deleted,pending}] [] - - Returns a description of the bug with Tracker id and the - corresponding Tracker URL. is not needed if there is a - default project set. Search defaults to open bugs. - """ - (optlist, rest) = getopt.getopt(args, '', self._statusOpt.keys()) - (project, bugnum) = privmsgs.getArgs(rest, optional=1) - status = 'open' - for (option, _) in optlist: - option = option.lstrip('-').lower() - if option in self._statusOpt: - status = option - if not bugnum: - try: - int(project) - except ValueError: - irc.error('"%s" is not a proper bugnumber.' % project) - return - bugnum = project - project = self.registryValue('defaultProject', msg.args[0]) - if not project: - raise callbacks.ArgumentError - try: - url = self._getTrackerURL(project, self._bugLink, status) - #self.log.warning(url) - except TrackerError, e: - irc.error('%s. I can\'t find the Bugs link.' % e) - return - self._getTrackerInfo(irc, msg, url, bugnum) - _rfeLink = re.compile(r'"([^"]+)">RFE') def rfes(self, irc, msg, args): """[--{any,open,closed,deleted,pending}] [] @@ -310,40 +313,6 @@ class Sourceforge(callbacks.PrivmsgCommandAndRegexp): else: irc.error('Could not find RFE statistics.') - def rfe(self, irc, msg, args): - """[--{any,open,closed,deleted,pending}] [] - - Returns a description of the bug with Tracker id and the - corresponding Tracker URL. is not needed if there is a - default project set. Search defaults to open RFEs. - """ - (optlist, rest) = getopt.getopt(args, '', self._statusOpt.keys()) - (project, rfenum) = privmsgs.getArgs(rest, optional=1) - status = 'open' - for (option, _) in optlist: - option = option.lstrip('-').lower() - if option in self._statusOpt: - status = option - if not rfenum: - try: - int(project) - except ValueError: - irc.error('"%s" is not a proper rfenumber.' % project) - return - rfenum = project - project = self.registryValue('defaultProject', msg.args[0]) - if not project: - raise callbacks.ArgumentError - try: - url = self._getTrackerURL(project, self._rfeLink, status) - except TrackerError, e: - irc.error('%s. I can\'t find the RFEs link.' % e) - return - self._getTrackerInfo(irc, msg, url, rfenum) - - _bold = lambda self, m: (ircutils.bold(m[0]),) + m[1:] - _sfTitle = re.compile(r'Detail:(\d+) - ([^<]+)', re.I) - _linkType = re.compile(r'(\w+ \w+|\w+): Tracker Detailed View', re.I) def sfSnarfer(self, irc, msg, match): r"https?://(?:www\.)?(?:sourceforge|sf)\.net/tracker/" \ r".*\?(?:&?func=detail|&?aid=\d+|&?group_id=\d+|&?atid=\d+){4}" @@ -351,26 +320,12 @@ class Sourceforge(callbacks.PrivmsgCommandAndRegexp): return try: url = match.group(0) - s = webutils.getUrl(url) - resp = [] - head = '' - m = self._linkType.search(s) - n = self._sfTitle.search(s) - if m and n: - linktype = m.group(1) - linktype = utils.depluralize(linktype) - (num, desc) = n.groups() - head = '%s #%s:' % (ircutils.bold(linktype), num) - resp.append(desc) - else: + resp = self._getTrackerInfo(url) + if resp is None: self.log.warning('Invalid Tracker page snarfed: %s', url) - for r in self._regexps: - m = r.search(s) - if m: - resp.append('%s: %s' % self._bold(m.groups())) - irc.reply('%s #%s: %s' % (ircutils.bold(linktype), - ircutils.bold(num), '; '.join(resp)), prefixName = False) - except webutils.WebError, e: + else: + irc.reply(resp, prefixName=False) + except TrackerError, e: self.log.warning(str(e)) sfSnarfer = privmsgs.urlSnarfer(sfSnarfer) diff --git a/test/test_Sourceforge.py b/test/test_Sourceforge.py index 877880843..d86266586 100644 --- a/test/test_Sourceforge.py +++ b/test/test_Sourceforge.py @@ -34,56 +34,47 @@ import re from testsupport import * if network: - class SourceforgeTest(ChannelPluginTestCase, PluginDocumentation): + class SourceforgeTest(ChannelPluginTestCase): plugins = ('Sourceforge',) - def testBug(self): - self.assertHelp('bug') - m = self.getMsg('bugs gaim') - self.failUnless(m, 'No response from Sourceforge.') - n = re.search('#(\d+)', m.args[1]).group(1) - self.assertNotError('bug gaim %s' % n) - self.assertError('bug gaim') - self.assertRegexp('bug lkadf 9', 'find the Bugs') - def testAny(self): m = self.getMsg('bugs --any gaim') self.failUnless(m, 'No response from Sourceforge.') n = re.search('#(\d+)', m.args[1]).group(1) - self.assertNotError('bug --any gaim %s' % n) + self.assertNotError('tracker %s' % n) m = self.getMsg('rfes --any gaim') self.failUnless(m, 'No response from Sourceforge.') n = re.search('#(\d+)', m.args[1]).group(1) - self.assertNotError('rfe --any gaim %s' % n) + self.assertNotError('tracker %s' % n) def testClosed(self): m = self.getMsg('bugs --closed gaim') self.failUnless(m, 'No response from Sourceforge.') n = re.search('#(\d+)', m.args[1]).group(1) - self.assertNotError('bug --closed gaim %s' % n) + self.assertNotError('tracker %s' % n) m = self.getMsg('rfes --closed gaim') self.failUnless(m, 'No response from Sourceforge.') n = re.search('#(\d+)', m.args[1]).group(1) - self.assertNotError('rfe --closed gaim %s' % n) + self.assertNotError('tracker %s' % n) def testDeleted(self): m = self.getMsg('bugs --deleted gaim') self.failUnless(m, 'No response from Sourceforge.') n = re.search('#(\d+)', m.args[1]).group(1) - self.assertNotError('bug --deleted gaim %s' % n) + self.assertNotError('tracker %s' % n) m = self.getMsg('rfes --deleted gaim') self.failUnless(m, 'No response from Sourceforge.') n = re.search('#(\d+)', m.args[1]).group(1) - self.assertNotError('rfe --deleted gaim %s' % n) + self.assertNotError('tracker %s' % n) def testOpen(self): m = self.getMsg('bugs --open gaim') self.failUnless(m, 'No response from Sourceforge.') n = re.search('#(\d+)', m.args[1]).group(1) - self.assertNotError('bug --open gaim %s' % n) + self.assertNotError('tracker %s' % n) m = self.getMsg('rfes --open gaim') self.failUnless(m, 'No response from Sourceforge.') n = re.search('#(\d+)', m.args[1]).group(1) - self.assertNotError('rfe --open gaim %s' % n) + self.assertNotError('tracker %s' % n) def testBugs(self): self.assertHelp('bugs') @@ -97,14 +88,6 @@ if network: finally: conf.supybot.plugins.Sourceforge.defaultProject.set(original) - def testRfe(self): - m = self.getMsg('rfes gaim') - self.failUnless(m, 'No response from Sourceforge.') - n = re.search('#(\d+)', m.args[1]).group(1) - self.assertNotError('rfe gaim %s' % n) - self.assertError('rfe gaim') - self.assertRegexp('rfe lakdf 9', 'find the RFEs') - def testRfes(self): self.assertHelp('rfes') self.assertRegexp('rfes 83423', 'Use the rfe command') @@ -118,19 +101,23 @@ if network: conf.supybot.plugins.Sourceforge.defaultProject.set(original) def testDefaultproject(self): - self.assertHelp('bugs') try: original = conf.supybot.plugins.Sourceforge.defaultProject() - conf.supybot.plugins.Sourceforge.defaultProject.set('supybot') + conf.supybot.plugins.Sourceforge.defaultProject.setValue('supybot') self.assertNotError('bugs') - m = self.getMsg('bugs') - n = re.search('#(\d+)', m.args[1]).group(1) - self.assertNotError('bug supybot %s' % n) - # This should have the same effect as calling 'bug supybot %s' - self.assertNotError('bug %s' % n) + conf.supybot.plugins.Sourceforge.defaultProject.setValue('') + self.assertHelp('bugs') finally: conf.supybot.plugins.Sourceforge.defaultProject.set(original) + def testTracker(self): + bug = r'Bug.*Status.*: \w+' + rfe = r'Feature Request.*Status.*: \w+' + self.assertRegexp('tracker 589953', bug) + self.assertRegexp('tracker 712761', rfe) + self.assertRegexp('tracker 721761', 'Timo Hoenig') + self.assertRegexp('tracker 851239', 'Nobody/Anonymous') + def testSnarfer(self): s = r'.*Status.*: \w+' try: