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

Shellcheck workflow #9119

Merged
merged 5 commits into from
Dec 8, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
125 changes: 125 additions & 0 deletions .github/workflows/shellcheck.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
---
name: Shellcheck
on:
pull_request:
env:
SHELLCHECK_REPO: 'koalaman/shellcheck'
SHELLCHECK_VERSION: 'v0.9.0'
SHELLCHECK_SHA: '038fd81de6b7e20cc651571362683853670cdc71'
Comment on lines +6 to +8
Copy link
Contributor

Choose a reason for hiding this comment

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

Are Renovate or Dependabot able to monitor new releases for this kind of definition?

Copy link
Contributor

Choose a reason for hiding this comment

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

I'd say lets merge this PR and see if Renovate/Dependabot catch it in the future. I suspect it doesn't get rev'ed frequently and I'd rather have this in place with the chance of it going stale vs not have it in place.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I suspect Renovate / Dependabot won't catch this, but thankfully shellcheck only seems to release about once a year, and I don't think we'd miss out on much if we were one release behind.

jobs:
shellcheck:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Grab shellcheck
run: |
set -e

SHELLCHECK_TARBALL_URL="https://github.com/${SHELLCHECK_REPO}/releases/download/${SHELLCHECK_VERSION}/shellcheck-${SHELLCHECK_VERSION}.linux.x86_64.tar.xz"
SHELLCHECK_TARBALL_LOC="shellcheck.tar.xz"
curl -L "${SHELLCHECK_TARBALL_URL}" -o "${SHELLCHECK_TARBALL_LOC}"
tarball_sha=$(shasum ${SHELLCHECK_TARBALL_LOC} | awk '{print $1}')
if [ "${tarball_sha}" != "${SHELLCHECK_SHA}" ]; then
echo "Got invalid SHA for shellcheck: ${tarball_sha}"
exit 1
fi
tar -xvf "${SHELLCHECK_TARBALL_LOC}"
cd "shellcheck-${SHELLCHECK_VERSION}" || exit 1
mv shellcheck "${GITHUB_WORKSPACE}/shellcheck"

- name: Run shellcheck
shell: bash
run: |
set -o pipefail

# Make sure we already put the proper shellcheck binary in place
if [ ! -f "./shellcheck" ]; then
echo "shellcheck not found"
exit 1
fi

# Make sure we know what to compare the PR's changes against
if [ -z "${GITHUB_BASE_REF}" ]; then
echo "No base reference supplied"
exit 1
fi

num_findings=0

# Execute shellcheck and add errors based on the output
run_shellcheck() {
local modified_shell_script="${1}"
local findings_file="findings.txt"

# Remove leftover findings file from previous iterations
if [ -f "${findings_file}" ]; then
rm "${findings_file}"
fi

echo "Running shellcheck against ${modified_shell_script}..."

# If shellcheck reported no errors (exited with 0 status code), return
if ./shellcheck -f json -S warning "${modified_shell_script}" | jq -c '.[]' > "${findings_file}"; then
return 0
fi

# Walk each of the individual findings
while IFS= read -r finding; do
num_findings=$((num_findings+1))

line=$(echo "${finding}" | jq '.line')
end_line=$(echo "${finding}" | jq '.endLine')
column=$(echo "${finding}" | jq '.column')
end_column=$(echo "${finding}" | jq '.endColumn')
code=$(echo "${finding}" | jq '.code')
title="SC${code}"
message="$(echo "${finding}" | jq -r '.message') See https://github.com/koalaman/shellcheck/wiki/${title}"

echo "Line: ${line}"
echo "End line: ${end_line}"
echo "Column: ${column}"
echo "End column: ${end_column}"
echo "Title: ${title}"
echo "Message: ${message}"

# Raise an error with the file/line/etc
echo "::error file=${modified_shell_script},line=${line},endLine=${end_line},column=${column},endColumn=${end_column},title=${title}::${message}"
done < ${findings_file}
}

# Find the shell scripts that were created or modified by this PR
find_modified_shell_scripts() {
shell_scripts="shell_scripts.txt"
modified_files="modified_files.txt"
modified_shell_scripts="modified_shell_scripts.txt"

find . -name "*.sh" -or -name "*.bash" | sed 's#^\./##' > "${shell_scripts}"
git diff --name-only "origin/${GITHUB_BASE_REF}" HEAD > "${modified_files}"

if [ ! -s "${shell_scripts}" ] || [ ! -s "${modified_files}" ]; then
echo "No modified shell scripts detected"
exit 0
fi

if ! grep -Fxf "${shell_scripts}" "${modified_files}" > "${modified_shell_scripts}"; then
echo "No modified shell scripts detected"
exit 0
fi
}

git fetch origin "${GITHUB_BASE_REF}" || exit 1

find_modified_shell_scripts

# Loop through the modified shell scripts
while IFS= read -r modified_shell_script; do
run_shellcheck "${modified_shell_script}"
done < ${modified_shell_scripts}

# If shellcheck reported any findings, fail the workflow
if [ ${num_findings} -gt 0 ]; then
echo "shellcheck reported ${num_findings} findings."
exit 1
fi