From 4d2f5caddafb8dcc50bd9dd50d11a78b36b468ab Mon Sep 17 00:00:00 2001 From: "Matthieu Baerts (NGI0)" Date: Wed, 4 Jun 2025 13:29:54 +0200 Subject: [PATCH 1/4] tests: shellcheck: restrict warnings to warnings only And not lower severities like info and style. For the moment, there are too many info messages, e.g. not using double quotes everywhere or having functions that are not directly called. Let's not push people to fix those and create massive cleanup patches not fixing actual problems. Signed-off-by: Matthieu Baerts (NGI0) --- tests/patch/shellcheck/shellcheck.sh | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/tests/patch/shellcheck/shellcheck.sh b/tests/patch/shellcheck/shellcheck.sh index a96f648..03a9c99 100755 --- a/tests/patch/shellcheck/shellcheck.sh +++ b/tests/patch/shellcheck/shellcheck.sh @@ -40,8 +40,10 @@ for f in $(git show --diff-filter=M --pretty="" --name-only "${HEAD}" | grep -E ) done -incumbent=$(grep -i -c "(error)" $tmpfile_o) -incumbent_w=$(grep -i -c "SC[0-9]* (" $tmpfile_o) +# ex: SC3045 (warning): In POSIX sh, printf -v is undefined. +# severity: error, warning, info, style +incumbent=$(grep -c " (error):" $tmpfile_o) +incumbent_w=$(grep -c " (warning):" $tmpfile_o) pr "Building the tree with the patch" git checkout -q $HEAD @@ -57,8 +59,9 @@ for f in $(git show --diff-filter=AM --pretty="" --name-only "${HEAD}" | grep -E ) done -current=$(grep -i -c "(error)" $tmpfile_n) -current_w=$(grep -i -c "SC[0-9]* (" $tmpfile_n) +# severity: error, warning, info, style +current=$(grep -c " (error):" $tmpfile_n) +current_w=$(grep -c " (warning):" $tmpfile_n) echo "Errors before: $incumbent (+warn: $incumbent_w) this patch: $current (+warn: $current_w)" >&$DESC_FD From 397b61a134ac7a7482deb3021060e689201cf45d Mon Sep 17 00:00:00 2001 From: "Matthieu Baerts (NGI0)" Date: Wed, 4 Jun 2025 14:53:06 +0200 Subject: [PATCH 2/4] tests: shellcheck: keep files compliant If a file was shellcheck compliant before or is new, it is interesting to tell the reviewers when this status changes or if the new file is not shellcheck compliant from the beginning. A new dedicated file is used for each modified shell script, using a hash of the file path to cope with files with the same base name. If the status is different than before, warnings + info + style are added to the errors count. Note: it is not clear if the log message about a file no longer being shellcheck compliant any more should be more visible or not, i.e. sent to $DESC_FD. Signed-off-by: Matthieu Baerts (NGI0) --- tests/patch/shellcheck/shellcheck.sh | 35 ++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/tests/patch/shellcheck/shellcheck.sh b/tests/patch/shellcheck/shellcheck.sh index 03a9c99..83b33e8 100755 --- a/tests/patch/shellcheck/shellcheck.sh +++ b/tests/patch/shellcheck/shellcheck.sh @@ -31,11 +31,14 @@ git checkout -q HEAD~ # Also ignore created, as not present in the parent commit for f in $(git show --diff-filter=M --pretty="" --name-only "${HEAD}" | grep -E "\.sh$"); do ( - echo "Checking $f" + sha=$(echo $f | sha256sum | awk '{print $1}') + echo "Checking $f - $sha" echo cd $(dirname $f) - shellcheck -x $(basename $f) | tee -a $tmpfile_o + sha="${tmpfile_o}_${sha}" + rm -f "${sha}" + shellcheck -x $(basename $f) | tee -a "${tmpfile_o}" "${sha}" echo ) done @@ -50,11 +53,14 @@ git checkout -q $HEAD for f in $(git show --diff-filter=AM --pretty="" --name-only "${HEAD}" | grep -E "\.sh$"); do ( - echo "Checking $f" + sha=$(echo $f | sha256sum | awk '{print $1}') + echo "Checking $f - $sha" echo cd $(dirname $f) - shellcheck -x $(basename $f) | tee -a $tmpfile_n + sha="${tmpfile_n}_${sha}" + rm -f "${sha}" + shellcheck -x $(basename $f) | tee -a "${tmpfile_n}" "${sha}" echo ) done @@ -63,6 +69,25 @@ done current=$(grep -c " (error):" $tmpfile_n) current_w=$(grep -c " (warning):" $tmpfile_n) +# if a file was compliant before or is new, mark everything as error to keep it good. +for f in "${tmpfile_n}_"*; do + [ ! -s "${f}" ] && continue # still compliant + + sha="${f:${#tmpfile_n}+1}" + old="${tmpfile_o}_${sha}" + [ -s "${old}" ] && continue # wasn't compliant + + fname=$(head -n2 "${f}" | tail -n1 | sed "s/^In \(\S\+\.sh\) line [0-9]\+:/\1/g") + if [ -f "${old}" ]; then + echo "${fname} was shellcheck compliant, not anymore" 1>&2 + else + echo "${fname} is a new file, but not shellcheck compliant" 1>&2 + fi + + extra=$(grep -c -E " \((warning|info|style)\):" "${f}") + current=$((current + extra)) +done + echo "Errors before: $incumbent (+warn: $incumbent_w) this patch: $current (+warn: $current_w)" >&$DESC_FD if [ $current -gt $incumbent ]; then @@ -78,6 +103,6 @@ if [ $current_w -gt $incumbent_w ]; then rc=250 fi -rm "$tmpfile_o" "$tmpfile_n" +rm "$tmpfile_o"* "$tmpfile_n"* exit $rc From 4883ea2aa7de79f56130158dd1ba6db301359c6f Mon Sep 17 00:00:00 2001 From: "Matthieu Baerts (NGI0)" Date: Wed, 4 Jun 2025 16:35:36 +0200 Subject: [PATCH 3/4] tests: error rc in case of errors and warnings Before, in case of new errors and new warnings, the script was exiting with rc=250 (warning) instead of rc=1 (error). This is fixed simply by looking at the warnings counter before the errors one, so rc=1 will be set last. Signed-off-by: Matthieu Baerts (NGI0) --- tests/patch/pylint/pylint.sh | 12 ++++++------ tests/patch/shellcheck/shellcheck.sh | 12 ++++++------ tests/patch/yamllint/yamllint.sh | 12 ++++++------ 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/tests/patch/pylint/pylint.sh b/tests/patch/pylint/pylint.sh index 6b90b2c..59d2ad3 100755 --- a/tests/patch/pylint/pylint.sh +++ b/tests/patch/pylint/pylint.sh @@ -48,6 +48,12 @@ current_w=$(grep -i -c ": [WC][0-9][0-9][0-9][0-9]: " $tmpfile_n) echo "Errors before: $incumbent (+warn: $incumbent_w) this patch: $current (+warn: $current_w)" >&$DESC_FD +if [ $current_w -gt $incumbent_w ]; then + echo "New warnings added" 1>&2 + + rc=250 +fi + if [ $current -gt $incumbent ]; then echo "New errors added" 1>&2 diff -U 0 $tmpfile_o $tmpfile_n 1>&2 @@ -55,12 +61,6 @@ if [ $current -gt $incumbent ]; then rc=1 fi -if [ $current_w -gt $incumbent_w ]; then - echo "New warnings added" 1>&2 - - rc=250 -fi - rm "$tmpfile_o" "$tmpfile_n" exit $rc diff --git a/tests/patch/shellcheck/shellcheck.sh b/tests/patch/shellcheck/shellcheck.sh index 83b33e8..d0a574a 100755 --- a/tests/patch/shellcheck/shellcheck.sh +++ b/tests/patch/shellcheck/shellcheck.sh @@ -90,6 +90,12 @@ done echo "Errors before: $incumbent (+warn: $incumbent_w) this patch: $current (+warn: $current_w)" >&$DESC_FD +if [ $current_w -gt $incumbent_w ]; then + echo "New warnings added" 1>&2 + + rc=250 +fi + if [ $current -gt $incumbent ]; then echo "New errors added" 1>&2 diff -U 0 $tmpfile_o $tmpfile_n 1>&2 @@ -97,12 +103,6 @@ if [ $current -gt $incumbent ]; then rc=1 fi -if [ $current_w -gt $incumbent_w ]; then - echo "New warnings added" 1>&2 - - rc=250 -fi - rm "$tmpfile_o"* "$tmpfile_n"* exit $rc diff --git a/tests/patch/yamllint/yamllint.sh b/tests/patch/yamllint/yamllint.sh index 099e9fc..51f80a9 100755 --- a/tests/patch/yamllint/yamllint.sh +++ b/tests/patch/yamllint/yamllint.sh @@ -48,6 +48,12 @@ current_w=$(grep -i -c " warning " $tmpfile_n) echo "Errors before: $incumbent (+warn: $incumbent_w) this patch: $current (+warn: $current_w)" >&$DESC_FD +if [ $current_w -gt $incumbent_w ]; then + echo "New warnings added" 1>&2 + + rc=250 +fi + if [ $current -gt $incumbent ]; then echo "New errors added" 1>&2 diff -U 0 $tmpfile_o $tmpfile_n 1>&2 @@ -55,12 +61,6 @@ if [ $current -gt $incumbent ]; then rc=1 fi -if [ $current_w -gt $incumbent_w ]; then - echo "New warnings added" 1>&2 - - rc=250 -fi - rm "$tmpfile_o" "$tmpfile_n" exit $rc From 440cfca27f409ae3a02dea9168c9e2b039b94041 Mon Sep 17 00:00:00 2001 From: "Matthieu Baerts (NGI0)" Date: Wed, 4 Jun 2025 16:47:19 +0200 Subject: [PATCH 4/4] tests: pylint/shellcheck/yamllint: shellcheck compliant It sounds good to have the script checking for shellcheck compliance to be shellcheck compliant :) While at it, pylint and yamllint scripts have also be modified because they are inspired by the shellcheck one. Before the modifications, shellcheck was complaining about: 53 note: Double quote to prevent globbing and word splitting. [SC2086] 4 warning: Quote this to prevent word splitting. [SC2046] 3 error: Argument mixes string and array. Use * or separate argument. [SC2145] 2 warning: Use 'cd ... || exit' or 'cd ... || return' in case cd fails. [SC2164] Not any more. Also fix the indentation around the 'diff' at the end of each script, and in shellcheck.sh, s/Building/Checking/ like the others. Signed-off-by: Matthieu Baerts (NGI0) --- tests/patch/pylint/pylint.sh | 30 ++++++++++----------- tests/patch/shellcheck/shellcheck.sh | 40 ++++++++++++++-------------- tests/patch/yamllint/yamllint.sh | 30 ++++++++++----------- 3 files changed, 50 insertions(+), 50 deletions(-) diff --git a/tests/patch/pylint/pylint.sh b/tests/patch/pylint/pylint.sh index 59d2ad3..f8b3980 100755 --- a/tests/patch/pylint/pylint.sh +++ b/tests/patch/pylint/pylint.sh @@ -5,13 +5,13 @@ HEAD=$(git rev-parse HEAD) rc=0 pr() { - echo " ====== $@ ======" | tee -a /dev/stderr + echo " ====== $* ======" | tee -a /dev/stderr } # If it doesn't touch .py files, don't bother. Ignore deleted. if ! git show --diff-filter=AM --pretty="" --name-only "${HEAD}" | grep -q -E "\.py$" then - echo "No python scripts touched, skip" >&$DESC_FD + echo "No python scripts touched, skip" >&"$DESC_FD" exit 0 fi @@ -30,35 +30,35 @@ git checkout -q HEAD~ # Also ignore created, as not present in the parent commit for f in $(git show --diff-filter=M --pretty="" --name-only "${HEAD}" | grep -E "\.py$"); do - pylint $f | tee -a $tmpfile_o + pylint "$f" | tee -a "$tmpfile_o" done -incumbent=$(grep -i -c ": E[0-9][0-9][0-9][0-9]: " $tmpfile_o) -incumbent_w=$(grep -i -c ": [WC][0-9][0-9][0-9][0-9]: " $tmpfile_o) +incumbent=$(grep -i -c ": E[0-9][0-9][0-9][0-9]: " "$tmpfile_o") +incumbent_w=$(grep -i -c ": [WC][0-9][0-9][0-9][0-9]: " "$tmpfile_o") pr "Checking the tree with the patch" -git checkout -q $HEAD +git checkout -q "$HEAD" for f in $(git show --diff-filter=AM --pretty="" --name-only "${HEAD}" | grep -E "\.py$"); do - pylint $f | tee -a $tmpfile_n + pylint "$f" | tee -a "$tmpfile_n" done -current=$(grep -i -c ": E[0-9][0-9][0-9][0-9]: " $tmpfile_n) -current_w=$(grep -i -c ": [WC][0-9][0-9][0-9][0-9]: " $tmpfile_n) +current=$(grep -i -c ": E[0-9][0-9][0-9][0-9]: " "$tmpfile_n") +current_w=$(grep -i -c ": [WC][0-9][0-9][0-9][0-9]: " "$tmpfile_n") -echo "Errors before: $incumbent (+warn: $incumbent_w) this patch: $current (+warn: $current_w)" >&$DESC_FD +echo "Errors before: $incumbent (+warn: $incumbent_w) this patch: $current (+warn: $current_w)" >&"$DESC_FD" -if [ $current_w -gt $incumbent_w ]; then +if [ "$current_w" -gt "$incumbent_w" ]; then echo "New warnings added" 1>&2 rc=250 fi -if [ $current -gt $incumbent ]; then - echo "New errors added" 1>&2 - diff -U 0 $tmpfile_o $tmpfile_n 1>&2 +if [ "$current" -gt "$incumbent" ]; then + echo "New errors added" 1>&2 + diff -U 0 "$tmpfile_o" "$tmpfile_n" 1>&2 - rc=1 + rc=1 fi rm "$tmpfile_o" "$tmpfile_n" diff --git a/tests/patch/shellcheck/shellcheck.sh b/tests/patch/shellcheck/shellcheck.sh index d0a574a..1d647a0 100755 --- a/tests/patch/shellcheck/shellcheck.sh +++ b/tests/patch/shellcheck/shellcheck.sh @@ -5,13 +5,13 @@ HEAD=$(git rev-parse HEAD) rc=0 pr() { - echo " ====== $@ ======" | tee -a /dev/stderr + echo " ====== $* ======" | tee -a /dev/stderr } # If it doesn't touch .sh files, don't bother. Ignore deleted. if ! git show --diff-filter=AM --pretty="" --name-only "${HEAD}" | grep -q -E "\.sh$" then - echo "No shell scripts touched, skip" >&$DESC_FD + echo "No shell scripts touched, skip" >&"$DESC_FD" exit 0 fi @@ -31,43 +31,43 @@ git checkout -q HEAD~ # Also ignore created, as not present in the parent commit for f in $(git show --diff-filter=M --pretty="" --name-only "${HEAD}" | grep -E "\.sh$"); do ( - sha=$(echo $f | sha256sum | awk '{print $1}') + sha=$(echo "$f" | sha256sum | awk '{print $1}') echo "Checking $f - $sha" echo - cd $(dirname $f) + cd "$(dirname "$f")" || exit 1 sha="${tmpfile_o}_${sha}" rm -f "${sha}" - shellcheck -x $(basename $f) | tee -a "${tmpfile_o}" "${sha}" + shellcheck -x "$(basename "$f")" | tee -a "${tmpfile_o}" "${sha}" echo ) done # ex: SC3045 (warning): In POSIX sh, printf -v is undefined. # severity: error, warning, info, style -incumbent=$(grep -c " (error):" $tmpfile_o) -incumbent_w=$(grep -c " (warning):" $tmpfile_o) +incumbent=$(grep -c " (error):" "$tmpfile_o") +incumbent_w=$(grep -c " (warning):" "$tmpfile_o") -pr "Building the tree with the patch" -git checkout -q $HEAD +pr "Checking the tree with the patch" +git checkout -q "$HEAD" for f in $(git show --diff-filter=AM --pretty="" --name-only "${HEAD}" | grep -E "\.sh$"); do ( - sha=$(echo $f | sha256sum | awk '{print $1}') + sha=$(echo "$f" | sha256sum | awk '{print $1}') echo "Checking $f - $sha" echo - cd $(dirname $f) + cd "$(dirname "$f")" || exit 1 sha="${tmpfile_n}_${sha}" rm -f "${sha}" - shellcheck -x $(basename $f) | tee -a "${tmpfile_n}" "${sha}" + shellcheck -x "$(basename "$f")" | tee -a "${tmpfile_n}" "${sha}" echo ) done # severity: error, warning, info, style -current=$(grep -c " (error):" $tmpfile_n) -current_w=$(grep -c " (warning):" $tmpfile_n) +current=$(grep -c " (error):" "$tmpfile_n") +current_w=$(grep -c " (warning):" "$tmpfile_n") # if a file was compliant before or is new, mark everything as error to keep it good. for f in "${tmpfile_n}_"*; do @@ -88,19 +88,19 @@ for f in "${tmpfile_n}_"*; do current=$((current + extra)) done -echo "Errors before: $incumbent (+warn: $incumbent_w) this patch: $current (+warn: $current_w)" >&$DESC_FD +echo "Errors before: $incumbent (+warn: $incumbent_w) this patch: $current (+warn: $current_w)" >&"$DESC_FD" -if [ $current_w -gt $incumbent_w ]; then +if [ "$current_w" -gt "$incumbent_w" ]; then echo "New warnings added" 1>&2 rc=250 fi -if [ $current -gt $incumbent ]; then - echo "New errors added" 1>&2 - diff -U 0 $tmpfile_o $tmpfile_n 1>&2 +if [ "$current" -gt "$incumbent" ]; then + echo "New errors added" 1>&2 + diff -U 0 "$tmpfile_o" "$tmpfile_n" 1>&2 - rc=1 + rc=1 fi rm "$tmpfile_o"* "$tmpfile_n"* diff --git a/tests/patch/yamllint/yamllint.sh b/tests/patch/yamllint/yamllint.sh index 51f80a9..2688ccc 100755 --- a/tests/patch/yamllint/yamllint.sh +++ b/tests/patch/yamllint/yamllint.sh @@ -5,13 +5,13 @@ HEAD=$(git rev-parse HEAD) rc=0 pr() { - echo " ====== $@ ======" | tee -a /dev/stderr + echo " ====== $* ======" | tee -a /dev/stderr } # If it doesn't touch .yaml files, don't bother. Ignore deleted. if ! git show --diff-filter=AM --pretty="" --name-only "${HEAD}" | grep -q -E "\.yaml$" then - echo "No YAML files touched, skip" >&$DESC_FD + echo "No YAML files touched, skip" >&"$DESC_FD" exit 0 fi @@ -30,35 +30,35 @@ git checkout -q HEAD~ # Also ignore created, as not present in the parent commit for f in $(git show --diff-filter=M --pretty="" --name-only "${HEAD}" | grep -E "\.yaml$"); do - yamllint $f | tee -a $tmpfile_o + yamllint "$f" | tee -a "$tmpfile_o" done -incumbent=$(grep -i -c " error " $tmpfile_o) -incumbent_w=$(grep -i -c " warning " $tmpfile_o) +incumbent=$(grep -i -c " error " "$tmpfile_o") +incumbent_w=$(grep -i -c " warning " "$tmpfile_o") pr "Checking the tree with the patch" -git checkout -q $HEAD +git checkout -q "$HEAD" for f in $(git show --diff-filter=AM --pretty="" --name-only "${HEAD}" | grep -E "\.yaml$"); do - yamllint $f | tee -a $tmpfile_n + yamllint "$f" | tee -a "$tmpfile_n" done -current=$(grep -i -c " error " $tmpfile_n) -current_w=$(grep -i -c " warning " $tmpfile_n) +current=$(grep -i -c " error " "$tmpfile_n") +current_w=$(grep -i -c " warning " "$tmpfile_n") -echo "Errors before: $incumbent (+warn: $incumbent_w) this patch: $current (+warn: $current_w)" >&$DESC_FD +echo "Errors before: $incumbent (+warn: $incumbent_w) this patch: $current (+warn: $current_w)" >&"$DESC_FD" -if [ $current_w -gt $incumbent_w ]; then +if [ "$current_w" -gt "$incumbent_w" ]; then echo "New warnings added" 1>&2 rc=250 fi -if [ $current -gt $incumbent ]; then - echo "New errors added" 1>&2 - diff -U 0 $tmpfile_o $tmpfile_n 1>&2 +if [ "$current" -gt "$incumbent" ]; then + echo "New errors added" 1>&2 + diff -U 0 "$tmpfile_o" "$tmpfile_n" 1>&2 - rc=1 + rc=1 fi rm "$tmpfile_o" "$tmpfile_n"