Skip to content

Commit 3b0aa0d

Browse files
committed
Merge branch 'ab/ci-github-workflow-markup' into seen
Build a moral equivalent of js/ci-github-workflow-markup on top of ab/ci-setup-simplify. * ab/ci-github-workflow-markup: ci: call `finalize_test_case_output` a little later ci: use `--github-workflow-markup` in the GitHub workflow ci: optionally mark up output in the GitHub workflow test(junit): avoid line feeds in XML attributes tests: refactor --write-junit-xml code ci: make it easier to find failed tests' logs in the GitHub workflow
2 parents 55c9e66 + cb725c8 commit 3b0aa0d

File tree

7 files changed

+244
-127
lines changed

7 files changed

+244
-127
lines changed

.github/workflows/main.yml

Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -129,11 +129,7 @@ jobs:
129129
shell: bash
130130
- name: test
131131
shell: bash
132-
run: . /etc/profile && make -C t -e
133-
- name: ci/print-test-failures.sh
134-
if: failure()
135-
shell: bash
136-
run: ci/print-test-failures.sh
132+
run: . /etc/profile && make -C t -e || ci/print-test-failures-github.sh
137133
- name: Upload failed tests' directories
138134
if: failure() && env.FAILED_TEST_ARTIFACTS != ''
139135
uses: actions/upload-artifact@v2
@@ -218,11 +214,7 @@ jobs:
218214
shell: bash
219215
- name: test
220216
shell: bash
221-
run: . /etc/profile && make -C t -e
222-
- name: ci/print-test-failures.sh
223-
if: failure()
224-
shell: bash
225-
run: ci/print-test-failures.sh
217+
run: . /etc/profile && make -C t -e || ci/print-test-failures-github.sh
226218
- name: Upload failed tests' directories
227219
if: failure() && env.FAILED_TEST_ARTIFACTS != ''
228220
uses: actions/upload-artifact@v2
@@ -265,10 +257,8 @@ jobs:
265257
- run: ci/lib.sh --build
266258
- run: make
267259
- run: ci/lib.sh --test
268-
- run: make test
260+
- run: make test || ci/print-test-failures-github.sh
269261
if: success()
270-
- run: ci/print-test-failures.sh
271-
if: failure()
272262
- name: Upload failed tests' directories
273263
if: failure() && env.FAILED_TEST_ARTIFACTS != ''
274264
uses: actions/upload-artifact@v2
@@ -301,10 +291,8 @@ jobs:
301291
- run: ci/lib.sh --build
302292
- run: make
303293
- run: ci/lib.sh --test
304-
- run: make test
294+
- run: make test || ci/print-test-failures-github.sh
305295
if: success() && matrix.vector.skip-tests != 'no'
306-
- run: ci/print-test-failures.sh
307-
if: failure() && matrix.vector.skip-tests != 'no'
308296
- name: Upload failed tests' directories
309297
if: failure() && env.FAILED_TEST_ARTIFACTS != ''
310298
uses: actions/upload-artifact@v1

ci/lib.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ MAKEFLAGS="DEVELOPER=$DEVELOPER SKIP_DASHED_BUILT_INS=$SKIP_DASHED_BUILT_INS"
7474
case "$CI_TYPE" in
7575
github-actions)
7676
setenv --test GIT_PROVE_OPTS "--timer --jobs 10"
77-
GIT_TEST_OPTS="--verbose-log -x"
77+
GIT_TEST_OPTS="--verbose-log -x --github-workflow-markup"
7878
MAKEFLAGS="$MAKEFLAGS --jobs=10"
7979
test Windows != "$RUNNER_OS" ||
8080
GIT_TEST_OPTS="--no-chain-lint --no-bin-wrappers $GIT_TEST_OPTS"

ci/print-test-failures-github.sh

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
#!/bin/sh
2+
3+
. ${0%/*}/lib-ci-type.sh
4+
5+
set -e
6+
7+
case "$CI_TYPE" in
8+
github-actions)
9+
handle_failed_tests () {
10+
mkdir -p t/failed-test-artifacts
11+
echo "FAILED_TEST_ARTIFACTS=t/failed-test-artifacts" >>$GITHUB_ENV
12+
13+
for test_exit in t/test-results/*.exit
14+
do
15+
test 0 != "$(cat "$test_exit")" || continue
16+
17+
test_name="${test_exit%.exit}"
18+
test_name="${test_name##*/}"
19+
printf "\\e[33m\\e[1m=== Failed test: ${test_name} ===\\e[m\\n"
20+
cat "t/test-results/$test_name.markup"
21+
22+
trash_dir="t/trash directory.$test_name"
23+
cp "t/test-results/$test_name.out" t/failed-test-artifacts/
24+
tar czf t/failed-test-artifacts/"$test_name".trash.tar.gz "$trash_dir"
25+
done
26+
return 1
27+
}
28+
;;
29+
*)
30+
echo "Unhandled CI type: $CI_TYPE" >&2
31+
exit 1
32+
;;
33+
esac
34+
35+
handle_failed_tests

