ci: add shellcheck step (#484)

This commit is contained in:
DevCats
2025-11-27 02:00:04 -05:00
committed by GitHub
parent 7c4ef92c8c
commit 70ca76e86d
55 changed files with 731 additions and 238 deletions
+1 -1
View File
@@ -57,7 +57,7 @@ mkdir -p "registry/${NAMESPACE}/modules/${MODULE_NAME}"
cp -r examples/modules/* "registry/${NAMESPACE}/modules/${MODULE_NAME}/"
# Change to module directory
cd "registry/${NAMESPACE}/modules/${MODULE_NAME}"
cd "registry/${NAMESPACE}/modules/${MODULE_NAME}" || exit
# Detect OS
if [[ "$OSTYPE" == "darwin"* ]]; then
+1 -1
View File
@@ -58,7 +58,7 @@ mkdir -p "registry/${NAMESPACE}/templates/${TEMPLATE_NAME}"
cp -r examples/templates/* "registry/${NAMESPACE}/templates/${TEMPLATE_NAME}/"
# Change to template directory
cd "registry/${NAMESPACE}/templates/${TEMPLATE_NAME}"
cd "registry/${NAMESPACE}/templates/${TEMPLATE_NAME}" || exit
# Detect OS and replace placeholders
if [[ "$OSTYPE" == "darwin"* ]]; then
+95
View File
@@ -0,0 +1,95 @@
#!/usr/bin/env bash
set -euo pipefail
# Auto-detect which shell scripts to validate based on changed files from paths-filter
# Uses paths-filter outputs from GitHub Actions:
# ALL_CHANGED_FILES - all files changed in the PR (for logging)
# SHARED_CHANGED - boolean indicating if shared infrastructure changed
# SHELL_CHANGED_FILES - only .sh files (for processing)
# Validates all shell scripts if shared infrastructure changes
#
# This script validates all shell scripts across the repository
validate_shell_script() {
local file="$1"
echo "Validating $file"
# Run shellcheck with warning severity level
# Using gcc format for better IDE/editor integration
if ! shellcheck --severity=warning --format=gcc "$file"; then
return 1
fi
return 0
}
main() {
echo "==> Detecting changed files..."
if [[ -n "${ALL_CHANGED_FILES:-}" ]]; then
echo "Changed files in PR:"
echo "$ALL_CHANGED_FILES" | tr ' ' '\n' | sed 's/^/ - /'
echo ""
fi
# Determine which files to check
local files_to_check=()
if [[ "${SHARED_CHANGED:-false}" == "true" ]]; then
echo "==> Shared infrastructure changed"
echo "==> Validating all shell scripts for safety"
# Find all .sh files in the repository, excluding node_modules, .git, and .terraform
mapfile -t files_to_check < <(find . -type f -name "*.sh" ! -path "*/node_modules/*" ! -path "*/.git/*" ! -path "*/.terraform/*" | sort)
elif [[ -z "${SHELL_CHANGED_FILES:-}" ]]; then
echo "✓ No shell script files changed, skipping validation"
exit 0
else
# Process only changed shell scripts
CHANGED_FILES=$(echo "$SHELL_CHANGED_FILES" | tr ' ' '\n')
while IFS= read -r file; do
if [[ -f "$file" && "$file" == *.sh ]]; then
files_to_check+=("$file")
fi
done <<< "$CHANGED_FILES"
fi
if [[ ${#files_to_check[@]} -eq 0 ]]; then
echo "✓ No shell scripts to validate"
exit 0
fi
echo "==> Validating ${#files_to_check[@]} shell script(s):"
for file in "${files_to_check[@]}"; do
echo " - $file"
done
echo ""
# Validate each file
local status=0
local failed_files=()
for file in "${files_to_check[@]}"; do
if ! validate_shell_script "$file"; then
status=1
failed_files+=("$file")
fi
done
# Report results
if [[ $status -eq 0 ]]; then
echo ""
echo "✓ All shell scripts passed validation"
else
echo ""
echo "❌ ShellCheck validation failed for ${#failed_files[@]} file(s):"
for file in "${failed_files[@]}"; do
echo " - $file"
done
fi
exit $status
}
main
+2 -2
View File
@@ -45,7 +45,7 @@ else
module="${BASH_REMATCH[2]}"
module_dir="registry/${namespace}/modules/${module}"
if [[ -d "$module_dir" ]] && [[ ! " ${MODULE_DIRS[*]} " =~ " ${module_dir} " ]]; then
if [[ -d "$module_dir" ]] && [[ ! " ${MODULE_DIRS[*]} " =~ " $module_dir " ]]; then
MODULE_DIRS+=("$module_dir")
fi
fi
@@ -67,7 +67,7 @@ else
for module_dir in "${MODULE_DIRS[@]}"; do
while IFS= read -r test_file; do
test_dir=$(dirname "$test_file")
if [[ ! " ${test_dirs[*]} " =~ " ${test_dir} " ]]; then
if [[ ! " ${test_dirs[*]} " =~ " $test_dir " ]]; then
test_dirs+=("$test_dir")
fi
done < <(find "$module_dir" -type f -name "*.tftest.hcl")
+10 -4
View File
@@ -29,13 +29,16 @@ main() {
echo ""
fi
local script_dir=$(dirname "$(readlink -f "$0")")
local registry_dir=$(readlink -f "$script_dir/../registry")
local script_dir
script_dir=$(dirname "$(readlink -f "$0")")
local registry_dir
registry_dir=$(readlink -f "$script_dir/../registry")
if [[ "${SHARED_CHANGED:-false}" == "true" ]]; then
echo "==> Shared infrastructure changed"
echo "==> Validating all modules for safety"
local subdirs=$(find "$registry_dir" -mindepth 3 -maxdepth 3 -path "*/modules/*" -type d | sort)
local subdirs
subdirs=$(find "$registry_dir" -mindepth 3 -maxdepth 3 -path "*/modules/*" -type d | sort)
elif [[ -z "${MODULE_CHANGED_FILES:-}" ]]; then
echo "✓ No module files changed, skipping validation"
exit 0
@@ -49,11 +52,14 @@ main() {
fi
if [[ "$file" =~ ^registry/([^/]+)/modules/([^/]+)/ ]]; then
local namespace
namespace="${BASH_REMATCH[1]}"
local module
module="${BASH_REMATCH[2]}"
local module_dir
module_dir="registry/${namespace}/modules/${module}"
if [[ -d "$module_dir" ]] && [[ ! " ${MODULE_DIRS[*]} " =~ " ${module_dir} " ]]; then
if [[ -d "$module_dir" ]] && [[ ! " ${MODULE_DIRS[*]} " =~ " $module_dir " ]]; then
MODULE_DIRS+=("$module_dir")
fi
fi
+1 -1
View File
@@ -42,7 +42,7 @@ while IFS= read -r file; do
module="${BASH_REMATCH[2]}"
module_dir="registry/${namespace}/modules/${module}"
if [[ -f "$module_dir/main.test.ts" ]] && [[ ! " ${MODULE_DIRS[*]} " =~ " ${module_dir} " ]]; then
if [[ -f "$module_dir/main.test.ts" ]] && [[ ! " ${MODULE_DIRS[*]} " =~ " $module_dir " ]]; then
MODULE_DIRS+=("$module_dir")
fi
fi
+73
View File
@@ -0,0 +1,73 @@
#!/usr/bin/env bash
set -eo pipefail
# Validates that shell scripts source external files BEFORE enabling 'set -u'
# This prevents failures when sourced files (like /etc/bashrc) reference undefined variables
#
# Background: When 'set -u' is active, any reference to undefined variables causes the script to exit.
# System files like /etc/bashrc may reference variables (like $EUID) that aren't set in the script context.
#
# Correct pattern:
# #!/bin/bash
# source "$HOME/.bashrc" # Source first
# set -euo pipefail # Then enable strict mode
#
# Incorrect pattern:
# #!/bin/bash
# set -euo pipefail # set -u enabled first
# source "$HOME/.bashrc" # This may fail if bashrc references undefined vars
echo "==> Validating 'set -u' usage order in shell scripts..."
# Track if we found any issues
found_issues=0
total_checked=0
# Find all shell scripts
while IFS= read -r file; do
# Skip if file doesn't exist (should not happen, but be safe)
[[ -f "$file" ]] || continue
# Check if file has both 'set -u' and 'source'/'.'
# Look for: set -u, set -eu, set -euo, set -uo, etc.
# Only check for sourcing common system/user files that might have undefined variables
if grep -q "^set -[a-z]*u" "$file" && grep -q -E "^\s*(source|\.)\s+.*(\\\$HOME/\.bashrc|/etc/bashrc|/etc/os-release)" "$file"; then
total_checked=$((total_checked + 1))
# Get the first occurrence of each pattern with line numbers
set_u_line=$(grep -n "^set -[a-z]*u" "$file" | head -1 | cut -d: -f1)
source_line=$(grep -n -E "^\s*(source|\.)\s+.*(\\\$HOME/\.bashrc|/etc/bashrc|/etc/os-release)" "$file" | head -1 | cut -d: -f1)
# Check if set -u comes before source (which is problematic)
if [[ "$set_u_line" -lt "$source_line" ]]; then
echo "ERROR: $file"
echo " 'set -u' at line $set_u_line comes before 'source' at line $source_line"
echo " This may cause failures when sourcing system files with undefined variables."
echo ""
found_issues=$((found_issues + 1))
fi
fi
done < <(find registry -name "*.sh" -type f ! -path "*/node_modules/*" ! -path "*/.git/*" ! -path "*/.terraform/*" | sort)
# Report results
if [[ $found_issues -gt 0 ]]; then
echo "================================================================"
echo "FAILED: Found $found_issues script(s) with incorrect 'set -u' order"
echo ""
echo "Fix: Move 'source' statements BEFORE 'set -u' to prevent failures"
echo "Example:"
echo " #!/bin/bash"
echo " source \"\$HOME/.bashrc\" # Source first"
echo " set -euo pipefail # Then enable strict mode"
echo ""
echo "See: SHELLCHECK_RESEARCH_REPORT.md for detailed analysis"
echo "================================================================"
exit 1
fi
if [[ $total_checked -eq 0 ]]; then
echo "No scripts found with both 'set -u' and 'source' statements"
else
echo "All $total_checked script(s) have correct 'set -u' ordering"
fi