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'
31 "talloc" : "lib/talloc",
32 "replace" : "lib/replace",
33 "tevent" : "lib/tevent",
40 defaulttasks
= [ "ctdb", "samba", "samba-xc", "samba-ctdb", "samba-libs", "ldb", "tdb", "talloc", "replace", "tevent", "pidl" ]
42 samba_configure_params
= " --picky-developer ${PREFIX} --with-profiling-data"
44 samba_libs_envvars
= "PYTHONPATH=${PYTHON_PREFIX}/site-packages:$PYTHONPATH"
45 samba_libs_envvars
+= " PKG_CONFIG_PATH=$PKG_CONFIG_PATH:${PREFIX_DIR}/lib/pkgconfig"
46 samba_libs_envvars
+= " ADDITIONAL_CFLAGS='-Wmissing-prototypes'"
47 samba_libs_configure_base
= samba_libs_envvars
+ " ./configure --abi-check --enable-debug --picky-developer -C ${PREFIX}"
48 samba_libs_configure_libs
= samba_libs_configure_base
+ " --bundled-libraries=NONE"
49 samba_libs_configure_samba
= samba_libs_configure_base
+ " --bundled-libraries=!talloc,!pytalloc-util,!tdb,!pytdb,!ldb,!pyldb,!pyldb-util,!tevent,!pytevent"
52 "ctdb" : [ ("random-sleep", "../script/random-sleep.sh 60 600", "text/plain"),
53 ("configure", "./configure ${PREFIX}", "text/plain"),
54 ("make", "make all", "text/plain"),
55 ("install", "make install", "text/plain"),
56 ("test", "make autotest", "text/plain"),
57 ("check-clean-tree", "../script/clean-source-tree.sh", "text/plain"),
58 ("clean", "make clean", "text/plain") ],
60 # We have 'test' before 'install' because, 'test' should work without 'install'
61 "samba" : [ ("configure", "./configure.developer --with-selftest-prefix=./bin/ab" + samba_configure_params
, "text/plain"),
62 ("make", "make -j", "text/plain"),
63 ("test", "make test FAIL_IMMEDIATELY=1", "text/plain"),
64 ("install", "make install", "text/plain"),
65 ("check-clean-tree", "script/clean-source-tree.sh", "text/plain"),
66 ("clean", "make clean", "text/plain") ],
68 # Test cross-compile infrastructure
69 "samba-xc" : [ ("configure-native", "./configure.developer --with-selftest-prefix=./bin/ab" + samba_configure_params
, "text/plain"),
70 ("configure-cross-execute", "./configure.developer -b ./bin-xe --cross-compile --cross-execute=script/identity_cc.sh" \
71 " --cross-answers=./bin-xe/cross-answers.txt --with-selftest-prefix=./bin-xe/ab" + samba_configure_params
, "text/plain"),
72 ("configure-cross-answers", "./configure.developer -b ./bin-xa --cross-compile" \
73 " --cross-answers=./bin-xe/cross-answers.txt --with-selftest-prefix=./bin-xa/ab" + samba_configure_params
, "text/plain"),
74 ("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")],
77 "samba-ctdb" : [ ("random-sleep", "script/random-sleep.sh 60 600", "text/plain"),
79 # make sure we have tdb around:
80 ("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"),
81 ("tdb-make", "cd lib/tdb && make", "text/plain"),
82 ("tdb-install", "cd lib/tdb && make install", "text/plain"),
85 # build samba with cluster support (also building ctdb):
86 ("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"),
87 ("samba-make", "make", "text/plain"),
88 ("samba-check", "./bin/smbd -b | grep CLUSTER_SUPPORT", "text/plain"),
89 ("samba-install", "make install", "text/plain"),
90 ("ctdb-check", "test -e ${PREFIX_DIR}/sbin/ctdbd", "text/plain"),
93 ("check-clean-tree", "script/clean-source-tree.sh", "text/plain"),
94 ("clean", "make clean", "text/plain"),
95 ("ctdb-clean", "cd ./ctdb && make clean", "text/plain") ],
98 ("random-sleep", "script/random-sleep.sh 60 600", "text/plain"),
99 ("talloc-configure", "cd lib/talloc && " + samba_libs_configure_libs
, "text/plain"),
100 ("talloc-make", "cd lib/talloc && make", "text/plain"),
101 ("talloc-install", "cd lib/talloc && make install", "text/plain"),
103 ("tdb-configure", "cd lib/tdb && " + samba_libs_configure_libs
, "text/plain"),
104 ("tdb-make", "cd lib/tdb && make", "text/plain"),
105 ("tdb-install", "cd lib/tdb && make install", "text/plain"),
107 ("tevent-configure", "cd lib/tevent && " + samba_libs_configure_libs
, "text/plain"),
108 ("tevent-make", "cd lib/tevent && make", "text/plain"),
109 ("tevent-install", "cd lib/tevent && make install", "text/plain"),
111 ("ldb-configure", "cd lib/ldb && " + samba_libs_configure_libs
, "text/plain"),
112 ("ldb-make", "cd lib/ldb && make", "text/plain"),
113 ("ldb-install", "cd lib/ldb && make install", "text/plain"),
115 ("nondevel-configure", "./configure ${PREFIX}", "text/plain"),
116 ("nondevel-make", "make -j", "text/plain"),
117 ("nondevel-check", "./bin/smbd -b | grep WITH_NTVFS_FILESERVER && exit 1; exit 0", "text/plain"),
118 ("nondevel-install", "make install", "text/plain"),
119 ("nondevel-dist", "make dist", "text/plain"),
121 # retry with all modules shared
122 ("allshared-distclean", "make distclean", "text/plain"),
123 ("allshared-configure", samba_libs_configure_samba
+ " --with-shared-modules=ALL", "text/plain"),
124 ("allshared-make", "make", "text/plain"),
126 # retry with all modules static
127 ("allstatic-distclean", "make distclean", "text/plain"),
128 ("allstatic-configure", samba_libs_configure_samba
+ " --with-static-modules=ALL", "text/plain"),
129 ("allstatic-make", "make", "text/plain"),
131 # retry without any required modules
132 ("none-distclean", "make distclean", "text/plain"),
133 ("none-configure", samba_libs_configure_samba
+ " --with-static-modules=!FORCED,!DEFAULT --with-shared-modules=!FORCED,!DEFAULT", "text/plain"),
134 ("none-make", "make", "text/plain"),
136 # retry with nonshared smbd and smbtorture
137 ("nonshared-distclean", "make distclean", "text/plain"),
138 ("nonshared-configure", samba_libs_configure_base
+ " --bundled-libraries=talloc,tdb,pytdb,ldb,pyldb,tevent,pytevent --with-static-modules=ALL --nonshared-binary=smbtorture,smbd/smbd", "text/plain"),
139 ("nonshared-make", "make", "text/plain")],
142 ("random-sleep", "../../script/random-sleep.sh 60 600", "text/plain"),
143 ("configure", "./configure --enable-developer -C ${PREFIX}", "text/plain"),
144 ("make", "make", "text/plain"),
145 ("install", "make install", "text/plain"),
146 ("test", "make test", "text/plain"),
147 ("check-clean-tree", "../../script/clean-source-tree.sh", "text/plain"),
148 ("distcheck", "make distcheck", "text/plain"),
149 ("clean", "make clean", "text/plain") ],
152 ("random-sleep", "../../script/random-sleep.sh 60 600", "text/plain"),
153 ("configure", "./configure --enable-developer -C ${PREFIX}", "text/plain"),
154 ("make", "make", "text/plain"),
155 ("install", "make install", "text/plain"),
156 ("test", "make test", "text/plain"),
157 ("check-clean-tree", "../../script/clean-source-tree.sh", "text/plain"),
158 ("distcheck", "make distcheck", "text/plain"),
159 ("clean", "make clean", "text/plain") ],
162 ("random-sleep", "../../script/random-sleep.sh 60 600", "text/plain"),
163 ("configure", "./configure --enable-developer -C ${PREFIX}", "text/plain"),
164 ("make", "make", "text/plain"),
165 ("install", "make install", "text/plain"),
166 ("test", "make test", "text/plain"),
167 ("check-clean-tree", "../../script/clean-source-tree.sh", "text/plain"),
168 ("distcheck", "make distcheck", "text/plain"),
169 ("clean", "make clean", "text/plain") ],
172 ("random-sleep", "../../script/random-sleep.sh 60 600", "text/plain"),
173 ("configure", "./configure --enable-developer -C ${PREFIX}", "text/plain"),
174 ("make", "make", "text/plain"),
175 ("install", "make install", "text/plain"),
176 ("test", "make test", "text/plain"),
177 ("check-clean-tree", "../../script/clean-source-tree.sh", "text/plain"),
178 ("distcheck", "make distcheck", "text/plain"),
179 ("clean", "make clean", "text/plain") ],
182 ("random-sleep", "../../script/random-sleep.sh 60 600", "text/plain"),
183 ("configure", "./configure --enable-developer -C ${PREFIX}", "text/plain"),
184 ("make", "make", "text/plain"),
185 ("install", "make install", "text/plain"),
186 ("test", "make test", "text/plain"),
187 ("check-clean-tree", "../../script/clean-source-tree.sh", "text/plain"),
188 ("distcheck", "make distcheck", "text/plain"),
189 ("clean", "make clean", "text/plain") ],
192 ("random-sleep", "../script/random-sleep.sh 60 600", "text/plain"),
193 ("configure", "perl Makefile.PL PREFIX=${PREFIX_DIR}", "text/plain"),
194 ("touch", "touch *.yp", "text/plain"),
195 ("make", "make", "text/plain"),
196 ("test", "make test", "text/plain"),
197 ("install", "make install", "text/plain"),
198 ("checkout-yapp-generated", "git checkout lib/Parse/Pidl/IDL.pm lib/Parse/Pidl/Expr.pm", "text/plain"),
199 ("check-clean-tree", "../script/clean-source-tree.sh", "text/plain"),
200 ("clean", "make clean", "text/plain") ],
202 # these are useful for debugging autobuild
203 'pass' : [ ("pass", 'echo passing && /bin/true', "text/plain") ],
204 'fail' : [ ("fail", 'echo failing && /bin/false', "text/plain") ]
207 def run_cmd(cmd
, dir=".", show
=None, output
=False, checkfail
=True):
209 show
= options
.verbose
211 print("Running: '%s' in '%s'" % (cmd
, dir))
213 return Popen([cmd
], shell
=True, stdout
=PIPE
, cwd
=dir).communicate()[0]
215 return check_call(cmd
, shell
=True, cwd
=dir)
217 return call(cmd
, shell
=True, cwd
=dir)
220 class builder(object):
221 '''handle build of one directory'''
223 def __init__(self
, name
, sequence
):
225 self
.dir = builddirs
[name
]
227 self
.tag
= self
.name
.replace('/', '_')
228 self
.sequence
= sequence
230 self
.stdout_path
= "%s/%s.stdout" % (gitroot
, self
.tag
)
231 self
.stderr_path
= "%s/%s.stderr" % (gitroot
, self
.tag
)
233 print("stdout for %s in %s" % (self
.name
, self
.stdout_path
))
234 print("stderr for %s in %s" % (self
.name
, self
.stderr_path
))
235 run_cmd("rm -f %s %s" % (self
.stdout_path
, self
.stderr_path
))
236 self
.stdout
= open(self
.stdout_path
, 'w')
237 self
.stderr
= open(self
.stderr_path
, 'w')
238 self
.stdin
= open("/dev/null", 'r')
239 self
.sdir
= "%s/%s" % (testbase
, self
.tag
)
240 self
.prefix
= "%s/prefix/%s" % (testbase
, self
.tag
)
241 run_cmd("rm -rf %s" % self
.sdir
)
242 cleanup_list
.append(self
.sdir
)
243 cleanup_list
.append(self
.prefix
)
244 os
.makedirs(self
.sdir
)
245 run_cmd("rm -rf %s" % self
.sdir
)
246 run_cmd("git clone --recursive --shared %s %s" % (test_master
, self
.sdir
), dir=test_master
, show
=True)
249 def start_next(self
):
250 if self
.next
== len(self
.sequence
):
251 print '%s: Completed OK' % self
.name
254 (self
.stage
, self
.cmd
, self
.output_mime_type
) = self
.sequence
[self
.next
]
255 self
.cmd
= self
.cmd
.replace("${PYTHON_PREFIX}", get_python_lib(standard_lib
=1, prefix
=self
.prefix
))
256 self
.cmd
= self
.cmd
.replace("${PREFIX}", "--prefix=%s" % self
.prefix
)
257 self
.cmd
= self
.cmd
.replace("${PREFIX_DIR}", "%s" % self
.prefix
)
258 # if self.output_mime_type == "text/x-subunit":
259 # self.cmd += " | %s --immediate" % (os.path.join(os.path.dirname(__file__), "selftest/format-subunit"))
260 print '%s: [%s] Running %s' % (self
.name
, self
.stage
, self
.cmd
)
262 os
.chdir("%s/%s" % (self
.sdir
, self
.dir))
263 self
.proc
= Popen(self
.cmd
, shell
=True,
264 stdout
=self
.stdout
, stderr
=self
.stderr
, stdin
=self
.stdin
)
269 class buildlist(object):
270 '''handle build of multiple directories'''
272 def __init__(self
, tasklist
, tasknames
, rebase_url
, rebase_branch
="master"):
275 self
.tail_proc
= None
278 tasknames
= defaulttasks
280 # If we are only running one test,
281 # do not sleep randomly to wait for it to start
282 os
.environ
['AUTOBUILD_RANDOM_SLEEP_OVERRIDE'] = '1'
285 b
= builder(n
, tasks
[n
])
288 rebase_remote
= "rebaseon"
289 retry_task
= [ ("retry",
291 git remote add -t %s %s %s
295 git describe %s/%s > old_remote_branch.desc
297 git describe %s/%s > remote_branch.desc
298 diff old_remote_branch.desc remote_branch.desc
301 rebase_branch
, rebase_remote
, rebase_url
,
303 rebase_remote
, rebase_branch
,
305 rebase_remote
, rebase_branch
309 self
.retry
= builder('retry', retry_task
)
310 self
.need_retry
= False
313 if self
.tail_proc
is not None:
314 self
.tail_proc
.terminate()
315 self
.tail_proc
.wait()
316 self
.tail_proc
= None
317 if self
.retry
is not None:
318 self
.retry
.proc
.terminate()
319 self
.retry
.proc
.wait()
322 if b
.proc
is not None:
323 run_cmd("killbysubdir %s > /dev/null 2>&1" % b
.sdir
, checkfail
=False)
335 b
.status
= b
.proc
.poll()
341 ret
= self
.retry
.proc
.poll()
343 self
.need_retry
= True
353 if options
.retry
and self
.need_retry
:
355 print("retry needed")
356 return (0, None, None, None, "retry")
359 if os
.WIFSIGNALED(b
.status
) or os
.WEXITSTATUS(b
.status
) != 0:
361 return (b
.status
, b
.name
, b
.stage
, b
.tag
, "%s: [%s] failed '%s' with status %d" % (b
.name
, b
.stage
, b
.cmd
, b
.status
))
364 return (0, None, None, None, "All OK")
366 def write_system_info(self
):
367 filename
= 'system-info.txt'
368 f
= open(filename
, 'w')
369 for cmd
in ['uname -a', 'free', 'cat /proc/cpuinfo']:
370 print >>f
, '### %s' % cmd
371 print >>f
, run_cmd(cmd
, output
=True, checkfail
=False)
376 def tarlogs(self
, fname
):
377 tar
= tarfile
.open(fname
, "w:gz")
379 tar
.add(b
.stdout_path
, arcname
="%s.stdout" % b
.tag
)
380 tar
.add(b
.stderr_path
, arcname
="%s.stderr" % b
.tag
)
381 if os
.path
.exists("autobuild.log"):
382 tar
.add("autobuild.log")
383 sys_info
= self
.write_system_info()
387 def remove_logs(self
):
389 os
.unlink(b
.stdout_path
)
390 os
.unlink(b
.stderr_path
)
392 def start_tail(self
):
394 cmd
= "tail -f *.stdout *.stderr"
396 self
.tail_proc
= Popen(cmd
, shell
=True)
401 if options
.nocleanup
:
403 print("Cleaning up ....")
404 for d
in cleanup_list
:
405 run_cmd("rm -rf %s" % d
)
409 '''get to the top of the git repo'''
412 if os
.path
.isdir(os
.path
.join(p
, ".git")):
414 p
= os
.path
.abspath(os
.path
.join(p
, '..'))
418 def daemonize(logfile
):
420 if pid
== 0: # Parent
423 if pid
!= 0: # Actual daemon
428 import resource
# Resource usage information.
429 maxfd
= resource
.getrlimit(resource
.RLIMIT_NOFILE
)[1]
430 if maxfd
== resource
.RLIM_INFINITY
:
431 maxfd
= 1024 # Rough guess at maximum number of open file descriptors.
432 for fd
in range(0, maxfd
):
437 os
.open(logfile
, os
.O_RDWR | os
.O_CREAT
)
441 def write_pidfile(fname
):
442 '''write a pid file, cleanup on exit'''
443 f
= open(fname
, mode
='w')
444 f
.write("%u\n" % os
.getpid())
448 def rebase_tree(rebase_url
, rebase_branch
= "master"):
449 rebase_remote
= "rebaseon"
450 print("Rebasing on %s" % rebase_url
)
451 run_cmd("git describe HEAD", show
=True, dir=test_master
)
452 run_cmd("git remote add -t %s %s %s" %
453 (rebase_branch
, rebase_remote
, rebase_url
),
454 show
=True, dir=test_master
)
455 run_cmd("git fetch %s" % rebase_remote
, show
=True, dir=test_master
)
456 if options
.fix_whitespace
:
457 run_cmd("git rebase --force-rebase --whitespace=fix %s/%s" %
458 (rebase_remote
, rebase_branch
),
459 show
=True, dir=test_master
)
461 run_cmd("git rebase --force-rebase %s/%s" %
462 (rebase_remote
, rebase_branch
),
463 show
=True, dir=test_master
)
464 diff
= run_cmd("git --no-pager diff HEAD %s/%s" %
465 (rebase_remote
, rebase_branch
),
466 dir=test_master
, output
=True)
468 print("No differences between HEAD and %s/%s - exiting" %
469 (rebase_remote
, rebase_branch
))
471 run_cmd("git describe %s/%s" %
472 (rebase_remote
, rebase_branch
),
473 show
=True, dir=test_master
)
474 run_cmd("git describe HEAD", show
=True, dir=test_master
)
475 run_cmd("git --no-pager diff --stat HEAD %s/%s" %
476 (rebase_remote
, rebase_branch
),
477 show
=True, dir=test_master
)
479 def push_to(push_url
, push_branch
= "master"):
480 push_remote
= "pushto"
481 print("Pushing to %s" % push_url
)
483 run_cmd("git config --replace-all core.editor script/commit_mark.sh", dir=test_master
)
484 run_cmd("git commit --amend -c HEAD", dir=test_master
)
485 # the notes method doesn't work yet, as metze hasn't allowed refs/notes/* in master
486 # run_cmd("EDITOR=script/commit_mark.sh git notes edit HEAD", dir=test_master)
487 run_cmd("git remote add -t %s %s %s" %
488 (push_branch
, push_remote
, push_url
),
489 show
=True, dir=test_master
)
490 run_cmd("git push %s +HEAD:%s" %
491 (push_remote
, push_branch
),
492 show
=True, dir=test_master
)
494 def_testbase
= os
.getenv("AUTOBUILD_TESTBASE", "/memdisk/%s" % os
.getenv('USER'))
496 gitroot
= find_git_root()
498 raise Exception("Failed to find git root")
500 parser
= OptionParser()
501 parser
.add_option("", "--tail", help="show output while running", default
=False, action
="store_true")
502 parser
.add_option("", "--keeplogs", help="keep logs", default
=False, action
="store_true")
503 parser
.add_option("", "--nocleanup", help="don't remove test tree", default
=False, action
="store_true")
504 parser
.add_option("", "--testbase", help="base directory to run tests in (default %s)" % def_testbase
,
505 default
=def_testbase
)
506 parser
.add_option("", "--passcmd", help="command to run on success", default
=None)
507 parser
.add_option("", "--verbose", help="show all commands as they are run",
508 default
=False, action
="store_true")
509 parser
.add_option("", "--rebase", help="rebase on the given tree before testing",
510 default
=None, type='str')
511 parser
.add_option("", "--pushto", help="push to a git url on success",
512 default
=None, type='str')
513 parser
.add_option("", "--mark", help="add a Tested-By signoff before pushing",
514 default
=False, action
="store_true")
515 parser
.add_option("", "--fix-whitespace", help="fix whitespace on rebase",
516 default
=False, action
="store_true")
517 parser
.add_option("", "--retry", help="automatically retry if master changes",
518 default
=False, action
="store_true")
519 parser
.add_option("", "--email", help="send email to the given address on failure",
520 type='str', default
=None)
521 parser
.add_option("", "--email-from", help="send email from the given address",
522 type='str', default
="autobuild@samba.org")
523 parser
.add_option("", "--email-server", help="send email via the given server",
524 type='str', default
='localhost')
525 parser
.add_option("", "--always-email", help="always send email, even on success",
527 parser
.add_option("", "--daemon", help="daemonize after initial setup",
529 parser
.add_option("", "--branch", help="the branch to work on (default=master)",
530 default
="master", type='str')
531 parser
.add_option("", "--log-base", help="location where the logs can be found (default=cwd)",
532 default
=gitroot
, type='str')
533 parser
.add_option("", "--attach-logs", help="Attach logs to mails sent on success/failure?",
534 default
=False, action
="store_true")
536 def send_email(subject
, text
, log_tar
):
537 outer
= MIMEMultipart()
538 outer
['Subject'] = subject
539 outer
['To'] = options
.email
540 outer
['From'] = options
.email_from
541 outer
['Date'] = email
.utils
.formatdate(localtime
= True)
542 outer
.preamble
= 'Autobuild mails are now in MIME because we optionally attach the logs.\n'
543 outer
.attach(MIMEText(text
, 'plain'))
544 if options
.attach_logs
:
545 fp
= open(log_tar
, 'rb')
546 msg
= MIMEApplication(fp
.read(), 'gzip', email
.encoders
.encode_base64
)
548 # Set the filename parameter
549 msg
.add_header('Content-Disposition', 'attachment', filename
=os
.path
.basename(log_tar
))
551 content
= outer
.as_string()
552 s
= smtplib
.SMTP(options
.email_server
)
553 s
.sendmail(options
.email_from
, [options
.email
], content
)
557 def email_failure(status
, failed_task
, failed_stage
, failed_tag
, errstr
,
558 elapsed_time
, log_base
=None):
559 '''send an email to options.email about the failure'''
560 elapsed_minutes
= elapsed_time
/ 60.0
561 user
= os
.getenv("USER")
567 Your autobuild on %s failed after %.1f minutes
568 when trying to test %s with the following error:
572 the autobuild has been abandoned. Please fix the error and resubmit.
574 A summary of the autobuild process is here:
577 ''' % (platform
.node(), elapsed_minutes
, failed_task
, errstr
, log_base
)
579 if failed_task
!= 'rebase':
581 You can see logs of the failed task here:
586 or you can get full logs of all tasks in this job here:
590 The top commit for the tree that was built was:
594 ''' % (log_base
, failed_tag
, log_base
, failed_tag
, log_base
, top_commit_msg
)
596 logs
= os
.path
.join(gitroot
, 'logs.tar.gz')
597 send_email('autobuild failure on %s for task %s during %s'
598 % (platform
.node(), failed_task
, failed_stage
),
601 def email_success(elapsed_time
, log_base
=None):
602 '''send an email to options.email about a successful build'''
603 user
= os
.getenv("USER")
609 Your autobuild on %s has succeeded after %.1f minutes.
611 ''' % (platform
.node(), elapsed_time
/ 60.)
616 you can get full logs of all tasks in this job here:
623 The top commit for the tree that was built was:
628 logs
= os
.path
.join(gitroot
, 'logs.tar.gz')
629 send_email('autobuild sucess on %s ' % platform
.node(),
633 (options
, args
) = parser
.parse_args()
636 if options
.rebase
is None:
637 raise Exception('You can only use --retry if you also rebase')
639 testbase
= "%s/b%u" % (options
.testbase
, os
.getpid())
640 test_master
= "%s/master" % testbase
642 # get the top commit message, for emails
643 top_commit_msg
= run_cmd("git log -1", dir=gitroot
, output
=True)
646 os
.makedirs(testbase
)
647 except Exception, reason
:
648 raise Exception("Unable to create %s : %s" % (testbase
, reason
))
649 cleanup_list
.append(testbase
)
652 logfile
= os
.path
.join(testbase
, "log")
653 print "Forking into the background, writing progress to %s" % logfile
656 write_pidfile(gitroot
+ "/autobuild.pid")
658 start_time
= time
.time()
662 run_cmd("rm -rf %s" % test_master
)
663 cleanup_list
.append(test_master
)
664 run_cmd("git clone --recursive --shared %s %s" % (gitroot
, test_master
), show
=True, dir=gitroot
)
671 if options
.rebase
is not None:
672 rebase_tree(options
.rebase
, rebase_branch
=options
.branch
)
674 cleanup_list
.append(gitroot
+ "/autobuild.pid")
676 elapsed_time
= time
.time() - start_time
677 email_failure(-1, 'rebase', 'rebase', 'rebase',
678 'rebase on %s failed' % options
.branch
,
679 elapsed_time
, log_base
=options
.log_base
)
681 blist
= buildlist(tasks
, args
, options
.rebase
, rebase_branch
=options
.branch
)
684 (status
, failed_task
, failed_stage
, failed_tag
, errstr
) = blist
.run()
685 if status
!= 0 or errstr
!= "retry":
692 cleanup_list
.append(gitroot
+ "/autobuild.pid")
696 print("waiting for tail to flush")
699 elapsed_time
= time
.time() - start_time
702 if options
.passcmd
is not None:
703 print("Running passcmd: %s" % options
.passcmd
)
704 run_cmd(options
.passcmd
, dir=test_master
)
705 if options
.pushto
is not None:
706 push_to(options
.pushto
, push_branch
=options
.branch
)
707 if options
.keeplogs
or options
.attach_logs
:
708 blist
.tarlogs("logs.tar.gz")
709 print("Logs in logs.tar.gz")
710 if options
.always_email
:
711 email_success(elapsed_time
, log_base
=options
.log_base
)
717 # something failed, gather a tar of the logs
718 blist
.tarlogs("logs.tar.gz")
720 if options
.email
is not None:
721 email_failure(status
, failed_task
, failed_stage
, failed_tag
, errstr
,
722 elapsed_time
, log_base
=options
.log_base
)
726 print("Logs in logs.tar.gz")