launchpad-dev team mailing list archive
-
launchpad-dev team
-
Mailing list archive
-
Message #06711
Hacky script to get critical bug breakdown for Launchpad
Hello Launchpadders,
I've attached a hacky script that gets the by-project breakdown of
critical bugs on launchpad-project.
Probably mostly useful for whoever is chairing the team lead meeting
and needs a quick way to get the data, as well as folk currently in
maintenance squads.
Current output:
$ python critical-bugs.py
launchpad 238
loggerhead 10
launchpad-buildd 2
lazr.delegates 1
lazr.restful 1
oops-tools 1
qa-tagger 1
Total: 254 (+34, -30 since 2011-03-09)
cheers,
jml
PS. Although the number of critical bugs has increased, that's because
we've been making great progress in reporting critical bugs that are
already there. i.e. it's an increase in reports, not defects. We're
making great progress in actually *fixing* the defects.
PPS. If you want to improve the script, please find a home for it &
share it with the list.
from datetime import datetime, timedelta, tzinfo
from operator import attrgetter
import os
import re
from StringIO import StringIO
from launchpadlib.launchpad import Launchpad
from launchpadlib import uris
CACHE_DIR = os.path.expanduser('~/.launchpadlib/cache')
SERVICE_ROOT = uris.LPNET_SERVICE_ROOT
CRITICAL = u'Critical'
CLOSED_STATUSES = [
u"Invalid",
u"Opinion",
u"Expired",
u"Won't Fix",
u'Fix Released',
]
OPEN_STATUSES = [
u"New",
u"Incomplete",
u"Confirmed",
u"Triaged",
u"In Progress",
u"Fix Committed"]
ALL_STATUSES = OPEN_STATUSES + CLOSED_STATUSES
_title_re = re.compile(r'^.*: "(.*)"$')
class BugTask(object):
def __init__(self, lp_task):
self._lp_task = lp_task
self.title = _title_re.match(lp_task.title).group(1)
def __repr__(self):
return '<BugTask %s/%s>' % (self.bug_id, self.target_name)
def __str__(self):
return '#%s: %s <%s:%s>' % (
self.bug_id,
self.title,
self.target_name,
self._lp_task.status,
)
@property
def bug_id(self):
return int(self._lp_task.bug_link.split('/')[-1])
@property
def date_created(self):
return self._lp_task.date_created
@property
def target_name(self):
return self._lp_task.bug_target_name
def as_dict(self):
return self._lp_task._wadl_resource.representation
class _UTC(tzinfo):
"""UTC"""
def utcoffset(self, dt):
return timedelta(0)
def tzname(self, dt):
return "UTC"
def dst(self, dt):
return timedelta(0)
UTC = _UTC()
def get_bug_stats(project, since):
open_tasks = map(
BugTask,
project.searchTasks(
importance=CRITICAL,
status=OPEN_STATUSES,
))
new_tasks = [t for t in open_tasks if t.date_created >= since]
closed_tasks = [
BugTask(t) for t in project.searchTasks(
importance=CRITICAL,
status=CLOSED_STATUSES,
modified_since=since,
)
if t.date_closed >= since]
return open_tasks, new_tasks, closed_tasks
def groupby(sequence, key):
output = {}
for thing in sequence:
k = key(thing)
if k in output:
output[k].append(thing)
else:
output[k] = [thing]
return output
def per_target(tasks):
by_target = groupby(tasks, attrgetter('target_name')).items()
return sorted(by_target, key=lambda (x, y): (-len(y), x))
def format_table(table):
table = [map(str, row) for row in table]
widths = [max([len(cell) for cell in column]) for column in zip(*table)]
output = StringIO()
for row in table:
for column, cell in enumerate(row):
width = widths[column] + 1
try:
float(cell)
except ValueError:
output.write(cell.ljust(width))
else:
output.write(cell.rjust(width))
output.write('\n')
return output.getvalue()
def main(args):
launchpad = Launchpad.login_anonymously(
'jml-crit-bug', SERVICE_ROOT, CACHE_DIR)
lpp = launchpad.projects['launchpad-project']
last_week = (datetime.now() - timedelta(days=7)).replace(tzinfo=UTC)
open_tasks, new_tasks, closed_tasks = get_bug_stats(lpp, last_week)
by_target = per_target(open_tasks)
target_counts = [(target, len(tasks)) for target, tasks in by_target]
print format_table(target_counts)
print 'Total: %s (+%s, -%s since %s)' % (
len(open_tasks), len(new_tasks), len(closed_tasks), last_week.date())
if __name__ == '__main__':
main([])
Follow ups