Skip to content

Commit fe4750c

Browse files
owineclaude
andcommitted
feat: add shellcheck validation to deployment scripts
Add comprehensive shell script linting with shellcheck: Script Fixes: - Fix lib/ssh-helpers.sh issues - Change ${@:3} to ${*:3} for proper string concatenation - Add quotes around variables in comparisons (SC2086) - All retry functions now follow best practices - Fix health-check.sh issues - Quote SSH_USER and SSH_HOST variables properly - Add shellcheck configuration - Create .shellcheckrc to disable SC1091 (sourced files) - Add shellcheck directives to all scripts Lint Workflow Integration: - Add new "shellcheck" job to lint.yml - Validates all deployment scripts in parallel - Runs on every lint workflow execution - Checks compose-workflow repository (owine/compose-workflow) - Update lint-summary job - Include shellcheck results in summary - Add shellcheck status to final determination - Display shellcheck validation results - Update Discord notifications - Add shellcheck status to validation summary - Include dedicated shellcheck failure section - Show actionable error messages Benefits: ✅ Catch common shell scripting errors early ✅ Enforce best practices (quoting, variable usage) ✅ Improve script reliability and maintainability ✅ Validate scripts on every workflow run ✅ Prevent deployment of broken scripts All deployment scripts now pass shellcheck validation with best practices enforced across the codebase. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
1 parent b4e6e4d commit fe4750c

File tree

8 files changed

+119
-12
lines changed

8 files changed

+119
-12
lines changed

.github/workflows/lint.yml

Lines changed: 96 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,70 @@ jobs:
154154
- name: Run actionlint
155155
uses: raven-actions/actionlint@963d4779ef039e217e5d0e6fd73ce9ab7764e493 # v2.1.0
156156

157+
shellcheck:
158+
name: Shell script validation
159+
runs-on: ubuntu-24.04
160+
timeout-minutes: 5
161+
steps:
162+
- name: Checkout compose-workflow repository
163+
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
164+
with:
165+
repository: owine/compose-workflow
166+
ref: main
167+
168+
- name: Display version information
169+
run: |
170+
echo "📋 ShellCheck Validation"
171+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
172+
echo "Repository: compose-workflow (deployment scripts)"
173+
echo "Runner: ${{ runner.os }} ${{ runner.arch }}"
174+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
175+
176+
- name: Run shellcheck on deployment scripts
177+
run: |
178+
echo "🐚 Starting ShellCheck validation for deployment scripts..."
179+
echo ""
180+
181+
# Find and validate all shell scripts
182+
SCRIPTS=$(find scripts/deployment -name "*.sh" -type f | sort)
183+
184+
if [ -z "$SCRIPTS" ]; then
185+
echo "⚠️ No shell scripts found in scripts/deployment/"
186+
exit 0
187+
fi
188+
189+
echo "📁 Scripts to validate:"
190+
# shellcheck disable=SC2001
191+
echo "$SCRIPTS" | sed 's/^/ • /'
192+
echo ""
193+
194+
# Run shellcheck on all scripts
195+
FAILED=0
196+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
197+
198+
for script in $SCRIPTS; do
199+
echo "🔍 Checking: $script"
200+
if shellcheck "$script"; then
201+
echo " ✅ PASSED"
202+
else
203+
echo " ❌ FAILED"
204+
FAILED=1
205+
fi
206+
echo ""
207+
done
208+
209+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
210+
211+
if [ $FAILED -eq 0 ]; then
212+
echo "🎉 ALL SHELL SCRIPTS PASSED VALIDATION"
213+
echo " All deployment scripts follow best practices"
214+
else
215+
echo "💥 SHELL SCRIPT VALIDATION FAILED"
216+
echo " Fix the issues shown above"
217+
echo " Run locally: shellcheck scripts/deployment/**/*.sh"
218+
exit 1
219+
fi
220+
157221
lint:
158222
strategy:
159223
matrix:
@@ -358,7 +422,7 @@ jobs:
358422
lint-summary:
359423
name: Lint Summary
360424
runs-on: ubuntu-24.04
361-
needs: [scanning, actionlint, lint]
425+
needs: [scanning, actionlint, shellcheck, lint]
362426
if: always()
363427
timeout-minutes: 5
364428
steps:
@@ -463,6 +527,26 @@ jobs:
463527
464528
echo ""
465529
530+
# ShellCheck Shell Script Validation Results
531+
echo "🐚 SHELL SCRIPT VALIDATION (SHELLCHECK)"
532+
echo "───────────────────────────────────────────────────────────────────────────────────"
533+
case "${{ needs.shellcheck.result }}" in
534+
"success")
535+
echo "✅ PASSED - All deployment scripts follow best practices"
536+
SHELLCHECK_OK=true
537+
;;
538+
"failure")
539+
echo "❌ FAILED - Shell script issues detected"
540+
SHELLCHECK_OK=false
541+
;;
542+
*)
543+
echo "❓ UNKNOWN - Unexpected shellcheck result: ${{ needs.shellcheck.result }}"
544+
SHELLCHECK_OK=false
545+
;;
546+
esac
547+
548+
echo ""
549+
466550
# Detailed Lint Results with Error Reproduction
467551
echo "📋 CODE QUALITY VALIDATION - DETAILED RESULTS"
468552
echo "───────────────────────────────────────────────────────────────────────────────────"
@@ -580,7 +664,7 @@ jobs:
580664
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
581665
582666
# Final determination
583-
if [[ "$SCANNING_OK" == "true" && "$ACTIONLINT_OK" == "true" && "$LINT_OK" == "true" ]]; then
667+
if [[ "$SCANNING_OK" == "true" && "$ACTIONLINT_OK" == "true" && "$SHELLCHECK_OK" == "true" && "$LINT_OK" == "true" ]]; then
584668
echo "🎉 FINAL STATUS: ALL VALIDATION CHECKS PASSED"
585669
echo " Repository is ready for deployment"
586670
exit 0
@@ -591,6 +675,7 @@ jobs:
591675
echo " Failed components:"
592676
[[ "$SCANNING_OK" != "true" ]] && echo " • GitGuardian security scanning"
593677
[[ "$ACTIONLINT_OK" != "true" ]] && echo " • Workflow validation (actionlint)"
678+
[[ "$SHELLCHECK_OK" != "true" ]] && echo " • Shell script validation (shellcheck)"
594679
[[ "$LINT_OK" != "true" ]] && echo " • Code quality validation (see detailed errors above)"
595680
echo ""
596681
exit 1
@@ -599,7 +684,7 @@ jobs:
599684
notify:
600685
name: Discord Notification
601686
runs-on: ubuntu-24.04
602-
needs: [scanning, actionlint, lint, lint-summary]
687+
needs: [scanning, actionlint, shellcheck, lint, lint-summary]
603688
if: always()
604689
steps:
605690
- name: Configure 1Password Service Account
@@ -628,6 +713,7 @@ jobs:
628713
629714
**🔒 Security Scan:** ${{ needs.scanning.result == 'success' && '✅ No secrets detected' || needs.scanning.result == 'skipped' && '⏭️ Skipped (PR/manual)' || '❌ Issues found' }}
630715
**⚙️ Workflow Validation:** ${{ needs.actionlint.result == 'success' && '✅ All workflows valid' || '❌ Issues detected' }}
716+
**🐚 Shell Scripts:** ${{ needs.shellcheck.result == 'success' && '✅ Best practices followed' || '❌ Issues detected' }}
631717
**📋 Code Quality:** ${{ needs.lint.result == 'success' && '✅ All stacks valid' || '❌ Issues detected' }}
632718
633719
**📂 Validated Stacks:** `${{ join(fromJson(inputs.stacks), '`, `') }}`
@@ -641,6 +727,13 @@ jobs:
641727
• Fix workflow syntax, shellcheck, or expression errors
642728
• Test locally: `actionlint .github/workflows/*.yml`' || '' }}
643729
730+
${{ needs.shellcheck.result == 'failure' && '
731+
**🐚 Shell Script Issues:**
732+
• Shell script best practices violations detected
733+
• Review the **Shell Script Validation** job for details
734+
• Fix quoting, variable usage, or syntax issues
735+
• Test locally: `shellcheck scripts/deployment/**/*.sh`' || '' }}
736+
644737
${{ needs.lint.result == 'failure' && '
645738
**🚨 Action Required:**
646739
• Review stack validation errors in workflow logs

scripts/deployment/.shellcheckrc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# ShellCheck configuration for deployment scripts
2+
# Disable SC1091 - Not following sourced files
3+
# This is intentional as library files are in a known location (lib/)
4+
disable=SC1091

scripts/deployment/cleanup-stack.sh

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@ set -euo pipefail
77

88
# Get script directory and source libraries
99
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
10+
# shellcheck source=lib/ssh-helpers.sh
1011
source "$SCRIPT_DIR/lib/ssh-helpers.sh"
12+
# shellcheck source=lib/common.sh
1113
source "$SCRIPT_DIR/lib/common.sh"
1214

1315
# Default values

scripts/deployment/deploy-stacks.sh

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ set -euo pipefail
77

88
# Get script directory and source libraries
99
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
10+
# shellcheck source=lib/ssh-helpers.sh
11+
# shellcheck source=lib/common.sh
1012
source "$SCRIPT_DIR/lib/ssh-helpers.sh"
1113
source "$SCRIPT_DIR/lib/common.sh"
1214

scripts/deployment/detect-removed-stacks.sh

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ set -euo pipefail
77

88
# Get script directory and source libraries
99
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
10+
# shellcheck source=lib/ssh-helpers.sh
11+
# shellcheck source=lib/common.sh
1012
source "$SCRIPT_DIR/lib/ssh-helpers.sh"
1113
source "$SCRIPT_DIR/lib/common.sh"
1214

scripts/deployment/health-check.sh

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ set -euo pipefail
77

88
# Get script directory and source libraries
99
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
10+
# shellcheck source=lib/ssh-helpers.sh
11+
# shellcheck source=lib/common.sh
1012
source "$SCRIPT_DIR/lib/ssh-helpers.sh"
1113
source "$SCRIPT_DIR/lib/common.sh"
1214

@@ -568,7 +570,7 @@ if echo "$HEALTH_RESULT" | grep -q "GITHUB_OUTPUT_START"; then
568570
else
569571
log_warning "GITHUB_OUTPUT_START marker not found, attempting to read from temp file..."
570572
# Try to read from temp file on remote server
571-
TEMP_FILE_CONTENT=$(ssh -o "StrictHostKeyChecking no" $SSH_USER@$SSH_HOST 'cat /tmp/github_health_check_outputs.txt 2>/dev/null' || echo "")
573+
TEMP_FILE_CONTENT=$(ssh -o "StrictHostKeyChecking no" "$SSH_USER@$SSH_HOST" 'cat /tmp/github_health_check_outputs.txt 2>/dev/null' || echo "")
572574

573575
if [ -n "$TEMP_FILE_CONTENT" ]; then
574576
log_success "Successfully read outputs from temp file"

scripts/deployment/lib/ssh-helpers.sh

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,19 @@ set -euo pipefail
88
retry() {
99
local max_attempts=$1
1010
local delay=$2
11-
local command="${@:3}"
11+
local command="${*:3}"
1212
local attempt=1
1313

14-
while [ $attempt -le $max_attempts ]; do
14+
while [ "$attempt" -le "$max_attempts" ]; do
1515
echo "Attempt $attempt of $max_attempts: $command"
1616
if eval "$command"; then
1717
echo "✅ Command succeeded on attempt $attempt"
1818
return 0
1919
else
2020
echo "❌ Command failed on attempt $attempt"
21-
if [ $attempt -lt $max_attempts ]; then
21+
if [ "$attempt" -lt "$max_attempts" ]; then
2222
echo "⏳ Waiting ${delay}s before retry..."
23-
sleep $delay
23+
sleep "$delay"
2424
delay=$((delay * 2)) # Exponential backoff
2525
fi
2626
attempt=$((attempt + 1))
@@ -35,11 +35,11 @@ retry() {
3535
ssh_retry() {
3636
local max_attempts=$1
3737
local delay=$2
38-
local ssh_cmd="${@:3}"
38+
local ssh_cmd="${*:3}"
3939
local attempt=1
4040
local last_exit_code=1
4141

42-
while [ $attempt -le $max_attempts ]; do
42+
while [ "$attempt" -le "$max_attempts" ]; do
4343
echo "SSH Attempt $attempt of $max_attempts" >&2
4444
if eval "$ssh_cmd"; then
4545
echo "✅ SSH command succeeded on attempt $attempt" >&2
@@ -55,9 +55,9 @@ ssh_retry() {
5555
*) echo "Unknown error code: $last_exit_code" >&2 ;;
5656
esac
5757

58-
if [ $attempt -lt $max_attempts ]; then
58+
if [ "$attempt" -lt "$max_attempts" ]; then
5959
echo "⏳ Waiting ${delay}s before SSH retry..." >&2
60-
sleep $delay
60+
sleep "$delay"
6161
fi
6262
attempt=$((attempt + 1))
6363
fi

scripts/deployment/rollback-stacks.sh

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ set -euo pipefail
77

88
# Get script directory and source libraries
99
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
10+
# shellcheck source=lib/ssh-helpers.sh
11+
# shellcheck source=lib/common.sh
1012
source "$SCRIPT_DIR/lib/ssh-helpers.sh"
1113
source "$SCRIPT_DIR/lib/common.sh"
1214

0 commit comments

Comments
 (0)