בדיקת קוד אוטומטית עם Hooks: איכות מובטחת בזמן הכתיבה

PostToolUse Hooks מריצים lint אוטומטית אחרי כל כתיבה. קוד יציאה 2 שולח שגיאות ל-Claude לתיקון אוטומטי.


Claude Code כותב קוד מהר, אבל לא תמיד זוכר להריץ lint. אתה מבקש ממנו "לבדוק תוך כדי כתיבה" — לפעמים עושה, לפעמים לא. Hooks פותרים את הבעיה הזו: הם מעבירים את האחריות לבדיקת הקוד מ-Claude למערכת.

המאמר הזה מתמקד בדבר אחד: שימוש ב-PostToolUse Hooks להפעלה אוטומטית של בדיקות אחרי שClaude כתב קוד, כדי שכל שינוי בקובץ יעמוד בסטנדרטים שלך.


הגישה: PostToolUse + סינון לפי סוג קובץ

הלוגיקה של Hook לבדיקת קוד פשוטה:

  1. Claude קורא ל-Write או ל-Edit כדי לכתוב קובץ
  2. ה-Hook מיירט את האירוע ומקבל את נתיב הקובץ
  3. לפי הסיומת, מחליט איזה כלי בדיקה להריץ
  4. בדיקה עברה: קוד יציאה 0, Claude ממשיך
  5. בדיקה נכשלה: קוד יציאה 2, השגיאות נשלחות ל-Claude לתיקון

קוד יציאה 2 הוא המפתח: Claude מקבל את השגיאה ומתקן אותה אוטומטית, ויוצר מחזור "כתוב→בדוק→תקן".


הגדרה בסיסית: פרויקטים בשפה אחת

Ruby (RuboCop)

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "bash -c 'file=$(echo \"$CLAUDE_TOOL_INPUT\" | jq -r .file_path 2>/dev/null); [[ \"$file\" == *.rb ]] && rubocop -A \"$file\" --no-color -q || true'"
          }
        ]
      }
    ]
  }
}

JavaScript/TypeScript (ESLint)

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "bash -c 'file=$(echo \"$CLAUDE_TOOL_INPUT\" | jq -r .file_path 2>/dev/null); [[ \"$file\" =~ \\.(js|ts|jsx|tsx)$ ]] && npx eslint --fix \"$file\" || true'"
          }
        ]
      }
    ]
  }
}

Python (ruff)

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "bash -c 'file=$(echo \"$CLAUDE_TOOL_INPUT\" | jq -r .file_path 2>/dev/null); [[ \"$file\" == *.py ]] && ruff check --fix \"$file\" && ruff format \"$file\" || true'"
          }
        ]
      }
    ]
  }
}

הגדרה מתקדמת: פרויקטים רב-לשוניים

צור .claude/hooks/lint.sh:

#!/bin/bash
set -e

input=$(cat)
file=$(echo "$input" | jq -r '.tool_input.file_path // empty')

[[ -z "$file" ]] && exit 0
[[ ! -f "$file" ]] && exit 0

ext="${file##*.}"

case "$ext" in
  rb)    rubocop -A "$file" --no-color -q ;;
  js|ts|jsx|tsx) npx eslint --fix "$file" --quiet ;;
  py)    ruff check --fix "$file"; ruff format "$file" ;;
  go)    gofmt -w "$file"; golangci-lint run "$file" 2>&1 ;;
  *)     exit 0 ;;
esac

הפנה לסקריפט ב-settings.json:

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [{ "type": "command", "command": "bash .claude/hooks/lint.sh" }]
      }
    ]
  }
}

גרימת Claude לתקן אוטומטית

קוד יציאה 2 + stderr הוא המפתח לתיקון אוטומטי:

run_lint() {
  local output exit_code
  output=$(rubocop "$file" --no-color 2>&1)
  exit_code=$?
  if [[ $exit_code -ne 0 ]]; then
    echo "$output" >&2
    exit 2
  fi
  rubocop -A "$file" --no-color -q
}

אי-הכללת קבצים שאינם זקוקים לבדיקה

skip_patterns=("vendor/" "node_modules/" "db/schema.rb" ".min.js" "_test.go")
for pattern in "${skip_patterns[@]}"; do
  [[ "$file" == *"$pattern"* ]] && exit 0
done

התוצאה בפועל

אחרי ההגדרה, תהליך העבודה נראה כך:

  1. אתה מבקש מ-Claude לכתוב קובץ Ruby
  2. Claude כותב אותו עם הכלי Write
  3. ה-Hook מריץ rubocop -A אוטומטית — מוצא 3 בעיות
  4. RuboCop מתקן 2 אוטומטית; השלישית דורשת שיקול דעת אנושי
  5. הבעיה השלישית נשלחת ל-Claude דרך stderr
  6. Claude מתקן את הקוד, ה-Hook מופעל שוב
  7. הבדיקה השנייה עברה — סיום

לעולם לא תצטרך להריץ פקודת בדיקה ידנית.


גלובלי מול רמת פרויקט

גלובלי (~/.claude/settings.json): כשמשתמשים באותן כללים בכל הפרויקטים.

רמת פרויקט (.claude/settings.json ב-git): מומלץ לצוותים. כל מי שפותח את המאגר מקבל את ההגדרה הנכונה אוטומטית.

השניים יכולים להתקיים יחד; hooks של פרויקט מתמזגים עם הגלובליים.


סיכום

בדיקת קוד אוטומטית עם Hooks מסתכמת בשלושה שלבים:

  1. PostToolUse + matcher "Write|Edit" ליירוט כתיבות קובץ
  2. קבלת נתיב הקובץ והפנייתו ל-linter המתאים לפי הסיומת
  3. בכישלון, יציאה עם קוד 2 כדי שClaude יראה את השגיאה ויתקן

התחל עם שפה אחת. כשעובד, הוסף עוד. שמור את הסקריפטים ב-.claude/hooks/ ושתף עם הצוות.