mirror of
https://github.com/coder/registry.git
synced 2026-06-02 20:48:14 +00:00
ci: add shellcheck step (#484)
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Executable
+95
@@ -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
|
||||
@@ -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")
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Executable
+73
@@ -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
|
||||
Reference in New Issue
Block a user