Merge branch 'js/ci-discard-prove-state' into maint-2.43
The way CI testing used "prove" could lead to running the test suite twice needlessly, which has been corrected. * js/ci-discard-prove-state: ci: avoid running the test suite _twice_ ci: add support for GitLab CI ci: install test dependencies for linux-musl ci: squelch warnings when testing with unusable Git repo ci: unify setup of some environment variables ci: split out logic to set up failed test artifacts ci: group installation of Docker dependencies ci: make grouping setup more generic ci: reorder definitions for grouping functionsmaint
commit
c8bcf66bf7
|
@ -0,0 +1,53 @@
|
||||||
|
default:
|
||||||
|
timeout: 2h
|
||||||
|
|
||||||
|
workflow:
|
||||||
|
rules:
|
||||||
|
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
|
||||||
|
- if: $CI_COMMIT_TAG
|
||||||
|
- if: $CI_COMMIT_REF_PROTECTED == "true"
|
||||||
|
|
||||||
|
test:
|
||||||
|
image: $image
|
||||||
|
before_script:
|
||||||
|
- ./ci/install-docker-dependencies.sh
|
||||||
|
script:
|
||||||
|
- useradd builder --create-home
|
||||||
|
- chown -R builder "${CI_PROJECT_DIR}"
|
||||||
|
- sudo --preserve-env --set-home --user=builder ./ci/run-build-and-tests.sh
|
||||||
|
after_script:
|
||||||
|
- |
|
||||||
|
if test "$CI_JOB_STATUS" != 'success'
|
||||||
|
then
|
||||||
|
sudo --preserve-env --set-home --user=builder ./ci/print-test-failures.sh
|
||||||
|
fi
|
||||||
|
parallel:
|
||||||
|
matrix:
|
||||||
|
- jobname: linux-sha256
|
||||||
|
image: ubuntu:latest
|
||||||
|
CC: clang
|
||||||
|
- jobname: linux-gcc
|
||||||
|
image: ubuntu:20.04
|
||||||
|
CC: gcc
|
||||||
|
CC_PACKAGE: gcc-8
|
||||||
|
- jobname: linux-TEST-vars
|
||||||
|
image: ubuntu:20.04
|
||||||
|
CC: gcc
|
||||||
|
CC_PACKAGE: gcc-8
|
||||||
|
- jobname: linux-gcc-default
|
||||||
|
image: ubuntu:latest
|
||||||
|
CC: gcc
|
||||||
|
- jobname: linux-leaks
|
||||||
|
image: ubuntu:latest
|
||||||
|
CC: gcc
|
||||||
|
- jobname: linux-asan-ubsan
|
||||||
|
image: ubuntu:latest
|
||||||
|
CC: clang
|
||||||
|
- jobname: pedantic
|
||||||
|
image: fedora:latest
|
||||||
|
- jobname: linux-musl
|
||||||
|
image: alpine:latest
|
||||||
|
artifacts:
|
||||||
|
paths:
|
||||||
|
- t/failed-test-artifacts
|
||||||
|
when: on_failure
|
|
@ -3,6 +3,10 @@
|
||||||
# Install dependencies required to build and test Git inside container
|
# Install dependencies required to build and test Git inside container
|
||||||
#
|
#
|
||||||
|
|
||||||
|
. ${0%/*}/lib.sh
|
||||||
|
|
||||||
|
begin_group "Install dependencies"
|
||||||
|
|
||||||
case "$jobname" in
|
case "$jobname" in
|
||||||
linux32)
|
linux32)
|
||||||
linux32 --32bit i386 sh -c '
|
linux32 --32bit i386 sh -c '
|
||||||
|
@ -12,11 +16,26 @@ linux32)
|
||||||
'
|
'
|
||||||
;;
|
;;
|
||||||
linux-musl)
|
linux-musl)
|
||||||
apk add --update build-base curl-dev openssl-dev expat-dev gettext \
|
apk add --update shadow sudo build-base curl-dev openssl-dev expat-dev gettext \
|
||||||
pcre2-dev python3 musl-libintl perl-utils ncurses >/dev/null
|
pcre2-dev python3 musl-libintl perl-utils ncurses \
|
||||||
|
apache2 apache2-http2 apache2-proxy apache2-ssl apache2-webdav apr-util-dbd_sqlite3 \
|
||||||
|
bash cvs gnupg perl-cgi perl-dbd-sqlite >/dev/null
|
||||||
|
;;
|
||||||
|
linux-*)
|
||||||
|
# Required so that apt doesn't wait for user input on certain packages.
|
||||||
|
export DEBIAN_FRONTEND=noninteractive
|
||||||
|
|
||||||
|
apt update -q &&
|
||||||
|
apt install -q -y sudo git make language-pack-is libsvn-perl apache2 libssl-dev \
|
||||||
|
libcurl4-openssl-dev libexpat-dev tcl tk gettext zlib1g-dev \
|
||||||
|
perl-modules liberror-perl libauthen-sasl-perl libemail-valid-perl \
|
||||||
|
libdbd-sqlite3-perl libio-socket-ssl-perl libnet-smtp-ssl-perl ${CC_PACKAGE:-${CC:-gcc}} \
|
||||||
|
apache2 cvs cvsps gnupg libcgi-pm-perl subversion
|
||||||
;;
|
;;
|
||||||
pedantic)
|
pedantic)
|
||||||
dnf -yq update >/dev/null &&
|
dnf -yq update >/dev/null &&
|
||||||
dnf -yq install make gcc findutils diffutils perl python3 gettext zlib-devel expat-devel openssl-devel curl-devel pcre2-devel >/dev/null
|
dnf -yq install make gcc findutils diffutils perl python3 gettext zlib-devel expat-devel openssl-devel curl-devel pcre2-devel >/dev/null
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
|
end_group "Install dependencies"
|
||||||
|
|
196
ci/lib.sh
196
ci/lib.sh
|
@ -1,16 +1,7 @@
|
||||||
# Library of functions shared by all CI scripts
|
# Library of functions shared by all CI scripts
|
||||||
|
|
||||||
if test true != "$GITHUB_ACTIONS"
|
if test true = "$GITHUB_ACTIONS"
|
||||||
then
|
then
|
||||||
begin_group () { :; }
|
|
||||||
end_group () { :; }
|
|
||||||
|
|
||||||
group () {
|
|
||||||
shift
|
|
||||||
"$@"
|
|
||||||
}
|
|
||||||
set -x
|
|
||||||
else
|
|
||||||
begin_group () {
|
begin_group () {
|
||||||
need_to_end_group=t
|
need_to_end_group=t
|
||||||
echo "::group::$1" >&2
|
echo "::group::$1" >&2
|
||||||
|
@ -23,27 +14,50 @@ else
|
||||||
need_to_end_group=
|
need_to_end_group=
|
||||||
echo '::endgroup::' >&2
|
echo '::endgroup::' >&2
|
||||||
}
|
}
|
||||||
trap end_group EXIT
|
elif test true = "$GITLAB_CI"
|
||||||
|
then
|
||||||
group () {
|
begin_group () {
|
||||||
set +x
|
need_to_end_group=t
|
||||||
begin_group "$1"
|
printf "\e[0Ksection_start:$(date +%s):$(echo "$1" | tr ' ' _)\r\e[0K$1\n"
|
||||||
shift
|
trap "end_group '$1'" EXIT
|
||||||
# work around `dash` not supporting `set -o pipefail`
|
set -x
|
||||||
(
|
|
||||||
"$@" 2>&1
|
|
||||||
echo $? >exit.status
|
|
||||||
) |
|
|
||||||
sed 's/^\(\([^ ]*\):\([0-9]*\):\([0-9]*:\) \)\(error\|warning\): /::\5 file=\2,line=\3::\1/'
|
|
||||||
res=$(cat exit.status)
|
|
||||||
rm exit.status
|
|
||||||
end_group
|
|
||||||
return $res
|
|
||||||
}
|
}
|
||||||
|
|
||||||
begin_group "CI setup"
|
end_group () {
|
||||||
|
test -n "$need_to_end_group" || return 0
|
||||||
|
set +x
|
||||||
|
need_to_end_group=
|
||||||
|
printf "\e[0Ksection_end:$(date +%s):$(echo "$1" | tr ' ' _)\r\e[0K\n"
|
||||||
|
trap - EXIT
|
||||||
|
}
|
||||||
|
else
|
||||||
|
begin_group () { :; }
|
||||||
|
end_group () { :; }
|
||||||
|
|
||||||
|
set -x
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
group () {
|
||||||
|
group="$1"
|
||||||
|
shift
|
||||||
|
begin_group "$group"
|
||||||
|
|
||||||
|
# work around `dash` not supporting `set -o pipefail`
|
||||||
|
(
|
||||||
|
"$@" 2>&1
|
||||||
|
echo $? >exit.status
|
||||||
|
) |
|
||||||
|
sed 's/^\(\([^ ]*\):\([0-9]*\):\([0-9]*:\) \)\(error\|warning\): /::\5 file=\2,line=\3::\1/'
|
||||||
|
res=$(cat exit.status)
|
||||||
|
rm exit.status
|
||||||
|
|
||||||
|
end_group "$group"
|
||||||
|
return $res
|
||||||
|
}
|
||||||
|
|
||||||
|
begin_group "CI setup"
|
||||||
|
trap "end_group 'CI setup'" EXIT
|
||||||
|
|
||||||
# Set 'exit on error' for all CI scripts to let the caller know that
|
# Set 'exit on error' for all CI scripts to let the caller know that
|
||||||
# something went wrong.
|
# something went wrong.
|
||||||
#
|
#
|
||||||
|
@ -71,10 +85,32 @@ skip_branch_tip_with_tag () {
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Check whether we can use the path passed via the first argument as Git
|
||||||
|
# repository.
|
||||||
|
is_usable_git_repository () {
|
||||||
|
# We require Git in our PATH, otherwise we cannot access repositories
|
||||||
|
# at all.
|
||||||
|
if ! command -v git >/dev/null
|
||||||
|
then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# And the target directory needs to be a proper Git repository.
|
||||||
|
if ! git -C "$1" rev-parse 2>/dev/null
|
||||||
|
then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
# Save some info about the current commit's tree, so we can skip the build
|
# Save some info about the current commit's tree, so we can skip the build
|
||||||
# job if we encounter the same tree again and can provide a useful info
|
# job if we encounter the same tree again and can provide a useful info
|
||||||
# message.
|
# message.
|
||||||
save_good_tree () {
|
save_good_tree () {
|
||||||
|
if ! is_usable_git_repository .
|
||||||
|
then
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
echo "$(git rev-parse $CI_COMMIT^{tree}) $CI_COMMIT $CI_JOB_NUMBER $CI_JOB_ID" >>"$good_trees_file"
|
echo "$(git rev-parse $CI_COMMIT^{tree}) $CI_COMMIT $CI_JOB_NUMBER $CI_JOB_ID" >>"$good_trees_file"
|
||||||
# limit the file size
|
# limit the file size
|
||||||
tail -1000 "$good_trees_file" >"$good_trees_file".tmp
|
tail -1000 "$good_trees_file" >"$good_trees_file".tmp
|
||||||
|
@ -90,6 +126,11 @@ skip_good_tree () {
|
||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if ! is_usable_git_repository .
|
||||||
|
then
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
if ! good_tree_info="$(grep "^$(git rev-parse $CI_COMMIT^{tree}) " "$good_trees_file")"
|
if ! good_tree_info="$(grep "^$(git rev-parse $CI_COMMIT^{tree}) " "$good_trees_file")"
|
||||||
then
|
then
|
||||||
# Haven't seen this tree yet, or no cached good trees file yet.
|
# Haven't seen this tree yet, or no cached good trees file yet.
|
||||||
|
@ -121,6 +162,11 @@ skip_good_tree () {
|
||||||
}
|
}
|
||||||
|
|
||||||
check_unignored_build_artifacts () {
|
check_unignored_build_artifacts () {
|
||||||
|
if ! is_usable_git_repository .
|
||||||
|
then
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
! git ls-files --other --exclude-standard --error-unmatch \
|
! git ls-files --other --exclude-standard --error-unmatch \
|
||||||
-- ':/*' 2>/dev/null ||
|
-- ':/*' 2>/dev/null ||
|
||||||
{
|
{
|
||||||
|
@ -133,6 +179,26 @@ handle_failed_tests () {
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
create_failed_test_artifacts () {
|
||||||
|
mkdir -p t/failed-test-artifacts
|
||||||
|
|
||||||
|
for test_exit in t/test-results/*.exit
|
||||||
|
do
|
||||||
|
test 0 != "$(cat "$test_exit")" || continue
|
||||||
|
|
||||||
|
test_name="${test_exit%.exit}"
|
||||||
|
test_name="${test_name##*/}"
|
||||||
|
printf "\\e[33m\\e[1m=== Failed test: ${test_name} ===\\e[m\\n"
|
||||||
|
echo "The full logs are in the 'print test failures' step below."
|
||||||
|
echo "See also the 'failed-tests-*' artifacts attached to this run."
|
||||||
|
cat "t/test-results/$test_name.markup"
|
||||||
|
|
||||||
|
trash_dir="t/trash directory.$test_name"
|
||||||
|
cp "t/test-results/$test_name.out" t/failed-test-artifacts/
|
||||||
|
tar czf t/failed-test-artifacts/"$test_name".trash.tar.gz "$trash_dir"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
# GitHub Action doesn't set TERM, which is required by tput
|
# GitHub Action doesn't set TERM, which is required by tput
|
||||||
export TERM=${TERM:-dumb}
|
export TERM=${TERM:-dumb}
|
||||||
|
|
||||||
|
@ -156,11 +222,8 @@ then
|
||||||
# among *all* phases)
|
# among *all* phases)
|
||||||
cache_dir="$HOME/test-cache/$SYSTEM_PHASENAME"
|
cache_dir="$HOME/test-cache/$SYSTEM_PHASENAME"
|
||||||
|
|
||||||
export GIT_PROVE_OPTS="--timer --jobs 10 --state=failed,slow,save"
|
GIT_TEST_OPTS="--write-junit-xml"
|
||||||
export GIT_TEST_OPTS="--verbose-log -x --write-junit-xml"
|
JOBS=10
|
||||||
MAKEFLAGS="$MAKEFLAGS --jobs=10"
|
|
||||||
test windows_nt != "$CI_OS_NAME" ||
|
|
||||||
GIT_TEST_OPTS="--no-chain-lint --no-bin-wrappers $GIT_TEST_OPTS"
|
|
||||||
elif test true = "$GITHUB_ACTIONS"
|
elif test true = "$GITHUB_ACTIONS"
|
||||||
then
|
then
|
||||||
CI_TYPE=github-actions
|
CI_TYPE=github-actions
|
||||||
|
@ -173,40 +236,63 @@ then
|
||||||
CC="${CC_PACKAGE:-${CC:-gcc}}"
|
CC="${CC_PACKAGE:-${CC:-gcc}}"
|
||||||
DONT_SKIP_TAGS=t
|
DONT_SKIP_TAGS=t
|
||||||
handle_failed_tests () {
|
handle_failed_tests () {
|
||||||
mkdir -p t/failed-test-artifacts
|
|
||||||
echo "FAILED_TEST_ARTIFACTS=t/failed-test-artifacts" >>$GITHUB_ENV
|
echo "FAILED_TEST_ARTIFACTS=t/failed-test-artifacts" >>$GITHUB_ENV
|
||||||
|
create_failed_test_artifacts
|
||||||
for test_exit in t/test-results/*.exit
|
|
||||||
do
|
|
||||||
test 0 != "$(cat "$test_exit")" || continue
|
|
||||||
|
|
||||||
test_name="${test_exit%.exit}"
|
|
||||||
test_name="${test_name##*/}"
|
|
||||||
printf "\\e[33m\\e[1m=== Failed test: ${test_name} ===\\e[m\\n"
|
|
||||||
echo "The full logs are in the 'print test failures' step below."
|
|
||||||
echo "See also the 'failed-tests-*' artifacts attached to this run."
|
|
||||||
cat "t/test-results/$test_name.markup"
|
|
||||||
|
|
||||||
trash_dir="t/trash directory.$test_name"
|
|
||||||
cp "t/test-results/$test_name.out" t/failed-test-artifacts/
|
|
||||||
tar czf t/failed-test-artifacts/"$test_name".trash.tar.gz "$trash_dir"
|
|
||||||
done
|
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
cache_dir="$HOME/none"
|
cache_dir="$HOME/none"
|
||||||
|
|
||||||
export GIT_PROVE_OPTS="--timer --jobs 10"
|
GIT_TEST_OPTS="--github-workflow-markup"
|
||||||
export GIT_TEST_OPTS="--verbose-log -x --github-workflow-markup"
|
JOBS=10
|
||||||
MAKEFLAGS="$MAKEFLAGS --jobs=10"
|
elif test true = "$GITLAB_CI"
|
||||||
test windows != "$CI_OS_NAME" ||
|
then
|
||||||
GIT_TEST_OPTS="--no-chain-lint --no-bin-wrappers $GIT_TEST_OPTS"
|
CI_TYPE=gitlab-ci
|
||||||
|
CI_BRANCH="$CI_COMMIT_REF_NAME"
|
||||||
|
CI_COMMIT="$CI_COMMIT_SHA"
|
||||||
|
case "$CI_JOB_IMAGE" in
|
||||||
|
macos-*)
|
||||||
|
CI_OS_NAME=osx;;
|
||||||
|
alpine:*|fedora:*|ubuntu:*)
|
||||||
|
CI_OS_NAME=linux;;
|
||||||
|
*)
|
||||||
|
echo "Could not identify OS image" >&2
|
||||||
|
env >&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
CI_REPO_SLUG="$CI_PROJECT_PATH"
|
||||||
|
CI_JOB_ID="$CI_JOB_ID"
|
||||||
|
CC="${CC_PACKAGE:-${CC:-gcc}}"
|
||||||
|
DONT_SKIP_TAGS=t
|
||||||
|
handle_failed_tests () {
|
||||||
|
create_failed_test_artifacts
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
cache_dir="$HOME/none"
|
||||||
|
|
||||||
|
runs_on_pool=$(echo "$CI_JOB_IMAGE" | tr : -)
|
||||||
|
JOBS=$(nproc)
|
||||||
else
|
else
|
||||||
echo "Could not identify CI type" >&2
|
echo "Could not identify CI type" >&2
|
||||||
env >&2
|
env >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
MAKEFLAGS="$MAKEFLAGS --jobs=$JOBS"
|
||||||
|
GIT_PROVE_OPTS="--timer --jobs $JOBS"
|
||||||
|
|
||||||
|
GIT_TEST_OPTS="$GIT_TEST_OPTS --verbose-log -x"
|
||||||
|
case "$CI_OS_NAME" in
|
||||||
|
windows|windows_nt)
|
||||||
|
GIT_TEST_OPTS="$GIT_TEST_OPTS --no-chain-lint --no-bin-wrappers"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
export GIT_TEST_OPTS
|
||||||
|
export GIT_PROVE_OPTS
|
||||||
|
|
||||||
good_trees_file="$cache_dir/good-trees"
|
good_trees_file="$cache_dir/good-trees"
|
||||||
|
|
||||||
mkdir -p "$cache_dir"
|
mkdir -p "$cache_dir"
|
||||||
|
@ -285,5 +371,5 @@ esac
|
||||||
|
|
||||||
MAKEFLAGS="$MAKEFLAGS CC=${CC:-cc}"
|
MAKEFLAGS="$MAKEFLAGS CC=${CC:-cc}"
|
||||||
|
|
||||||
end_group
|
end_group "CI setup"
|
||||||
set -x
|
set -x
|
||||||
|
|
|
@ -51,6 +51,12 @@ do
|
||||||
tar czf failed-test-artifacts/"$test_name".trash.tar.gz "$trash_dir"
|
tar czf failed-test-artifacts/"$test_name".trash.tar.gz "$trash_dir"
|
||||||
continue
|
continue
|
||||||
;;
|
;;
|
||||||
|
gitlab-ci)
|
||||||
|
mkdir -p failed-test-artifacts
|
||||||
|
cp "${TEST_EXIT%.exit}.out" failed-test-artifacts/
|
||||||
|
tar czf failed-test-artifacts/"$test_name".trash.tar.gz "$trash_dir"
|
||||||
|
continue
|
||||||
|
;;
|
||||||
*)
|
*)
|
||||||
echo "Unhandled CI type: $CI_TYPE" >&2
|
echo "Unhandled CI type: $CI_TYPE" >&2
|
||||||
exit 1
|
exit 1
|
||||||
|
|
|
@ -67,7 +67,8 @@ for DEFAULT_HTTPD_MODULE_PATH in '/usr/libexec/apache2' \
|
||||||
'/usr/lib/apache2/modules' \
|
'/usr/lib/apache2/modules' \
|
||||||
'/usr/lib64/httpd/modules' \
|
'/usr/lib64/httpd/modules' \
|
||||||
'/usr/lib/httpd/modules' \
|
'/usr/lib/httpd/modules' \
|
||||||
'/usr/libexec/httpd'
|
'/usr/libexec/httpd' \
|
||||||
|
'/usr/lib/apache2'
|
||||||
do
|
do
|
||||||
if test -d "$DEFAULT_HTTPD_MODULE_PATH"
|
if test -d "$DEFAULT_HTTPD_MODULE_PATH"
|
||||||
then
|
then
|
||||||
|
@ -127,6 +128,20 @@ else
|
||||||
"Could not identify web server at '$LIB_HTTPD_PATH'"
|
"Could not identify web server at '$LIB_HTTPD_PATH'"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if test -n "$LIB_HTTPD_DAV" && test -f /etc/os-release
|
||||||
|
then
|
||||||
|
case "$(grep "^ID=" /etc/os-release | cut -d= -f2-)" in
|
||||||
|
alpine)
|
||||||
|
# The WebDAV module in Alpine Linux is broken at least up to
|
||||||
|
# Alpine v3.16 as the default DBM driver is missing.
|
||||||
|
#
|
||||||
|
# https://gitlab.alpinelinux.org/alpine/aports/-/issues/13112
|
||||||
|
test_skip_or_die GIT_TEST_HTTPD \
|
||||||
|
"Apache WebDAV module does not have default DBM backend driver"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
install_script () {
|
install_script () {
|
||||||
write_script "$HTTPD_ROOT_PATH/$1" <"$TEST_PATH/$1"
|
write_script "$HTTPD_ROOT_PATH/$1" <"$TEST_PATH/$1"
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue