Logo Search packages:      
Sourcecode: ubuntu-qa-tools version File versions  Download package

ml-fixes-report.py

#!/usr/bin/env python2.5
#
# This script will parse a -changes mbox to find
# Launchpad-Bugs-Fixed and Changed-By information
# to identify who fixed a bug task with an upload.
# Then the Launchpad API is used to determine the
# date the bug task was created and fix released
# and the number of days to fix it is calculated.
# This data is then put into a shiny report.
#
# Example usage:
# ml-fixes-report.py jaunty-changes.mbox
#
# Copyright 2009 Canonical, Ltd
# Author: Brian Murray <brian@ubuntu.com>
# Licensed under the GNU General Public License, version 3.

from mailbox import PortableUnixMailbox
from email import message_from_file
from email.errors import MessageParseError
from email.utils import parseaddr
from email.utils import getaddresses
from sys import argv, stderr
from operator import itemgetter
from datetime import *
import os

# launchpadlib bits
from launchpadlib.launchpad import Launchpad, EDGE_SERVICE_ROOT, STAGING_SERVICE_ROOT
from launchpadlib.errors import HTTPError
from launchpadlib.credentials import Credentials

MESSAGE_NOT_PARSEABLE = object()

def message_factory(fp):
    try:
        return message_from_file(fp)
    except MessageParseError:
        # Don't return None since that will stop the mailbox iterator.
        return MESSAGE_NOT_PARSEABLE


def show_progress(iterator, interval=100):
    """Show signs of progress."""
    for count, item in enumerate(iterator):
        if count % interval == 0:
            stderr.write('.')
        yield item


def scan_bugs(messages):
    bug_numbers = []
    for count, message in enumerate(messages):
        # Skip broken messages.
        if message is MESSAGE_NOT_PARSEABLE:
            continue

        for part in message.walk():
            if not part.is_multipart():
                for line in part.get_payload(decode=True).splitlines():
                    if line.startswith('Source: '):
                        sourcepackage = line[8:].split()[0]
                    if line.startswith('Distribution: '):
                        distribution = line[14:].split()[0]
                    if line.startswith('Changed-By: '):
                        fixer = line[12:].split()[-1].strip('<>')
                    if line.startswith('Launchpad-Bugs-Fixed: '):
                        if distribution == '%s' % release:
                            for bug_number in line[22:].split():
                                if bug_number in bug_numbers:
                                    continue
                                try:
                                    task = launchpad.load('https://api.edge.launchpad.net/beta/ubuntu/+source/%s/+bug/%s' % ( sourcepackage, bug_number ))
                                    bug = launchpad.bugs[bug_number]
                                except HTTPError, error:
                                    print "There was an error with LP: #%s: %s" % (bug_number, error)
                                try:
                                    if [tag for tag in bug.tags if 'regression-' in tag]:
                                # change the class to highlight for any bug that has a regression- tag in it
                                        table_row = '<tr class="highlight">'
                                    else:
                                        table_row = "<tr>"
                                    table_row += "<td>%s</td>" % bug.id
                                    table_row += "<td><a href='http://launchpad.net/bugs/%s'>%s</a></td>" % (bug.id, bug.title.encode('utf-8'))
                                    # maybe assignee should be a link to the person's launchpad page
                                    table_row += "<td>%s</td>" % sourcepackage
                                    table_row += "<td>%s</td>" % fixer
                                    if task.date_created:
                                        #table_row += "<td>%s</td>" % task.date_created[:10].encode('utf-8')
                                        table_row += "<td>%s</td>" % task.date_created.strftime("%Y-%m-%d")
                                        #date_created = task.date_created[:10]
                                    else:
                                        #table_row += "<td>ERROR</td>"
                                        print "LP: #%s has no date created" % (bug_number)
                                        continue
                                    if task.date_fix_released and task.date_fix_released.strftime('%Y-%m-%d') > '2008-11-01':
                                    #if task.date_fix_released and task.date_fix_released[:10] > '2008-11-01':
                                    #    table_row += "<td>%s</td>" % task.date_fix_released[:10].encode('utf-8')
                                        table_row += "<td>%s</td>" % task.date_fix_released.strftime("%Y-%m-%d")
                                        #date_fixed = task.date_fix_released[:10]
                                    else:
                                        # using Missing horks sorting by days_to_fix
                                        #table_row += "<td>Missing</td>"
                                        print "LP: #%s has no date fix released" % (bug_number)
                                        continue
                                    if task.date_created and task.date_fix_released:
                                        #days_to_fix = datetime.strptime(task.date_fix_released[:10], '%Y-%m-%d') - datetime.strptime(task.date_created[:10], '%Y-%m-%d')
                                        days_to_fix = task.date_fix_released - task.date_created
                                        table_row += "<td>%s</td>" % days_to_fix.days
                                    #else:
                                        #table_row += "<td>Unknown</td>"
                                    table_row += "</tr>"
                                    table_row += "\n"
                                    datafile.write(table_row)
                                    # only count rows that show up on the report not hokey ones
                                    counts['total'] = counts.setdefault('total', 0) + 1
                                    counts[fixer] = counts.setdefault(fixer, 0) + 1
                                except HTTPError, error:
                                    print "There was an error with bug LP: #%s: %s" % (bug_number, error.content)
                                bug_numbers.append(bug_number)
                        
                            #task = launchpad.load('https://api.edge.launchpad.net/beta/ubuntu/+source/%s/+bug/%s' % ( sourcepackage, bug ))
                            #print "LP: #%s %s task was fixed by %s in %s" % ( bug, sourcepackage, fixer, distribution )
                            #if task.date_created is None and task.date_fix_released is None:
                                #print "\tProbable incorrect bug number in changelog!"
                            #else:
                                #print "\tIt was reported on %s and fixed on %s" % ( task.date_created, task.date_fix_released )
                    

