source: trunk/packages/invirt-dev/build-hooks/post-build @ 3036

Last change on this file since 3036 was 3036, checked in by gdb, 14 years ago

Added reporting

  • Property svn:executable set to *
File size: 5.0 KB
Line 
1#!/usr/bin/env python
2"""
3A script for reporting the results of an invirtibuild.  Supports any
4combination of the following reporting mechanisms.
5
6Note that all strings are interpolated with a dictionary containing
7the following keys:
8
9build_id, commit, failed_stage, inserted_at, package,
10pocket, principal, result, short_commit, traceback, version
11
12== zephyr ==
13
14To configure zephyr, add something like the following to your invirt config:
15
16build:
17 hooks:
18  post_build:
19   zephyr: &post_build_zepyhr
20    class: myclass [required]
21    instance: myinstance [optional]
22    zsig: myzsig [optional]
23  failed_build:
24   zephyr: *post_build_zephyr
25
26== mail ==
27
28To configure email notifications, add something like the following to your invirt config:
29
30build:
31 hooks:
32  post_build:
33   mail: &post_build_mail
34    to: myemail@example.com [required]
35    from: myemail@example.com [required]
36    subject: My Subject [optional]
37  failed_build:
38   mail: *post_build_mail
39
40post_build values will be used when this script is invoked as
41post-build, while failed_build values will be used when it is invoked
42as failed-build.
43"""
44
45import optparse
46import os
47import re
48import sys
49import textwrap
50
51from email.mime import text
52
53from invirt import common, database, builder
54from invirt.config import structs as config
55
56def make_msg(build, values, verbose=True, success=lambda x: x, failure=lambda x: x):
57    values = dict(values)
58    if not verbose and values['traceback'] is not None:
59        values['traceback'] = textwrap.fill('\n'.join(values['traceback'].split('\n')[-2:]))
60
61    if build.succeeded:
62        values['result'] = success(values['result'])
63        msg = """Build of %(package)s v%(version)s in %(pocket)s %(result)s.
64
65Branch %(pocket)s has been advanced to %(short_commit)s.
66
67(Build %(build_id)s was submitted by %(principal)s at %(inserted_at)s.)""" % values
68    else:
69        values['result'] = failure(values['result'])
70        msg = """Build of %(package)s v%(version)s in %(pocket)s %(result)s while %(failed_stage)s.
71
72%(traceback)s
73
74(Build %(build_id)s was submitted by %(principal)s at %(inserted_at)s.)""" % values
75    return msg
76
77def zephyr_escape(m):
78    m = re.sub('@', '@@', m)
79    m = re.sub('}', '@(})', m)
80    return m
81
82def zephyr_success(m):
83    return '}@{@color(green)%s}@{' % zephyr_escape(m)
84
85def zephyr_failure(m):
86    return '}@{@color(red)%s}@{' % zephyr_escape(m)
87
88def main():
89    parser = optparse.OptionParser('Usage: %prog build_id')
90    opts, args = parser.parse_args()
91    if len(args) != 1:
92        parser.print_help()
93        return 1
94    prog = os.path.basename(sys.argv[0])
95
96    database.connect()
97    build = database.Build.query().get(args[0])
98    short_commit = builder.canonicalize_commit(build.package, build.commit, shorten=True)
99    values = { 'build_id' : build.build_id,
100               'commit' : build.commit,
101               'failed_stage' : build.failed_stage,
102               'inserted_at' : build.inserted_at,
103               'package' : build.package,
104               'pocket' : build.pocket,
105               'principal' : build.principal,
106               'short_commit' : short_commit,
107               'traceback' : build.traceback,
108               'version' : build.version }
109    if build.succeeded:
110        values['result'] = 'succeeded'
111    else:
112        values['result'] = 'failed'
113
114    try:
115        if prog == 'post-build':
116            hook_config = config.build.hooks.post_build
117        elif prog == 'failed-build':
118            hook_config = config.build.hooks.failed_build
119        else:
120            print >>sys.stderr, '{post,failed}-build invoke with unrecognized name %s' % prog
121            return 2
122    except common.InvirtConfigError:
123        print >>sys.stderr, 'No hook configuration found for %s.' % prog
124        return 1
125
126    try:
127        zephyr_config = hook_config.zephyr
128        klass = zephyr_config['class'] % values
129    except common.InvirtConfigError:
130        print >>sys.stderr, 'No zephyr configuration specified for %s.' % prog
131    else:
132        msg = '@{%s}' % make_msg(build, values, verbose=False,
133                                 success=zephyr_success, failure=zephyr_failure)
134        instance = zephyr_config.get('instance', 'build_%(build_id)s') % values
135        zsig = zephyr_config.get('zsig', 'XVM Buildbot') % values
136        common.captureOutput(['zwrite', '-c', klass, '-i', instance, '-s',
137                              zsig, '-d', '-m', msg],
138                             stdout=None, stderr=None)
139
140    try:
141        mail_config = hook_config.mail
142        to = mail_config.to % values
143        sender = mail_config['from'] % values
144    except common.InvirtConfigError:
145        print >>sys.stderr, 'No email configuration specified for %s.' % prog
146    else:
147        msg = make_msg(build, values)
148        email = text.MIMEText(msg)
149        email['To'] = to % values
150        email['From'] = sender % values
151        email['Subject'] = mail_config.get('subject', 'XVM build %(build_id)s has %(result)s') % values
152        common.captureOutput(['sendmail', '-t'], email.as_string(),
153                             stdout=None, stderr=None)
154       
155if __name__ == '__main__':
156    sys.exit(main())
Note: See TracBrowser for help on using the repository browser.