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

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

Added a TODO item

  • Property svn:executable set to *
File size: 5.1 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        # TODO: better heuristic
60        values['traceback'] = textwrap.fill('\n'.join(values['traceback'].split('\n')[-2:]))
61
62    if build.succeeded:
63        values['result'] = success(values['result'])
64        msg = """Build of %(package)s v%(version)s in %(pocket)s %(result)s.
65
66Branch %(pocket)s has been advanced to %(short_commit)s.
67
68(Build %(build_id)s was submitted by %(principal)s at %(inserted_at)s.)""" % values
69    else:
70        values['result'] = failure(values['result'])
71        msg = """Build of %(package)s v%(version)s in %(pocket)s %(result)s while %(failed_stage)s.
72
73%(traceback)s
74
75(Build %(build_id)s was submitted by %(principal)s at %(inserted_at)s.)""" % values
76    return msg
77
78def zephyr_escape(m):
79    m = re.sub('@', '@@', m)
80    m = re.sub('}', '@(})', m)
81    return m
82
83def zephyr_success(m):
84    return '}@{@color(green)%s}@{' % zephyr_escape(m)
85
86def zephyr_failure(m):
87    return '}@{@color(red)%s}@{' % zephyr_escape(m)
88
89def main():
90    parser = optparse.OptionParser('Usage: %prog build_id')
91    opts, args = parser.parse_args()
92    if len(args) != 1:
93        parser.print_help()
94        return 1
95    prog = os.path.basename(sys.argv[0])
96
97    database.connect()
98    build = database.Build.query().get(args[0])
99    short_commit = builder.canonicalize_commit(build.package, build.commit, shorten=True)
100    values = { 'build_id' : build.build_id,
101               'commit' : build.commit,
102               'failed_stage' : build.failed_stage,
103               'inserted_at' : build.inserted_at,
104               'package' : build.package,
105               'pocket' : build.pocket,
106               'principal' : build.principal,
107               'short_commit' : short_commit,
108               'traceback' : build.traceback,
109               'version' : build.version }
110    if build.succeeded:
111        values['result'] = 'succeeded'
112    else:
113        values['result'] = 'failed'
114
115    try:
116        if prog == 'post-build':
117            hook_config = config.build.hooks.post_build
118        elif prog == 'failed-build':
119            hook_config = config.build.hooks.failed_build
120        else:
121            print >>sys.stderr, '{post,failed}-build invoke with unrecognized name %s' % prog
122            return 2
123    except common.InvirtConfigError:
124        print >>sys.stderr, 'No hook configuration found for %s.' % prog
125        return 1
126
127    try:
128        zephyr_config = hook_config.zephyr
129        klass = zephyr_config['class'] % values
130    except common.InvirtConfigError:
131        print >>sys.stderr, 'No zephyr configuration specified for %s.' % prog
132    else:
133        msg = '@{%s}' % make_msg(build, values, verbose=False,
134                                 success=zephyr_success, failure=zephyr_failure)
135        instance = zephyr_config.get('instance', 'build_%(build_id)s') % values
136        zsig = zephyr_config.get('zsig', 'XVM Buildbot') % values
137        common.captureOutput(['zwrite', '-c', klass, '-i', instance, '-s',
138                              zsig, '-d', '-m', msg],
139                             stdout=None, stderr=None)
140
141    try:
142        mail_config = hook_config.mail
143        to = mail_config.to % values
144        sender = mail_config['from'] % values
145    except common.InvirtConfigError:
146        print >>sys.stderr, 'No email configuration specified for %s.' % prog
147    else:
148        msg = make_msg(build, values)
149        email = text.MIMEText(msg)
150        email['To'] = to % values
151        email['From'] = sender % values
152        email['Subject'] = mail_config.get('subject', 'XVM build %(build_id)s has %(result)s') % values
153        common.captureOutput(['sendmail', '-t'], email.as_string(),
154                             stdout=None, stderr=None)
155       
156if __name__ == '__main__':
157    sys.exit(main())
Note: See TracBrowser for help on using the repository browser.