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} --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}"
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"
53 "ctdb" : [ ("random-sleep", "../script/random-sleep.sh 60 600", "text/plain"),
54 ("configure", "./configure ${PREFIX}", "text/plain"),
55 ("make", "make all", "text/plain"),
56 ("install", "make install", "text/plain"),
57 ("test", "make autotest", "text/plain"),
58 ("check-clean-tree", "../script/clean-source-tree.sh", "text/plain"),
59 ("clean", "make clean", "text/plain") ],
61 # We have 'test' before 'install' because, 'test' should work without 'install'
62 "samba" : [ ("configure", "./configure.developer --with-selftest-prefix=./bin/ab" + samba_configure_params
, "text/plain"),
63 ("make", "make -j", "text/plain"),
64 ("test", "make test FAIL_IMMEDIATELY=1", "text/plain"),
65 ("install", "make install", "text/plain"),
66 ("check-clean-tree", "script/clean-source-tree.sh", "text/plain"),
67 ("clean", "make clean", "text/plain") ],
69 # Test cross-compile infrastructure
70 "samba-xc" : [ ("configure-native", "./configure.developer --with-selftest-prefix=./bin/ab" + samba_configure_params
, "text/plain"),
71 ("configure-cross-execute", "./configure.developer -b ./bin-xe --cross-compile --cross-execute=script/identity_cc.sh" \
72 " --cross-answers=./bin-xe/cross-answers.txt --with-selftest-prefix=./bin-xe/ab" + samba_configure_params
, "text/plain"),
73 ("configure-cross-answers", "./configure.developer -b ./bin-xa --cross-compile" \
74 " --cross-answers=./bin-xe/cross-answers.txt --with-selftest-prefix=./bin-xa/ab" + samba_configure_params
, "text/plain"),
75 ("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")],
78 "samba-ctdb" : [ ("random-sleep", "script/random-sleep.sh 60 600", "text/plain"),
80 # make sure we have tdb around:
81 ("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"),
82 ("tdb-make", "cd lib/tdb && make", "text/plain"),
83 ("tdb-install", "cd lib/tdb && make install", "text/plain"),
86 # build samba with cluster support (also building ctdb):
87 ("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"),
88 ("samba-make", "make", "text/plain"),
89 ("samba-check", "./bin/smbd -b | grep CLUSTER_SUPPORT", "text/plain"),
90 ("samba-install", "make install", "text/plain"),
91 ("ctdb-check", "test -e ${PREFIX_DIR}/sbin/ctdbd", "text/plain"),
94 ("check-clean-tree", "script/clean-source-tree.sh", "text/plain"),
95 ("clean", "make clean", "text/plain"),
96 ("ctdb-clean", "cd ./ctdb && make clean", "text/plain") ],
99 ("random-sleep", "script/random-sleep.sh 60 600", "text/plain"),
100 ("talloc-configure", "cd lib/talloc && " + samba_libs_configure_libs
, "text/plain"),
101 ("talloc-make", "cd lib/talloc && make", "text/plain"),
102 ("talloc-install", "cd lib/talloc && make install", "text/plain"),
104 ("tdb-configure", "cd lib/tdb && " + samba_libs_configure_libs
, "text/plain"),
105 ("tdb-make", "cd lib/tdb && make", "text/plain"),
106 ("tdb-install", "cd lib/tdb && make install", "text/plain"),
108 ("tevent-configure", "cd lib/tevent && " + samba_libs_configure_libs
, "text/plain"),
109 ("tevent-make", "cd lib/tevent && make", "text/plain"),
110 ("tevent-install", "cd lib/tevent && make install", "text/plain"),
112 ("ldb-configure", "cd lib/ldb && " + samba_libs_configure_libs
, "text/plain"),
113 ("ldb-make", "cd lib/ldb && make", "text/plain"),
114 ("ldb-install", "cd lib/ldb && make install", "text/plain"),
116 ("nondevel-configure", "./configure ${PREFIX}", "text/plain"),
117 ("nondevel-make", "make -j", "text/plain"),
118 ("nondevel-check", "./bin/smbd -b | grep WITH_NTVFS_FILESERVER && exit 1; exit 0", "text/plain"),
119 ("nondevel-install", "make install", "text/plain"),
120 ("nondevel-dist", "make dist", "text/plain"),
122 # retry with all modules shared
123 ("allshared-distclean", "make distclean", "text/plain"),
124 ("allshared-configure", samba_libs_configure_samba
+ " --with-shared-modules=ALL", "text/plain"),
125 ("allshared-make", "make -j", "text/plain")],
128 ("random-sleep", "script/random-sleep.sh 60 600", "text/plain"),
129 # build with all modules static
130 ("allstatic-configure", "./configure.developer " + samba_configure_params
+ " --with-static-modules=ALL", "text/plain"),
131 ("allstatic-make", "make -j", "text/plain"),
133 # retry without any required modules
134 ("none-distclean", "make distclean", "text/plain"),
135 ("none-configure", "./configure.developer " + samba_configure_params
+ " --with-static-modules=!FORCED,!DEFAULT --with-shared-modules=!FORCED,!DEFAULT", "text/plain"),
136 ("none-make", "make -j", "text/plain"),
138 # retry with nonshared smbd and smbtorture
139 ("nonshared-distclean", "make distclean", "text/plain"),
140 ("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"),
141 ("nonshared-make", "make -j", "text/plain")],
144 ("random-sleep", "../../script/random-sleep.sh 60 600", "text/plain"),
145 ("configure", "./configure --enable-developer -C ${PREFIX}", "text/plain"),
146 ("make", "make", "text/plain"),
147 ("install", "make install", "text/plain"),
148 ("test", "make test", "text/plain"),
149 ("check-clean-tree", "../../script/clean-source-tree.sh", "text/plain"),
150 ("distcheck", "make distcheck", "text/plain"),
151 ("clean", "make clean", "text/plain") ],
154 ("random-sleep", "../../script/random-sleep.sh 60 600", "text/plain"),
155 ("configure", "./configure --enable-developer -C ${PREFIX}", "text/plain"),
156 ("make", "make", "text/plain"),
157 ("install", "make install", "text/plain"),
158 ("test", "make test", "text/plain"),
159 ("check-clean-tree", "../../script/clean-source-tree.sh", "text/plain"),
160 ("distcheck", "make distcheck", "text/plain"),
161 ("clean", "make clean", "text/plain") ],
164 ("random-sleep", "../../script/random-sleep.sh 60 600", "text/plain"),
165 ("configure", "./configure --enable-developer -C ${PREFIX}", "text/plain"),
166 ("make", "make", "text/plain"),
167 ("install", "make install", "text/plain"),
168 ("test", "make test", "text/plain"),
169 ("check-clean-tree", "../../script/clean-source-tree.sh", "text/plain"),
170 ("distcheck", "make distcheck", "text/plain"),
171 ("clean", "make clean", "text/plain") ],
174 ("random-sleep", "../../script/random-sleep.sh 60 600", "text/plain"),
175 ("configure", "./configure --enable-developer -C ${PREFIX}", "text/plain"),
176 ("make", "make", "text/plain"),
177 ("install", "make install", "text/plain"),
178 ("test", "make test", "text/plain"),
179 ("check-clean-tree", "../../script/clean-source-tree.sh", "text/plain"),
180 ("distcheck", "make distcheck", "text/plain"),
181 ("clean", "make clean", "text/plain") ],
184 ("random-sleep", "../../script/random-sleep.sh 60 600", "text/plain"),
185 ("configure", "./configure --enable-developer -C ${PREFIX}", "text/plain"),
186 ("make", "make", "text/plain"),
187 ("install", "make install", "text/plain"),
188 ("test", "make test", "text/plain"),
189 ("check-clean-tree", "../../script/clean-source-tree.sh", "text/plain"),
190 ("distcheck", "make distcheck", "text/plain"),
191 ("clean", "make clean", "text/plain") ],
194 ("random-sleep", "../script/random-sleep.sh 60 600", "text/plain"),
195 ("configure", "perl Makefile.PL PREFIX=${PREFIX_DIR}", "text/plain"),
196 ("touch", "touch *.yp", "text/plain"),
197 ("make", "make", "text/plain"),
198 ("test", "make test", "text/plain"),
199 ("install", "make install", "text/plain"),
200 ("checkout-yapp-generated", "git checkout lib/Parse/Pidl/IDL.pm lib/Parse/Pidl/Expr.pm", "text/plain"),
201 ("check-clean-tree", "../script/clean-source-tree.sh", "text/plain"),
202 ("clean", "make clean", "text/plain") ],
204 # these are useful for debugging autobuild
205 'pass' : [ ("pass", 'echo passing && /bin/true', "text/plain") ],
206 'fail' : [ ("fail", 'echo failing && /bin/false', "text/plain") ]
209 def run_cmd(cmd
, dir=".", show
=None, output
=False, checkfail
=True):
211 show
= options
.verbose
213 print("Running: '%s' in '%s'" % (cmd
, dir))
215 return Popen([cmd
], shell
=True, stdout
=PIPE
, cwd
=dir).communicate()[0]
217 return check_call(cmd
, shell
=True, cwd
=dir)
219 return call(cmd
, shell
=True, cwd
=dir)
222 class builder(object):
223 '''handle build of one directory'''
225 def __init__(self
, name
, sequence
, cp
=True):
227 self
.dir = builddirs
[name
]
229 self
.tag
= self
.name
.replace('/', '_')
230 self
.sequence
= sequence
232 self
.stdout_path
= "%s/%s.stdout" % (gitroot
, self
.tag
)
233 self
.stderr_path
= "%s/%s.stderr" % (gitroot
, self
.tag
)
235 print("stdout for %s in %s" % (self
.name
, self
.stdout_path
))
236 print("stderr for %s in %s" % (self
.name
, self
.stderr_path
))
237 run_cmd("rm -f %s %s" % (self
.stdout_path
, self
.stderr_path
))
238 self
.stdout
= open(self
.stdout_path
, 'w')
239 self
.stderr
= open(self
.stderr_path
, 'w')
240 self
.stdin
= open("/dev/null", 'r')
241 self
.sdir
= "%s/%s" % (testbase
, self
.tag
)
242 self
.prefix
= "%s/prefix/%s" % (testbase
, self
.tag
)
243 run_cmd("rm -rf %s" % self
.sdir
)
244 cleanup_list
.append(self
.sdir
)
245 cleanup_list
.append(self
.prefix
)
246 os
.makedirs(self
.sdir
)
247 run_cmd("rm -rf %s" % self
.sdir
)
249 run_cmd("cp --recursive --link --archive %s %s" % (test_master
, self
.sdir
), dir=test_master
, show
=True)
251 run_cmd("git clone --recursive --shared %s %s" % (test_master
, self
.sdir
), dir=test_master
, show
=True)
254 def start_next(self
):
255 if self
.next
== len(self
.sequence
):
256 print '%s: Completed OK' % self
.name
259 (self
.stage
, self
.cmd
, self
.output_mime_type
) = self
.sequence
[self
.next
]
260 self
.cmd
= self
.cmd
.replace("${PYTHON_PREFIX}", get_python_lib(standard_lib
=1, prefix
=self
.prefix
))
261 self
.cmd
= self
.cmd
.replace("${PREFIX}", "--prefix=%s" % self
.prefix
)
262 self
.cmd
= self
.cmd
.replace("${PREFIX_DIR}", "%s" % self
.prefix
)
263 # if self.output_mime_type == "text/x-subunit":
264 # self.cmd += " | %s --immediate" % (os.path.join(os.path.dirname(__file__), "selftest/format-subunit"))
265 print '%s: [%s] Running %s' % (self
.name
, self
.stage
, self
.cmd
)
267 os
.chdir("%s/%s" % (self
.sdir
, self
.dir))
268 self
.proc
= Popen(self
.cmd
, shell
=True,
269 stdout
=self
.stdout
, stderr
=self
.stderr
, stdin
=self
.stdin
)
274 class buildlist(object):
275 '''handle build of multiple directories'''
277 def __init__(self
, tasklist
, tasknames
, rebase_url
, rebase_branch
="master"):
280 self
.tail_proc
= None
283 tasknames
= defaulttasks
285 # If we are only running one test,
286 # do not sleep randomly to wait for it to start
287 os
.environ
['AUTOBUILD_RANDOM_SLEEP_OVERRIDE'] = '1'
290 b
= builder(n
, tasks
[n
], cp
=n
is not "pidl")
293 rebase_remote
= "rebaseon"
294 retry_task
= [ ("retry",
296 git remote add -t %s %s %s
300 git describe %s/%s > old_remote_branch.desc
302 git describe %s/%s > remote_branch.desc
303 diff old_remote_branch.desc remote_branch.desc
306 rebase_branch
, rebase_remote
, rebase_url
,
308 rebase_remote
, rebase_branch
,
310 rebase_remote
, rebase_branch
314 self
.retry
= builder('retry', retry_task
, cp
=False)
315 self
.need_retry
= False
318 if self
.tail_proc
is not None:
319 self
.tail_proc
.terminate()
320 self
.tail_proc
.wait()
321 self
.tail_proc
= None
322 if self
.retry
is not None:
323 self
.retry
.proc
.terminate()
324 self
.retry
.proc
.wait()
327 if b
.proc
is not None:
328 run_cmd("killbysubdir %s > /dev/null 2>&1" % b
.sdir
, checkfail
=False)
340 b
.status
= b
.proc
.poll()
346 ret
= self
.retry
.proc
.poll()
348 self
.need_retry
= True
358 if options
.retry
and self
.need_retry
:
360 print("retry needed")
361 return (0, None, None, None, "retry")
364 if os
.WIFSIGNALED(b
.status
) or os
.WEXITSTATUS(b
.status
) != 0:
366 return (b
.status
, b
.name
, b
.stage
, b
.tag
, "%s: [%s] failed '%s' with status %d" % (b
.name
, b
.stage
, b
.cmd
, b
.status
))
369 return (0, None, None, None, "All OK")
371 def write_system_info(self
):
372 filename
= 'system-info.txt'
373 f
= open(filename
, 'w')
374 for cmd
in ['uname -a', 'free', 'cat /proc/cpuinfo']:
375 print >>f
, '### %s' % cmd
376 print >>f
, run_cmd(cmd
, output
=True, checkfail
=False)
381 def tarlogs(self
, fname
):
382 tar
= tarfile
.open(fname
, "w:gz")
384 tar
.add(b
.stdout_path
, arcname
="%s.stdout" % b
.tag
)
385 tar
.add(b
.stderr_path
, arcname
="%s.stderr" % b
.tag
)
386 if os
.path
.exists("autobuild.log"):
387 tar
.add("autobuild.log")
388 sys_info
= self
.write_system_info()
392 def remove_logs(self
):
394 os
.unlink(b
.stdout_path
)
395 os
.unlink(b
.stderr_path
)
397 def start_tail(self
):
399 cmd
= "tail -f *.stdout *.stderr"
401 self
.tail_proc
= Popen(cmd
, shell
=True)
406 if options
.nocleanup
:
408 print("Cleaning up ....")
409 for d
in cleanup_list
:
410 run_cmd("rm -rf %s" % d
)
414 '''get to the top of the git repo'''
417 if os
.path
.isdir(os
.path
.join(p
, ".git")):
419 p
= os
.path
.abspath(os
.path
.join(p
, '..'))
423 def daemonize(logfile
):
425 if pid
== 0: # Parent
428 if pid
!= 0: # Actual daemon
433 import resource
# Resource usage information.
434 maxfd
= resource
.getrlimit(resource
.RLIMIT_NOFILE
)[1]
435 if maxfd
== resource
.RLIM_INFINITY
:
436 maxfd
= 1024 # Rough guess at maximum number of open file descriptors.
437 for fd
in range(0, maxfd
):
442 os
.open(logfile
, os
.O_RDWR | os
.O_CREAT
)
446 def write_pidfile(fname
):
447 '''write a pid file, cleanup on exit'''
448 f
= open(fname
, mode
='w')
449 f
.write("%u\n" % os
.getpid())
453 def rebase_tree(rebase_url
, rebase_branch
= "master"):
454 rebase_remote
= "rebaseon"
455 print("Rebasing on %s" % rebase_url
)
456 run_cmd("git describe HEAD", show
=True, dir=test_master
)
457 run_cmd("git remote add -t %s %s %s" %
458 (rebase_branch
, rebase_remote
, rebase_url
),
459 show
=True, dir=test_master
)
460 run_cmd("git fetch %s" % rebase_remote
, show
=True, dir=test_master
)
461 if options
.fix_whitespace
:
462 run_cmd("git rebase --force-rebase --whitespace=fix %s/%s" %
463 (rebase_remote
, rebase_branch
),
464 show
=True, dir=test_master
)
466 run_cmd("git rebase --force-rebase %s/%s" %
467 (rebase_remote
, rebase_branch
),
468 show
=True, dir=test_master
)
469 diff
= run_cmd("git --no-pager diff HEAD %s/%s" %
470 (rebase_remote
, rebase_branch
),
471 dir=test_master
, output
=True)
473 print("No differences between HEAD and %s/%s - exiting" %
474 (rebase_remote
, rebase_branch
))
476 run_cmd("git describe %s/%s" %
477 (rebase_remote
, rebase_branch
),
478 show
=True, dir=test_master
)
479 run_cmd("git describe HEAD", show
=True, dir=test_master
)
480 run_cmd("git --no-pager diff --stat HEAD %s/%s" %
481 (rebase_remote
, rebase_branch
),
482 show
=True, dir=test_master
)
484 def push_to(push_url
, push_branch
= "master"):
485 push_remote
= "pushto"
486 print("Pushing to %s" % push_url
)
488 run_cmd("git config --replace-all core.editor script/commit_mark.sh", dir=test_master
)
489 run_cmd("git commit --amend -c HEAD", dir=test_master
)
490 # the notes method doesn't work yet, as metze hasn't allowed refs/notes/* in master
491 # run_cmd("EDITOR=script/commit_mark.sh git notes edit HEAD", dir=test_master)
492 run_cmd("git remote add -t %s %s %s" %
493 (push_branch
, push_remote
, push_url
),
494 show
=True, dir=test_master
)
495 run_cmd("git push %s +HEAD:%s" %
496 (push_remote
, push_branch
),
497 show
=True, dir=test_master
)
499 def_testbase
= os
.getenv("AUTOBUILD_TESTBASE", "/memdisk/%s" % os
.getenv('USER'))
501 gitroot
= find_git_root()
503 raise Exception("Failed to find git root")
505 parser
= OptionParser()
506 parser
.add_option("", "--tail", help="show output while running", default
=False, action
="store_true")
507 parser
.add_option("", "--keeplogs", help="keep logs", default
=False, action
="store_true")
508 parser
.add_option("", "--nocleanup", help="don't remove test tree", default
=False, action
="store_true")
509 parser
.add_option("", "--testbase", help="base directory to run tests in (default %s)" % def_testbase
,
510 default
=def_testbase
)
511 parser
.add_option("", "--passcmd", help="command to run on success", default
=None)
512 parser
.add_option("", "--verbose", help="show all commands as they are run",
513 default
=False, action
="store_true")
514 parser
.add_option("", "--rebase", help="rebase on the given tree before testing",
515 default
=None, type='str')
516 parser
.add_option("", "--pushto", help="push to a git url on success",
517 default
=None, type='str')
518 parser
.add_option("", "--mark", help="add a Tested-By signoff before pushing",
519 default
=False, action
="store_true")
520 parser
.add_option("", "--fix-whitespace", help="fix whitespace on rebase",
521 default
=False, action
="store_true")
522 parser
.add_option("", "--retry", help="automatically retry if master changes",
523 default
=False, action
="store_true")
524 parser
.add_option("", "--email", help="send email to the given address on failure",
525 type='str', default
=None)
526 parser
.add_option("", "--email-from", help="send email from the given address",
527 type='str', default
="autobuild@samba.org")
528 parser
.add_option("", "--email-server", help="send email via the given server",
529 type='str', default
='localhost')
530 parser
.add_option("", "--always-email", help="always send email, even on success",
532 parser
.add_option("", "--daemon", help="daemonize after initial setup",
534 parser
.add_option("", "--branch", help="the branch to work on (default=master)",
535 default
="master", type='str')
536 parser
.add_option("", "--log-base", help="location where the logs can be found (default=cwd)",
537 default
=gitroot
, type='str')
538 parser
.add_option("", "--attach-logs", help="Attach logs to mails sent on success/failure?",
539 default
=False, action
="store_true")
541 def send_email(subject
, text
, log_tar
):
542 outer
= MIMEMultipart()
543 outer
['Subject'] = subject
544 outer
['To'] = options
.email
545 outer
['From'] = options
.email_from
546 outer
['Date'] = email
.utils
.formatdate(localtime
= True)
547 outer
.preamble
= 'Autobuild mails are now in MIME because we optionally attach the logs.\n'
548 outer
.attach(MIMEText(text
, 'plain'))
549 if options
.attach_logs
:
550 fp
= open(log_tar
, 'rb')
551 msg
= MIMEApplication(fp
.read(), 'gzip', email
.encoders
.encode_base64
)
553 # Set the filename parameter
554 msg
.add_header('Content-Disposition', 'attachment', filename
=os
.path
.basename(log_tar
))
556 content
= outer
.as_string()
557 s
= smtplib
.SMTP(options
.email_server
)
558 s
.sendmail(options
.email_from
, [options
.email
], content
)
562 def email_failure(status
, failed_task
, failed_stage
, failed_tag
, errstr
,
563 elapsed_time
, log_base
=None):
564 '''send an email to options.email about the failure'''
565 elapsed_minutes
= elapsed_time
/ 60.0
566 user
= os
.getenv("USER")
572 Your autobuild on %s failed after %.1f minutes
573 when trying to test %s with the following error:
577 the autobuild has been abandoned. Please fix the error and resubmit.
579 A summary of the autobuild process is here:
582 ''' % (platform
.node(), elapsed_minutes
, failed_task
, errstr
, log_base
)
584 if failed_task
!= 'rebase':
586 You can see logs of the failed task here:
591 or you can get full logs of all tasks in this job here:
595 The top commit for the tree that was built was:
599 ''' % (log_base
, failed_tag
, log_base
, failed_tag
, log_base
, top_commit_msg
)
601 logs
= os
.path
.join(gitroot
, 'logs.tar.gz')
602 send_email('autobuild failure on %s for task %s during %s'
603 % (platform
.node(), failed_task
, failed_stage
),
606 def email_success(elapsed_time
, log_base
=None):
607 '''send an email to options.email about a successful build'''
608 user
= os
.getenv("USER")
614 Your autobuild on %s has succeeded after %.1f minutes.
616 ''' % (platform
.node(), elapsed_time
/ 60.)
621 you can get full logs of all tasks in this job here:
628 The top commit for the tree that was built was:
633 logs
= os
.path
.join(gitroot
, 'logs.tar.gz')
634 send_email('autobuild sucess on %s ' % platform
.node(),
638 (options
, args
) = parser
.parse_args()
641 if options
.rebase
is None:
642 raise Exception('You can only use --retry if you also rebase')
644 testbase
= "%s/b%u" % (options
.testbase
, os
.getpid())
645 test_master
= "%s/master" % testbase
647 # get the top commit message, for emails
648 top_commit_msg
= run_cmd("git log -1", dir=gitroot
, output
=True)
651 os
.makedirs(testbase
)
652 except Exception, reason
:
653 raise Exception("Unable to create %s : %s" % (testbase
, reason
))
654 cleanup_list
.append(testbase
)
657 logfile
= os
.path
.join(testbase
, "log")
658 print "Forking into the background, writing progress to %s" % logfile
661 write_pidfile(gitroot
+ "/autobuild.pid")
663 start_time
= time
.time()
667 run_cmd("rm -rf %s" % test_master
)
668 cleanup_list
.append(test_master
)
669 run_cmd("git clone --recursive --shared %s %s" % (gitroot
, test_master
), show
=True, dir=gitroot
)
676 if options
.rebase
is not None:
677 rebase_tree(options
.rebase
, rebase_branch
=options
.branch
)
679 cleanup_list
.append(gitroot
+ "/autobuild.pid")
681 elapsed_time
= time
.time() - start_time
682 email_failure(-1, 'rebase', 'rebase', 'rebase',
683 'rebase on %s failed' % options
.branch
,
684 elapsed_time
, log_base
=options
.log_base
)
686 blist
= buildlist(tasks
, args
, options
.rebase
, rebase_branch
=options
.branch
)
689 (status
, failed_task
, failed_stage
, failed_tag
, errstr
) = blist
.run()
690 if status
!= 0 or errstr
!= "retry":
697 cleanup_list
.append(gitroot
+ "/autobuild.pid")
701 print("waiting for tail to flush")
704 elapsed_time
= time
.time() - start_time
707 if options
.passcmd
is not None:
708 print("Running passcmd: %s" % options
.passcmd
)
709 run_cmd(options
.passcmd
, dir=test_master
)
710 if options
.pushto
is not None:
711 push_to(options
.pushto
, push_branch
=options
.branch
)
712 if options
.keeplogs
or options
.attach_logs
:
713 blist
.tarlogs("logs.tar.gz")
714 print("Logs in logs.tar.gz")
715 if options
.always_email
:
716 email_success(elapsed_time
, log_base
=options
.log_base
)
722 # something failed, gather a tar of the logs
723 blist
.tarlogs("logs.tar.gz")
725 if options
.email
is not None:
726 email_failure(status
, failed_task
, failed_stage
, failed_tag
, errstr
,
727 elapsed_time
, log_base
=options
.log_base
)
729 elapsed_minutes
= elapsed_time
/ 60.0
732 ####################################################################
736 Your autobuild on %s failed after %.1f minutes
737 when trying to test %s with the following error:
741 the autobuild has been abandoned. Please fix the error and resubmit.
743 ####################################################################
745 ''' % (platform
.node(), elapsed_minutes
, failed_task
, errstr
)
749 print("Logs in logs.tar.gz")