Fix exception handling when both python-pysqlite2 and sqlite3 are installed.
[amitay/build-farm.git] / import-and-analyse.py
1 #!/usr/bin/python
2 # Write sqlite entries for test reports in the build farm
3 # Copyright (C) 2007-2010 Jelmer Vernooij <jelmer@samba.org>
4 # Copyright (C) 2007-2010 Andrew Bartlett <abartlet@samba.org>
5 # Published under the GNU GPL
6
7 """Script to parse build farm log files from the data directory, import
8 them into the database, add links to the oldrevs/ directory and send
9 some mail chastising the possible culprits when the build fails, based
10 on recent commits.
11 """
12
13 from buildfarm import data
14 from buildfarm.sqldb import StormCachingBuildFarm
15 from email.mime.text import MIMEText
16 import logging
17 import optparse
18 import smtplib
19
20 parser = optparse.OptionParser("import-and-analyse [options]")
21 parser.add_option("--dry-run", help="Will cause the script to send output to stdout instead of to sendmail.", action="store_true")
22 parser.add_option("--verbose", help="Be verbose", action="count")
23
24 (opts, args) = parser.parse_args()
25
26 buildfarm = StormCachingBuildFarm(timeout=40.0)
27
28 smtp = smtplib.SMTP()
29 smtp.connect()
30
31 def check_and_send_mails(tree, host, compiler, cur, old):
32     t = buildfarm.trees[tree]
33
34     (cur_rev, cur_rev_timestamp) = cur.revision_details()
35     cur_status = cur.status()
36
37     (old_rev, old_rev_timestamp) = old.revision_details()
38     old_status = old.status()
39
40     if not cur_status.regressed_since(old_status):
41         if opts.verbose >= 3:
42             print "... hasn't regressed since %s: %s" % (old_rev, old_status)
43         return
44
45     recipients = set()
46     change_log = ""
47
48     for rev in t.get_branch().log(from_rev=cur.revision, exclude_revs=set([old.revision])):
49         recipients.add(rev.author)
50         recipients.add(rev.committer)
51         change_log += """
52 revision: %s
53 author: %s
54 committer: %s
55 message:
56     %s
57 """ % (rev.revision, rev.author, rev.committer, rev.message)
58
59     body = """
60 Broken build for tree %(tree)s on host %(host)s with compiler %(compiler)s
61
62 Tree %(tree)s is %(scm)s branch %(branch)s.
63
64 Build status for new revision %(cur_rev)s is %(cur_status)s
65 Build status for old revision %(old_rev)s was %(old_status)s
66
67 See http://build.samba.org/?function=View+Build;host=%(host)s;tree=%(tree)s;compiler=%(compiler)s
68
69 The build may have been broken by one of the following commits:
70
71 %(change_log)s
72     """ % {
73         "tree": tree.encode("utf-8"),
74         "host": host.encode("utf-8"),
75         "compiler": compiler.encode("utf-8"),
76         "change_log": change_log,
77         "scm": t.scm,
78         "branch": t.branch,
79         "cur_rev": cur_rev,
80         "old_rev": old_rev,
81         "cur_status": cur_status,
82         "old_status": old_status,
83         }
84
85     msg = MIMEText(body)
86     msg["Subject"] = "BUILD of %s:%s BROKEN on %s with %s AT REVISION %s" % (tree, t.branch, host, compiler, cur_rev)
87     msg["From"] = "\"Build Farm\" <build@samba.org>"
88     msg["To"] = ",".join(recipients)
89     if not opts.dry_run:
90         smtp.sendmail(msg["From"], [msg["To"]], msg.as_string())
91     else:
92         print msg.as_string()
93
94
95 for build in buildfarm.get_new_builds():
96     if build in buildfarm.builds:
97         continue
98
99     if not opts.dry_run:
100         try:
101             build = buildfarm.builds.upload_build(build)
102         except data.MissingRevisionInfo:
103             print "No revision info in %r, skipping" % build
104             continue
105
106     try:
107         (rev, rev_timestamp) = build.revision_details()
108     except data.MissingRevisionInfo:
109         print "No revision info in %r, skipping" % build
110         continue
111
112     if opts.verbose >= 2:
113         print "%s... " % build,
114         print str(build.status())
115
116     try:
117         if opts.dry_run:
118             # Perhaps this is a dry run and rev is not in the database yet?
119             prev_rev = buildfarm.builds.get_latest_revision(build.tree, build.host, build.compiler)
120         else:
121             prev_rev = buildfarm.builds.get_previous_revision(build.tree, build.host, build.compiler, rev)
122     except data.NoSuchBuildError:
123         if opts.verbose >= 1:
124             print "Unable to find previous build for %s,%s,%s" % (build.tree, build.host, build.compiler)
125         # Can't send a nastygram until there are 2 builds..
126     else:
127         try:
128             assert prev_rev is not None
129             prev_build = buildfarm.builds.get_build(build.tree, build.host, build.compiler, prev_rev)
130         except data.NoSuchBuildError:
131             if opts.verbose >= 1:
132                 print "Previous build %s has disappeared" % prev_build
133         else:
134             check_and_send_mails(build.tree, build.host, build.compiler, build, prev_build)
135
136     if not opts.dry_run:
137         # When the new web script is introduced, kill the build here:
138         # build.remove()
139         buildfarm.commit()
140
141 smtp.quit()