mirror of
https://github.com/Mikaela/Limnoria.git
synced 2025-01-30 14:14:37 +01:00
Yay! Finally able to consolidate Sourceforge.{rfe,bug} into
Sourceforge.tracker. Less code, more functionality. What could be better?
This commit is contained in:
parent
c428e8908b
commit
08fc07b698
@ -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.
|
||||||
|
@ -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)
|
||||||
|
|
||||||
|
@ -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:
|
||||||
|
Loading…
Reference in New Issue
Block a user