t/test-lib-functions.sh

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -795,7 +795,7 @@ test_verify_prereq () {
795795
}
796796

797797
test_expect_failure () {
798-
test_start_
798+
test_start_ "$@"
799799
test "$#" = 3 && { test_prereq=$1; shift; } || test_prereq=
800800
test "$#" = 2 ||
801801
BUG "not 2 or 3 parameters to test-expect-failure"
@@ -815,7 +815,7 @@ test_expect_failure () {
815815
}
816816

817817
test_expect_success () {
818-
test_start_
818+
test_start_ "$@"
819819
test "$#" = 3 && { test_prereq=$1; shift; } || test_prereq=
820820
test "$#" = 2 ||
821821
BUG "not 2 or 3 parameters to test-expect-success"
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
# Library of functions to mark up test scripts' output suitable for
2+
# pretty-printing it in GitHub workflows.
3+
#
4+
# Copyright (c) 2022 Johannes Schindelin
5+
#
6+
# This program is free software: you can redistribute it and/or modify
7+
# it under the terms of the GNU General Public License as published by
8+
# the Free Software Foundation, either version 2 of the License, or
9+
# (at your option) any later version.
10+
#
11+
# This program is distributed in the hope that it will be useful,
12+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
# GNU General Public License for more details.
15+
#
16+
# You should have received a copy of the GNU General Public License
17+
# along with this program. If not, see http://www.gnu.org/licenses/ .
18+
#
19+
# The idea is for `test-lib.sh` to source this file when run in GitHub
20+
# workflows; these functions will then override (empty) functions
21+
# that are are called at the appropriate times during the test runs.
22+
23+
start_test_output () {
24+
test -n "$GIT_TEST_TEE_OUTPUT_FILE" ||
25+
die "--github-workflow-markup requires --verbose-log"
26+
github_markup_output="${GIT_TEST_TEE_OUTPUT_FILE%.out}.markup"
27+
>$github_markup_output
28+
GIT_TEST_TEE_OFFSET=0
29+
}
30+
31+
# No need to override start_test_case_output
32+
33+
finalize_test_case_output () {
34+
test_case_result=$1
35+
shift
36+
case "$test_case_result" in
37+
failure)
38+
echo >>$github_markup_output "::error::failed: $this_test.$test_count $1"
39+
;;
40+
fixed)
41+
echo >>$github_markup_output "::notice::fixed: $this_test.$test_count $1"
42+
;;
43+
esac
44+
echo >>$github_markup_output "::group::$test_case_result: $this_test.$test_count $*"
45+
test-tool >>$github_markup_output path-utils skip-n-bytes \
46+
"$GIT_TEST_TEE_OUTPUT_FILE" $GIT_TEST_TEE_OFFSET
47+
echo >>$github_markup_output "::endgroup::"
48+
}
49+
50+
# No need to override finalize_test_output

