Properly added and abstracted trackers commands

This commit is contained in:
James Vega 2004-09-04 05:51:30 +00:00
parent d98de454b9
commit 977a33a43f
2 changed files with 59 additions and 49 deletions

View File

@ -96,11 +96,6 @@ conf.registerChannelValue(conf.supybot.plugins.Sourceforge, 'trackerSnarfer',
conf.registerChannelValue(conf.supybot.plugins.Sourceforge, 'defaultProject', conf.registerChannelValue(conf.supybot.plugins.Sourceforge, 'defaultProject',
registry.String('', """Sets the default project to use in the case that no registry.String('', """Sets the default project to use in the case that no
explicit project is given.""")) explicit project is given."""))
#conf.registerGlobalValue(conf.supybot.plugins.Sourceforge,
# 'enableSeparateTrackersCommands',
# registry.Boolean(True, """Determines whether the bot will recognize the
# tracker types as commands. For example, "@bugs supybot" would be the same
# as calling "@trackers bugs supybot"."""))
class Sourceforge(callbacks.PrivmsgCommandAndRegexp): class Sourceforge(callbacks.PrivmsgCommandAndRegexp):
""" """
@ -112,7 +107,7 @@ class Sourceforge(callbacks.PrivmsgCommandAndRegexp):
_reopts = re.I _reopts = re.I
_infoRe = re.compile(r'<td nowrap>(\d+)</td><td><a href=' _infoRe = re.compile(r'<td nowrap>(\d+)</td><td><a href='
r'"([^"]+)">([^<]+)</a>', _reopts) r'"([^"]+)">([^<]+)</a>', re.I)
_hrefOpts = '&set=custom&_assigned_to=0&_status=%s&_category=100' \ _hrefOpts = '&set=custom&_assigned_to=0&_status=%s&_category=100' \
'&_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)
@ -132,20 +127,10 @@ class Sourceforge(callbacks.PrivmsgCommandAndRegexp):
super(Sourceforge, self).__init__() super(Sourceforge, self).__init__()
self.__class__.sf = self.__class__.sourceforge self.__class__.sf = self.__class__.sourceforge
# def isCommand(self, methodName):
# if hasattr(self, methodName):
# return True
# if methodName not in ('bugs', 'rfes', 'patches'):
# return False
# elif self.registryValue('enableSeparateTrackersCommands'):
# return True
# else:
# return False
def _formatResp(self, text, num=''): def _formatResp(self, text, num=''):
""" """
Parses the Sourceforge query to return a list of tuples that Parses the Sourceforge query to return a list of tuples that
contain the bug/rfe information. contain the tracker information.
""" """
if num: if num:
for item in ifilter(lambda s, n=num: s and n in s, for item in ifilter(lambda s, n=num: s and n in s,
@ -157,6 +142,9 @@ class Sourceforge(callbacks.PrivmsgCommandAndRegexp):
yield (item[0], utils.htmlToText(item[2])) yield (item[0], utils.htmlToText(item[2]))
def _getTrackerURL(self, project, regex, status): def _getTrackerURL(self, project, regex, status):
"""
Searches the project's Summary page to find the proper tracker link.
"""
try: try:
text = webutils.getUrl('%s%s' % (self._projectURL, project)) text = webutils.getUrl('%s%s' % (self._projectURL, project))
m = regex.search(text) m = regex.search(text)
@ -169,6 +157,9 @@ class Sourceforge(callbacks.PrivmsgCommandAndRegexp):
raise callbacks.Error, str(e) raise callbacks.Error, str(e)
def _getTrackerList(self, url): def _getTrackerList(self, url):
"""
Searches the tracker list page and returns a list of the trackers.
"""
try: try:
text = webutils.getUrl(url) text = webutils.getUrl(url)
if "No matches found." in text: if "No matches found." in text:
@ -188,6 +179,9 @@ class Sourceforge(callbacks.PrivmsgCommandAndRegexp):
_sfTitle = re.compile(r'Detail:(\d+) - ([^<]+)</title>', re.I) _sfTitle = re.compile(r'Detail:(\d+) - ([^<]+)</title>', re.I)
_linkType = re.compile(r'(\w+ \w+|\w+): Tracker Detailed View', re.I) _linkType = re.compile(r'(\w+ \w+|\w+): Tracker Detailed View', re.I)
def _getTrackerInfo(self, url): def _getTrackerInfo(self, url):
"""
Parses the specific tracker page, returning useful information.
"""
try: try:
s = webutils.getUrl(url) s = webutils.getUrl(url)
resp = [] resp = []
@ -231,33 +225,22 @@ class Sourceforge(callbacks.PrivmsgCommandAndRegexp):
'rfes': re.compile(r'"([^"]+)">RFE'), 'rfes': re.compile(r'"([^"]+)">RFE'),
'patches': re.compile(r'"([^"]+)">Patches'), 'patches': re.compile(r'"([^"]+)">Patches'),
} }
def trackers(self, irc, msg, args): def _trackers(self, irc, args, msg, tracker):
"""[--{any,open,closed,deleted,pending}] {bugs,patches,rfes}
[<project>]
Returns a list of the most recent trackers filed against <project>.
<project> is not needed if there is a default project set. Search
defaults to open trackers.
"""
(optlist, rest) = getopt.getopt(args, '', self._statusOpt.keys()) (optlist, rest) = getopt.getopt(args, '', self._statusOpt.keys())
(tracker, project) = privmsgs.getArgs(rest, optional=1) project = privmsgs.getArgs(rest, required=0, optional=1)
status = 'open' status = 'open'
for (option, _) in optlist: for (option, _) in optlist:
option = option.lstrip('-').lower() option = option.lstrip('-').lower()
if option in self._statusOpt: if option in self._statusOpt:
status = option status = option
try: try:
int(tracker) int(project)
# They want the tracker command, they're giving us an id#. s = 'Use the tracker command to get information about a specific'\
s = 'Use the tracker command (e.g., tracker %s) for info about a'\ 'tracker.'
' specific tracker.' % tracker
irc.error(s) irc.error(s)
return return
except ValueError: except ValueError:
pass pass
tracker = tracker.lower()
if tracker not in self._trackerLink:
raise callbacks.ArgumentError
if not project: if not project:
project = self.registryValue('defaultProject', msg.args[0]) project = self.registryValue('defaultProject', msg.args[0])
if not project: if not project:
@ -271,6 +254,33 @@ class Sourceforge(callbacks.PrivmsgCommandAndRegexp):
return return
irc.reply(self._getTrackerList(url)) irc.reply(self._getTrackerList(url))
def bugs(self, irc, msg, args):
"""[--{any,open,closed,deleted,pending}] [<project>]
Returns a list of the most recent bugs filed against <project>.
<project> is not needed if there is a default project set. Search
defaults to open bugs.
"""
self._trackers(irc, args, msg, 'bugs')
def rfes(self, irc, msg, args):
"""[--{any,open,closed,deleted,pending}] [<project>]
Returns a list of the most recent rfes filed against <project>.
<project> is not needed if there is a default project set. Search
defaults to open rfes.
"""
self._trackers(irc, args, msg, 'rfes')
def patches(self, irc, msg, args):
"""[--{any,open,closed,deleted,pending}] [<project>]
Returns a list of the most recent patches filed against <project>.
<project> is not needed if there is a default project set. Search
defaults to open patches.
"""
self._trackers(irc, args, msg, 'patches')
_totbugs = re.compile(r'Bugs</a>\s+?\( <b>([^<]+)</b>', re.S | re.I) _totbugs = re.compile(r'Bugs</a>\s+?\( <b>([^<]+)</b>', re.S | re.I)
def _getNumBugs(self, project): def _getNumBugs(self, project):
text = webutils.getUrl('%s%s' % (self._projectURL, project)) text = webutils.getUrl('%s%s' % (self._projectURL, project))
@ -291,7 +301,7 @@ class Sourceforge(callbacks.PrivmsgCommandAndRegexp):
return '' return ''
def total(self, irc, msg, args): def total(self, irc, msg, args):
"""[bugs|rfes] [<project>] """{bugs,rfes} [<project>]
Returns the total count of open bugs or rfes. <project> is only Returns the total count of open bugs or rfes. <project> is only
necessary if a default project is not set. necessary if a default project is not set.

View File

@ -40,54 +40,54 @@ class SourceforgeTest(ChannelPluginTestCase):
plugins = ('Sourceforge',) plugins = ('Sourceforge',)
if network: if network:
def testAny(self): def testAny(self):
m = self.getMsg('trackers --any bugs 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('tracker %s' % n) self.assertNotError('tracker %s' % n)
m = self.getMsg('trackers --any rfes 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('tracker %s' % n) self.assertNotError('tracker %s' % n)
def testClosed(self): def testClosed(self):
m = self.getMsg('trackers --closed bugs 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('tracker %s' % n) self.assertNotError('tracker %s' % n)
m = self.getMsg('trackers --closed patches gaim') m = self.getMsg('patches --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('tracker %s' % n) self.assertNotError('tracker %s' % n)
def testDeleted(self): def testDeleted(self):
m = self.getMsg('trackers --deleted bugs 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('tracker %s' % n) self.assertNotError('tracker %s' % n)
m = self.getMsg('trackers --deleted rfes 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('tracker %s' % n) self.assertNotError('tracker %s' % n)
def testOpen(self): def testOpen(self):
m = self.getMsg('trackers --open bugs 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('tracker %s' % n) self.assertNotError('tracker %s' % n)
m = self.getMsg('trackers --open rfes 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('tracker %s' % n) self.assertNotError('tracker %s' % n)
def testTrackers(self): def testTrackers(self):
self.assertHelp('trackers bugs') self.assertHelp('bugs')
self.assertRegexp('trackers bugs 83423', 'find the Bug') self.assertRegexp('bugs 83423', 'use the tracker')
try: try:
original = Sf.defaultProject() original = Sf.defaultProject()
Sf.defaultProject.set('supybot') Sf.defaultProject.set('supybot')
self.assertRegexp('trackers bugs alkjfi83fa8', 'find the Bugs') self.assertRegexp('bugs alkjfi83fa8', 'find the Bugs')
self.assertNotError('trackers rfes gaim') self.assertNotError('rfes gaim')
self.assertNotError('trackers patches') self.assertNotError('patches')
finally: finally:
Sf.defaultProject.set(original) Sf.defaultProject.set(original)
@ -95,9 +95,9 @@ class SourceforgeTest(ChannelPluginTestCase):
try: try:
original = Sf.defaultProject() original = Sf.defaultProject()
Sf.defaultProject.setValue('supybot') Sf.defaultProject.setValue('supybot')
self.assertNotError('trackers bugs') self.assertNotError('bugs')
Sf.defaultProject.setValue('') Sf.defaultProject.setValue('')
self.assertHelp('trackers bugs') self.assertHelp('bugs')
finally: finally:
Sf.defaultProject.set(original) Sf.defaultProject.set(original)