home / skills / josiahsiegel / claude-plugin-marketplace / shellcheck-cicd-2025

shellcheck-cicd-2025 skill

/plugins/bash-master/skills/shellcheck-cicd-2025

npx playbooks add skill josiahsiegel/claude-plugin-marketplace --skill shellcheck-cicd-2025

Review the files below or copy the command above to add this skill to your agents.

Files (1)
SKILL.md
9.2 KB
---
name: shellcheck-cicd-2025
description: ShellCheck validation as non-negotiable 2025 workflow practice
---

## 🚨 CRITICAL GUIDELINES

### Windows File Path Requirements

**MANDATORY: Always Use Backslashes on Windows for File Paths**

When using Edit or Write tools on Windows, you MUST use backslashes (`\`) in file paths, NOT forward slashes (`/`).

**Examples:**
- ❌ WRONG: `D:/repos/project/file.tsx`
- ✅ CORRECT: `D:\repos\project\file.tsx`

This applies to:
- Edit tool file_path parameter
- Write tool file_path parameter
- All file operations on Windows systems


### Documentation Guidelines

**NEVER create new documentation files unless explicitly requested by the user.**

- **Priority**: Update existing README.md files rather than creating new documentation
- **Repository cleanliness**: Keep repository root clean - only README.md unless user requests otherwise
- **Style**: Documentation should be concise, direct, and professional - avoid AI-generated tone
- **User preference**: Only create additional .md files when user specifically asks for documentation


---

# ShellCheck CI/CD Integration (2025)

## ShellCheck: Non-Negotiable in 2025

ShellCheck is now considered **mandatory** in modern bash workflows (2025 best practices):

### Latest Version: v0.11.0 (August 2025)

**What's New:**
- Full Bash 5.3 support (`${| cmd; }` and `source -p`)
- **New warnings**: SC2327/SC2328 (capture group issues)
- **POSIX.1-2024 compliance**: SC3013 removed (-ot/-nt/-ef now POSIX standard)
- Enhanced static analysis capabilities
- Improved performance and accuracy

### Why Mandatory?

- Catches subtle bugs before production
- Prevents common security vulnerabilities
- Enforces consistent code quality
- Required by most DevOps teams
- Standard in enterprise environments
- Supports latest POSIX.1-2024 standard

## Installation

```bash
# Ubuntu/Debian
apt-get install shellcheck

# macOS
brew install shellcheck

# Alpine (Docker)
apk add shellcheck

# Windows (WSL/Git Bash)
choco install shellcheck

# Or download binary
wget https://github.com/koalaman/shellcheck/releases/latest/download/shellcheck-stable.linux.x86_64.tar.xz
tar -xf shellcheck-stable.linux.x86_64.tar.xz
sudo cp shellcheck-stable/shellcheck /usr/local/bin/
```

## GitHub Actions Integration

### Mandatory Pre-Merge Check

```yaml
# .github/workflows/shellcheck.yml
name: ShellCheck

on:
  pull_request:
    paths:
      - '**.sh'
      - '**Dockerfile'
  push:
    branches: [main]

jobs:
  shellcheck:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3

    - name: Run ShellCheck
      uses: ludeeus/action-shellcheck@master
      with:
        severity: warning
        format: gcc  # or: tty, json, checkstyle
        scandir: './scripts'
        # Fail on any issues
        ignore_paths: 'node_modules'

    # Block merge on failures
    - name: Annotate PR
      if: failure()
      uses: actions/github-script@v6
      with:
        script: |
          github.rest.issues.createComment({
            issue_number: context.issue.number,
            owner: context.repo.owner,
            repo: context.repo.repo,
            body: '⛔ ShellCheck validation failed. Fix issues before merging.'
          })
```

## Azure DevOps Integration

```yaml
# azure-pipelines.yml
trigger:
- main

pr:
- main

stages:
- stage: Validate
  jobs:
  - job: ShellCheck
    pool:
      vmImage: 'ubuntu-24.04'

    steps:
    - script: |
        sudo apt-get install -y shellcheck
      displayName: 'Install ShellCheck'

    - script: |
        find . -name "*.sh" -type f | xargs shellcheck --format=gcc --severity=warning
      displayName: 'Run ShellCheck'
      failOnStderr: true

    - task: PublishTestResults@2
      condition: always()
      inputs:
        testResultsFormat: 'JUnit'
        testResultsFiles: '**/shellcheck-results.xml'
        failTaskOnFailedTests: true
```

## Git Hooks (Pre-Commit)

```bash
# .git/hooks/pre-commit
#!/usr/bin/env bash
set -o errexit
set -o nounset
set -o pipefail

# Find all staged .sh files
mapfile -t STAGED_SH < <(git diff --cached --name-only --diff-filter=ACMR | grep '\.sh$' || true)

if [ ${#STAGED_SH[@]} -eq 0 ]; then
  exit 0
fi

echo "Running ShellCheck on staged files..."

# Run ShellCheck
shellcheck --format=gcc --severity=warning "${STAGED_SH[@]}"

if [ $? -ne 0 ]; then
  echo "⛔ ShellCheck failed. Fix issues before committing."
  exit 1
fi

echo "✅ ShellCheck passed"
exit 0
```

**Install Pre-Commit Hook:**
```bash
chmod +x .git/hooks/pre-commit

# Or use pre-commit framework
# .pre-commit-config.yaml
repos:
- repo: https://github.com/shellcheck-py/shellcheck-py
  rev: v0.11.0.0
  hooks:
  - id: shellcheck
    args: ['--severity=warning']

# Install
pip install pre-commit
pre-commit install
```

## VS Code Integration

```json
// .vscode/settings.json
{
  "shellcheck.enable": true,
  "shellcheck.run": "onType",
  "shellcheck.executablePath": "/usr/local/bin/shellcheck",
  "shellcheck.exclude": ["SC1090", "SC1091"],  // Optional excludes
  "shellcheck.customArgs": [
    "-x",  // Follow source files
    "--severity=warning"
  ]
}
```

## Docker Build Integration

```dockerfile
# Dockerfile with ShellCheck validation
FROM alpine:3.19 AS builder

# Install ShellCheck
RUN apk add --no-cache shellcheck bash

# Copy scripts
COPY scripts/ /scripts/

# Validate all scripts before continuing
RUN find /scripts -name "*.sh" -type f -exec shellcheck --severity=warning {} +

# Final stage
FROM alpine:3.19
COPY --from=builder /scripts/ /scripts/
RUN chmod +x /scripts/*.sh

ENTRYPOINT ["/scripts/entrypoint.sh"]
```

## Common ShellCheck Rules (2025)

### New in v0.11.0: SC2327/SC2328 - Capture Groups

```bash
# ❌ Bad - Capture groups may not work as expected
if [[ "$string" =~ ([0-9]+)\.([0-9]+) ]]; then
  echo "$1"  # Wrong: $1 is script arg, not capture group
fi

# ✅ Good - Use BASH_REMATCH array
if [[ "$string" =~ ([0-9]+)\.([0-9]+) ]]; then
  echo "${BASH_REMATCH[1]}.${BASH_REMATCH[2]}"
fi
```

### SC2294: eval Negates Array Benefits (New)

```bash
# ❌ Bad - eval defeats array safety
eval "command ${array[@]}"

# ✅ Good - Direct array usage
command "${array[@]}"
```

### SC2295: Quote Expansions Inside ${}

```bash
# ❌ Bad
echo "${var-$default}"  # $default not quoted

# ✅ Good
echo "${var-"$default"}"
```

### SC2086: Quote Variables

```bash
# ❌ Bad
file=$1
cat $file  # Fails if filename has spaces

# ✅ Good
file=$1
cat "$file"
```

### SC2046: Quote Command Substitution

```bash
# ❌ Bad
for file in $(find . -name "*.txt"); do
  echo $file
done

# ✅ Good
find . -name "*.txt" -print0 | while IFS= read -r -d '' file; do
  echo "$file"
done
```

### SC2155: Separate Declaration and Assignment

```bash
# ❌ Bad
local result=$(command)  # Hides command exit code

# ✅ Good
local result
result=$(command)
```

### SC2164: Use cd || exit

```bash
# ❌ Bad
cd /some/directory
./script.sh  # Runs in wrong dir if cd fails

# ✅ Good
cd /some/directory || exit 1
./script.sh
```

## Google Shell Style Guide (50-Line Limit)

2025 recommendation: Keep scripts under 50 lines:

```bash
# ❌ Bad: 500-line monolithic script
#!/usr/bin/env bash
# ... 500 lines of code ...

# ✅ Good: Modular scripts < 50 lines each

# lib/logging.sh (20 lines)
log_info() { echo "[INFO] $*"; }
log_error() { echo "[ERROR] $*" >&2; }

# lib/validation.sh (30 lines)
validate_input() { ... }
check_dependencies() { ... }

# main.sh (40 lines)
source "$(dirname "$0")/lib/logging.sh"
source "$(dirname "$0")/lib/validation.sh"

main() {
  validate_input "$@"
  check_dependencies
  # ... core logic ...
}

main "$@"
```

## Enforce in CI/CD

### Fail Build on Issues

```yaml
# Strict enforcement
- name: ShellCheck (Strict)
  run: |
    shellcheck --severity=warning scripts/*.sh
  # Exit code 1 fails the build

# Advisory only (warnings but don't fail)
- name: ShellCheck (Advisory)
  run: |
    shellcheck --severity=warning scripts/*.sh || true
  # Logs warnings but doesn't fail
```

### Generate Reports

```bash
# JSON format for parsing
shellcheck --format=json scripts/*.sh > shellcheck-report.json

# GitHub annotations format
shellcheck --format=gcc scripts/*.sh

# Human-readable
shellcheck --format=tty scripts/*.sh
```

## Modern Error Handling Trio (2025)

Always use with ShellCheck validation:

```bash
#!/usr/bin/env bash

# Modern error handling (non-negotiable in 2025)
set -o errexit   # Exit on command failure
set -o nounset   # Exit on undefined variable
set -o pipefail  # Exit on pipe failure

# ShellCheck approved
main() {
  local config_file="${1:?Config file required}"

  if [[ ! -f "$config_file" ]]; then
    echo "Error: Config file not found: $config_file" >&2
    return 1
  fi

  # Safe command execution
  local result
  result=$(process_config "$config_file")

  echo "$result"
}

main "$@"
```

## Best Practices (2025)

1. **Run ShellCheck in CI/CD (mandatory)**
2. **Use pre-commit hooks** to catch issues early
3. **Keep scripts under 50 lines** (Google Style Guide)
4. **Use modern error handling trio** (errexit, nounset, pipefail)
5. **Fix all warnings** before merging
6. **Document any disabled rules** with reasoning
7. **Integrate with IDE** for real-time feedback

## Resources

- [ShellCheck](https://www.shellcheck.net)
- [Google Shell Style Guide](https://google.github.io/styleguide/shellguide.html)
- [ShellCheck GitHub Action](https://github.com/ludeeus/action-shellcheck)