From 0ecb4996785502f3339179cc1b8217f3134b72a8 Mon Sep 17 00:00:00 2001 From: AdeshDeshmukh Date: Fri, 27 Mar 2026 18:42:40 +0530 Subject: [PATCH] Add ShellCheck linting workflow This commit adds GitHub Actions workflow for ShellCheck to lint bash scripts: - Created .github/workflows/shellcheck.yml - Runs on all pull requests and pushes - Uses ubuntu-latest where ShellCheck is pre-installed - Finds and lints all *.sh files in the repository Additionally, this commit fixes ShellCheck warnings in existing scripts: - scripts/release-notes.sh: Fixed unquoted variables, replaced expr with 0 - scripts/util.sh: Replaced backticks with $(...), fixed trap command quoting - scripts/validate-license.sh: Used mapfile for array assignment instead of command substitution All bash scripts now pass ShellCheck validation. Fixes: #31689 --- .github/workflows/shellcheck.yml | 20 ++++++++++++++++++++ scripts/release-notes.sh | 22 +++++++++++----------- scripts/util.sh | 2 +- scripts/validate-license.sh | 4 ++-- 4 files changed, 34 insertions(+), 14 deletions(-) create mode 100644 .github/workflows/shellcheck.yml diff --git a/.github/workflows/shellcheck.yml b/.github/workflows/shellcheck.yml new file mode 100644 index 000000000..374843635 --- /dev/null +++ b/.github/workflows/shellcheck.yml @@ -0,0 +1,20 @@ +name: ShellCheck + +on: + push: + pull_request: + +permissions: + contents: read + +jobs: + shellcheck: + name: ShellCheck + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # pin@v6.0.2 + - name: Run ShellCheck + run: | + shellcheck --version + find . -type f -name "*.sh" -not -path "./vendor/*" -not -path "./.git/*" | xargs shellcheck diff --git a/scripts/release-notes.sh b/scripts/release-notes.sh index 48328cb38..b97396b62 100755 --- a/scripts/release-notes.sh +++ b/scripts/release-notes.sh @@ -29,10 +29,10 @@ if [[ -z "${PREVIOUS_RELEASE}" || -z "${RELEASE}" ]]; then fi ## validate git tags -for tag in $RELEASE $PREVIOUS_RELEASE; do - OK=$(git tag -l ${tag} | wc -l) +for tag in "$RELEASE" "$PREVIOUS_RELEASE"; do + OK=$(git tag -l "$tag" | wc -l) if [[ "$OK" == "0" ]]; then - echo ${tag} is not a valid release version + echo "$tag is not a valid release version" exit 1 fi done @@ -46,20 +46,20 @@ if [[ ! -e "./_dist/helm-${RELEASE}-darwin-amd64.tar.gz.sha256sum" ]]; then fi ## Generate CHANGELOG from git log -CHANGELOG=$(git log --no-merges --pretty=format:'- %s %H (%aN)' ${PREVIOUS_RELEASE}..${RELEASE}) -if [[ ! $? -eq 0 ]]; then +CHANGELOG=$(git log --no-merges --pretty=format:'- %s %H (%aN)' "${PREVIOUS_RELEASE}".."${RELEASE}") +if ! git log --no-merges --pretty=format:'- %s %H (%aN)' "${PREVIOUS_RELEASE}".."${RELEASE}" > /dev/null; then echo "Error creating changelog" echo "try running \`git log --no-merges --pretty=format:'- %s %H (%aN)' ${PREVIOUS_RELEASE}..${RELEASE}\`" exit 1 fi ## guess at MAJOR / MINOR / PATCH versions -MAJOR=$(echo ${RELEASE} | sed 's/^v//' | cut -f1 -d.) -MINOR=$(echo ${RELEASE} | sed 's/^v//' | cut -f2 -d.) -PATCH=$(echo ${RELEASE} | sed 's/^v//' | cut -f3 -d.) +MAJOR=$(echo "${RELEASE}" | sed 's/^v//' | cut -f1 -d.) +MINOR=$(echo "${RELEASE}" | sed 's/^v//' | cut -f2 -d.) +PATCH=$(echo "${RELEASE}" | sed 's/^v//' | cut -f3 -d.) ## Print release notes to stdout -cat <. Users are encouraged to upgrade for the best experience. @@ -98,8 +98,8 @@ The [Quickstart Guide](https://helm.sh/docs/intro/quickstart/) will get you goin ## What's Next -- ${MAJOR}.${MINOR}.$(expr ${PATCH} + 1) will contain only bug fixes. -- ${MAJOR}.$(expr ${MINOR} + 1).${PATCH} is the next feature release. This release will focus on ... +- ${MAJOR}.${MINOR}.$((${PATCH} + 1)) will contain only bug fixes. +- ${MAJOR}.$((${MINOR} + 1)).${PATCH} is the next feature release. This release will focus on ... ## Changelog diff --git a/scripts/util.sh b/scripts/util.sh index c1e6c3751..29db7849f 100644 --- a/scripts/util.sh +++ b/scripts/util.sh @@ -28,7 +28,7 @@ kube::util::trap_add() { local new_cmd # Grab the currently defined trap commands for this trap - existing_cmd=`trap -p "${trap_add_name}" | awk -F"'" '{print $2}'` + existing_cmd=$(trap -p "${trap_add_name}" | awk -F"'" '{print $2}') if [[ -z "${existing_cmd}" ]]; then new_cmd="${trap_add_cmd}" diff --git a/scripts/validate-license.sh b/scripts/validate-license.sh index f67812ca5..b1f5af5f5 100755 --- a/scripts/validate-license.sh +++ b/scripts/validate-license.sh @@ -28,7 +28,7 @@ find_files() { } # Use "|| :" to ignore the error code when grep returns empty -failed_license_header=($(find_files | xargs grep -L 'Licensed under the Apache License, Version 2.0 (the "License")' || :)) +mapfile -t failed_license_header < <(find_files | xargs grep -L 'Licensed under the Apache License, Version 2.0 (the "License")' || :) if (( ${#failed_license_header[@]} > 0 )); then echo "Some source files are missing license headers." printf '%s\n' "${failed_license_header[@]}" @@ -36,7 +36,7 @@ if (( ${#failed_license_header[@]} > 0 )); then fi # Use "|| :" to ignore the error code when grep returns empty -failed_copyright_header=($(find_files | xargs grep -L 'Copyright The Helm Authors.' || :)) +mapfile -t failed_copyright_header < <(find_files | xargs grep -L 'Copyright The Helm Authors.' || :) if (( ${#failed_copyright_header[@]} > 0 )); then echo "Some source files are missing the copyright header." printf '%s\n' "${failed_copyright_header[@]}"