#!/usr/bin/env python """ A script for reporting the results of an invirtibuild. Supports any combination of the following reporting mechanisms. Note that all strings are interpolated with a dictionary containing the following keys: build_id, commit, failed_stage, inserted_at, package, pocket, principal, result, short_commit, traceback, version == zephyr == To configure zephyr, add something like the following to your invirt config: build: hooks: post_build: zephyr: &post_build_zepyhr class: myclass [required] instance: myinstance [optional] zsig: myzsig [optional] failed_build: zephyr: *post_build_zephyr == mail == To configure email notifications, add something like the following to your invirt config: build: hooks: post_build: mail: &post_build_mail to: myemail@example.com [required] from: myemail@example.com [required] subject: My Subject [optional] failed_build: mail: *post_build_mail post_build values will be used when this script is invoked as post-build, while failed_build values will be used when it is invoked as failed-build. """ import optparse import os import re import sys import textwrap from email.mime import text from invirt import common, database, builder from invirt.config import structs as config def make_msg(build, values, verbose=True, success=lambda x: x, failure=lambda x: x): values = dict(values) if not verbose and values['traceback'] is not None: # TODO: better heuristic values['traceback'] = textwrap.fill('\n'.join(values['traceback'].split('\n')[-2:])) if build.succeeded: values['result'] = success(values['result']) msg = """Build of %(package)s %(version)s in %(pocket)s %(result)s. Branch %(pocket)s has been advanced to %(short_commit)s. (Build %(build_id)s was submitted by %(principal)s at %(inserted_at)s.)""" % values else: values['result'] = failure(values['result']) msg = """Build of %(package)s %(version)s in %(pocket)s %(result)s while %(failed_stage)s. %(traceback)s (Build %(build_id)s was submitted by %(principal)s at %(inserted_at)s.)""" % values return msg def zephyr_escape(m): m = re.sub('@', '@@', m) m = re.sub('}', '@(})', m) return m def zephyr_success(m): return '}@{@color(green)%s}@{' % zephyr_escape(m) def zephyr_failure(m): return '}@{@color(red)%s}@{' % zephyr_escape(m) def main(): parser = optparse.OptionParser('Usage: %prog build_id') opts, args = parser.parse_args() if len(args) != 1: parser.print_help() return 1 prog = os.path.basename(sys.argv[0]) database.connect() build = database.Build.query().get(args[0]) short_commit = builder.canonicalize_commit(build.package, build.commit, shorten=True) values = { 'build_id' : build.build_id, 'commit' : build.commit, 'failed_stage' : build.failed_stage, 'inserted_at' : build.inserted_at, 'package' : build.package, 'pocket' : build.pocket, 'principal' : build.principal, 'short_commit' : short_commit, 'traceback' : build.traceback, 'version' : build.version } if build.succeeded: values['result'] = 'succeeded' else: values['result'] = 'failed' try: if prog == 'post-build': hook_config = config.build.hooks.post_build elif prog == 'failed-build': hook_config = config.build.hooks.failed_build else: print >>sys.stderr, '{post,failed}-build invoke with unrecognized name %s' % prog return 2 except common.InvirtConfigError: print >>sys.stderr, 'No hook configuration found for %s.' % prog return 1 try: zephyr_config = hook_config.zephyr klass = zephyr_config['class'] % values except common.InvirtConfigError: print >>sys.stderr, 'No zephyr configuration specified for %s.' % prog else: msg = '@{%s}' % make_msg(build, values, verbose=False, success=zephyr_success, failure=zephyr_failure) instance = zephyr_config.get('instance', 'build_%(build_id)s') % values zsig = zephyr_config.get('zsig', 'XVM Buildbot') % values common.captureOutput(['zwrite', '-c', klass, '-i', instance, '-s', zsig, '-d', '-m', msg], stdout=None, stderr=None) try: mail_config = hook_config.mail to = mail_config.to % values sender = mail_config['from'] % values except common.InvirtConfigError: print >>sys.stderr, 'No email configuration specified for %s.' % prog else: msg = make_msg(build, values) email = text.MIMEText(msg) email['To'] = to % values email['From'] = sender % values email['Subject'] = mail_config.get('subject', 'XVM build %(result)s: %(package)s %(version)s in %(pocket)s') % values common.captureOutput(['sendmail', '-t'], email.as_string(), stdout=None, stderr=None) if __name__ == '__main__': sys.exit(main())