Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for filenames with spaces #40

Merged
merged 7 commits into from
Apr 29, 2021
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
240 changes: 148 additions & 92 deletions entrypoint.sh
Original file line number Diff line number Diff line change
@@ -1,48 +1,72 @@
#!/bin/bash
#!/usr/bin/env bash

cd "$GITHUB_WORKSPACE" || exit 1
cd "$GITHUB_WORKSPACE" || {
printf 'Directory not found: "%s"\n' "$GITHUB_WORKSPACE"
exit 1
}

SHELLCHECK_DISABLE=0
SHFMT_DISABLE=0
SH_CHECKER_COMMENT=0
CHECKBASHISMS_ENABLE=0

if [ "${INPUT_SH_CHECKER_SHELLCHECK_DISABLE}" == "1" ] || [ "${INPUT_SH_CHECKER_SHELLCHECK_DISABLE}" == "true" ]; then
SHELLCHECK_DISABLE=1
shopt -s nocasematch

if [[ "${INPUT_SH_CHECKER_SHELLCHECK_DISABLE}" =~ ^(1|true|on|yes)$ ]]; then
SHELLCHECK_DISABLE=1
fi

if [ "${INPUT_SH_CHECKER_SHFMT_DISABLE}" == "1" ] || [ "${INPUT_SH_CHECKER_SHFMT_DISABLE}" == "true" ]; then
SHFMT_DISABLE=1
if [[ "${INPUT_SH_CHECKER_SHFMT_DISABLE}" =~ ^(1|true|on|yes)$ ]]; then
SHFMT_DISABLE=1
fi

if [ "${INPUT_SH_CHECKER_COMMENT}" == "1" ] || [ "${INPUT_SH_CHECKER_COMMENT}" == "true" ]; then
SH_CHECKER_COMMENT=1
if [[ "${INPUT_SH_CHECKER_COMMENT}" =~ ^(1|true|on|yes)$ ]]; then
SH_CHECKER_COMMENT=1
fi

if [ "$SHELLCHECK_DISABLE" == "1" ] && [ "$SHFMT_DISABLE" == "1" ]; then
echo "All checks are disabled, it's mean that \`sh_checker_shellcheck_disable\` and \`sh_checker_shfmt_disable\` are true"
if [[ "${INPUT_SH_CHECKER_CHECKBASHISMS_ENABLE}" =~ ^(1|true|on|yes)$ ]]; then
CHECKBASHISMS_ENABLE=1
fi

if [ "${INPUT_SH_CHECKER_CHECKBASHISMS_ENABLE}" == "1" ] || [ "${INPUT_SH_CHECKER_CHECKBASHISMS_ENABLE}" == "true" ]; then
CHECKBASHISMS_ENABLE=1
if ((SHELLCHECK_DISABLE == 1 && SHFMT_DISABLE == 1 && CHECKBASHISMS_ENABLE != 1)); then
echo "All checks are disabled: \`sh_checker_shellcheck_disable\` and \`sh_checker_shfmt_disable\` are both set to 1/true."
fi

# Internal functions
_show_sh_files() {
local sh_files
sh_files="$(shfmt -f .)"

if [ -n "$INPUT_SH_CHECKER_EXCLUDE" ]; then
for i in $INPUT_SH_CHECKER_EXCLUDE; do
sh_files="$(echo "$sh_files" | grep -Ev "$i")"
done
fi

echo "$sh_files"
# using a global, as returning arrays in bash is ugly
# setting IFS to \n allows for spaces in file names:
IFS=$'\n' mapfile -t sh_files < <(shfmt -f .)

if [ -z "$INPUT_SH_CHECKER_EXCLUDE" ]; then
return 0
fi

OLDIFS="$IFS"
IFS=$' \t\n' read -d '' -ra excludes <<<"$INPUT_SH_CHECKER_EXCLUDE"
IFS=$'\n'
sh_all=("${sh_files[@]}")
sh_files=()
excluded=()
local sh exclude
for sh in "${sh_all[@]}"; do
for exclude in "${excludes[@]}"; do
grep -q -E "$exclude" <<<"$sh" || continue
excluded+=("$sh")
continue 2
done
sh_files+=("$sh")
done
if (("${#excluded[@]}" != 0)); then
printf 'The following %d shell script(s) will not be checked:\n' "${#excluded[@]}"
printf '"%s"\n' "${excluded[@]}"
fi
IFS="$OLDIFS"
}

