Yay! Finally able to consolidate Sourceforge.{rfe,bug} into

Sourceforge.tracker. Less code, more functionality. What could be better?
This commit is contained in:
James Vega 2004-04-15 06:20:21 +00:00
parent c428e8908b
commit 08fc07b698
3 changed files with 73 additions and 127 deletions

View File

@ -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 * Added supybot.log.individualPluginLogfiles, which determines
whether plugin logs will be logged to their individual logfiles whether plugin logs will be logged to their individual logfiles
in addition to the misc.log logfile. in addition to the misc.log logfile.

View File

@ -108,13 +108,15 @@ class Sourceforge(callbacks.PrivmsgCommandAndRegexp):
'&_group=100&order=artifact_id&sort=DESC' '&_group=100&order=artifact_id&sort=DESC'
_resolution=re.compile(r'<b>(Resolution):</b> <a.+?<br>(.+?)</td>',_reopts) _resolution=re.compile(r'<b>(Resolution):</b> <a.+?<br>(.+?)</td>',_reopts)
_assigned=re.compile(r'<b>(Assigned To):</b> <a.+?<br>(.+?)</td>', _reopts) _assigned=re.compile(r'<b>(Assigned To):</b> <a.+?<br>(.+?)</td>', _reopts)
_submitted = re.compile(r'<b>(Submitted By):</b><br>([^<]+)</td>', _reopts) _submitted = re.compile(r'<b>(Submitted By):</b><br>([^-]+) - '
r'(?:nobody|<a href)', _reopts)
_priority = re.compile(r'<b>(Priority):</b> <a.+?<br>(.+?)</td>', _reopts) _priority = re.compile(r'<b>(Priority):</b> <a.+?<br>(.+?)</td>', _reopts)
_status = re.compile(r'<b>(Status):</b> <a.+?<br>(.+?)</td>', _reopts) _status = re.compile(r'<b>(Status):</b> <a.+?<br>(.+?)</td>', _reopts)
_regexps =(_resolution, _assigned, _submitted, _priority, _status) _regexps =(_resolution, _assigned, _submitted, _priority, _status)
_statusOpt = {'any':100, 'open':1, 'closed':2, 'deleted':3, 'pending':4} _statusOpt = {'any':100, 'open':1, 'closed':2, 'deleted':3, 'pending':4}
_projectURL = 'http://sourceforge.net/projects/' _projectURL = 'http://sourceforge.net/projects/'
_trackerURL = 'https://sourceforge.net/support/tracker.php?aid='
def __init__(self): def __init__(self):
callbacks.PrivmsgCommandAndRegexp.__init__(self) callbacks.PrivmsgCommandAndRegexp.__init__(self)
self.__class__.sf = self.__class__.sourceforge self.__class__.sf = self.__class__.sourceforge
@ -159,16 +161,49 @@ class Sourceforge(callbacks.PrivmsgCommandAndRegexp):
except webutils.WebError, e: except webutils.WebError, e:
raise callbacks.Error, str(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+) - ([^<]+)</title>', re.I)
_linkType = re.compile(r'(\w+ \w+|\w+): Tracker Detailed View', re.I)
def _getTrackerInfo(self, url):
try: try:
text = webutils.getUrl(url) s = webutils.getUrl(url)
head = '%s <http://sourceforge.net%s>' self.log.warning(s)
resp = [head % match for match in self._formatResp(text,num)] resp = []
if resp: head = ''
irc.reply(resp[0]) m = self._linkType.search(s)
return n = self._sfTitle.search(s)
irc.errorPossibleBug('No Trackers were found.') 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: except webutils.WebError, e:
raise TrackerError, str(e)
def tracker(self, irc, msg, args):
"""<num>
Returns a description of the tracker with Tracker id <num> 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)) irc.error(str(e))
_bugLink = re.compile(r'"([^"]+)">Bugs') _bugLink = re.compile(r'"([^"]+)">Bugs')
@ -225,38 +260,6 @@ class Sourceforge(callbacks.PrivmsgCommandAndRegexp):
else: else:
irc.error('Could not find bug statistics.') irc.error('Could not find bug statistics.')
def bug(self, irc, msg, args):
"""[--{any,open,closed,deleted,pending}] [<project>] <num>
Returns a description of the bug with Tracker id <num> and the
corresponding Tracker URL. <project> 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') _rfeLink = re.compile(r'"([^"]+)">RFE')
def rfes(self, irc, msg, args): def rfes(self, irc, msg, args):
"""[--{any,open,closed,deleted,pending}] [<project>] """[--{any,open,closed,deleted,pending}] [<project>]
@ -310,40 +313,6 @@ class Sourceforge(callbacks.PrivmsgCommandAndRegexp):
else: else:
irc.error('Could not find RFE statistics.') irc.error('Could not find RFE statistics.')
def rfe(self, irc, msg, args):
"""[--{any,open,closed,deleted,pending}] [<project>] <num>
Returns a description of the bug with Tracker id <num> and the
corresponding Tracker URL. <project> 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+) - ([^<]+)</title>', re.I)
_linkType = re.compile(r'(\w+ \w+|\w+): Tracker Detailed View', re.I)
def sfSnarfer(self, irc, msg, match): def sfSnarfer(self, irc, msg, match):
r"https?://(?:www\.)?(?:sourceforge|sf)\.net/tracker/" \ r"https?://(?:www\.)?(?:sourceforge|sf)\.net/tracker/" \
r".*\?(?:&?func=detail|&?aid=\d+|&?group_id=\d+|&?atid=\d+){4}" r".*\?(?:&?func=detail|&?aid=\d+|&?group_id=\d+|&?atid=\d+){4}"
@ -351,26 +320,12 @@ class Sourceforge(callbacks.PrivmsgCommandAndRegexp):
return return
try: try:
url = match.group(0) url = match.group(0)
s = webutils.getUrl(url) resp = self._getTrackerInfo(url)
resp = [] if resp is None:
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:
self.log.warning('Invalid Tracker page snarfed: %s', url) self.log.warning('Invalid Tracker page snarfed: %s', url)
for r in self._regexps: else:
m = r.search(s) irc.reply(resp, prefixName=False)
if m: except TrackerError, e:
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:
self.log.warning(str(e)) self.log.warning(str(e))
sfSnarfer = privmsgs.urlSnarfer(sfSnarfer) sfSnarfer = privmsgs.urlSnarfer(sfSnarfer)

View File

@ -34,56 +34,47 @@ import re
from testsupport import * from testsupport import *
if network: if network:
class SourceforgeTest(ChannelPluginTestCase, PluginDocumentation): class SourceforgeTest(ChannelPluginTestCase):
plugins = ('Sourceforge',) 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): def testAny(self):
m = self.getMsg('bugs --any gaim') m = self.getMsg('bugs --any gaim')
self.failUnless(m, 'No response from Sourceforge.') self.failUnless(m, 'No response from Sourceforge.')
n = re.search('#(\d+)', m.args[1]).group(1) 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') m = self.getMsg('rfes --any gaim')
self.failUnless(m, 'No response from Sourceforge.') self.failUnless(m, 'No response from Sourceforge.')
n = re.search('#(\d+)', m.args[1]).group(1) n = re.search('#(\d+)', m.args[1]).group(1)
self.assertNotError('rfe --any gaim %s' % n) self.assertNotError('tracker %s' % n)
def testClosed(self): def testClosed(self):
m = self.getMsg('bugs --closed gaim') m = self.getMsg('bugs --closed gaim')
self.failUnless(m, 'No response from Sourceforge.') self.failUnless(m, 'No response from Sourceforge.')
n = re.search('#(\d+)', m.args[1]).group(1) 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') m = self.getMsg('rfes --closed gaim')
self.failUnless(m, 'No response from Sourceforge.') self.failUnless(m, 'No response from Sourceforge.')
n = re.search('#(\d+)', m.args[1]).group(1) n = re.search('#(\d+)', m.args[1]).group(1)
self.assertNotError('rfe --closed gaim %s' % n) self.assertNotError('tracker %s' % n)
def testDeleted(self): def testDeleted(self):
m = self.getMsg('bugs --deleted gaim') m = self.getMsg('bugs --deleted gaim')
self.failUnless(m, 'No response from Sourceforge.') self.failUnless(m, 'No response from Sourceforge.')
n = re.search('#(\d+)', m.args[1]).group(1) 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') m = self.getMsg('rfes --deleted gaim')
self.failUnless(m, 'No response from Sourceforge.') self.failUnless(m, 'No response from Sourceforge.')
n = re.search('#(\d+)', m.args[1]).group(1) n = re.search('#(\d+)', m.args[1]).group(1)
self.assertNotError('rfe --deleted gaim %s' % n) self.assertNotError('tracker %s' % n)
def testOpen(self): def testOpen(self):
m = self.getMsg('bugs --open gaim') m = self.getMsg('bugs --open gaim')
self.failUnless(m, 'No response from Sourceforge.') self.failUnless(m, 'No response from Sourceforge.')
n = re.search('#(\d+)', m.args[1]).group(1) 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') m = self.getMsg('rfes --open gaim')
self.failUnless(m, 'No response from Sourceforge.') self.failUnless(m, 'No response from Sourceforge.')
n = re.search('#(\d+)', m.args[1]).group(1) n = re.search('#(\d+)', m.args[1]).group(1)
self.assertNotError('rfe --open gaim %s' % n) self.assertNotError('tracker %s' % n)
def testBugs(self): def testBugs(self):
self.assertHelp('bugs') self.assertHelp('bugs')
@ -97,14 +88,6 @@ if network:
finally: finally:
conf.supybot.plugins.Sourceforge.defaultProject.set(original) 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): def testRfes(self):
self.assertHelp('rfes') self.assertHelp('rfes')
self.assertRegexp('rfes 83423', 'Use the rfe command') self.assertRegexp('rfes 83423', 'Use the rfe command')
@ -118,19 +101,23 @@ if network:
conf.supybot.plugins.Sourceforge.defaultProject.set(original) conf.supybot.plugins.Sourceforge.defaultProject.set(original)
def testDefaultproject(self): def testDefaultproject(self):
self.assertHelp('bugs')
try: try:
original = conf.supybot.plugins.Sourceforge.defaultProject() original = conf.supybot.plugins.Sourceforge.defaultProject()
conf.supybot.plugins.Sourceforge.defaultProject.set('supybot') conf.supybot.plugins.Sourceforge.defaultProject.setValue('supybot')
self.assertNotError('bugs') self.assertNotError('bugs')
m = self.getMsg('bugs') conf.supybot.plugins.Sourceforge.defaultProject.setValue('')
n = re.search('#(\d+)', m.args[1]).group(1) self.assertHelp('bugs')
self.assertNotError('bug supybot %s' % n)
# This should have the same effect as calling 'bug supybot %s'
self.assertNotError('bug %s' % n)
finally: finally:
conf.supybot.plugins.Sourceforge.defaultProject.set(original) 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): def testSnarfer(self):
s = r'.*Status.*: \w+' s = r'.*Status.*: \w+'
try: try: