1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196
|
#!/bin/sh
set -eu
usage() {
cat <<EOF
usage: debci-batch [OPTIONS]
Options:
-f, --force Force test run on packages, even if no package in
its dependency chain changed. A package will still
not be tested if it was already tested today.
-j N Test at most N packages in parallel
(default: 1)
--offline Puts debci-batch offline. New test runs will not be
started.
--online Puts debci-batch online. New test runs will be
started normally.
$@
EOF
}
short_options='j:f'
long_options='force,offline,online'
debci_base_dir=$(readlink -f $(dirname $(readlink -f $0))/..)
cd $debci_base_dir
. lib/environment.sh
. lib/functions.sh
tmp_dir=$(mktemp -d)
cleanup() {
if [ -d "$tmp_dir" ]; then
rm -rf "$tmp_dir"
fi
}
trap cleanup INT TERM EXIT
one_month_ago="${tmp_dir}/one_month_ago"
touch -d '1 month ago' "${one_month_ago}"
run() {
if which update-testbed >/dev/null 2>/dev/null; then
log "I: Updating backend testbed"
update-testbed
else
log "W: Backend $debci_backend does not provide a way to update testbed!"
fi
log "I: Finished update of backend testbed"
log "I: building/updating chdist for $debci_suite"
debci-setup-chdist
log "I: start processing of all packages"
process_all_packages
log "I: finished processing of all packages"
}
all_packages_with_fastest_first() {
# list of all packages, sorted by duration of their last test suite run
#
# new package have "unknown" as duration, and will sort first due to how
# sort(1) works. We acknowledge that behavior and give new packages a chance
# to be efficient. If they are not, they will be placed at the end of the
# queue for the next run.
debci-status --field duration_seconds --all | sort -k 2,2 -n | cut -d ' ' -f 1
}
process_all_packages() {
local start=$(date +%s)
# determine packages which need to be tested
packages=''
for pkg in $(all_packages_with_fastest_first); do
if needs_processing $pkg; then
packages="$packages $pkg"
else
report_status "$pkg" "skip"
fi
done
if [ "$maxjobs" -eq 1 ]; then
for pkg in $packages; do
debci-test --index "$pkg"
if [ -f "${debci_status_dir}/packages.json" ]; then
local last_update=$(stat --format=%Y "${debci_status_dir}/packages.json")
local now=$(date +%s)
local update_interval=3600 # 1 hour
if [ $(($now - $last_update)) -gt $update_interval ]; then
debci-generate-index
fi
else
debci-generate-index
fi
done
else
args=''
for pkg in $packages; do
args="$args --index $pkg"
done
parallel -n 2 -j "$maxjobs" debci-test -- $args
fi
local finish=$(date +%s)
debci-generate-index --duration $(($finish - $start))
}
needs_processing() {
status_dir=$(status_dir_for_package "$pkg")
last_status=$(debci-status "$pkg")
mkdir -p "${status_dir}"
debci-list-dependencies "$pkg" > "$tmp_dir/${pkg}-deps.txt"
reason="$status_dir/reason.txt"
run=1
if [ "$last_status" = 'tmpfail' ]; then
run=0
echo "∙ Retrying run since last attempt failed" >> $reason
fi
if [ -n "$force" ]; then
run=0
echo "∙ Forced test run for $pkg" >> $reason
fi
if [ -f "${status_dir}/latest.json" -a "${status_dir}/latest.json" -ot "${one_month_ago}" ]; then
run=0
echo '∙ Forcing test run after 1 month without one' >> $reason
fi
if [ -f "$status_dir/dependencies.txt" ]; then
if diff -u --label last-run/dependencies.txt "$status_dir/dependencies.txt" --label current-run/dependencies.txt "$tmp_dir/${pkg}-deps.txt" > "$tmp_dir/${pkg}-changed-deps.diff"; then
: # no need to run tests
else
run=0
echo "∙ There were changes in the dependency chain since last test run:" >> $reason
cat "$tmp_dir/${pkg}-changed-deps.diff" >> $reason
fi
else
run=0
echo "∙ First test run for $pkg" >> $reason
fi
if [ "$run" -eq 0 ]; then
cp "$tmp_dir/${pkg}-deps.txt" "${status_dir}/dependencies.txt"
fi
return $run
}
# default configuration
maxjobs=1
force=''
offline_marker="$debci_data_basedir/offline"
while true; do
arg="$1"
shift
case "$arg" in
-j)
maxjobs="$1"
shift
;;
-f|--force)
force="$arg"
;;
--offline)
touch "${offline_marker}"
exit 0
;;
--online)
rm -f "${offline_marker}"
exit 0
;;
--)
break
;;
esac
done
if [ -e "${offline_marker}" ]; then
exit 0
fi
run_with_lock_or_exit \
/var/lock/debci-batch-${debci_suite}-${debci_arch}.lock \
run "$@"
|