Skip to content

Commit d246942

Browse files
test(action): run the action script tests with CRLF jq output (#145)
* test(action): run the action script tests with CRLF jq output Each test runner of the GitHub Action and of the GitLab CI template runs a second time with a jq that ends each line with CRLF, as jq on Windows does. The scripts now remove the CR from the gate outputs, the annotation count and lines, the job summary, the GitLab user id and the GitLab page count. The GitLab comment step looped without end on such output. The comment compare now ignores each CR. Signed-off-by: Bart Waardenburg <bart@waardenburg.dev> * test(action): give annotate.sh and summary.sh the CRLF jq, and name a failed CRLF run Signed-off-by: Bart Waardenburg <bart@waardenburg.dev> * test(ci): mark the literal awk program of the CRLF jq for shellcheck Signed-off-by: Bart Waardenburg <bart@waardenburg.dev> --------- Signed-off-by: Bart Waardenburg <bart@waardenburg.dev>
1 parent 2d8044b commit d246942

8 files changed

Lines changed: 71 additions & 15 deletions

File tree

‎action/scripts/analyze.sh‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -344,4 +344,5 @@ else
344344
output sarif ""
345345
fi
346346
output path-prefix "$PREFIX"
347-
jq -r -f "${ACTION_JQ_DIR}/gates.jq" "$RESULTS" >> "$GITHUB_OUTPUT"
347+
# jq on Windows ends each line with CRLF. An output value must not keep the CR.
348+
jq -r -f "${ACTION_JQ_DIR}/gates.jq" "$RESULTS" | tr -d '\r' >> "$GITHUB_OUTPUT"

‎action/scripts/annotate.sh‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,11 @@ if [ -z "$SARIF_FILE" ] || [ ! -f "$SARIF_FILE" ]; then
1919
exit 0
2020
fi
2121

22-
total="$(jq '[.runs[]?.results[]?] | length' "$SARIF_FILE")"
22+
# jq on Windows ends each line with CRLF, so `tr` removes the CR.
23+
total="$(jq '[.runs[]?.results[]?] | length' "$SARIF_FILE" | tr -d '\r')"
2324
# analyze.sh wrote the prefix into the SARIF paths, so this step adds none.
24-
jq -r --arg max "$MAX_ANNOTATIONS" --arg prefix "" -f "${ACTION_JQ_DIR}/annotations.jq" "$SARIF_FILE"
25+
jq -r --arg max "$MAX_ANNOTATIONS" --arg prefix "" -f "${ACTION_JQ_DIR}/annotations.jq" "$SARIF_FILE" \
26+
| tr -d '\r'
2527
if [ "$total" -gt "$MAX_ANNOTATIONS" ]; then
2628
echo "::notice::cargo-fallow wrote ${MAX_ANNOTATIONS} of ${total} findings as annotations, errors first. The job summary and the report files hold all of them."
2729
fi

‎action/scripts/comment.sh‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ comments="$(gh api --paginate "repos/${GH_REPO}/issues/${PR_NUMBER}/comments")"
8080
# ends each line with CRLF, so `tr` removes the CR.
8181
match="$(printf '%s' "$comments" | jq -r --arg marker "$MARKER" --arg author "$COMMENT_AUTHOR" \
8282
--rawfile body "$BODY" \
83-
'def norm: gsub("\r\n"; "\n") | sub("\\s+$"; "");
83+
'def norm: gsub("\r"; "") | sub("\\s+$"; "");
8484
.[] | select(.user.login == $author and ((.body // "") | startswith($marker)))
8585
| "\(.id) \((.body | norm) == ($body | norm))"' | tr -d '\r' | head -n 1)"
8686
existing="${match%% *}"

‎action/scripts/summary.sh‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,4 +28,4 @@ jq -r \
2828
--arg max "$MAX_FINDINGS" \
2929
--arg prefix "" \
3030
"${sarif_args[@]}" \
31-
-f "${ACTION_JQ_DIR}/summary.jq" "$RESULTS_FILE" >> "$GITHUB_STEP_SUMMARY"
31+
-f "${ACTION_JQ_DIR}/summary.jq" "$RESULTS_FILE" | tr -d '\r' >> "$GITHUB_STEP_SUMMARY"

‎action/tests/run.sh‎

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,15 @@ line_count() {
4646
# A PATH with jq and the base tools, without cargo, cargo-fallow and gh.
4747
TOOLS="$WORK/tools"
4848
mkdir -p "$TOOLS"
49-
ln -s "$(command -v jq)" "$TOOLS/jq"
49+
if [ -n "${ACTION_TEST_JQ_CRLF:-}" ]; then
50+
# jq on Windows ends each output line with CRLF. In this run, each script
51+
# gets such a jq, and each assertion must still pass.
52+
printf '#!/usr/bin/env bash\nset -o pipefail\n"%s" "$@" | awk '"'"'{ printf "%%s\\r\\n", $0 }'"'"'\n' \
53+
"$(command -v jq)" > "$TOOLS/jq"
54+
chmod +x "$TOOLS/jq"
55+
else
56+
ln -s "$(command -v jq)" "$TOOLS/jq"
57+
fi
5058
# install.sh checks the release signature with node.
5159
if command -v node > /dev/null 2>&1; then ln -s "$(command -v node)" "$TOOLS/node"; fi
5260
BASE_PATH="$TOOLS:/usr/bin:/bin"
@@ -643,18 +651,20 @@ assert_contains "$OUT" "pull request from a fork" "a fork pull request explains
643651
# --- annotate.sh, summary.sh and gate.sh -------------------------------------
644652

645653
echo "annotate.sh, summary.sh and gate.sh"
646-
OUT="$(ACTION_JQ_DIR="$JQ_DIR" SARIF_FILE="$FIXTURES/complexity.sarif" MAX_ANNOTATIONS=2 bash "$SCRIPTS/annotate.sh" 2>&1)"
654+
OUT="$(PATH="$BASE_PATH" ACTION_JQ_DIR="$JQ_DIR" SARIF_FILE="$FIXTURES/complexity.sarif" MAX_ANNOTATIONS=2 bash "$SCRIPTS/annotate.sh" 2>&1)"
647655
assert_equals "$(printf '%s\n' "$OUT" | grep -c '^::warning file=')" "2" "annotate: the cap limits the annotations"
648656
assert_contains "$OUT" "::notice::cargo-fallow wrote 2 of 3 findings as annotations, errors first." "annotate: the cap gives a notice"
649-
OUT="$(ACTION_JQ_DIR="$JQ_DIR" SARIF_FILE="" MAX_ANNOTATIONS=2 bash "$SCRIPTS/annotate.sh" 2>&1)"
657+
assert_not_contains "$OUT" $'\r' "annotate: no line keeps a CR"
658+
OUT="$(PATH="$BASE_PATH" ACTION_JQ_DIR="$JQ_DIR" SARIF_FILE="" MAX_ANNOTATIONS=2 bash "$SCRIPTS/annotate.sh" 2>&1)"
650659
assert_contains "$OUT" "No SARIF log, so no annotations." "annotate: no SARIF log"
651-
OUT="$(ACTION_JQ_DIR="$JQ_DIR" SARIF_FILE="$FIXTURES/complexity.sarif" MAX_ANNOTATIONS=x bash "$SCRIPTS/annotate.sh" 2>&1)"
660+
OUT="$(PATH="$BASE_PATH" ACTION_JQ_DIR="$JQ_DIR" SARIF_FILE="$FIXTURES/complexity.sarif" MAX_ANNOTATIONS=x bash "$SCRIPTS/annotate.sh" 2>&1)"
652661
assert_contains "$OUT" "Invalid 'max-annotations' input" "annotate: a bad cap fails"
653662

654-
OUT="$(ACTION_JQ_DIR="$JQ_DIR" RESULTS_FILE="$FIXTURES/error.json" SARIF_FILE="" FALLOW_COMMAND=check EXIT_CODE=2 MAX_FINDINGS=50 \
663+
OUT="$(PATH="$BASE_PATH" ACTION_JQ_DIR="$JQ_DIR" RESULTS_FILE="$FIXTURES/error.json" SARIF_FILE="" FALLOW_COMMAND=check EXIT_CODE=2 MAX_FINDINGS=50 \
655664
GITHUB_STEP_SUMMARY=/dev/stdout bash "$SCRIPTS/summary.sh" 2>&1)"
656665
assert_contains "$OUT" "### cargo fallow check" "summary: an error document with no SARIF log"
657-
OUT="$(ACTION_JQ_DIR="$JQ_DIR" RESULTS_FILE="$FIXTURES/dupes-missing.json" FALLOW_COMMAND=dupes EXIT_CODE=2 MAX_FINDINGS=50 \
666+
assert_not_contains "$OUT" $'\r' "summary: no line keeps a CR"
667+
OUT="$(PATH="$BASE_PATH" ACTION_JQ_DIR="$JQ_DIR" RESULTS_FILE="$FIXTURES/dupes-missing.json" FALLOW_COMMAND=dupes EXIT_CODE=2 MAX_FINDINGS=50 \
658668
bash "$SCRIPTS/summary.sh" 2>&1)"
659669
assert_contains "$OUT" "No JSON report, so no job summary." "summary: no report file"
660670

@@ -832,8 +842,20 @@ run_analyze INPUT_COMMAND=mutants STUB_JSON="$FIXTURES/mutants.json" INPUT_CHANG
832842
assert_equals "$(call_args 1)" "mutants --fail-on-issues --format json " "scope: mutants ignores changed-since"
833843
assert_contains "$OUT" "The mutants run ignores them" "scope: mutants explains the ignored input"
834844

845+
# A second run gives each script a jq that writes CRLF, as jq on Windows does.
846+
CRLF_FAILED=0
847+
if [ -z "${ACTION_TEST_JQ_CRLF:-}" ]; then
848+
echo
849+
echo "Again with CRLF jq output:"
850+
ACTION_TEST_JQ_CRLF=1 bash "$0" || CRLF_FAILED=1
851+
fi
852+
835853
echo "${PASSED} passed, ${FAILED} failed"
836854
if [ "$FAILED" -gt 0 ]; then
837855
printf ' %s\n' "${FAILURES[@]}"
838856
exit 1
839857
fi
858+
if [ "$CRLF_FAILED" -ne 0 ]; then
859+
echo "The run with CRLF jq output failed."
860+
exit 1
861+
fi

‎changelog.d/test-action-crlf-jq.md‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
### Fixed
2+
3+
- The GitHub Action and the GitLab CI template now work with a jq that ends
4+
each line with CRLF, as jq on Windows does. The gate outputs, the
5+
annotation count, the job summary and the GitLab note pages no longer keep
6+
a CR. With bash 3.2, the GitLab comment step could loop without end. A
7+
comment compare now ignores each CR. The script tests run a second time with such a
8+
jq.

‎ci/scripts/comment.sh‎

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,8 @@ api() {
6060

6161
# The user of the token. Only a note of this user with the marker is the note
6262
# of the job: another user can write the marker in a note of their own.
63-
me="$(api --retry 3 "${CI_API_V4_URL}/user" | jq -r '.id // empty')" || api_warning read
63+
# jq on Windows ends each line with CRLF, so `tr` removes the CR.
64+
me="$(api --retry 3 "${CI_API_V4_URL}/user" | jq -r '.id // empty' | tr -d '\r')" || api_warning read
6465
[ -n "$me" ] || api_warning read
6566

6667
# One line `<id> <same>` for the note of the job, or nothing. `same` is true
@@ -71,10 +72,10 @@ page=1
7172
while [ -z "$match" ]; do
7273
notes="$(api --retry 3 "${NOTES}?per_page=100&page=${page}")" || api_warning read
7374
match="$(printf '%s' "$notes" | jq -r --arg marker "$MARKER" --argjson me "$me" --rawfile body "$BODY" \
74-
'def norm: gsub("\r\n"; "\n") | sub("\\s+$"; "");
75+
'def norm: gsub("\r"; "") | sub("\\s+$"; "");
7576
[.[] | select((.system | not) and .author.id == $me and ((.body // "") | startswith($marker)))
7677
| "\(.id) \((.body | norm) == ($body | norm))"] | first // empty' | tr -d '\r')" || api_warning read
77-
[ "$(printf '%s' "$notes" | jq 'length')" -lt 100 ] && break
78+
[ "$(printf '%s' "$notes" | jq 'length' | tr -d '\r')" -lt 100 ] && break
7879
page=$((page + 1))
7980
done
8081
existing="${match%% *}"

‎ci/tests/run.sh‎

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,17 @@ fi
9292
EOF
9393
chmod +x "$BIN/cargo-fallow" "$BIN/curl"
9494
BASE_PATH="$BIN:/usr/bin:/bin"
95-
ln -s "$(command -v jq)" "$BIN/jq"
95+
if [ -n "${CI_TEST_JQ_CRLF:-}" ]; then
96+
# jq on Windows ends each output line with CRLF. In this run, each script
97+
# gets such a jq, and each assertion must still pass. The awk program is
98+
# literal text.
99+
# shellcheck disable=SC2016
100+
printf '#!/usr/bin/env bash\nset -o pipefail\n"%s" "$@" | awk '"'"'{ printf "%%s\\r\\n", $0 }'"'"'\n' \
101+
"$(command -v jq)" > "$BIN/jq"
102+
chmod +x "$BIN/jq"
103+
else
104+
ln -s "$(command -v jq)" "$BIN/jq"
105+
fi
96106

97107
reset() {
98108
STUB_LOG="$WORK/stub.log"
@@ -334,9 +344,21 @@ assert_contains "$(cat "$SCRIPTS/run.sh")" "CARGO_FALLOW_CODE_QUALITY_FILE:=gl-c
334344
assert_not_contains "$(cat "$TEMPLATE")" "$(printf '\t')" "the template has no tab"
335345
assert_contains "$(cat "$TEMPLATE")" 'CARGO_FALLOW_REF: ""' "the template downloads no script of an unpinned ref by default"
336346

347+
# A second run gives each script a jq that writes CRLF, as jq on Windows does.
348+
CRLF_FAILED=0
349+
if [ -z "${CI_TEST_JQ_CRLF:-}" ]; then
350+
echo
351+
echo "Again with CRLF jq output:"
352+
CI_TEST_JQ_CRLF=1 bash "$0" || CRLF_FAILED=1
353+
fi
354+
337355
echo
338356
echo "${PASSED} passed, ${FAILED} failed"
339357
if [ "$FAILED" -gt 0 ]; then
340358
printf ' %s\n' "${FAILURES[@]}"
341359
exit 1
342360
fi
361+
if [ "$CRLF_FAILED" -ne 0 ]; then
362+
echo "The run with CRLF jq output failed."
363+
exit 1
364+
fi

0 commit comments

Comments
 (0)