Cope with unknown hosts in dead host list.
[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, "host": host, "compiler": compiler,
74         "change_log": change_log,
75         "scm": t.scm,
76         "branch": t.branch,
77         "cur_rev": cur_rev,
78         "old_rev": old_rev,
79         "cur_status": cur_status,
80         "old_status": old_status,
81         }
82
83     msg = MIMEText(body)
84     msg["Subject"] = "BUILD of %s:%s BROKEN on %s with %s AT REVISION %s" % (tree, t.branch, host, compiler, cur_rev)
85     msg["From"] = "\"Build Farm\" <build@samba.org>"
86     msg["To"] = ",".join(recipients)
87     if not opts.dry_run:
88         smtp.sendmail(msg["From"], [msg["To"]], msg.as_string())
89     else:
90         print msg.as_string()
91
92
93 for build in buildfarm.get_new_builds():
94     if build in buildfarm.builds:
95         continue
96
97     if not opts.dry_run:
98         try:
99             build = buildfarm.builds.upload_build(build)
100         except data.MissingRevisionInfo:
101             print "No revision info in %r, skipping" % build
102             continue
103
104     try:
105         (rev, rev_timestamp) = build.revision_details()
106     except data.MissingRevisionInfo:
107         print "No revision info in %r, skipping" % build
108         continue
109
110     if opts.verbose >= 2:
111         print "%s... " % build,
112         print str(build.status())
113
114     try:
115         if opts.dry_run:
116             # Perhaps this is a dry run and rev is not in the database yet?
117             prev_rev = buildfarm.builds.get_latest_revision(build.tree, build.host, build.compiler)
118         else:
119             prev_rev = buildfarm.builds.get_previous_revision(build.tree, build.host, build.compiler, rev)
120     except data.NoSuchBuildError:
121         if opts.verbose >= 1:
122             print "Unable to find previous build for %s,%s,%s" % (build.tree, build.host, build.compiler)
123         # Can't send a nastygram until there are 2 builds..
124     else:
125         try:
126             assert prev_rev is not None
127             prev_build = buildfarm.builds.get_build(build.tree, build.host, build.compiler, prev_rev)
128         except data.NoSuchBuildError:
129             if opts.verbose >= 1:
130                 print "Previous build %s has disappeared" % prev_build
131         else:
132             check_and_send_mails(build.tree, build.host, build.compiler, build, prev_build)
133
134     if not opts.dry_run:
135         # When the new web script is introduced, kill the build here:
136         # build.remove()
137         buildfarm.commit()
138
139 smtp.quit()