_comment_on_github() {
local -r content="
local content
IFS= read -r -d '' content <<EOF
#### \`sh-checker report\`

To get the full details, please check in the [job]("https://github.com/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID") output.
Expand All @@ -51,104 +75,136 @@ To get the full details, please check in the [job]("https://github.com/$GITHUB_R
<summary>shellcheck errors</summary>

\`\`\`
${1:-No errors or shellcheck is disabled}
$1
\`\`\`
</details>

<details>
<summary>shfmt erros</summary>
<summary>shfmt errors</summary>

\`\`\`
${2:-No errors or shfmt is disabled}
$2
\`\`\`
</details>

"
local -r payload=$(echo "$content" | jq -R --slurp '{body: .}')
local -r comment_url=$(jq -r .pull_request.comments_url <"$GITHUB_EVENT_PATH")
EOF
local -r payload=$(jq -R --slurp '{body: .}' <<<"$content")
local -r comment_url=$(jq -r .pull_request.comments_url <"$GITHUB_EVENT_PATH")

echo "Commenting on the pull request"
echo "$payload" | curl -s -S -H "Authorization: token $GITHUB_TOKEN" --header "Content-Type: application/json" --data @- "$comment_url" >/dev/null
echo "Commenting on the pull request"
curl -s -S -H "Authorization: token $GITHUB_TOKEN" --header "Content-Type: application/json" --data @- "$comment_url" <<<"$payload" >/dev/null
}

sh_files="$(_show_sh_files)"

test "$sh_files" || {
if ((ONLY_DIFF == 1)); then
echo "No shell scripts were changed."
else
echo "No shell scripts found in this repository. Make a sure that you did a checkout :)"
fi
exit 0
_show_sh_files

((${#sh_files[@]} == 0)) && {
if ((ONLY_DIFF == 1)); then
echo "No shell scripts were changed."
exit 0
fi
if [ -n "$INPUT_SH_CHECKER_EXCLUDE" ]; then
if ((${#excluded[@]} == ${#sh_all[@]})); then
printf 'All %d shell script(s) have been excluded per your sh_checker_exclude setting:\n' "${#sh_all[@]}"
IFS=$' \t\n' printf '"%s"\n' "${excludes[@]}"
exit 0
fi
fi
echo "No shell scripts were found in this repository. Please check your settings."
exit 0
}

# Validate sh files
shellcheck_code=0
checkbashisms_code=0
shfmt_code=0
exit_code=0

if [ "$SHELLCHECK_DISABLE" != "1" ]; then
echo -e "Validating shell scripts files using shellcheck\n"
# shellcheck disable=SC2086
shellcheck_error=$( (shellcheck $sh_files) | while read -r x; do echo "$x"; done)
test -n "$shellcheck_error" && {
shellcheck_code="1"
}
shellcheck_error='shellcheck checking is disabled.'
shfmt_error='shfmt checking is disabled.'

if ((SHELLCHECK_DISABLE != 1)); then
printf "Validating %d shell script(s) using 'shellcheck %s':\\n" "${#sh_files[@]}" "$SHELLCHECK_OPTS"
IFS=$' \t\n' read -d '' -ra args <<<"$SHELLCHECK_OPTS"
shellcheck_output="$(shellcheck "${args[@]}" "${sh_files[@]}" 2>&1)"
shellcheck_code=$?
if ((shellcheck_code == 0)); then
printf -v shellcheck_error "'shellcheck %s' found no issues.\\n" "$SHELLCHECK_OPTS"
else
# .shellcheck returns 0-4: https://github.com/koalaman/shellcheck/blob/dff8f9492a153b4ad8ac7d085136ce532e8ea081/shellcheck.hs#L191
exit_code=$shellcheck_code
IFS= read -r -d '' shellcheck_error <<EOF

'shellcheck $SHELLCHECK_OPTS' returned error $shellcheck_code finding the following syntactical issues:

----------
$shellcheck_output
----------

You can address the above issues in on of three ways:
1. Manually correct the issue in the offending shell script;
2. Disable specific issues by adding the comment:
# shellcheck disable=NNNN
above the line that contains the issue, where NNNN is the error code;
3. Add '-e NNNN' to the SHELLCHECK_OPTS setting in your .yml action file.


EOF
fi
printf '%s' "$shellcheck_error"
fi

if [ "$SHFMT_DISABLE" != "1" ]; then
echo -e "Validating shell scripts files using shfmt\n"
# shellcheck disable=SC2086
shfmt_error="$(eval shfmt $SHFMT_OPTS -d $sh_files)"
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lost the -d, per #44

shfmt_code="$?"
fi
if ((SHFMT_DISABLE != 1)); then
printf "Validating %d shell script(s) using 'shfmt %s':\\n" "${#sh_files[@]}" "$SHFMT_OPTS"
IFS=$' \t\n' read -d '' -ra args <<<"$SHFMT_OPTS"
shfmt_output="$(shfmt "${args[@]}" "${sh_files[@]}" 2>&1)"
shfmt_code=$?
if ((shfmt_code == 0)); then
printf -v shfmt_error "'shfmt %s' found no issues.\\n" "$SHFMT_OPTS"
else
# shfmt returns 0 or 1: https://github.com/mvdan/sh/blob/dbbad59b44d586c0f3d044a3820c18c41b495e2a/cmd/shfmt/main.go#L72
((exit_code |= 8))
IFS= read -r -d '' shfmt_error <<EOF

if [ "$CHECKBASHISMS_ENABLE" == "1" ]; then
echo -e "Validating 'bashisms' for shell scripts files using checkbashisms\n"
# shellcheck disable=SC2086
checkbashisms_error="$(checkbashisms $sh_files)"
checkbashisms_code="$?"
fi
'shfmt $SHFMT_OPTS' returned error $shfmt_code finding the following formatting issues:

# Outputs
if [ "$SHELLCHECK_DISABLE" != 1 ]; then
test "$shellcheck_code" != "0" && {
echo -e "$shellcheck_error"
echo -e "\nThe files above have some shellcheck issues\n"
exit_code=1
}
fi
----------
$shfmt_output
----------

You can reformat the above files to meet shfmt's requirements by typing:

shfmt $SHFMT_OPTS -w filename

if [ "$SHFMT_DISABLE" != 1 ]; then
test "$shfmt_code" != "0" && {
echo -e "$shfmt_error"
echo -e "\nThe files above have some formatting problems, you can use \`shfmt -w\` to fix them\n"
exit_code=1
}
EOF
fi
printf '%s' "$shfmt_error"
fi

if [ "$CHECKBASHISMS_ENABLE" == "1" ]; then
test "$checkbashisms_code" != "0" && {
echo -e "$checkbashisms_error"
echo -e "\nThe files above have some checkbashisms issues\n"
if ((checkbashisms_code != 4)); then
exit_code=1
else
# see https://github.com/duggan/shlint/blob/0fcd979319e3f37c2cd53ccea0b51e16fda710a1/lib/checkbashisms#L489
echo -e "Ignoring 'could not find any possible bashisms in bash script' issues"
fi
}
if ((CHECKBASHISMS_ENABLE == 1)); then
printf '\n\nValidating %d shell script(s) files using checkbashisms:\n' "${#sh_files[@]}"
checkbashisms "${sh_files[@]}"
checkbashisms_code=$?
if ((checkbashisms_code == 0)); then
printf '\ncheckbashisms found no issues.\n'
else
printf '\ncheckbashisms returned error %d finding the bashisms listed above.\n' "$checkbashisms_code"
if ((checkbashisms_code == 4)); then
# see https://github.com/duggan/shlint/blob/0fcd979319e3f37c2cd53ccea0b51e16fda710a1/lib/checkbashisms#L489
printf "\\nIgnoring 'could not find any possible bashisms in bash script' issues\\n"
else
# checkbashisms returns 0-3: https://linux.die.net/man/1/checkbashisms
((exit_code |= (checkbashisms_code << 4)))
fi
fi
fi

if [ "$shellcheck_code" != "0" ] || [ "$shfmt_code" != "0" ]; then
if [ "$GITHUB_EVENT_NAME" == "pull_request" ] && [ "$SH_CHECKER_COMMENT" == "1" ]; then
_comment_on_github "$shellcheck_error" "$shfmt_error"
fi
if ((shellcheck_code != 0 || shfmt_code != 0)); then
if [ "$GITHUB_EVENT_NAME" == "pull_request" ] && ((SH_CHECKER_COMMENT == 1)); then
_comment_on_github "$shellcheck_error" "$shfmt_error"
fi
fi

if [ "$shellcheck_code" == "0" ] && [ "$shfmt_code" == "0" ]; then
echo -e "All sh files found looks fine :)\n"
if ((exit_code == 0)); then
printf '\nNo issues found in the %d shell script(s) scanned :)\n' "${#sh_files[@]}"
fi

exit "$exit_code"
exit $exit_code