import os import sys import urllib import csv import re import smtplib import subprocess import htmllib import formatter from optparse import make_option import StringIO from jhbuild.commands import Command, register_command import jhbuild.moduleset def _get_ticket_uri(number): return 'http://dev.laptop.org/ticket/' + number def _send_mail(sender, from_address, to_address, subject, text): msg = 'From: %s<%s>\nTo: %s\nSubject: %s\n%s' % \ (sender, from_address, to_address, subject, text) server = smtplib.SMTP('localhost') server.sendmail(from_address, to_address, msg) server.quit() class TextWriter(object): def __init__(self, out): self.out = out def write_headline(self, headline): self.out.write('= ' + headline + ' =\n\n') def write_tickets(self, tickets, compact=False): for ticket in tickets: number = ticket['number'] summary = ticket['summary'] if compact: self.out.write('* #%s %s\n' % (number, summary)) else: self.out.write(summary + '\n') self.out.write(_get_ticket_uri(number) + '\n\n') if compact: self.out.write('\n') def write_testcases(self, testcases): for number, testcase in testcases: self.out.write('#%s\n\n%s\n\n\n' % (number, testcase)) class ReleaseReport(object): def __init__(self, config, release): module, self._version = release.rsplit('-', 1) module_set = jhbuild.moduleset.load(config) self._module = module_set.modules[module] self._config = config self._tickets = [] self._testcases = [] def generate(self): cwd = os.getcwd() os.chdir(self._module.get_srcdir(self._config)) p = subprocess.Popen(['git', 'tag'], stdout=subprocess.PIPE) tags = p.stdout.read().split('\n') tags = [ tag for tag in tags if tag.startswith('v') ] release_tag = 'v' + self._version try: i = tags.index(release_tag) except ValueError: print 'The tag you provided does not exist.' return if i > 0: previous = tags[i - 1] interval = previous + '..' + release_tag else: interval = release_tag p = subprocess.Popen(['git', 'log', interval, '--pretty=format:%an|||%s'], stdout=subprocess.PIPE) commits = p.stdout.read().split('\n') tickets = [] for row in commits: author, subject = row.split('|||') match = re.search("\#([0-9]*)", subject) if match: tickets.append(match.group(1)) for n in tickets: f = urllib.urlopen('http://dev.laptop.org/ticket/%s?format=csv' % n) reader = csv.DictReader(f) row = reader.next() ticket = { 'number' : row['id'], 'summary' : row['summary'] } self._tickets.append(ticket) f.close() url = 'http://dev.laptop.org/ticket/%s?format=rss' % n import feedparser parser = feedparser.parse(url) for entry in parser.entries: out = StringIO.StringIO() writer = formatter.DumbWriter(out) form = formatter.AbstractFormatter(writer) html_parser = htmllib.HTMLParser(form) html_parser.feed(entry['summary_detail']['value']) html_parser.close() comment = out.getvalue().strip() out.close() marker = '|testcase|' i = comment.lower().find(marker) if i >= 0: i += len(marker) self._testcases.append([n, comment[i:].strip()]) os.chdir(cwd) def write(self, writer): writer.write_headline('Closed tickets') writer.write_tickets(self._tickets, compact=True) if self._testcases: writer.write_headline('Testcases') writer.write_testcases(self._testcases) def save(self): pass class ReviewsReport(object): def __init__(self, config): self._requested = {} self._approved = {} self._rejected = {} self._state_path = os.path.join(config.get_user_path(), 'reviews') def generate(self): f = urllib.urlopen('http://dev.laptop.org/query?' \ 'format=csv&' \ 'component=sugar&' \ 'component=datastore&' \ 'component=presence-service&' \ 'component=journal-activity&' \ 'col=id&col=summary&col=keywords&' \ 'keywords=~r%2B&keywords=~r-&keywords=~r%3F') reader = csv.reader(f) reader.next() for row in reader: number = row[0] keyword = row[2] ticket = { 'number' : row[0], 'summary' : row[1] } if 'r?' in keyword: ticket['review_state'] = 'r?' self._requested[number] = ticket if 'r+' in keyword: ticket['review_state'] = 'r+' self._approved[number] = ticket if 'r-' in keyword: ticket['review_state'] = 'r-' self._rejected[number] = ticket f.close() def write(self, writer): old_requested, old_approved, old_rejected = self._load() requested = self._diff_tickets(old_requested, self._requested) approved = self._diff_tickets(old_approved, self._approved) rejected = self._diff_tickets(old_rejected, self._rejected) if requested: writer.write_headline('New requests') writer.write_tickets(requested) if approved: writer.write_headline('Approved requests') writer.write_tickets(approved) if rejected: writer.write_headline('Rejected requests') writer.write_tickets(rejected) def save(self): s = json.write([self._requested, self._approved, self._rejected]) f = open(os.path.join(self._state_path), 'w') f.write(s) f.close() def _load(self): path = os.path.join(self._state_path) if os.path.exists(path): f = open(path, 'r') result = json.read(f.read()) f.close() return result else: return ({}, {}, {}) def _diff_tickets(self, old, new): diff = [] for number, ticket in new.items(): if number in old: old_ticket = old[number] if old_ticket['review_state'] != ticket['review_state']: diff.append(ticket) else: diff.append(ticket) return diff class cmd_report(Command): name = 'report' usage_args = '' def __init__(self): Command.__init__(self, [ make_option('-t', '--type', action='store', dest='type', default=None, help='specify the report type'), make_option('-s', '--sendto', action='append', dest='sendto', default=None, help='send report to the specified mail address') ]) def run(self, config, options, args): report_types = [ 'reviews', 'release' ] if options.type not in report_types: print 'Available reports:\n' + '\n'.join(report_types) return 1 if options.type == 'reviews': report = ReviewsReport(config) elif options.type == 'release': if args: report = ReleaseReport(config, args[0]) else: print 'Please provide a module name.' return 1 report.generate() out = StringIO.StringIO() report.write(TextWriter(out)) text = out.getvalue() out.close() if options.sendto: if text: print 'Sending to ' + ', '.join(options.sendto) for to_address in options.sendto: _send_mail('Release Team', 'mpgritti@gmail.com', to_address, 'Reviews report', text) else: print 'Empty report, do not send' else: print text report.save() try: import json register_command(cmd_report) except ImportError: print 'Disable report, json-py is not installed.'