mcpField
S
shellcheck-cicd-2025

shellcheck-cicd-2025

github.com/josiahsiegel测试与质量59159 次安装19 周前更新
代码仓库

关于 shellcheck-cicd-2025

为 Bash 开发者提供 ShellCheck 与 CI/CD 集成及脚本规范指导,涵盖 GitHub Actions、Azure DevOps、Git hooks、VS Code 和 Docker 构建。

主要功能

  1. 01配置 GitHub Actions 检查
  2. 02集成 Azure DevOps 流水线
  3. 03通过 Git hooks 执行检查
  4. 04在 VS Code 中启用 ShellCheck
  5. 05生成多种格式的检查报告

适用场景

  1. 01在合并前检查 Bash 脚本
  2. 02在提交时拦截脚本问题
  3. 03将 ShellCheck 纳入 Docker 构建
  4. 04为团队制定脚本质量规范

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/josiahsiegel/claude-plugin-marketplace --skill shellcheck-cicd-2025

安装后在 Claude Code 中输入/shellcheck-cicd-2025确认已加载。

详细介绍

🚨 关键指南

Windows 文件路径要求

强制要求:在 Windows 上始终使用反斜杠表示文件路径

在 Windows 上使用 Edit 或 Write 工具时,文件路径必须使用反斜杠(\),而不是正斜杠(/)。

示例:

  • ❌ 错误:D:/repos/project/file.tsx
  • ✅ 正确:D:\repos\project\file.tsx

适用于:

  • Edit 工具的 file_path 参数
  • Write 工具的 file_path 参数
  • Windows 系统上的所有文件操作
文档指南

除非用户明确要求,否则绝不创建新的文档文件。

  • 优先事项:更新现有的 README.md 文件,而不是创建新文档
  • 保持仓库整洁:保持仓库根目录整洁——除非用户另有要求,否则仅保留 README.md
  • 风格:文档应简洁、直接且专业——避免使用 AI 生成式语气
  • 用户偏好:仅在用户明确要求提供文档时,才创建额外的 .md 文件

ShellCheck CI/CD 集成(2025)

ShellCheck:2025 年不可妥协的要求

ShellCheck 现在被视为现代 Bash 工作流中的必备工具(2025 年最佳实践):

最新版本:v0.11.0(2025 年 8 月)

新增内容:

  • 完整支持 Bash 5.3(${| cmd; } 和 source -p)
  • 新增警告:SC2327/SC2328(捕获组问题)
  • 符合 POSIX.1-2024 标准:移除 SC3013(-ot/-nt/-ef 现为 POSIX 标准)
  • 增强静态分析能力
  • 提升性能和准确性
为什么是必备工具?
  • 在投入生产前发现细微错误
  • 预防常见安全漏洞
  • 确保代码质量一致
  • 大多数 DevOps 团队都要求使用
  • 是企业环境中的标准工具
  • 支持最新的 POSIX.1-2024 标准

安装

# 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 集成

必须执行的合并前检查
# .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 集成

# 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(提交前)

# .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

安装提交前钩子:

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 集成

// .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 构建集成

# 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"]

常见 ShellCheck 规则(2025)

v0.11.0 新增:SC2327/SC2328 - 捕获组
# ❌ 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 会抵消数组的优势(新增)
# ❌ Bad - eval defeats array safety
eval "command ${array[@]}"

# ✅ Good - Direct array usage
command "${array[@]}"
SC2295:在 ${} 内引用展开式
# ❌ Bad
echo "${var-$default}"  # $default not quoted

# ✅ Good
echo "${var-"$default"}"
SC2086:引用变量
# ❌ Bad
file=$1
cat $file  # Fails if filename has spaces

# ✅ Good
file=$1
cat "$file"
SC2046:引用命令替换
# ❌ 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:分离声明和赋值
# ❌ Bad
local result=$(command)  # Hides command exit code

# ✅ Good
local result
result=$(command)
SC2164:使用 cd || exit
# ❌ Bad
cd /some/directory
./script.sh  # Runs in wrong dir if cd fails

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

Google Shell 风格指南(50 行限制)

2025 年建议:将脚本控制在 50 行以内:

# ❌ 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 "$@"

在 CI/CD 中强制执行

遇到问题时使构建失败
# 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
生成报告
# 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

现代错误处理三件套(2025)

始终结合 ShellCheck 验证使用:

#!/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 "$@"

最佳实践(2025)

  1. 在 CI/CD 中运行 ShellCheck(必备)
  2. 使用提交前钩子,及早发现问题
  3. 将脚本控制在 50 行以内(Google 风格指南)
  4. 使用现代错误处理三件套(errexit、nounset、pipefail)
  5. 合并前修复所有警告
  6. 说明禁用任何规则的原因
  7. 集成到 IDE 中,获取实时反馈

资源

评论

支持 Markdown