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: