コミット前に自動でlint+テストを走らせる
何をするHooksか
Section titled “何をするHooksか”Claudeがコードを編集するたびに、自動的にlintとテストを実行します。問題があればClaudeに通知し、自動修正を促します。「Claudeがきれいに書いてくれたと思ったら、lintエラーがたくさんあった」という状況を防ぎます。
※Hooks: Claude Codeの特定の操作(ツール実行前後など)に独自のシェルコマンドを自動実行できる設定機能。
settings.json の実際のコード
Section titled “settings.json の実際のコード”基本パターン(ファイル保存後にlintを実行)
Section titled “基本パターン(ファイル保存後にlintを実行)”{ "hooks": { "PostToolUse": [ { "matcher": "Edit|Write", "hooks": [ { "type": "command", "command": "FILE=$(echo $CLAUDE_TOOL_INPUT | jq -r '.file_path'); if [[ \"$FILE\" == *.ts || \"$FILE\" == *.tsx || \"$FILE\" == *.js ]]; then cd $CLAUDE_PROJECT_DIR && npx eslint --fix \"$FILE\" 2>&1; fi" } ] } ] }}テスト実行パターン(テストファイルに変更があれば自動実行)
Section titled “テスト実行パターン(テストファイルに変更があれば自動実行)”{ "hooks": { "PostToolUse": [ { "matcher": "Edit|Write", "hooks": [ { "type": "command", "command": "FILE=$(echo $CLAUDE_TOOL_INPUT | jq -r '.file_path'); if [[ \"$FILE\" == *test* || \"$FILE\" == *spec* ]]; then cd $CLAUDE_PROJECT_DIR && npx vitest run \"$FILE\" 2>&1 | tail -20; fi" } ] } ] }}コミット前に全テストを実行するHook(PreToolUseでブロック)
Section titled “コミット前に全テストを実行するHook(PreToolUseでブロック)”{ "hooks": { "PreToolUse": [ { "matcher": "Bash", "hooks": [ { "type": "command", "command": "COMMAND=$(echo $CLAUDE_TOOL_INPUT | jq -r '.command'); if echo \"$COMMAND\" | grep -q 'git commit'; then cd $CLAUDE_PROJECT_DIR && npm run test -- --run 2>&1; fi" } ] } ] }}※コミット: Gitでファイルの変更を履歴として記録する操作。※npm: Node.jsのパッケージ管理ツール。`npm install` でライブラリをインストールする。
より実用的なスクリプト版
Section titled “より実用的なスクリプト版”複雑なロジックはシェルスクリプトにまとめると管理しやすくなります。
~/.claude/hooks/lint-on-save.sh:
#!/bin/bash
set -e
# 対象ファイルを取得FILE_PATH=$(echo "$CLAUDE_TOOL_INPUT" | jq -r '.file_path')
# TypeScript/JavaScript ファイルのみ対象if [[ ! "$FILE_PATH" =~ \.(ts|tsx|js|jsx)$ ]]; then exit 0fi
# プロジェクトディレクトリに移動cd "$CLAUDE_PROJECT_DIR"
echo "🔍 Linting: $FILE_PATH"
# ESLint を実行(自動修正あり)if ! npx eslint --fix "$FILE_PATH" 2>&1; then echo "❌ ESLintエラーが残っています。確認してください。" exit 0 # エラーでも続行(ブロックしない)fi
# TypeScriptの型チェック(TypeScriptファイルのみ)if [[ "$FILE_PATH" =~ \.tsx?$ ]]; then if ! npx tsc --noEmit --skipLibCheck 2>&1 | head -20; then echo "⚠️ TypeScriptの型エラーがあります" fifi
echo "✅ Lint完了"chmod +x ~/.claude/hooks/lint-on-save.shsettings.json から呼び出す:
{ "hooks": { "PostToolUse": [ { "matcher": "Edit|Write", "hooks": [ { "type": "command", "command": "~/.claude/hooks/lint-on-save.sh" } ] } ] }}※TypeScript: JavaScriptに型定義を追加した言語。型チェックによりバグを事前に発見しやすくなる。
- ClaudeがEdit/Writeツールでファイルを保存する
- PostToolUse Hookが発火
lint-on-save.shが実行される- TypeScript/JSファイルの場合のみlintが実行される
- ESLintが自動修正できるものは修正
- 修正できないエラーがある場合は、次のClaude応答に「ESLintエラーがあります」と通知
- Claudeが通知を受け取り、エラーを修正する
カスタマイズ例
Section titled “カスタマイズ例”Rubyプロジェクト向け(RuboCop)
Section titled “Rubyプロジェクト向け(RuboCop)”#!/bin/bashFILE_PATH=$(echo "$CLAUDE_TOOL_INPUT" | jq -r '.file_path')
if [[ ! "$FILE_PATH" =~ \.rb$ ]]; then exit 0fi
cd "$CLAUDE_PROJECT_DIR"bundle exec rubocop --autocorrect "$FILE_PATH" 2>&1Pythonプロジェクト向け(black + flake8)
Section titled “Pythonプロジェクト向け(black + flake8)”#!/bin/bashFILE_PATH=$(echo "$CLAUDE_TOOL_INPUT" | jq -r '.file_path')
if [[ ! "$FILE_PATH" =~ \.py$ ]]; then exit 0fi
cd "$CLAUDE_PROJECT_DIR"black "$FILE_PATH" 2>&1flake8 "$FILE_PATH" 2>&1Goプロジェクト向け(gofmt + go vet)
Section titled “Goプロジェクト向け(gofmt + go vet)”#!/bin/bashFILE_PATH=$(echo "$CLAUDE_TOOL_INPUT" | jq -r '.file_path')
if [[ ! "$FILE_PATH" =~ \.go$ ]]; then exit 0fi
gofmt -w "$FILE_PATH" 2>&1cd "$CLAUDE_PROJECT_DIR"go vet ./... 2>&1eslint --fixは自動修正しますが、修正後の結果をClaudeは認識しません。修正後の内容がClaudeの想定と異なる場合があります。- テストの実行時間が長いプロジェクトでは、全テストではなく変更ファイルに関連するテストだけ実行するように調整してください。
- PostToolUse Hookは非ブロッキング(終了コードに関わらず続行)として動作します。エラーはClaudeへの通知として扱われます。