2 # run tests on all Samba subprojects and push to a git tree on success
3 # Copyright Andrew Tridgell 2010
4 # released under GNU GPL v3 or later
6 from subprocess
import call
, check_call
,Popen
, PIPE
7 import os
, tarfile
, sys
, time
8 from optparse
import OptionParser
11 from email
.mime
.text
import MIMEText
12 from email
.mime
.base
import MIMEBase
13 from email
.mime
.application
import MIMEApplication
14 from email
.mime
.multipart
import MIMEMultipart
15 from distutils
.sysconfig
import get_python_lib
18 # This speeds up testing remarkably.
19 os
.environ
['TDB_NO_FSYNC'] = '1'
32 "talloc" : "lib/talloc",
33 "replace" : "lib/replace",
34 "tevent" : "lib/tevent",
41 defaulttasks
= [ "ctdb", "samba", "samba-xc", "samba-ctdb", "samba-libs", "samba-static", "ldb", "tdb", "talloc", "replace", "tevent", "pidl" ]
43 samba_configure_params
= " --picky-developer ${PREFIX} ${EXTRA_PYTHON} --with-profiling-data"
45 samba_libs_envvars
= "PYTHONPATH=${PYTHON_PREFIX}/site-packages:$PYTHONPATH"
46 samba_libs_envvars
+= " PKG_CONFIG_PATH=$PKG_CONFIG_PATH:${PREFIX_DIR}/lib/pkgconfig"
47 samba_libs_envvars
+= " ADDITIONAL_CFLAGS='-Wmissing-prototypes'"
48 samba_libs_configure_base
= samba_libs_envvars
+ " ./configure --abi-check --enable-debug --picky-developer -C ${PREFIX} ${EXTRA_PYTHON}"
49 samba_libs_configure_libs
= samba_libs_configure_base
+ " --bundled-libraries=NONE"
50 samba_libs_configure_samba
= samba_libs_configure_base
+ " --bundled-libraries=!talloc,!pytalloc-util,!tdb,!pytdb,!ldb,!pyldb,!pyldb-util,!tevent,!pytevent"
52 if os
.environ
.get("AUTOBUILD_NO_EXTRA_PYTHON", "0") == "1":
55 extra_python
= "--extra-python=/usr/bin/python3"
58 "ctdb" : [ ("random-sleep", "../script/random-sleep.sh 60 600", "text/plain"),
59 ("configure", "./configure ${PREFIX}", "text/plain"),
60 ("make", "make all", "text/plain"),
61 ("install", "make install", "text/plain"),
62 ("test", "make autotest", "text/plain"),
63 ("check-clean-tree", "../script/clean-source-tree.sh", "text/plain"),
64 ("clean", "make clean", "text/plain") ],
66 # We have 'test' before 'install' because, 'test' should work without 'install'
67 "samba" : [ ("configure", "./configure.developer --with-selftest-prefix=./bin/ab" + samba_configure_params
, "text/plain"),
68 ("make", "make -j", "text/plain"),
69 ("test", "make test FAIL_IMMEDIATELY=1", "text/plain"),
70 ("install", "make install", "text/plain"),
71 ("check-clean-tree", "script/clean-source-tree.sh", "text/plain"),
72 ("clean", "make clean", "text/plain") ],
74 # Test cross-compile infrastructure
75 "samba-xc" : [ ("configure-native", "./configure.developer --with-selftest-prefix=./bin/ab" + samba_configure_params
, "text/plain"),
76 ("configure-cross-execute", "./configure.developer -b ./bin-xe --cross-compile --cross-execute=script/identity_cc.sh" \
77 " --cross-answers=./bin-xe/cross-answers.txt --with-selftest-prefix=./bin-xe/ab" + samba_configure_params
, "text/plain"),
78 ("configure-cross-answers", "./configure.developer -b ./bin-xa --cross-compile" \
79 " --cross-answers=./bin-xe/cross-answers.txt --with-selftest-prefix=./bin-xa/ab" + samba_configure_params
, "text/plain"),
80 ("compare-results", "script/compare_cc_results.py ./bin/c4che/default.cache.py ./bin-xe/c4che/default.cache.py ./bin-xa/c4che/default.cache.py", "text/plain")],
83 "samba-ctdb" : [ ("random-sleep", "script/random-sleep.sh 60 600", "text/plain"),
85 # make sure we have tdb around:
86 ("tdb-configure", "cd lib/tdb && PYTHONPATH=${PYTHON_PREFIX}/site-packages:$PYTHONPATH PKG_CONFIG_PATH=$PKG_CONFIG_PATH:${PREFIX_DIR}/lib/pkgconfig ./configure --bundled-libraries=NONE --abi-check --enable-debug -C ${PREFIX}", "text/plain"),
87 ("tdb-make", "cd lib/tdb && make", "text/plain"),
88 ("tdb-install", "cd lib/tdb && make install", "text/plain"),
91 # build samba with cluster support (also building ctdb):
92 ("samba-configure", "PYTHONPATH=${PYTHON_PREFIX}/site-packages:$PYTHONPATH PKG_CONFIG_PATH=${PREFIX_DIR}/lib/pkgconfig:${PKG_CONFIG_PATH} ./configure.developer --picky-developer ${PREFIX} --with-selftest-prefix=./bin/ab --with-cluster-support --bundled-libraries=!tdb", "text/plain"),
93 ("samba-make", "make", "text/plain"),
94 ("samba-check", "./bin/smbd -b | grep CLUSTER_SUPPORT", "text/plain"),
95 ("samba-install", "make install", "text/plain"),
96 ("ctdb-check", "test -e ${PREFIX_DIR}/sbin/ctdbd", "text/plain"),
99 ("check-clean-tree", "script/clean-source-tree.sh", "text/plain"),
100 ("clean", "make clean", "text/plain"),
101 ("ctdb-clean", "cd ./ctdb && make clean", "text/plain") ],
104 ("random-sleep", "script/random-sleep.sh 60 600", "text/plain"),
105 ("talloc-configure", "cd lib/talloc && " + samba_libs_configure_libs
, "text/plain"),
106 ("talloc-make", "cd lib/talloc && make", "text/plain"),
107 ("talloc-install", "cd lib/talloc && make install", "text/plain"),
109 ("tdb-configure", "cd lib/tdb && " + samba_libs_configure_libs
, "text/plain"),
110 ("tdb-make", "cd lib/tdb && make", "text/plain"),
111 ("tdb-install", "cd lib/tdb && make install", "text/plain"),
113 ("tevent-configure", "cd lib/tevent && " + samba_libs_configure_libs
, "text/plain"),
114 ("tevent-make", "cd lib/tevent && make", "text/plain"),
115 ("tevent-install", "cd lib/tevent && make install", "text/plain"),
117 ("ldb-configure", "cd lib/ldb && " + samba_libs_configure_libs
, "text/plain"),
118 ("ldb-make", "cd lib/ldb && make", "text/plain"),
119 ("ldb-install", "cd lib/ldb && make install", "text/plain"),
121 ("nondevel-configure", "./configure ${PREFIX}", "text/plain"),
122 ("nondevel-make", "make -j", "text/plain"),
123 ("nondevel-check", "./bin/smbd -b | grep WITH_NTVFS_FILESERVER && exit 1; exit 0", "text/plain"),
124 ("nondevel-install", "make install", "text/plain"),
125 ("nondevel-dist", "make dist", "text/plain"),
127 # retry with all modules shared
128 ("allshared-distclean", "make distclean", "text/plain"),
129 ("allshared-configure", samba_libs_configure_samba
+ " --with-shared-modules=ALL", "text/plain"),
130 ("allshared-make", "make -j", "text/plain")],
133 ("random-sleep", "script/random-sleep.sh 60 600", "text/plain"),
134 # build with all modules static
135 ("allstatic-configure", "./configure.developer " + samba_configure_params
+ " --with-static-modules=ALL", "text/plain"),
136 ("allstatic-make", "make -j", "text/plain"),
138 # retry without any required modules
139 ("none-distclean", "make distclean", "text/plain"),
140 ("none-configure", "./configure.developer " + samba_configure_params
+ " --with-static-modules=!FORCED,!DEFAULT --with-shared-modules=!FORCED,!DEFAULT", "text/plain"),
141 ("none-make", "make -j", "text/plain"),
143 # retry with nonshared smbd and smbtorture
144 ("nonshared-distclean", "make distclean", "text/plain"),
145 ("nonshared-configure", "./configure.developer " + samba_configure_params
+ " --bundled-libraries=talloc,tdb,pytdb,ldb,pyldb,tevent,pytevent --with-static-modules=ALL --nonshared-binary=smbtorture,smbd/smbd", "text/plain"),
146 ("nonshared-make", "make -j", "text/plain")],
149 ("random-sleep", "../../script/random-sleep.sh 60 600", "text/plain"),
150 ("configure", "./configure --enable-developer -C ${PREFIX} ${EXTRA_PYTHON}", "text/plain"),
151 ("make", "make", "text/plain"),
152 ("install", "make install", "text/plain"),
153 ("test", "make test", "text/plain"),
154 ("check-clean-tree", "../../script/clean-source-tree.sh", "text/plain"),
155 ("distcheck", "make distcheck", "text/plain"),
156 ("clean", "make clean", "text/plain") ],
159 ("random-sleep", "../../script/random-sleep.sh 60 600", "text/plain"),
160 ("configure", "./configure --enable-developer -C ${PREFIX} ${EXTRA_PYTHON}", "text/plain"),
161 ("make", "make", "text/plain"),
162 ("install", "make install", "text/plain"),
163 ("test", "make test", "text/plain"),
164 ("check-clean-tree", "../../script/clean-source-tree.sh", "text/plain"),
165 ("distcheck", "make distcheck", "text/plain"),
166 ("clean", "make clean", "text/plain") ],
169 ("random-sleep", "../../script/random-sleep.sh 60 600", "text/plain"),
170 ("configure", "./configure --enable-developer -C ${PREFIX} ${EXTRA_PYTHON}", "text/plain"),
171 ("make", "make", "text/plain"),
172 ("install", "make install", "text/plain"),
173 ("test", "make test", "text/plain"),
174 ("check-clean-tree", "../../script/clean-source-tree.sh", "text/plain"),
175 ("distcheck", "make distcheck", "text/plain"),
176 ("clean", "make clean", "text/plain") ],
179 ("random-sleep", "../../script/random-sleep.sh 60 600", "text/plain"),
180 ("configure", "./configure --enable-developer -C ${PREFIX}", "text/plain"),
181 ("make", "make", "text/plain"),
182 ("install", "make install", "text/plain"),
183 ("test", "make test", "text/plain"),
184 ("check-clean-tree", "../../script/clean-source-tree.sh", "text/plain"),
185 ("distcheck", "make distcheck", "text/plain"),
186 ("clean", "make clean", "text/plain") ],
189 ("random-sleep", "../../script/random-sleep.sh 60 600", "text/plain"),
190 ("configure", "./configure --enable-developer -C ${PREFIX} ${EXTRA_PYTHON}", "text/plain"),
191 ("make", "make", "text/plain"),
192 ("install", "make install", "text/plain"),
193 ("test", "make test", "text/plain"),
194 ("check-clean-tree", "../../script/clean-source-tree.sh", "text/plain"),
195 ("distcheck", "make distcheck", "text/plain"),
196 ("clean", "make clean", "text/plain") ],
199 ("random-sleep", "../script/random-sleep.sh 60 600", "text/plain"),
200 ("configure", "perl Makefile.PL PREFIX=${PREFIX_DIR}", "text/plain"),
201 ("touch", "touch *.yp", "text/plain"),
202 ("make", "make", "text/plain"),
203 ("test", "make test", "text/plain"),
204 ("install", "make install", "text/plain"),
205 ("checkout-yapp-generated", "git checkout lib/Parse/Pidl/IDL.pm lib/Parse/Pidl/Expr.pm", "text/plain"),
206 ("check-clean-tree", "../script/clean-source-tree.sh", "text/plain"),
207 ("clean", "make clean", "text/plain") ],
209 # these are useful for debugging autobuild
210 'pass' : [ ("pass", 'echo passing && /bin/true', "text/plain") ],
211 'fail' : [ ("fail", 'echo failing && /bin/false', "text/plain") ]
214 def run_cmd(cmd
, dir=".", show
=None, output
=False, checkfail
=True):
216 show
= options
.verbose
218 print("Running: '%s' in '%s'" % (cmd
, dir))
220 return Popen([cmd
], shell
=True, stdout
=PIPE
, cwd
=dir).communicate()[0]
222 return check_call(cmd
, shell
=True, cwd
=dir)
224 return call(cmd
, shell
=True, cwd
=dir)
227 class builder(object):
228 '''handle build of one directory'''
230 def __init__(self
, name
, sequence
, cp
=True):
232 self
.dir = builddirs
[name
]
234 self
.tag
= self
.name
.replace('/', '_')
235 self
.sequence
= sequence
237 self
.stdout_path
= "%s/%s.stdout" % (gitroot
, self
.tag
)
238 self
.stderr_path
= "%s/%s.stderr" % (gitroot
, self
.tag
)
240 print("stdout for %s in %s" % (self
.name
, self
.stdout_path
))
241 print("stderr for %s in %s" % (self
.name
, self
.stderr_path
))
242 run_cmd("rm -f %s %s" % (self
.stdout_path
, self
.stderr_path
))
243 self
.stdout
= open(self
.stdout_path
, 'w')
244 self
.stderr
= open(self
.stderr_path
, 'w')
245 self
.stdin
= open("/dev/null", 'r')
246 self
.sdir
= "%s/%s" % (testbase
, self
.tag
)
247 self
.prefix
= "%s/prefix/%s" % (testbase
, self
.tag
)
248 run_cmd("rm -rf %s" % self
.sdir
)
249 cleanup_list
.append(self
.sdir
)
250 cleanup_list
.append(self
.prefix
)
251 os
.makedirs(self
.sdir
)
252 run_cmd("rm -rf %s" % self
.sdir
)
254 run_cmd("cp --recursive --link --archive %s %s" % (test_master
, self
.sdir
), dir=test_master
, show
=True)
256 run_cmd("git clone --recursive --shared %s %s" % (test_master
, self
.sdir
), dir=test_master
, show
=True)
259 def start_next(self
):
260 if self
.next
== len(self
.sequence
):
261 print '%s: Completed OK' % self
.name
264 (self
.stage
, self
.cmd
, self
.output_mime_type
) = self
.sequence
[self
.next
]
265 self
.cmd
= self
.cmd
.replace("${PYTHON_PREFIX}", get_python_lib(standard_lib
=1, prefix
=self
.prefix
))
266 self
.cmd
= self
.cmd
.replace("${PREFIX}", "--prefix=%s" % self
.prefix
)
267 self
.cmd
= self
.cmd
.replace("${EXTRA_PYTHON}", "%s" % extra_python
)
268 self
.cmd
= self
.cmd
.replace("${PREFIX_DIR}", "%s" % self
.prefix
)
269 # if self.output_mime_type == "text/x-subunit":
270 # self.cmd += " | %s --immediate" % (os.path.join(os.path.dirname(__file__), "selftest/format-subunit"))
271 print '%s: [%s] Running %s' % (self
.name
, self
.stage
, self
.cmd
)
273 os
.chdir("%s/%s" % (self
.sdir
, self
.dir))
274 self
.proc
= Popen(self
.cmd
, shell
=True,
275 stdout
=self
.stdout
, stderr
=self
.stderr
, stdin
=self
.stdin
)
280 class buildlist(object):
281 '''handle build of multiple directories'''
283 def __init__(self
, tasklist
, tasknames
, rebase_url
, rebase_branch
="master"):
286 self
.tail_proc
= None
289 tasknames
= defaulttasks
291 # If we are only running one test,
292 # do not sleep randomly to wait for it to start
293 os
.environ
['AUTOBUILD_RANDOM_SLEEP_OVERRIDE'] = '1'
296 b
= builder(n
, tasks
[n
], cp
=n
is not "pidl")
299 rebase_remote
= "rebaseon"
300 retry_task
= [ ("retry",
302 git remote add -t %s %s %s
306 git describe %s/%s > old_remote_branch.desc
308 git describe %s/%s > remote_branch.desc
309 diff old_remote_branch.desc remote_branch.desc
312 rebase_branch
, rebase_remote
, rebase_url
,
314 rebase_remote
, rebase_branch
,
316 rebase_remote
, rebase_branch
320 self
.retry
= builder('retry', retry_task
, cp
=False)
321 self
.need_retry
= False
324 if self
.tail_proc
is not None:
325 self
.tail_proc
.terminate()
326 self
.tail_proc
.wait()
327 self
.tail_proc
= None
328 if self
.retry
is not None:
329 self
.retry
.proc
.terminate()
330 self
.retry
.proc
.wait()
333 if b
.proc
is not None:
334 run_cmd("killbysubdir %s > /dev/null 2>&1" % b
.sdir
, checkfail
=False)
346 b
.status
= b
.proc
.poll()
352 ret
= self
.retry
.proc
.poll()
354 self
.need_retry
= True
364 if options
.retry
and self
.need_retry
:
366 print("retry needed")
367 return (0, None, None, None, "retry")
370 if os
.WIFSIGNALED(b
.status
) or os
.WEXITSTATUS(b
.status
) != 0:
372 return (b
.status
, b
.name
, b
.stage
, b
.tag
, "%s: [%s] failed '%s' with status %d" % (b
.name
, b
.stage
, b
.cmd
, b
.status
))
375 return (0, None, None, None, "All OK")
377 def write_system_info(self
):
378 filename
= 'system-info.txt'
379 f
= open(filename
, 'w')
380 for cmd
in ['uname -a', 'free', 'cat /proc/cpuinfo']:
381 print >>f
, '### %s' % cmd
382 print >>f
, run_cmd(cmd
, output
=True, checkfail
=False)
387 def tarlogs(self
, fname
):
388 tar
= tarfile
.open(fname
, "w:gz")
390 tar
.add(b
.stdout_path
, arcname
="%s.stdout" % b
.tag
)
391 tar
.add(b
.stderr_path
, arcname
="%s.stderr" % b
.tag
)
392 if os
.path
.exists("autobuild.log"):
393 tar
.add("autobuild.log")
394 sys_info
= self
.write_system_info()
398 def remove_logs(self
):
400 os
.unlink(b
.stdout_path
)
401 os
.unlink(b
.stderr_path
)
403 def start_tail(self
):
405 cmd
= "tail -f *.stdout *.stderr"
407 self
.tail_proc
= Popen(cmd
, shell
=True)
412 if options
.nocleanup
:
414 print("Cleaning up ....")
415 for d
in cleanup_list
:
416 run_cmd("rm -rf %s" % d
)
420 '''get to the top of the git repo'''
423 if os
.path
.isdir(os
.path
.join(p
, ".git")):
425 p
= os
.path
.abspath(os
.path
.join(p
, '..'))
429 def daemonize(logfile
):
431 if pid
== 0: # Parent
434 if pid
!= 0: # Actual daemon
439 import resource
# Resource usage information.
440 maxfd
= resource
.getrlimit(resource
.RLIMIT_NOFILE
)[1]
441 if maxfd
== resource
.RLIM_INFINITY
:
442 maxfd
= 1024 # Rough guess at maximum number of open file descriptors.
443 for fd
in range(0, maxfd
):
448 os
.open(logfile
, os
.O_RDWR | os
.O_CREAT
)
452 def write_pidfile(fname
):
453 '''write a pid file, cleanup on exit'''
454 f
= open(fname
, mode
='w')
455 f
.write("%u\n" % os
.getpid())
459 def rebase_tree(rebase_url
, rebase_branch
= "master"):
460 rebase_remote
= "rebaseon"
461 print("Rebasing on %s" % rebase_url
)
462 run_cmd("git describe HEAD", show
=True, dir=test_master
)
463 run_cmd("git remote add -t %s %s %s" %
464 (rebase_branch
, rebase_remote
, rebase_url
),
465 show
=True, dir=test_master
)
466 run_cmd("git fetch %s" % rebase_remote
, show
=True, dir=test_master
)
467 if options
.fix_whitespace
:
468 run_cmd("git rebase --force-rebase --whitespace=fix %s/%s" %
469 (rebase_remote
, rebase_branch
),
470 show
=True, dir=test_master
)
472 run_cmd("git rebase --force-rebase %s/%s" %
473 (rebase_remote
, rebase_branch
),
474 show
=True, dir=test_master
)
475 diff
= run_cmd("git --no-pager diff HEAD %s/%s" %
476 (rebase_remote
, rebase_branch
),
477 dir=test_master
, output
=True)
479 print("No differences between HEAD and %s/%s - exiting" %
480 (rebase_remote
, rebase_branch
))
482 run_cmd("git describe %s/%s" %
483 (rebase_remote
, rebase_branch
),
484 show
=True, dir=test_master
)
485 run_cmd("git describe HEAD", show
=True, dir=test_master
)
486 run_cmd("git --no-pager diff --stat HEAD %s/%s" %
487 (rebase_remote
, rebase_branch
),
488 show
=True, dir=test_master
)
490 def push_to(push_url
, push_branch
= "master"):
491 push_remote
= "pushto"
492 print("Pushing to %s" % push_url
)
494 run_cmd("git config --replace-all core.editor script/commit_mark.sh", dir=test_master
)
495 run_cmd("git commit --amend -c HEAD", dir=test_master
)
496 # the notes method doesn't work yet, as metze hasn't allowed refs/notes/* in master
497 # run_cmd("EDITOR=script/commit_mark.sh git notes edit HEAD", dir=test_master)
498 run_cmd("git remote add -t %s %s %s" %
499 (push_branch
, push_remote
, push_url
),
500 show
=True, dir=test_master
)
501 run_cmd("git push %s +HEAD:%s" %
502 (push_remote
, push_branch
),
503 show
=True, dir=test_master
)
505 def_testbase
= os
.getenv("AUTOBUILD_TESTBASE", "/memdisk/%s" % os
.getenv('USER'))
507 gitroot
= find_git_root()
509 raise Exception("Failed to find git root")
511 parser
= OptionParser()
512 parser
.add_option("", "--tail", help="show output while running", default
=False, action
="store_true")
513 parser
.add_option("", "--keeplogs", help="keep logs", default
=False, action
="store_true")
514 parser
.add_option("", "--nocleanup", help="don't remove test tree", default
=False, action
="store_true")
515 parser
.add_option("", "--testbase", help="base directory to run tests in (default %s)" % def_testbase
,
516 default
=def_testbase
)
517 parser
.add_option("", "--passcmd", help="command to run on success", default
=None)
518 parser
.add_option("", "--verbose", help="show all commands as they are run",
519 default
=False, action
="store_true")
520 parser
.add_option("", "--rebase", help="rebase on the given tree before testing",
521 default
=None, type='str')
522 parser
.add_option("", "--pushto", help="push to a git url on success",
523 default
=None, type='str')
524 parser
.add_option("", "--mark", help="add a Tested-By signoff before pushing",
525 default
=False, action
="store_true")
526 parser
.add_option("", "--fix-whitespace", help="fix whitespace on rebase",
527 default
=False, action
="store_true")
528 parser
.add_option("", "--retry", help="automatically retry if master changes",
529 default
=False, action
="store_true")
530 parser
.add_option("", "--email", help="send email to the given address on failure",
531 type='str', default
=None)
532 parser
.add_option("", "--email-from", help="send email from the given address",
533 type='str', default
="autobuild@samba.org")
534 parser
.add_option("", "--email-server", help="send email via the given server",
535 type='str', default
='localhost')
536 parser
.add_option("", "--always-email", help="always send email, even on success",
538 parser
.add_option("", "--daemon", help="daemonize after initial setup",
540 parser
.add_option("", "--branch", help="the branch to work on (default=master)",
541 default
="master", type='str')
542 parser
.add_option("", "--log-base", help="location where the logs can be found (default=cwd)",
543 default
=gitroot
, type='str')
544 parser
.add_option("", "--attach-logs", help="Attach logs to mails sent on success/failure?",
545 default
=False, action
="store_true")
547 def send_email(subject
, text
, log_tar
):
548 outer
= MIMEMultipart()
549 outer
['Subject'] = subject
550 outer
['To'] = options
.email
551 outer
['From'] = options
.email_from
552 outer
['Date'] = email
.utils
.formatdate(localtime
= True)
553 outer
.preamble
= 'Autobuild mails are now in MIME because we optionally attach the logs.\n'
554 outer
.attach(MIMEText(text
, 'plain'))
555 if options
.attach_logs
:
556 fp
= open(log_tar
, 'rb')
557 msg
= MIMEApplication(fp
.read(), 'gzip', email
.encoders
.encode_base64
)
559 # Set the filename parameter
560 msg
.add_header('Content-Disposition', 'attachment', filename
=os
.path
.basename(log_tar
))
562 content
= outer
.as_string()
563 s
= smtplib
.SMTP(options
.email_server
)
564 s
.sendmail(options
.email_from
, [options
.email
], content
)
568 def email_failure(status
, failed_task
, failed_stage
, failed_tag
, errstr
,
569 elapsed_time
, log_base
=None):
570 '''send an email to options.email about the failure'''
571 elapsed_minutes
= elapsed_time
/ 60.0
572 user
= os
.getenv("USER")
578 Your autobuild on %s failed after %.1f minutes
579 when trying to test %s with the following error:
583 the autobuild has been abandoned. Please fix the error and resubmit.
585 A summary of the autobuild process is here:
588 ''' % (platform
.node(), elapsed_minutes
, failed_task
, errstr
, log_base
)
590 if failed_task
!= 'rebase':
592 You can see logs of the failed task here:
597 or you can get full logs of all tasks in this job here:
601 The top commit for the tree that was built was:
605 ''' % (log_base
, failed_tag
, log_base
, failed_tag
, log_base
, top_commit_msg
)
607 logs
= os
.path
.join(gitroot
, 'logs.tar.gz')
608 send_email('autobuild failure on %s for task %s during %s'
609 % (platform
.node(), failed_task
, failed_stage
),
612 def email_success(elapsed_time
, log_base
=None):
613 '''send an email to options.email about a successful build'''
614 user
= os
.getenv("USER")
620 Your autobuild on %s has succeeded after %.1f minutes.
622 ''' % (platform
.node(), elapsed_time
/ 60.)
627 you can get full logs of all tasks in this job here:
634 The top commit for the tree that was built was:
639 logs
= os
.path
.join(gitroot
, 'logs.tar.gz')
640 send_email('autobuild sucess on %s ' % platform
.node(),
644 (options
, args
) = parser
.parse_args()
647 if options
.rebase
is None:
648 raise Exception('You can only use --retry if you also rebase')
650 testbase
= "%s/b%u" % (options
.testbase
, os
.getpid())
651 test_master
= "%s/master" % testbase
653 # get the top commit message, for emails
654 top_commit_msg
= run_cmd("git log -1", dir=gitroot
, output
=True)
657 os
.makedirs(testbase
)
658 except Exception, reason
:
659 raise Exception("Unable to create %s : %s" % (testbase
, reason
))
660 cleanup_list
.append(testbase
)
663 logfile
= os
.path
.join(testbase
, "log")
664 print "Forking into the background, writing progress to %s" % logfile
667 write_pidfile(gitroot
+ "/autobuild.pid")
669 start_time
= time
.time()
673 run_cmd("rm -rf %s" % test_master
)
674 cleanup_list
.append(test_master
)
675 run_cmd("git clone --recursive --shared %s %s" % (gitroot
, test_master
), show
=True, dir=gitroot
)
682 if options
.rebase
is not None:
683 rebase_tree(options
.rebase
, rebase_branch
=options
.branch
)
685 cleanup_list
.append(gitroot
+ "/autobuild.pid")
687 elapsed_time
= time
.time() - start_time
688 email_failure(-1, 'rebase', 'rebase', 'rebase',
689 'rebase on %s failed' % options
.branch
,
690 elapsed_time
, log_base
=options
.log_base
)
692 blist
= buildlist(tasks
, args
, options
.rebase
, rebase_branch
=options
.branch
)
695 (status
, failed_task
, failed_stage
, failed_tag
, errstr
) = blist
.run()
696 if status
!= 0 or errstr
!= "retry":
703 cleanup_list
.append(gitroot
+ "/autobuild.pid")
707 print("waiting for tail to flush")
710 elapsed_time
= time
.time() - start_time
713 if options
.passcmd
is not None:
714 print("Running passcmd: %s" % options
.passcmd
)
715 run_cmd(options
.passcmd
, dir=test_master
)
716 if options
.pushto
is not None:
717 push_to(options
.pushto
, push_branch
=options
.branch
)
718 if options
.keeplogs
or options
.attach_logs
:
719 blist
.tarlogs("logs.tar.gz")
720 print("Logs in logs.tar.gz")
721 if options
.always_email
:
722 email_success(elapsed_time
, log_base
=options
.log_base
)
728 # something failed, gather a tar of the logs
729 blist
.tarlogs("logs.tar.gz")
731 if options
.email
is not None:
732 email_failure(status
, failed_task
, failed_stage
, failed_tag
, errstr
,
733 elapsed_time
, log_base
=options
.log_base
)
735 elapsed_minutes
= elapsed_time
/ 60.0
738 ####################################################################
742 Your autobuild on %s failed after %.1f minutes
743 when trying to test %s with the following error:
747 the autobuild has been abandoned. Please fix the error and resubmit.
749 ####################################################################
751 ''' % (platform
.node(), elapsed_minutes
, failed_task
, errstr
)
755 print("Logs in logs.tar.gz")