if __name__ == '__main__':

    # Check if the amount of arguments is correct
    if len(argv) < 2 or argv[1] in ('help', '-h', '--help'):
        print 'Usage: %s <bug_mailinglist_file> [<bug_mailinglist_file> ...]' % argv[0]
        exit(1)

    cachedir = os.path.expanduser("~/.launchpadlib/cache/")
    
    if not os.path.exists(cachedir):
        os.makedirs(cachedir,0700)
    
    script_name = argv[0].split("/")[-1].split('.')[0]
    
    credfile = os.path.expanduser('~/.launchpadlib/%s.cred' % script_name)
    
    try:
        credentials = Credentials()
        credentials.load(open(credfile))
        launchpad = Launchpad(credentials, EDGE_SERVICE_ROOT, cachedir)
    except:
        launchpad = Launchpad.get_token_and_login(script_name, EDGE_SERVICE_ROOT, cachedir)
        launchpad.credentials.save(open(credfile,"w",0600))    

    for mailbox_file in argv[1:]:
        mailbox = PortableUnixMailbox(
            open(mailbox_file, 'rb'), message_factory)

        release = argv[1].split('-')[0]

        datafile = open("%s-fixes-report.html" % release, 'w')

        counts = {}

        templatefile = open('template.html', 'r')

        for line in templatefile:
            if line.strip() == "<!-- *** Title Space *** -->":
                datafile.write("Bugs fixed during the %s release cycle\n" % release.capitalize())
            elif line.strip() == "<!-- *** Header Space *** -->":
                datafile.write("Bugs fixed during the %s release cycle\n" % release.capitalize())
            elif line.strip() == "<!-- *** Paragraph Space *** -->":
                datafile.write("This is a report of bug tasks from Launchpad-Bugs-Fixed in the %s changes mailing list.  All of the columns are sortable; give them a click!  However, it might take a bit as the table is quite long.\n" % release.capitalize())
            elif line.strip() == "<!-- *** Table Header Space *** -->":
                table_header = "<th></th>"  # bug number in this column
                table_header += "<th>Summary</th>"
                table_header += "<th>In</th>"
        #        table_header += "<th>Importance</th>"
        #        table_header += "<th>Status</th>"
                table_header += "<th>Fixer</th>"
                table_header += "<th>Date Created</th>"
                table_header += "<th>Date Fixed</th>"
                table_header += "<th>Days to Fix</th>"
                table_header += "\n"
                datafile.write(table_header)
            elif line.strip() == "<!-- *** Table Body Space *** -->":
                scan_bugs(mailbox)
            elif line.strip() == "<!-- *** Last Paragraph Space *** -->":
                datafile.write("A total of %s bug tasks were fixed during %s!<br><br>" % (counts['total'], release.capitalize()) )
                for k,v in sorted(counts.items(), key=itemgetter(1), reverse=True):
                    if k == 'total':
                        continue
                    if counts[k] == 1:
                        datafile.write("\n%s has %s fix<br>" % (k, counts[k]))
                    else:
                        datafile.write("\n%s has %s fixes<br>" % (k, counts[k]))
            else:
                datafile.write(line)
        datafile.close()

Generated by  Doxygen 1.6.0   Back to index