Update Launchpad statuses and move to class instances

Disable sf.net in the right place 
_sort() in get_bug_new() moved to a class method
instance method _sort() moved to class method _old_sort()
improve _sort (prefiously under get_bug_new) error handling
Added tag "#Depricated" by depricated class Launchpad methods
class Launchpad uses the "production" service alias
Log an exception in Launchpad.__init__ when accessing the API fails
Removed some commented-out code
Added 'ubottu' to the list of trackers (as an alias for LP)
This commit is contained in:
Terence Simpson
2011-03-12 17:35:09 +00:00
parent dd3c9627e7
commit 0ded75a6ae

View File

@ -102,12 +102,12 @@ class Bugtracker(callbacks.PluginRegexp):
if group.trackertype() in defined_bugtrackers.keys():
self.db[name] = defined_bugtrackers[group.trackertype()](name, group.url(), group.description())
else:
# raise BugtrackerError("Unknown trackertype: %s (%s)" % (group.trackertype(), name))
self.log.warning("Bugtracker: Unknown trackertype: %s (%s)" % (group.trackertype(), name))
self.shorthand = utils.abbrev(self.db.keys())
# Schedule bug reporting
self.shown = {}
#TODO: Remove everything below this line
if self.registryValue('imap_server') and self.registryValue('reportercache'):
try:
schedule.removeEvent(self.name() + '.bugreporter')
@ -117,7 +117,7 @@ class Bugtracker(callbacks.PluginRegexp):
self.events += [self.name() + '.bugreporter']
self.log.info('Bugtracker: Adding scheduled event "%s.bugreporter"' % self.name())
def die(self):
def die(self): #TODO: Remove me
try:
for event in self.events:
self.log.info('Bugtracker: Removing scheduled event "%s"' % event)
@ -127,6 +127,7 @@ class Bugtracker(callbacks.PluginRegexp):
pass
def is_ok(self, channel, tracker, bug):
'''Flood/repeat protection'''
now = time.time()
for k in self.shown.keys():
if self.shown[k] < now - self.registryValue('repeatdelay', channel):
@ -136,7 +137,7 @@ class Bugtracker(callbacks.PluginRegexp):
return True
return False
def is_new(self, tracker, tag, id):
def is_new(self, tracker, tag, id): #Depricated
bugreporter_base = self.registryValue('reportercache')
if not os.path.exists(os.path.join(bugreporter_base,tag,tracker.name,str(int(id/1000)),str(id))):
try:
@ -148,7 +149,7 @@ class Bugtracker(callbacks.PluginRegexp):
return True
return False
def reportnewbugs(self,irc):
def reportnewbugs(self,irc): #Depricated
# Compile list of bugs
self.log.info("Bugtracker: Checking for new bugs")
bugs = {}
@ -417,7 +418,6 @@ class Bugtracker(callbacks.PluginRegexp):
else:
for r in report:
irc.reply(makeClean(r), prefixNick=False)
# turlSnarfer = urlSnarfer(turlSnarfer)
# Only useful for launchpad developers
def oopsSnarfer(self, irc, msg, match):
@ -431,7 +431,6 @@ class Bugtracker(callbacks.PluginRegexp):
if not self.is_ok(channel, 'lpoops', oopsid):
return
irc.reply("https://lp-oops.canonical.com/oops.py/?oopsid=%s" % oopsid, prefixNick=False)
#irc.reply("https://devpad.canonical.com/~jamesh/oops.cgi/%s" % oopsid, prefixNick=False)
def cveSnarfer(self, irc, msg, match):
r"(cve[- ]\d{4}[- ]\d{4})"
@ -450,28 +449,30 @@ class Bugtracker(callbacks.PluginRegexp):
cve = cve[:380] + '...'
irc.reply("%s (%s)" % (cve,url), prefixNick=False)
def cveUrlSnarfer(self, irc, msg, match):
pass
def get_tracker(self,snarfurl,sfdata):
def get_tracker(self, snarfurl, sfdata):
snarfurl = snarfurl.replace('sf.net','sourceforge.net')
snarfhost = snarfurl.replace('http://','').replace('https://','')
if '/' in snarfurl:
snarfhost = snarfhost[:snarfhost.index('/')]
for t in self.db.keys():
tracker = self.db[t]
tracker = self.db.get(t, None)
if not tracker:
self.log.error("No tracker for key %r" % t)
continue
url = tracker.url.replace('http://','').replace('https://','')
if 'sourceforge.net' in url:
return None
# Try to find the correct sf tracker
if str(sfdata) in tracker.url:
return tracker
# sourceforge.net has no API or structured bug exporting, HTML
# scraping is not good enough. Especially as SF keep changing it
continue
if '/' in url:
url = url[:url.index('/')]
if url in snarfhost:
return tracker
if 'sourceforge.net' in snarfurl:
return self.db['sourceforge']
if 'sourceforge.net' in snarfurl: # See above
return None
# No tracker found, bummer. Let's try and add one
if 'show_bug.cgi' in snarfurl:
tracker = Bugzilla().get_tracker(snarfurl)
@ -612,6 +613,9 @@ class Issuezilla(IBugtracker):
return [(id, component, title, severity, status, assignee, "%s/show_bug.cgi?id=%d" % (self.url, id))]
class Launchpad(IBugtracker):
statuses = ["Unknown", "Invalid", "Opinion", "Won't Fix", "Fix Released", "Fix Committed", "New", "Incomplete", "Confirmed", "Triaged", "In Progress"]
severities = ["Unknown", "Undecided", "Wishlist", "Low", "Medium", "High", "Critical"]
def __init__(self, *args, **kwargs):
IBugtracker.__init__(self, *args, **kwargs)
self.lp = None
@ -626,67 +630,80 @@ class Launchpad(IBugtracker):
try: # Attempt to use launchpadlib, python bindings for the Launchpad API
from launchpadlib.launchpad import Launchpad
from launchpadlib.uris import LPNET_SERVICE_ROOT
cachedir = os.path.join(conf.supybot.directories.data.tmp(), 'lpcache')
if hasattr(Launchpad, 'login_anonymously'):
self.lp = Launchpad.login_anonymously("Ubuntu Bots - Bugtracker", LPNET_SERVICE_ROOT, cachedir)
else:
self.lp = Launchpad.login("Ubuntu Bots - Bugtracker", '', '', LPNET_SERVICE_ROOT, cahedir)
self.lp = Launchpad.login_anonymously("Ubuntu Bots - Bugtracker", 'production', cachedir)
else: #NOTE: Most people should have a launchpadlib new enough for .login_anonymously
self.lp = Launchpad.login("Ubuntu Bots - Bugtracker", '', '', 'production', cahedir)
except ImportError:
# Ask for launchpadlib to be installed
supylog.warning("Please install python-launchpadlib, the old interface is deprecated")
except Exception: # Something unexpected happened
self.lp = None
supylog.error("Error accessing Launchpad API")
supylog.exception("Unknown exception while accessing the Launchpad API")
def _parse(self, task):
def _parse(self, task): #Depricated
parser = email.FeedParser.FeedParser()
parser.feed(task)
return parser.close()
def _sort(self, task1, task2):
def get_bug(self, id): #TODO: Remove this method and rename 'get_new_bug' to 'get_bug'
if self.lp:
return self.get_bug_new(id)
return self.get_bug_old(id)
@classmethod
def _sort(cls, task1, task2):
task1_status = task1.status
task1_importance = task1.importance
task2_status = task2.status
task2_importance = task2.importance
if task1_status not in cls.statuses:
supylog.error("%r is an unknown status for Launchapd, update %s.statuses" % (task1_status, getattr(cls, '__name__', 'Launchpad')))
if task2_status not in cls.statuses:
supylog.error("%r is an unknown status for Launchapd, update %s.statuses" % (task1_status, getattr(cls, '__name__', 'Launchpad')))
return -1
return 1
if task1_importance not in cls.severities:
supylog.error("%r is an unknown status for Launchapd, update %s.severities" % (task1_importance, getattr(cls, '__name__', 'Launchpad')))
if task2_importance not in cls.severities:
supylog.error("%r is an unknown status for Launchapd, update %s.severities" % (task1_importance, getattr(cls, '__name__', 'Launchpad')))
return -1
return 1
if task1_status != task2_status:
if cls.statuses.index(task1_status) < cls.statuses.index(task2_status):
return -1
return 1
if task1_importance != task2_importance:
if cls.severities.index(task1_importance) < cls.severities.index(task2_importance):
return -1
return 1
return 0
@classmethod
def _old_sort(cls, task1, task2): #Depricated
# Status sort:
try:
statuses = ["Unknown", "Invalid", "Won't Fix", "Fix Released", "Fix Committed", "New", "Incomplete", "Confirmed", "Triaged", "In Progress"]
severities = ["Unknown", "Undecided", "Wishlist", "Low", "Medium", "High", "Critical"]
if task1['status'] not in statuses and task2['status'] in statuses: return -1
if task1['status'] in statuses and task2['status'] not in statuses: return 1
if task1['importance'] not in severities and task2['importance'] in severities: return -1
if task1['importance'] in severities and task2['importance'] not in severities: return 1
if task1['status'] not in cls.statuses and task2['status'] in cls.statuses: return -1
if task1['status'] in cls.statuses and task2['status'] not in cls.statuses: return 1
if task1['importance'] not in cls.severities and task2['importance'] in cls.severities: return -1
if task1['importance'] in cls.severities and task2['importance'] not in cls.severities: return 1
if not (task1['status'] == task2['status']):
if statuses.index(task1['status']) < statuses.index(task2['status']):
if cls.statuses.index(task1['status']) < cls.statuses.index(task2['status']):
return -1
return 1
if not (task1['importance'] == task2['importance']):
if severities.index(task1['importance']) < severities.index(task2['importance']):
if cls.severities.index(task1['importance']) < cls.severities.index(task2['importance']):
return -1
return 1
except: # Launchpad changed again?
return 0
return 0
def get_bug(self, id):
if self.lp:
return self.get_bug_new(id)
return self.get_bug_old(id)
def get_bug_new(self, id):
def _sort(task1, task2):
statuses = ["Unknown", "Invalid", "Won't Fix", "Fix Released", "Fix Committed", "New", "Incomplete", "Confirmed", "Triaged", "In Progress"]
severities = ["Unknown", "Undecided", "Wishlist", "Low", "Medium", "High", "Critical"]
task1_status = task1.status
task1_importance = task1.importance
task2_status = task2.status
task2_importance = task2.importance
if task1_status != task2_status:
if statuses.index(task1_status) < statuses.index(task2_status):
return -1
return 1
if task1_importance != task2_importance:
if severities.index(task1_importance) < severities.index(task2_importance):
return -1
return 1
return 0
def get_bug_new(self, id): #TODO: Rename this method to 'get_bug'
try:
bugdata = self.lp.bugs[id]
if bugdata.private:
@ -698,7 +715,7 @@ class Launchpad(IBugtracker):
if tasks.total_size != 1:
tasks = list(tasks)
tasks.sort(_sort)
tasks.sort(self._sort)
taskdata = tasks[-1]
else:
taskdata = tasks[0]
@ -728,7 +745,7 @@ class Launchpad(IBugtracker):
return [(id, t, bugdata.title, taskdata.importance, taskdata.status,
assignee, "%s/bugs/%s" % (self.url, id), extinfo)]
def get_bug_old(self, id):
def get_bug_old(self, id): #Depricated
if id == 1:
raise BugtrackerError, "https://bugs.launchpad.net/ubuntu/+bug/1 (Not reporting large bug)"
@ -752,7 +769,7 @@ class Launchpad(IBugtracker):
parser.feed(bugdata)
bugdata = parser.close()
taskdata = map(self._parse, taskdata)
taskdata.sort(self._sort)
taskdata.sort(self._old_sort)
taskdata = taskdata[-1]
except Exception, e:
@ -929,6 +946,7 @@ sfre = re.compile(r"""
resolution.*?<br>\s+(?P<resolution>\S+)
.*?
""", re.VERBOSE | re.DOTALL | re.I)
#NOTE: Until sf.net has a way to export formatted bug data, this will remain broken and unmaintained
class Sourceforge(IBugtracker):
_sf_url = 'http://sf.net/support/tracker.php?aid=%d'
def get_bug(self, id):
@ -956,7 +974,6 @@ for k in v.keys():
defined_bugtrackers[k.lower()] = v[k]
registerBugtracker('mozilla', 'http://bugzilla.mozilla.org', 'Mozilla', 'bugzilla')
#registerBugtracker('ubuntu', 'http://bugzilla.ubuntu.com', 'Ubuntu', 'bugzilla')
registerBugtracker('ubuntu', 'https://launchpad.net', 'Ubuntu', 'launchpad')
registerBugtracker('gnome', 'http://bugzilla.gnome.org', 'Gnome', 'bugzilla')
registerBugtracker('gnome2', 'http://bugs.gnome.org', 'Gnome', 'bugzilla')
@ -975,6 +992,7 @@ registerBugtracker('cups', 'http://www.cups.org/str.php', 'CUPS', 'str')
registerBugtracker('gnewsense', 'http://bugs.gnewsense.org/Bugs', 'gNewSense', 'wikiforms')
registerBugtracker('supybot', 'http://sourceforge.net/tracker/?group_id=58965&atid=489447', 'Supybot', 'sourceforge')
registerBugtracker('mantis', "http://www.mantisbt.org/bugs", "Mantis", 'mantis')
registerBugtracker('ubottu', 'https://launchpad.net' 'Ubottu', 'launchpad')
# Don't delete this one
registerBugtracker('sourceforge', 'http://sourceforge.net/tracker/', 'Sourceforge', 'sourceforge')
Class = Bugtracker