t/test-lib-junit.sh

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
# Library of functions to format test scripts' output in JUnit XML
2+
# format, to support Git's test suite result to be presented in an
3+
# easily digestible way on Azure Pipelines.
4+
#
5+
# Copyright (c) 2022 Johannes Schindelin
6+
#
7+
# This program is free software: you can redistribute it and/or modify
8+
# it under the terms of the GNU General Public License as published by
9+
# the Free Software Foundation, either version 2 of the License, or
10+
# (at your option) any later version.
11+
#
12+
# This program is distributed in the hope that it will be useful,
13+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
# GNU General Public License for more details.
16+
#
17+
# You should have received a copy of the GNU General Public License
18+
# along with this program. If not, see http://www.gnu.org/licenses/ .
19+
#
20+
# The idea is for `test-lib.sh` to source this file when the user asks
21+
# for JUnit XML; these functions will then override (empty) functions
22+
# that are are called at the appropriate times during the test runs.
23+
24+
start_test_output () {
25+
junit_xml_dir="$TEST_OUTPUT_DIRECTORY/out"
26+
mkdir -p "$junit_xml_dir"
27+
junit_xml_base=${1##*/}
28+
junit_xml_path="$junit_xml_dir/TEST-${junit_xml_base%.sh}.xml"
29+
junit_attrs="name=\"${junit_xml_base%.sh}\""
30+
junit_attrs="$junit_attrs timestamp=\"$(TZ=UTC \
31+
date +%Y-%m-%dT%H:%M:%S)\""
32+
write_junit_xml --truncate "<testsuites>" " <testsuite $junit_attrs>"
33+
junit_suite_start=$(test-tool date getnanos)
34+
if test -n "$GIT_TEST_TEE_OUTPUT_FILE"
35+
then
36+
GIT_TEST_TEE_OFFSET=0
37+
fi
38+
}
39+
40+
start_test_case_output () {
41+
junit_start=$(test-tool date getnanos)
42+
}
43+
44+
finalize_test_case_output () {
45+
test_case_result=$1
46+
shift
47+
case "$test_case_result" in
48+
ok)
49+
set "$*"
50+
;;
51+
failure)
52+
junit_insert="<failure message=\"not ok $test_count -"
53+
junit_insert="$junit_insert $(xml_attr_encode --no-lf "$1")\">"
54+
junit_insert="$junit_insert $(xml_attr_encode \
55+
"$(if test -n "$GIT_TEST_TEE_OUTPUT_FILE"
56+
then
57+
test-tool path-utils skip-n-bytes \
58+
"$GIT_TEST_TEE_OUTPUT_FILE" $GIT_TEST_TEE_OFFSET
59+
else
60+
printf '%s\n' "$@" | sed 1d
61+
fi)")"
62+
junit_insert="$junit_insert</failure>"
63+
if test -n "$GIT_TEST_TEE_OUTPUT_FILE"
64+
then
65+
junit_insert="$junit_insert<system-err>$(xml_attr_encode \
66+
"$(cat "$GIT_TEST_TEE_OUTPUT_FILE")")</system-err>"
67+
fi
68+
set "$1" " $junit_insert"
69+
;;
70+
fixed)
71+
set "$* (breakage fixed)"
72+
;;
73+
broken)
74+
set "$* (known breakage)"
75+
;;
76+
skip)
77+
message="$(xml_attr_encode --no-lf "$skipped_reason")"
78+
set "$1" " <skipped message=\"$message\" />"
79+
;;
80+
esac
81+
82+
junit_attrs="name=\"$(xml_attr_encode --no-lf "$this_test.$test_count $1")\""
83+
shift
84+
junit_attrs="$junit_attrs classname=\"$this_test\""
85+
junit_attrs="$junit_attrs time=\"$(test-tool \
86+
date getnanos $junit_start)\""
87+
write_junit_xml "$(printf '%s\n' \
88+
" <testcase $junit_attrs>" "$@" " </testcase>")"
89+
junit_have_testcase=t
90+
}
91+
92+
finalize_test_output () {
93+
if test -n "$junit_xml_path"
94+
then
95+
test -n "$junit_have_testcase" || {
96+
junit_start=$(test-tool date getnanos)
97+
write_junit_xml_testcase "all tests skipped"
98+
}
99+
100+
# adjust the overall time
101+
junit_time=$(test-tool date getnanos $junit_suite_start)
102+
sed -e "s/\(<testsuite.*\) time=\"[^\"]*\"/\1/" \
103+
-e "s/<testsuite [^>]*/& time=\"$junit_time\"/" \
104+
-e '/^ *<\/testsuite/d' \
105+
<"$junit_xml_path" >"$junit_xml_path.new"
106+
mv "$junit_xml_path.new" "$junit_xml_path"
107+
108+
write_junit_xml " </testsuite>" "</testsuites>"
109+
write_junit_xml=
110+
fi
111+
}
112+
113+
write_junit_xml () {
114+
case "$1" in
115+
--truncate)
116+
>"$junit_xml_path"
117+
junit_have_testcase=
118+
shift
119+
;;
120+
esac
121+
printf '%s\n' "$@" >>"$junit_xml_path"
122+
}
123+
124+
xml_attr_encode () {
125+
if test "x$1" = "x--no-lf"
126+
then
127+
shift
128+
printf '%s' "$*" | test-tool xml-encode
129+
else
130+
printf '%s\n' "$@" | test-tool xml-encode
131+
fi
132+
}

0 commit comments

Comments
 (0)