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 __future__
import print_function
7 from subprocess
import call
, check_call
, check_output
, Popen
, PIPE
, CalledProcessError
13 from optparse
import OptionParser
16 from email
.mime
.text
import MIMEText
17 from email
.mime
.base
import MIMEBase
18 from email
.mime
.application
import MIMEApplication
19 from email
.mime
.multipart
import MIMEMultipart
20 from distutils
.sysconfig
import get_python_lib
24 from waflib
.Build
import CACHE_SUFFIX
26 sys
.path
.insert(0, "./third_party/waf")
27 from waflib
.Build
import CACHE_SUFFIX
30 os
.environ
["PYTHONUNBUFFERED"] = "1"
32 # This speeds up testing remarkably.
33 os
.environ
['TDB_NO_FSYNC'] = '1'
37 '''get to the top of the git repo'''
40 if os
.path
.exists(os
.path
.join(p
, ".git")):
42 p
= os
.path
.abspath(os
.path
.join(p
, '..'))
46 gitroot
= find_git_root()
48 raise Exception("Failed to find git root")
51 def_testbase
= os
.getenv("AUTOBUILD_TESTBASE", "/memdisk/%s" % os
.getenv('USER'))
53 parser
= OptionParser()
54 parser
.add_option("--tail", help="show output while running", default
=False, action
="store_true")
55 parser
.add_option("--keeplogs", help="keep logs", default
=False, action
="store_true")
56 parser
.add_option("--nocleanup", help="don't remove test tree", default
=False, action
="store_true")
57 parser
.add_option("--skip-dependencies", help="skip to run task dependency tasks", default
=False, action
="store_true")
58 parser
.add_option("--testbase", help="base directory to run tests in (default %s)" % def_testbase
,
60 parser
.add_option("--full-testbase", help="full base directory to run tests in (default %s/b$PID)" % def_testbase
,
62 parser
.add_option("--passcmd", help="command to run on success", default
=None)
63 parser
.add_option("--verbose", help="show all commands as they are run",
64 default
=False, action
="store_true")
65 parser
.add_option("--rebase", help="rebase on the given tree before testing",
66 default
=None, type='str')
67 parser
.add_option("--pushto", help="push to a git url on success",
68 default
=None, type='str')
69 parser
.add_option("--mark", help="add a Tested-By signoff before pushing",
70 default
=False, action
="store_true")
71 parser
.add_option("--fix-whitespace", help="fix whitespace on rebase",
72 default
=False, action
="store_true")
73 parser
.add_option("--retry", help="automatically retry if master changes",
74 default
=False, action
="store_true")
75 parser
.add_option("--email", help="send email to the given address on failure",
76 type='str', default
=None)
77 parser
.add_option("--email-from", help="send email from the given address",
78 type='str', default
="autobuild@samba.org")
79 parser
.add_option("--email-server", help="send email via the given server",
80 type='str', default
='localhost')
81 parser
.add_option("--always-email", help="always send email, even on success",
83 parser
.add_option("--daemon", help="daemonize after initial setup",
85 parser
.add_option("--branch", help="the branch to work on (default=master)",
86 default
="master", type='str')
87 parser
.add_option("--log-base", help="location where the logs can be found (default=cwd)",
88 default
=gitroot
, type='str')
89 parser
.add_option("--attach-logs", help="Attach logs to mails sent on success/failure?",
90 default
=False, action
="store_true")
91 parser
.add_option("--restrict-tests", help="run as make test with this TESTS= regex",
93 parser
.add_option("--enable-coverage", dest
='enable_coverage',
94 action
="store_const", const
='--enable-coverage', default
='',
95 help="Add --enable-coverage option while configure")
97 (options
, args
) = parser
.parse_args()
100 if options
.rebase
is None:
101 raise Exception('You can only use --retry if you also rebase')
103 if options
.full_testbase
is not None:
104 testbase
= options
.full_testbase
106 testbase
= "%s/b%u" % (options
.testbase
, os
.getpid())
107 test_master
= "%s/master" % testbase
108 test_prefix
= "%s/prefix" % testbase
109 test_tmpdir
= "%s/tmp" % testbase
110 os
.environ
['TMPDIR'] = test_tmpdir
112 if options
.enable_coverage
:
113 LCOV_CMD
= "cd ${TEST_SOURCE_DIR} && lcov --capture --directory . --output-file ${LOG_BASE}/${NAME}.info --rc 'geninfo_adjust_src_path=${TEST_SOURCE_DIR}/'"
115 LCOV_CMD
= 'echo "lcov skipped since no --enable-coverage specified"'
117 CLEAN_SOURCE_TREE_CMD
= "cd ${TEST_SOURCE_DIR} && script/clean-source-tree.sh"
120 # If we are only running specific test,
121 # do not sleep randomly to wait for it to start
122 def random_sleep(low
, high
):
125 def random_sleep(low
, high
):
126 return 'sleep {}'.format(random
.randint(low
, high
))
134 "talloc": "lib/talloc",
135 "replace": "lib/replace",
136 "tevent": "lib/tevent",
138 "docs-xml": "docs-xml"
141 ctdb_configure_params
= " --enable-developer ${PREFIX}"
142 samba_configure_params
= " ${ENABLE_COVERAGE} ${PREFIX} --with-profiling-data"
144 samba_libs_envvars
= "PYTHONPATH=${PYTHON_PREFIX}:$PYTHONPATH"
145 samba_libs_envvars
+= " PKG_CONFIG_PATH=$PKG_CONFIG_PATH:${PREFIX_DIR}/lib/pkgconfig"
146 samba_libs_envvars
+= " ADDITIONAL_CFLAGS='-Wmissing-prototypes'"
147 samba_libs_configure_base
= samba_libs_envvars
+ " ./configure --abi-check ${ENABLE_COVERAGE} --enable-debug -C ${PREFIX}"
148 samba_libs_configure_libs
= samba_libs_configure_base
+ " --bundled-libraries=cmocka,popt,NONE"
149 samba_libs_configure_bundled_libs
= " --bundled-libraries=!talloc,!pytalloc-util,!tdb,!pytdb,!ldb,!pyldb,!pyldb-util,!tevent,!pytevent,!popt"
150 samba_libs_configure_samba
= samba_libs_configure_base
+ samba_libs_configure_bundled_libs
153 def format_option(name
, value
=None):
154 """Format option as str list."""
155 if value
is None: # boolean option
157 if not isinstance(value
, list): # single value option
160 return ['{}={}'.format(name
, item
) for item
in value
]
166 INJECT_SELFTEST_PREFIX
=1,
173 test_options
= format_option('--include-env', include_envs
)
175 test_options
= format_option('--exclude-env', exclude_envs
)
177 # join envs options to original test options
178 TESTS
= (TESTS
+ ' ' + ' '.join(test_options
)).strip()
182 _options
.append('FAIL_IMMEDIATELY=1')
184 _options
.append("TESTS='{}'".format(TESTS
))
186 if INJECT_SELFTEST_PREFIX
:
187 _options
.append("TEST_OPTIONS='--with-selftest-prefix={}'".format("${SELFTEST_PREFIX}"))
188 _options
.append("--directory='{}'".format("${TEST_SOURCE_DIR}"))
190 return ' '.join([cmd
] + _options
)
193 # When updating this list, also update .gitlab-ci.yml to add the job
194 # and to make it a dependency of 'page' for the coverage report.
199 ("random-sleep", random_sleep(300, 900)),
200 ("configure", "./configure " + ctdb_configure_params
),
201 ("make", "make all"),
202 ("install", "make install"),
203 ("test", "make autotest"),
204 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
205 ("clean", "make clean"),
210 ("random-sleep", random_sleep(300, 900)),
211 ("autoconf", "autoconf"),
212 ("configure", "./configure"),
213 ("make", "make html htmlman"),
214 ("clean", "make clean"),
219 "git-clone-required": True,
221 ("configure", "./configure.developer" + samba_configure_params
),
223 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
224 ("chmod-R-a-w", "chmod -R a-w ."),
229 "git-clone-required": True,
231 ("configure", "./configure.developer --with-system-mitkrb5 --with-experimental-mit-ad-dc" + samba_configure_params
),
233 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
234 ("chmod-R-a-w", "chmod -R a-w ."),
239 "git-clone-required": True,
241 ("configure", "./configure.developer --without-ad-dc --without-ldap --without-ads --without-json" + samba_configure_params
),
243 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
244 ("chmod-R-a-w", "chmod -R a-w ."),
249 "git-clone-required": True,
251 ("configure", "./configure.developer --without-ad-dc --with-system-heimdalkrb5" + samba_configure_params
),
253 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
254 ("chmod-R-a-w", "chmod -R a-w ."),
258 "samba-no-opath-build": {
259 "git-clone-required": True,
261 ("configure", "ADDITIONAL_CFLAGS='-DDISABLE_OPATH=1' ./configure.developer --without-ad-dc " + samba_configure_params
),
263 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
264 ("chmod-R-a-w", "chmod -R a-w ."),
268 # We have 'test' before 'install' because, 'test' should work without 'install (runs all the other envs)'
271 ("random-sleep", random_sleep(300, 900)),
272 ("configure", "./configure.developer" + samba_configure_params
),
274 ("test", make_test(exclude_envs
=[
287 "ad_dc_default_smb1",
295 "ad_member_idmap_rid",
296 "ad_member_idmap_ad",
303 "fileserver_smb1_done",
317 "ad_dc_default_smb1",
318 "ad_dc_default_smb1_done",
324 ("test-slow-none", make_test(cmd
='make test', TESTS
="--include=selftest/slow-none", include_envs
=["none"])),
326 ("install", "make install"),
327 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
328 ("clean", "make clean"),
332 # We have 'test' before 'install' because, 'test' should work without 'install (runs all the other envs)'
335 ("random-sleep", random_sleep(300, 900)),
336 ("configure", "./configure.developer --with-system-mitkrb5 --with-experimental-mit-ad-dc" + samba_configure_params
),
338 ("test", make_test(exclude_envs
=[
351 "ad_dc_default_smb1",
352 "ad_dc_default_smb1_done",
360 "ad_member_idmap_rid",
361 "ad_member_idmap_ad",
368 "fileserver_smb1_done",
382 "ad_dc_default_smb1",
383 "ad_dc_default_smb1_done",
390 ("install", "make install"),
391 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
392 ("clean", "make clean"),
397 "dependency": "samba-nt4-build",
399 ("random-sleep", random_sleep(300, 900)),
400 ("test", make_test(include_envs
=[
409 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
413 "samba-fileserver": {
414 "dependency": "samba-h5l-build",
416 ("random-sleep", random_sleep(300, 900)),
417 ("test", make_test(include_envs
=[
420 "fileserver_smb1_done",
422 "ktest", # ktest is also tested in samba and samba-mitkrb5
423 # but is tested here against a system Heimdal
426 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
431 "dependency": "samba-def-build",
433 ("random-sleep", random_sleep(300, 900)),
434 ("test", make_test(include_envs
=[
436 "ad_member_idmap_rid",
437 "ad_member_idmap_ad",
441 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
446 "dependency": "samba-no-opath-build",
448 ("random-sleep", random_sleep(300, 900)),
450 cmd
="make test DISABLE_OPATH=1",
460 "fileserver_smb1_done",
463 ("check-clean-tree", "script/clean-source-tree.sh"),
468 "dependency": "samba-def-build",
470 ("random-sleep", random_sleep(1, 1)),
471 ("test", make_test(include_envs
=[
479 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
484 "dependency": "samba-def-build",
486 ("random-sleep", random_sleep(1, 1)),
487 ("test", make_test(include_envs
=[
493 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
498 "dependency": "samba-def-build",
500 ("random-sleep", random_sleep(1, 1)),
501 ("test", make_test(include_envs
=[
508 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
513 "dependency": "samba-def-build",
515 ("random-sleep", random_sleep(1, 1)),
516 ("test", make_test(include_envs
=[
523 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
528 "dependency": "samba-def-build",
530 ("random-sleep", random_sleep(1, 1)),
531 ("test", make_test(include_envs
=[
532 "ad_dc_default", "ad_dc_default_smb1", "ad_dc_default_smb1_done"])),
534 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
539 "dependency": "samba-def-build",
541 ("random-sleep", random_sleep(1, 1)),
542 ("test", make_test(include_envs
=["ad_dc_slowtests", "ad_dc_backup"])),
544 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
548 "samba-schemaupgrade": {
549 "dependency": "samba-def-build",
551 ("random-sleep", random_sleep(1, 1)),
552 ("test", make_test(include_envs
=["schema_dc", "schema_pair_dc"])),
554 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
558 # We split out the ad_dc_ntvfs tests (which are long) so other test do not wait
559 # This is currently the longest task, so we don't randomly delay it.
560 "samba-ad-dc-ntvfs": {
561 "dependency": "samba-def-build",
563 ("random-sleep", random_sleep(1, 1)),
564 ("test", make_test(include_envs
=["ad_dc_ntvfs"])),
566 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
570 # Test fips compliance
572 "dependency": "samba-mit-build",
574 ("random-sleep", random_sleep(1, 1)),
575 ("test", make_test(include_envs
=["ad_dc_fips", "ad_member_fips"])),
576 # TODO: This seems to generate only an empty samba-fips.info ("lcov", LCOV_CMD),
577 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
581 # run the backup/restore testenvs separately as they're fairly standalone
582 # (and CI seems to max out at ~3 different DCs running at once)
584 "dependency": "samba-def-build",
586 ("random-sleep", random_sleep(300, 900)),
587 ("test", make_test(include_envs
=[
593 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
597 "dependency": "samba-def-build",
599 ("random-sleep", random_sleep(300, 900)),
600 ("test", make_test(include_envs
=[
606 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
611 "dependency": "samba-mit-build",
613 ("random-sleep", random_sleep(1, 1)),
614 ("test", make_test(include_envs
=[
616 "ad_member_idmap_rid",
617 "ad_member_idmap_ad",
621 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
625 "samba-ad-dc-1-mitkrb5": {
626 "dependency": "samba-mit-build",
628 ("random-sleep", random_sleep(1, 1)),
629 ("test", make_test(include_envs
=[
637 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
641 "samba-ad-dc-4-mitkrb5": {
642 "dependency": "samba-mit-build",
644 ("random-sleep", random_sleep(1, 1)),
645 ("test", make_test(include_envs
=[
652 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
658 ("configure", "./configure.developer --abi-check-disable" + samba_configure_params
),
660 ("test", make_test(TESTS
="${TESTS}")),
665 # Test cross-compile infrastructure
668 ("random-sleep", random_sleep(900, 1500)),
669 ("configure-native", "./configure.developer --with-selftest-prefix=./bin/ab" + samba_configure_params
),
670 ("configure-cross-execute", "./configure.developer --out ./bin-xe --cross-compile --cross-execute=script/identity_cc.sh" \
671 " --cross-answers=./bin-xe/cross-answers.txt --with-selftest-prefix=./bin-xe/ab" + samba_configure_params
),
672 ("verify-cross-execute-output", "grep '^Checking value of NSIG' ./bin-xe/cross-answers.txt"),
673 ("configure-cross-answers", "./configure.developer --out ./bin-xa --cross-compile" \
674 " --cross-answers=./bin-xe/cross-answers.txt --with-selftest-prefix=./bin-xa/ab" + samba_configure_params
),
675 ("compare-results", "script/compare_cc_results.py "
676 "./bin/c4che/default{} "
677 "./bin-xe/c4che/default{} "
678 "./bin-xa/c4che/default{}".format(*([CACHE_SUFFIX
]*3))),
679 ("modify-cross-answers", "sed -i.bak -e 's/^\\(Checking value of NSIG:\\) .*/\\1 \"1234\"/' ./bin-xe/cross-answers.txt"),
680 ("configure-cross-answers-modified", "./configure.developer --out ./bin-xa2 --cross-compile" \
681 " --cross-answers=./bin-xe/cross-answers.txt --with-selftest-prefix=./bin-xa2/ab" + samba_configure_params
),
682 ("verify-cross-answers", "test $(sed -n -e 's/VALUEOF_NSIG = \\(.*\\)/\\1/p' ./bin-xa2/c4che/default{})" \
683 " = \"'1234'\"".format(CACHE_SUFFIX
)),
684 ("invalidate-cross-answers", "sed -i.bak -e '/^Checking value of NSIG/d' ./bin-xe/cross-answers.txt"),
685 ("configure-cross-answers-fail", "./configure.developer --out ./bin-xa3 --cross-compile" \
686 " --cross-answers=./bin-xe/cross-answers.txt --with-selftest-prefix=./bin-xa3/ab" + samba_configure_params
+ \
691 # test build with -O3 -- catches extra warnings and bugs, tests the ad_dc environments
694 ("random-sleep", random_sleep(300, 900)),
695 ("configure", "ADDITIONAL_CFLAGS='-O3 -Wp,-D_FORTIFY_SOURCE=2' ./configure.developer --abi-check-disable" + samba_configure_params
),
697 ("test", make_test(cmd
='make test', TESTS
="--exclude=selftest/slow-none", include_envs
=["none"])),
698 ("quicktest", make_test(cmd
='make quicktest', include_envs
=["ad_dc", "ad_dc_smb1", "ad_dc_smb1_done"])),
700 ("install", "make install"),
701 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
702 ("clean", "make clean"),
708 ("random-sleep", random_sleep(900, 1500)),
710 # make sure we have tdb around:
711 ("tdb-configure", "cd lib/tdb && PYTHONPATH=${PYTHON_PREFIX}:$PYTHONPATH PKG_CONFIG_PATH=$PKG_CONFIG_PATH:${PREFIX_DIR}/lib/pkgconfig ./configure --bundled-libraries=NONE --abi-check --enable-debug -C ${PREFIX}"),
712 ("tdb-make", "cd lib/tdb && make"),
713 ("tdb-install", "cd lib/tdb && make install"),
715 # build samba with cluster support (also building ctdb):
717 "PYTHONPATH=${PYTHON_PREFIX}:$PYTHONPATH "
718 "PKG_CONFIG_PATH=${PREFIX_DIR}/lib/pkgconfig:${PKG_CONFIG_PATH} "
719 "./configure.developer ${PREFIX} "
720 "--with-selftest-prefix=./bin/ab "
722 "--with-cluster-support "
724 "--bundled-libraries=!tdb"),
725 ("samba-make", "make"),
726 ("samba-check", "./bin/smbd -b | grep CLUSTER_SUPPORT"),
727 ("samba-install", "make install"),
728 ("ctdb-check", "test -e ${PREFIX_DIR}/sbin/ctdbd"),
732 INJECT_SELFTEST_PREFIX
=0,
733 include_envs
=["clusteredmember"])
737 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
738 ("clean", "make clean"),
739 ("ctdb-clean", "cd ./ctdb && make clean"),
745 ("random-sleep", random_sleep(300, 900)),
746 ("talloc-configure", "cd lib/talloc && " + samba_libs_configure_libs
),
747 ("talloc-make", "cd lib/talloc && make"),
748 ("talloc-install", "cd lib/talloc && make install"),
750 ("tdb-configure", "cd lib/tdb && " + samba_libs_configure_libs
),
751 ("tdb-make", "cd lib/tdb && make"),
752 ("tdb-install", "cd lib/tdb && make install"),
754 ("tevent-configure", "cd lib/tevent && " + samba_libs_configure_libs
),
755 ("tevent-make", "cd lib/tevent && make"),
756 ("tevent-install", "cd lib/tevent && make install"),
758 ("ldb-configure", "cd lib/ldb && " + samba_libs_configure_libs
),
759 ("ldb-make", "cd lib/ldb && make"),
760 ("ldb-install", "cd lib/ldb && make install"),
762 ("nondevel-configure", "./configure ${PREFIX}"),
763 ("nondevel-make", "make -j"),
764 ("nondevel-check", "./bin/smbd -b | grep WITH_NTVFS_FILESERVER && exit 1; exit 0"),
765 ("nondevel-install", "make install"),
766 ("nondevel-dist", "make dist"),
768 # retry with all modules shared
769 ("allshared-distclean", "make distclean"),
770 ("allshared-configure", samba_libs_configure_samba
+ " --with-shared-modules=ALL"),
771 ("allshared-make", "make -j"),
777 # build the fuzzers (static) via the oss-fuzz script
778 ("fuzzers-mkdir-prefix", "mkdir -p ${PREFIX_DIR}"),
779 ("fuzzers-build", "OUT=${PREFIX_DIR} LIB_FUZZING_ENGINE= SANITIZER=address CXX= CFLAGS= ADDITIONAL_LDFLAGS='-fuse-ld=bfd' ./lib/fuzzing/oss-fuzz/build_samba.sh --enable-afl-fuzzer"),
783 # * Test smbd and smbtorture can build semi-static
785 # * Test Samba without python still builds.
787 # When this test fails due to more use of Python, the expectations
788 # is that the newly failing part of the code should be disabled
789 # when --disable-python is set (rather than major work being done
790 # to support this environment).
792 # The target here is for vendors shipping a minimal smbd.
793 "samba-minimal-smbd": {
795 ("random-sleep", random_sleep(300, 900)),
797 # build with all modules static
798 ("allstatic-configure", "./configure.developer " + samba_configure_params
+ " --with-static-modules=ALL"),
799 ("allstatic-make", "make -j"),
800 ("allstatic-test", make_test(TESTS
="samba3.smb2.create.*nt4_dc")),
803 # retry with nonshared smbd and smbtorture
804 ("nonshared-distclean", "make distclean"),
805 ("nonshared-configure", "./configure.developer " + samba_configure_params
+ " --bundled-libraries=ALL --with-static-modules=ALL --nonshared-binary=smbtorture,smbd/smbd"),
806 ("nonshared-make", "make -j"),
808 ("configure", "./configure.developer ${ENABLE_COVERAGE} ${PREFIX} --with-profiling-data --disable-python --without-ad-dc"),
810 ("find-python", "script/find_python.sh ${PREFIX}"),
811 ("test", "make test-nopython"),
813 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
814 ("clean", "make clean"),
816 ("talloc-configure", "cd lib/talloc && " + samba_libs_configure_base
+ " --bundled-libraries=cmocka,NONE --disable-python"),
817 ("talloc-make", "cd lib/talloc && make"),
818 ("talloc-install", "cd lib/talloc && make install"),
820 ("tdb-configure", "cd lib/tdb && " + samba_libs_configure_base
+ " --bundled-libraries=cmocka,NONE --disable-python"),
821 ("tdb-make", "cd lib/tdb && make"),
822 ("tdb-install", "cd lib/tdb && make install"),
824 ("tevent-configure", "cd lib/tevent && " + samba_libs_configure_base
+ " --bundled-libraries=cmocka,NONE --disable-python"),
825 ("tevent-make", "cd lib/tevent && make"),
826 ("tevent-install", "cd lib/tevent && make install"),
828 ("ldb-configure", "cd lib/ldb && " + samba_libs_configure_base
+ " --bundled-libraries=cmocka,NONE --disable-python"),
829 ("ldb-make", "cd lib/ldb && make"),
830 ("ldb-install", "cd lib/ldb && make install"),
832 # retry against installed library packages, but no required modules
833 ("libs-configure", samba_libs_configure_base
+ samba_libs_configure_bundled_libs
+ " --disable-python --without-ad-dc --with-static-modules=!FORCED,!DEFAULT --with-shared-modules=!FORCED,!DEFAULT"),
834 ("libs-make", "make -j"),
835 ("libs-install", "make install"),
836 ("libs-check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
837 ("libs-clean", "make clean"),
844 ("random-sleep", random_sleep(60, 600)),
845 ("configure", "./configure ${ENABLE_COVERAGE} --enable-developer -C ${PREFIX}"),
847 ("install", "make install"),
848 ("test", "make test"),
850 ("clean", "make clean"),
851 ("configure-no-lmdb", "./configure ${ENABLE_COVERAGE} --enable-developer --without-ldb-lmdb -C ${PREFIX}"),
852 ("make-no-lmdb", "make"),
853 ("test-no-lmdb", "make test"),
854 ("lcov-no-lmdb", LCOV_CMD
),
855 ("install-no-lmdb", "make install"),
856 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
857 ("distcheck", "make distcheck"),
858 ("clean", "make clean"),
864 ("random-sleep", random_sleep(60, 600)),
865 ("configure", "./configure ${ENABLE_COVERAGE} --enable-developer -C ${PREFIX}"),
867 ("install", "make install"),
868 ("test", "make test"),
870 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
871 ("distcheck", "make distcheck"),
872 ("clean", "make clean"),
878 ("random-sleep", random_sleep(60, 600)),
879 ("configure", "./configure ${ENABLE_COVERAGE} --enable-developer -C ${PREFIX}"),
881 ("install", "make install"),
882 ("test", "make test"),
884 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
885 ("distcheck", "make distcheck"),
886 ("clean", "make clean"),
892 ("random-sleep", random_sleep(60, 600)),
893 ("configure", "./configure ${ENABLE_COVERAGE} --enable-developer -C ${PREFIX}"),
895 ("install", "make install"),
896 ("test", "make test"),
898 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
899 ("distcheck", "make distcheck"),
900 ("clean", "make clean"),
906 ("random-sleep", random_sleep(60, 600)),
907 ("configure", "./configure ${ENABLE_COVERAGE} --enable-developer -C ${PREFIX}"),
909 ("install", "make install"),
910 ("test", "make test"),
912 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
913 ("distcheck", "make distcheck"),
914 ("clean", "make clean"),
919 "git-clone-required": True,
921 ("random-sleep", random_sleep(60, 600)),
922 ("configure", "perl Makefile.PL PREFIX=${PREFIX_DIR}"),
923 ("touch", "touch *.yp"),
925 ("test", "make test"),
926 ("install", "make install"),
927 ("checkout-yapp-generated", "git checkout lib/Parse/Pidl/IDL.pm lib/Parse/Pidl/Expr.pm"),
928 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
929 ("clean", "make clean"),
933 # these are useful for debugging autobuild
936 ("pass", 'echo passing && /bin/true'),
941 ("fail", 'echo failing && /bin/false'),
946 defaulttasks
= list(tasks
.keys())
948 defaulttasks
.remove("pass")
949 defaulttasks
.remove("fail")
950 defaulttasks
.remove("samba-def-build")
951 defaulttasks
.remove("samba-nt4-build")
952 defaulttasks
.remove("samba-mit-build")
953 defaulttasks
.remove("samba-h5l-build")
954 defaulttasks
.remove("samba-no-opath-build")
955 defaulttasks
.remove("samba-test-only")
956 defaulttasks
.remove("samba-fuzz")
957 defaulttasks
.remove("samba-fips")
958 if os
.environ
.get("AUTOBUILD_SKIP_SAMBA_O3", "0") == "1":
959 defaulttasks
.remove("samba-o3")
968 def run_cmd(cmd
, dir=".", show
=None, output
=False, checkfail
=True):
970 show
= options
.verbose
972 do_print("Running: '%s' in '%s'" % (cmd
, dir))
974 out
= check_output([cmd
], shell
=True, cwd
=dir)
975 return out
.decode(encoding
='utf-8', errors
='backslashreplace')
977 return check_call(cmd
, shell
=True, cwd
=dir)
979 return call(cmd
, shell
=True, cwd
=dir)
981 def rmdir_force(dirname
, re_raise
=True):
983 run_cmd("test -d %s && chmod -R +w %s; rm -rf %s" % (
984 dirname
, dirname
, dirname
), output
=True, show
=True)
985 except CalledProcessError
as e
:
986 do_print("Failed: '%s'" % (str(e
)))
987 run_cmd("tree %s" % dirname
, output
=True, show
=True)
993 class builder(object):
994 '''handle build of one directory'''
996 def __init__(self
, name
, definition
):
998 self
.dir = builddirs
.get(name
, '.')
999 self
.tag
= self
.name
.replace('/', '_')
1000 self
.definition
= definition
1001 self
.sequence
= definition
["sequence"]
1002 self
.git_clone_required
= False
1003 if "git-clone-required" in definition
:
1004 self
.git_clone_required
= bool(definition
["git-clone-required"])
1008 self
.stdout_path
= "%s/%s.stdout" % (gitroot
, self
.tag
)
1009 self
.stderr_path
= "%s/%s.stderr" % (gitroot
, self
.tag
)
1011 do_print("stdout for %s in %s" % (self
.name
, self
.stdout_path
))
1012 do_print("stderr for %s in %s" % (self
.name
, self
.stderr_path
))
1013 run_cmd("rm -f %s %s" % (self
.stdout_path
, self
.stderr_path
))
1014 self
.stdout
= open(self
.stdout_path
, 'w')
1015 self
.stderr
= open(self
.stderr_path
, 'w')
1016 self
.stdin
= open("/dev/null", 'r')
1017 self
.builder_dir
= "%s/%s" % (testbase
, self
.tag
)
1018 self
.test_source_dir
= self
.builder_dir
1019 self
.cwd
= "%s/%s" % (self
.builder_dir
, self
.dir)
1020 self
.selftest_prefix
= "%s/bin/ab" % (self
.cwd
)
1021 self
.prefix
= "%s/%s" % (test_prefix
, self
.tag
)
1023 self
.producer
= None
1025 if self
.git_clone_required
:
1026 assert "dependency" not in definition
1028 def mark_existing(self
):
1029 do_print('%s: Mark as existing dependency' % self
.name
)
1030 self
.next
= len(self
.sequence
)
1033 def add_consumer(self
, consumer
):
1034 do_print("%s: add consumer: %s" % (self
.name
, consumer
.name
))
1035 consumer
.producer
= self
1036 consumer
.test_source_dir
= self
.test_source_dir
1037 self
.consumers
.append(consumer
)
1039 def start_next(self
):
1040 if self
.producer
is not None:
1041 if not self
.producer
.done
:
1042 do_print("%s: Waiting for producer: %s" % (self
.name
, self
.producer
.name
))
1046 rmdir_force(self
.builder_dir
)
1047 rmdir_force(self
.prefix
)
1048 if self
.producer
is not None:
1049 run_cmd("mkdir %s" % (self
.builder_dir
), dir=test_master
, show
=True)
1050 elif not self
.git_clone_required
:
1051 run_cmd("cp -R -a -l %s %s" % (test_master
, self
.builder_dir
), dir=test_master
, show
=True)
1053 run_cmd("git clone --recursive --shared %s %s" % (test_master
, self
.builder_dir
), dir=test_master
, show
=True)
1055 if self
.next
== len(self
.sequence
):
1057 do_print('%s: Completed OK' % self
.name
)
1059 if not options
.nocleanup
and len(self
.consumers
) == 0:
1060 do_print('%s: Cleaning up' % self
.name
)
1061 rmdir_force(self
.builder_dir
)
1062 rmdir_force(self
.prefix
)
1063 for consumer
in self
.consumers
:
1064 if consumer
.next
!= 0:
1066 do_print('%s: Starting consumer %s' % (self
.name
, consumer
.name
))
1067 consumer
.start_next()
1068 if self
.producer
is not None:
1069 self
.producer
.consumers
.remove(self
)
1070 assert self
.producer
.done
1071 self
.producer
.start_next()
1072 do_print('%s: Remaining consumers %u' % (self
.name
, len(self
.consumers
)))
1074 (self
.stage
, self
.cmd
) = self
.sequence
[self
.next
]
1075 self
.cmd
= self
.cmd
.replace("${PYTHON_PREFIX}", get_python_lib(plat_specific
=1, standard_lib
=0, prefix
=self
.prefix
))
1076 self
.cmd
= self
.cmd
.replace("${PREFIX}", "--prefix=%s" % self
.prefix
)
1077 self
.cmd
= self
.cmd
.replace("${PREFIX_DIR}", "%s" % self
.prefix
)
1078 self
.cmd
= self
.cmd
.replace("${TESTS}", options
.restrict_tests
)
1079 self
.cmd
= self
.cmd
.replace("${TEST_SOURCE_DIR}", self
.test_source_dir
)
1080 self
.cmd
= self
.cmd
.replace("${SELFTEST_PREFIX}", self
.selftest_prefix
)
1081 self
.cmd
= self
.cmd
.replace("${LOG_BASE}", options
.log_base
)
1082 self
.cmd
= self
.cmd
.replace("${NAME}", self
.name
)
1083 self
.cmd
= self
.cmd
.replace("${ENABLE_COVERAGE}", options
.enable_coverage
)
1084 do_print('%s: [%s] Running %s in %r' % (self
.name
, self
.stage
, self
.cmd
, self
.cwd
))
1085 self
.proc
= Popen(self
.cmd
, shell
=True,
1086 close_fds
=True, cwd
=self
.cwd
,
1087 stdout
=self
.stdout
, stderr
=self
.stderr
, stdin
=self
.stdin
)
1090 def expand_dependencies(n
):
1092 if "dependency" in tasks
[n
]:
1093 depname
= tasks
[n
]["dependency"]
1094 assert depname
in tasks
1095 sdeps
= expand_dependencies(depname
)
1096 assert n
not in sdeps
1099 deps
.append(depname
)
1103 class buildlist(object):
1104 '''handle build of multiple directories'''
1106 def __init__(self
, tasknames
, rebase_url
, rebase_branch
="master"):
1107 self
.tail_proc
= None
1110 if options
.restrict_tests
:
1111 tasknames
= ["samba-test-only"]
1113 tasknames
= defaulttasks
1115 given_tasknames
= tasknames
.copy()
1116 implicit_tasknames
= []
1117 for n
in given_tasknames
:
1118 deps
= expand_dependencies(n
)
1120 if dep
in given_tasknames
:
1122 if dep
in implicit_tasknames
:
1124 implicit_tasknames
.append(dep
)
1126 tasknames
= implicit_tasknames
.copy()
1127 tasknames
.extend(given_tasknames
)
1128 do_print("given_tasknames: %s" % given_tasknames
)
1129 do_print("implicit_tasknames: %s" % implicit_tasknames
)
1130 do_print("tasknames: %s" % tasknames
)
1131 self
.tlist
= [builder(n
, tasks
[n
]) for n
in tasknames
]
1134 rebase_remote
= "rebaseon"
1136 "git-clone-required": True,
1140 git remote add -t %s %s %s
1144 git describe %s/%s > old_remote_branch.desc
1146 git describe %s/%s > remote_branch.desc
1147 diff old_remote_branch.desc remote_branch.desc
1150 rebase_branch
, rebase_remote
, rebase_url
,
1152 rebase_remote
, rebase_branch
,
1154 rebase_remote
, rebase_branch
1157 self
.retry
= builder('retry', retry_task
)
1158 self
.need_retry
= False
1160 if options
.skip_dependencies
:
1161 for b
in self
.tlist
:
1162 if b
.name
in implicit_tasknames
:
1165 for b
in self
.tlist
:
1166 do_print("b.name=%s" % b
.name
)
1167 if "dependency" not in b
.definition
:
1169 depname
= b
.definition
["dependency"]
1170 do_print("b.name=%s: dependency:%s" % (b
.name
, depname
))
1171 for p
in self
.tlist
:
1172 if p
.name
== depname
:
1175 def kill_kids(self
):
1176 if self
.tail_proc
is not None:
1177 self
.tail_proc
.terminate()
1178 self
.tail_proc
.wait()
1179 self
.tail_proc
= None
1180 if self
.retry
is not None:
1181 self
.retry
.proc
.terminate()
1182 self
.retry
.proc
.wait()
1184 for b
in self
.tlist
:
1185 if b
.proc
is not None:
1186 run_cmd("killbysubdir %s > /dev/null 2>&1" % b
.test_source_dir
, checkfail
=False)
1194 for b
in self
.tlist
:
1197 none_running
= False
1198 b
.status
= b
.proc
.poll()
1199 if b
.status
is None:
1204 ret
= self
.retry
.proc
.poll()
1206 self
.need_retry
= True
1214 for b
in self
.tlist
:
1217 self
.retry
.start_next()
1220 if options
.retry
and self
.need_retry
:
1222 do_print("retry needed")
1223 return (0, None, None, None, "retry")
1226 if os
.WIFSIGNALED(b
.status
) or os
.WEXITSTATUS(b
.status
) != 0:
1228 return (b
.status
, b
.name
, b
.stage
, b
.tag
, "%s: [%s] failed '%s' with status %d" % (b
.name
, b
.stage
, b
.cmd
, b
.status
))
1231 return (0, None, None, None, "All OK")
1233 def write_system_info(self
, filename
):
1234 with
open(filename
, 'w') as f
:
1235 for cmd
in ['uname -a',
1239 'cat /proc/cpuinfo',
1242 'df -m %s' % testbase
]:
1244 out
= run_cmd(cmd
, output
=True, checkfail
=False)
1245 except CalledProcessError
as e
:
1246 out
= "<failed: %s>" % str(e
)
1247 print('### %s' % cmd
, file=f
)
1251 def tarlogs(self
, fname
):
1252 with tarfile
.open(fname
, "w:gz") as tar
:
1253 for b
in self
.tlist
:
1254 tar
.add(b
.stdout_path
, arcname
="%s.stdout" % b
.tag
)
1255 tar
.add(b
.stderr_path
, arcname
="%s.stderr" % b
.tag
)
1256 if os
.path
.exists("autobuild.log"):
1257 tar
.add("autobuild.log")
1258 filename
= 'system-info.txt'
1259 self
.write_system_info(filename
)
1262 def remove_logs(self
):
1263 for b
in self
.tlist
:
1264 os
.unlink(b
.stdout_path
)
1265 os
.unlink(b
.stderr_path
)
1267 def start_tail(self
):
1268 cmd
= ["tail", "-f"]
1269 for b
in self
.tlist
:
1270 cmd
.append(b
.stdout_path
)
1271 cmd
.append(b
.stderr_path
)
1272 self
.tail_proc
= Popen(cmd
, close_fds
=True)
1275 def cleanup(do_raise
=False):
1276 if options
.nocleanup
:
1278 run_cmd("stat %s || true" % test_tmpdir
, show
=True)
1279 run_cmd("stat %s" % testbase
, show
=True)
1280 do_print("Cleaning up %r" % cleanup_list
)
1281 for d
in cleanup_list
:
1282 ok
= rmdir_force(d
, re_raise
=False)
1285 if os
.path
.isdir(d
):
1286 do_print("Killing, waiting and retry")
1287 run_cmd("killbysubdir %s > /dev/null 2>&1" % d
, checkfail
=False)
1289 do_print("Waiting and retry")
1291 rmdir_force(d
, re_raise
=do_raise
)
1294 def daemonize(logfile
):
1296 if pid
== 0: # Parent
1299 if pid
!= 0: # Actual daemon
1304 import resource
# Resource usage information.
1305 maxfd
= resource
.getrlimit(resource
.RLIMIT_NOFILE
)[1]
1306 if maxfd
== resource
.RLIM_INFINITY
:
1307 maxfd
= 1024 # Rough guess at maximum number of open file descriptors.
1308 for fd
in range(0, maxfd
):
1313 os
.open(logfile
, os
.O_RDWR | os
.O_CREAT
)
1318 def write_pidfile(fname
):
1319 '''write a pid file, cleanup on exit'''
1320 with
open(fname
, mode
='w') as f
:
1321 f
.write("%u\n" % os
.getpid())
1324 def rebase_tree(rebase_url
, rebase_branch
="master"):
1325 rebase_remote
= "rebaseon"
1326 do_print("Rebasing on %s" % rebase_url
)
1327 run_cmd("git describe HEAD", show
=True, dir=test_master
)
1328 run_cmd("git remote add -t %s %s %s" %
1329 (rebase_branch
, rebase_remote
, rebase_url
),
1330 show
=True, dir=test_master
)
1331 run_cmd("git fetch %s" % rebase_remote
, show
=True, dir=test_master
)
1332 if options
.fix_whitespace
:
1333 run_cmd("git rebase --force-rebase --whitespace=fix %s/%s" %
1334 (rebase_remote
, rebase_branch
),
1335 show
=True, dir=test_master
)
1337 run_cmd("git rebase --force-rebase %s/%s" %
1338 (rebase_remote
, rebase_branch
),
1339 show
=True, dir=test_master
)
1340 diff
= run_cmd("git --no-pager diff HEAD %s/%s" %
1341 (rebase_remote
, rebase_branch
),
1342 dir=test_master
, output
=True)
1344 do_print("No differences between HEAD and %s/%s - exiting" %
1345 (rebase_remote
, rebase_branch
))
1347 run_cmd("git describe %s/%s" %
1348 (rebase_remote
, rebase_branch
),
1349 show
=True, dir=test_master
)
1350 run_cmd("git describe HEAD", show
=True, dir=test_master
)
1351 run_cmd("git --no-pager diff --stat HEAD %s/%s" %
1352 (rebase_remote
, rebase_branch
),
1353 show
=True, dir=test_master
)
1356 def push_to(push_url
, push_branch
="master"):
1357 push_remote
= "pushto"
1358 do_print("Pushing to %s" % push_url
)
1360 run_cmd("git config --replace-all core.editor script/commit_mark.sh", dir=test_master
)
1361 run_cmd("git commit --amend -c HEAD", dir=test_master
)
1362 # the notes method doesn't work yet, as metze hasn't allowed refs/notes/* in master
1363 # run_cmd("EDITOR=script/commit_mark.sh git notes edit HEAD", dir=test_master)
1364 run_cmd("git remote add -t %s %s %s" %
1365 (push_branch
, push_remote
, push_url
),
1366 show
=True, dir=test_master
)
1367 run_cmd("git push %s +HEAD:%s" %
1368 (push_remote
, push_branch
),
1369 show
=True, dir=test_master
)
1372 def send_email(subject
, text
, log_tar
):
1373 if options
.email
is None:
1374 do_print("not sending email because the recipient is not set")
1375 do_print("the text content would have been:\n\nSubject: %s\n\n%s" %
1378 outer
= MIMEMultipart()
1379 outer
['Subject'] = subject
1380 outer
['To'] = options
.email
1381 outer
['From'] = options
.email_from
1382 outer
['Date'] = email
.utils
.formatdate(localtime
=True)
1383 outer
.preamble
= 'Autobuild mails are now in MIME because we optionally attach the logs.\n'
1384 outer
.attach(MIMEText(text
, 'plain', 'utf-8'))
1385 if options
.attach_logs
:
1386 with
open(log_tar
, 'rb') as fp
:
1387 msg
= MIMEApplication(fp
.read(), 'gzip', email
.encoders
.encode_base64
)
1388 # Set the filename parameter
1389 msg
.add_header('Content-Disposition', 'attachment', filename
=os
.path
.basename(log_tar
))
1391 content
= outer
.as_string()
1392 s
= smtplib
.SMTP(options
.email_server
)
1393 email_user
= os
.getenv('SMTP_USERNAME')
1394 email_password
= os
.getenv('SMTP_PASSWORD')
1395 if email_user
is not None:
1397 s
.login(email_user
, email_password
)
1399 s
.sendmail(options
.email_from
, [options
.email
], content
)
1404 def email_failure(status
, failed_task
, failed_stage
, failed_tag
, errstr
,
1405 elapsed_time
, log_base
=None, add_log_tail
=True):
1406 '''send an email to options.email about the failure'''
1407 elapsed_minutes
= elapsed_time
/ 60.0
1408 if log_base
is None:
1413 Your autobuild on %s failed after %.1f minutes
1414 when trying to test %s with the following error:
1418 the autobuild has been abandoned. Please fix the error and resubmit.
1420 A summary of the autobuild process is here:
1423 ''' % (platform
.node(), elapsed_minutes
, failed_task
, errstr
, log_base
)
1425 if options
.restrict_tests
:
1427 The build was restricted to tests matching %s\n""" % options
.restrict_tests
1429 if failed_task
!= 'rebase':
1431 You can see logs of the failed task here:
1436 or you can get full logs of all tasks in this job here:
1440 The top commit for the tree that was built was:
1444 ''' % (log_base
, failed_tag
, log_base
, failed_tag
, log_base
, top_commit_msg
)
1447 f
= open("%s/%s.stdout" % (gitroot
, failed_tag
), 'r')
1448 lines
= f
.readlines()
1449 log_tail
= "".join(lines
[-50:])
1450 num_lines
= len(lines
)
1452 # Also include stderr (compile failures) if < 50 lines of stdout
1453 f
= open("%s/%s.stderr" % (gitroot
, failed_tag
), 'r')
1454 log_tail
+= "".join(f
.readlines()[-(50 - num_lines
):])
1457 The last 50 lines of log messages:
1463 logs
= os
.path
.join(gitroot
, 'logs.tar.gz')
1464 send_email('autobuild[%s] failure on %s for task %s during %s'
1465 % (options
.branch
, platform
.node(), failed_task
, failed_stage
),
1469 def email_success(elapsed_time
, log_base
=None):
1470 '''send an email to options.email about a successful build'''
1471 if log_base
is None:
1476 Your autobuild on %s has succeeded after %.1f minutes.
1478 ''' % (platform
.node(), elapsed_time
/ 60.)
1480 if options
.restrict_tests
:
1482 The build was restricted to tests matching %s\n""" % options
.restrict_tests
1484 if options
.keeplogs
:
1487 you can get full logs of all tasks in this job here:
1494 The top commit for the tree that was built was:
1497 ''' % top_commit_msg
1499 logs
= os
.path
.join(gitroot
, 'logs.tar.gz')
1500 send_email('autobuild[%s] success on %s' % (options
.branch
, platform
.node()),
1504 # get the top commit message, for emails
1505 top_commit_msg
= run_cmd("git log -1", dir=gitroot
, output
=True)
1508 if options
.skip_dependencies
:
1509 run_cmd("stat %s" % testbase
, dir=testbase
, output
=True)
1511 os
.makedirs(testbase
)
1512 except Exception as reason
:
1513 raise Exception("Unable to create %s : %s" % (testbase
, reason
))
1514 cleanup_list
.append(testbase
)
1517 logfile
= os
.path
.join(testbase
, "log")
1518 do_print("Forking into the background, writing progress to %s" % logfile
)
1521 write_pidfile(gitroot
+ "/autobuild.pid")
1523 start_time
= time
.time()
1527 run_cmd("rm -rf %s" % test_tmpdir
, show
=True)
1528 os
.makedirs(test_tmpdir
)
1529 # The waf uninstall code removes empty directories all the way
1530 # up the tree. Creating a file in test_tmpdir stops it from
1532 run_cmd("touch %s" % os
.path
.join(test_tmpdir
,
1533 ".directory-is-not-empty"), show
=True)
1534 run_cmd("stat %s" % test_tmpdir
, show
=True)
1535 run_cmd("stat %s" % testbase
, show
=True)
1536 if options
.skip_dependencies
:
1537 run_cmd("stat %s" % test_master
, dir=testbase
, output
=True)
1539 run_cmd("git clone --recursive --shared %s %s" % (gitroot
, test_master
), show
=True, dir=gitroot
)
1545 if options
.rebase
is not None:
1546 rebase_tree(options
.rebase
, rebase_branch
=options
.branch
)
1548 cleanup_list
.append(gitroot
+ "/autobuild.pid")
1550 elapsed_time
= time
.time() - start_time
1551 email_failure(-1, 'rebase', 'rebase', 'rebase',
1552 'rebase on %s failed' % options
.branch
,
1553 elapsed_time
, log_base
=options
.log_base
)
1557 blist
= buildlist(args
, options
.rebase
, rebase_branch
=options
.branch
)
1560 (status
, failed_task
, failed_stage
, failed_tag
, errstr
) = blist
.run()
1561 if status
!= 0 or errstr
!= "retry":
1563 cleanup(do_raise
=True)
1568 cleanup_list
.append(gitroot
+ "/autobuild.pid")
1574 do_print("waiting for tail to flush")
1577 elapsed_time
= time
.time() - start_time
1579 if options
.passcmd
is not None:
1580 do_print("Running passcmd: %s" % options
.passcmd
)
1581 run_cmd(options
.passcmd
, dir=test_master
)
1582 if options
.pushto
is not None:
1583 push_to(options
.pushto
, push_branch
=options
.branch
)
1584 if options
.keeplogs
or options
.attach_logs
:
1585 blist
.tarlogs("logs.tar.gz")
1586 do_print("Logs in logs.tar.gz")
1587 if options
.always_email
:
1588 email_success(elapsed_time
, log_base
=options
.log_base
)
1594 # something failed, gather a tar of the logs
1595 blist
.tarlogs("logs.tar.gz")
1597 if options
.email
is not None:
1598 email_failure(status
, failed_task
, failed_stage
, failed_tag
, errstr
,
1599 elapsed_time
, log_base
=options
.log_base
)
1601 elapsed_minutes
= elapsed_time
/ 60.0
1604 ####################################################################
1608 Your autobuild[%s] on %s failed after %.1f minutes
1609 when trying to test %s with the following error:
1613 the autobuild has been abandoned. Please fix the error and resubmit.
1615 ####################################################################
1617 ''' % (options
.branch
, platform
.node(), elapsed_minutes
, failed_task
, errstr
))
1621 do_print("Logs in logs.tar.gz")