07ddcd09a6290c2eb35dff4195974b5265a115ee
[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()
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 >= 1:
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.rev, exclude_revs=set([old.rev])):
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     """ % {"tree": tree, "host": host, "compiler": compiler, "change_log": change_log, "scm": t.scm, "branch": t.branch,
73             "cur_rev": cur_rev, "old_rev": old_rev, "cur_status": cur_status, "old_status": old_status }
74
75     msg = MIMEText(body)
76     msg["Subject"] = "BUILD of %s:%s BROKEN on %s with %s AT REVISION %s" % (tree, t.branch, host, compiler, cur_rev)
77     msg["From"] = "\"Build Farm\" <build@samba.org>"
78     msg["To"] = ",".join(recipients.keys())
79     if not opts.dry_run:
80         smtp.send(msg["From"], [msg["To"]], msg.as_string())
81     else:
82         print msg.as_string()
83
84
85 for build in buildfarm.get_new_builds():
86     if opts.verbose >= 1:
87         print "Processing %s..." % build,
88
89     if not opts.dry_run:
90         buildfarm.builds.upload_build(build)
91
92     (rev, rev_timestamp) = build.revision_details()
93
94     if opts.verbose >= 1:
95         print str(build.status())
96
97     try:
98         if opts.dry_run:
99             # Perhaps this is a dry run and rev is not in the database yet?
100             prev_rev = buildfarm.builds.get_latest_revision(build.tree, build.host, build.compiler)
101         else:
102             prev_rev = buildfarm.builds.get_previous_revision(build.tree, build.host, build.compiler, rev)
103     except data.NoSuchBuildError:
104         if opts.verbose >= 1:
105             print "Unable to find previous build for %s,%s,%s" % (build.tree, build.host, build.compiler)
106         # Can't send a nastygram until there are 2 builds..
107         continue
108     else:
109         prev_build = buildfarm.get_build(build.tree, build.host, build.compiler, prev_rev)
110         check_and_send_mails(build.tree, build.host, build.compiler, build, prev_build)
111
112     if not opts.dry_run:
113         build.remove()
114         buildfarm.commit()
115
116 smtp.quit()