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