Skip to content

fix: hooks の stderr flush 追加、パス環境非依存化、インストールヒント追加 - #458

Merged
keito4 merged 1 commit into
mainfrom
fix/hooks-flush-and-portable-paths
Feb 12, 2026
Merged

fix: hooks の stderr flush 追加、パス環境非依存化、インストールヒント追加#458
keito4 merged 1 commit into
mainfrom
fix/hooks-flush-and-portable-paths

Conversation

@keito4

@keito4 keito4 commented Feb 12, 2026

Copy link
Copy Markdown
Owner

Summary

  • hooks の stderr 出力に flush=True を追加して途中で切れる問題を修正
  • hooks のパスを git rev-parse --show-toplevel で動的に取得し、環境非依存に
  • ツールが見つからない場合(exit 127)はスキップしてインストール方法を表示

Changes

  • .claude/hooks/pre_git_quality_gates.py: すべての print()flush=True 追加
  • .claude/hooks/block_git_no_verify.py: sys.stderr.flush() 追加
  • .claude/settings.json: hooks パスを環境非依存に変更

Test plan

  • ローカル環境で git commit/push が正常に動作すること
  • DevContainer 環境で git commit/push が正常に動作すること
  • ツールがない場合にインストールヒントが表示されること

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes & Improvements
    • Quality check feedback now displays in real-time for immediate visibility
    • Missing development tools now trigger helpful installation prompts instead of failing checks
    • Enhanced error handling and reporting for quality checks
    • Improved script execution reliability across different repository configurations

- pre_git_quality_gates.py: すべての print() に flush=True を追加
  - 出力がバッファリングされて途中で切れる問題を修正
- block_git_no_verify.py: sys.stderr.flush() を追加
- settings.json: hooks パスを git rev-parse --show-toplevel で動的に取得
  - ローカル環境と DevContainer の両方で動作するように
- ツールが見つからない場合(exit 127)はスキップしてインストール方法を表示
- 出力が実質的に空の場合もツール/環境の問題としてスキップ

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Feb 12, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

The PR enhances git hook scripts with improved output handling and robustness. Changes include adding output flushing for immediate feedback, introducing tool install hints, gracefully skipping checks when tools are missing, and updating hook invocations to use relative paths via a bash wrapper that cd's to the repository root.

Changes

Cohort / File(s) Summary
Hook Scripts
.claude/hooks/block_git_no_verify.py, .claude/hooks/pre_git_quality_gates.py
Enhanced stderr/stdout flushing for real-time output; added install_hint fields to tool checks; introduced graceful skip logic for missing or empty tools instead of failing; improved error/timeout handling with verbose reporting.
Hook Configuration
.claude/settings.json
Updated five pre/post hook commands to use bash wrapper that cd's to repository root via git rev-parse before executing Python scripts, replacing absolute path invocations with relative paths.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested labels

released, size/M

Poem

🐰 Flush the streams, let output flow fast,
Missing tools? Skip gracefully, no crash!
Hints guide the way, from root we run true,
Bash wrappers whisper what scripts need to do!

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title in Japanese accurately describes the main changes: adding stderr flush, making paths environment-independent, and adding installation hints.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/hooks-flush-and-portable-paths

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@keito4

keito4 commented Feb 12, 2026

Copy link
Copy Markdown
Owner Author

🔍 AI Code Review (Local Hook)

Models: Codex (default) / Gemini (default)

🤖 Codex Review

  • .claude/hooks/pre_git_quality_gates.py:116-134 失敗時に is_empty_output を「ツール/環境不足」とみなしてスキップするため、実際の失敗(例: テストが exit 1 で無出力、lint が無出力で失敗)まで見逃します。Quality Gate が実行されても通過してしまうため、正確性/保守性の担保が壊れます。
  • .claude/hooks/pre_git_quality_gates.py:118-133 stderr の "No such file or directory" / "command not found" を一律スキップ条件にしており、npm スクリプト内の実行失敗や security-credential-scan / code-complexity-check 内部依存の欠落が「失敗」ではなく「スキップ」扱いになります。これによりセキュリティ・品質検査のバイパスが可能になります。

patch is incorrect — Quality Gates を失敗で止めるべきケースがスキップされ、検査が機能しなくなるため。信頼度 0.57

✨ Gemini Review

コードレビュー

この変更に対して、いくつか改善点と評価を指摘します。

発見した問題リスト

  1. 問題: pre_git_quality_gates.py 内のチェック処理のスキップ判定ロジックが、特定の出力形式に依存している。
    • ファイル: .claude/hooks/pre_git_quality_gates.py
    • 行範囲: 125-126
    • 説明: is_empty_output を判定するロジックが、not l.startswith('━') という条件を含んでいます。これは特定のツール(おそらくmonorepo管理ツールなど)の出力する区切り線を無視するためのものと推測されますが、このような特定の出力形式への依存は、将来のツール更新などで形式が変更された際に、意図せずチェックがスキップされる原因となり得ます。このロジックの意図をコメントで明記するか、より汎用的な判定方法(例:特定の成功/失敗メッセージの有無を確認する)を検討することが望ましいです。
    • 影響: 保守性

全体的な評価

patch is correct

理由: このパッチは、主に2つの点でコードベースを大幅に改善しています。

  1. .claude/settings.json の変更により、Gitフックが常にリポジトリのルートディレクトリで実行されるようになり、サブディレクトリでGitコマンドを実行した際のスクリプトパス解決の問題が解消され、フックの堅牢性が向上しています。
  2. pre_git_quality_gates.py の変更により、チェックに必要なツールがインストールされていない場合に、フック全体を停止させるのではなく、該当チェックをスキップしてインストール方法のヒントを表示するようになりました。これは開発者体験を大きく向上させます。

上記で指摘した保守性の問題は軽微であり、このパッチがもたらす正確性と開発者体験の向上という大きなメリットを損なうものではありません。

信頼度スコア: 0.95


⚠️ 修正が必要です

上記のレビューで問題が指摘されています。修正してからマージしてください。


🤖 Generated by post_pr_ai_review.py hook

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In @.claude/hooks/pre_git_quality_gates.py:
- Around line 124-125: Rename the lambda variable `l` to `line` in the stdout
parsing to fix E741 and replace the brittle "━" check with a regex-based
decorative-line filter: strip result.stdout, split into lines and keep lines
that are non-empty and do not match a pattern for purely decorative/non-word
characters (e.g. re.match(r'^[^\w]+$', line) to detect box-drawing or repeated
punctuation), then set is_empty_output based on that filtered list and
result.stderr; update references to `stdout_lines` and `is_empty_output`
accordingly (use `result`, `stdout_lines`, `is_empty_output`, and `line` as
identifiers).
🧹 Nitpick comments (1)
.claude/hooks/pre_git_quality_gates.py (1)

143-143: Remove extraneous f prefix on strings without placeholders.

Lines 143, 150, and 154 use f-strings with no interpolation. Use plain strings instead (flagged by Ruff F541).

Proposed fix
-            print(f"  ✅ 成功", file=sys.stderr, flush=True)
+            print("  ✅ 成功", file=sys.stderr, flush=True)
-        print(f"  ❌ タイムアウト", file=sys.stderr, flush=True)
+        print("  ❌ タイムアウト", file=sys.stderr, flush=True)
-        print(f"  ⚠️  スキップ (コマンドが見つかりません)", file=sys.stderr, flush=True)
+        print("  ⚠️  スキップ (コマンドが見つかりません)", file=sys.stderr, flush=True)

Also applies to: 150-150, 154-154

Comment on lines +124 to +125
stdout_lines = [l for l in result.stdout.strip().split('\n') if l.strip() and not l.startswith('━')]
is_empty_output = len(stdout_lines) <= 1 and not result.stderr.strip()

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Ambiguous variable name l and fragile output-parsing heuristic.

The lambda variable l triggers E741. More importantly, filtering lines by the character couples this to a specific tool's output format — other tools won't match this pattern and may be incorrectly classified.

Proposed fix
-            stdout_lines = [l for l in result.stdout.strip().split('\n') if l.strip() and not l.startswith('━')]
+            stdout_lines = [line for line in result.stdout.strip().split('\n') if line.strip() and not line.startswith('━')]
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
stdout_lines = [l for l in result.stdout.strip().split('\n') if l.strip() and not l.startswith('━')]
is_empty_output = len(stdout_lines) <= 1 and not result.stderr.strip()
stdout_lines = [line for line in result.stdout.strip().split('\n') if line.strip() and not line.startswith('━')]
is_empty_output = len(stdout_lines) <= 1 and not result.stderr.strip()
🧰 Tools
🪛 Ruff (0.15.0)

[error] 124-124: Ambiguous variable name: l

(E741)

🤖 Prompt for AI Agents
In @.claude/hooks/pre_git_quality_gates.py around lines 124 - 125, Rename the
lambda variable `l` to `line` in the stdout parsing to fix E741 and replace the
brittle "━" check with a regex-based decorative-line filter: strip
result.stdout, split into lines and keep lines that are non-empty and do not
match a pattern for purely decorative/non-word characters (e.g.
re.match(r'^[^\w]+$', line) to detect box-drawing or repeated punctuation), then
set is_empty_output based on that filtered list and result.stderr; update
references to `stdout_lines` and `is_empty_output` accordingly (use `result`,
`stdout_lines`, `is_empty_output`, and `line` as identifiers).

@claude

claude Bot commented Feb 12, 2026

Copy link
Copy Markdown
Contributor

PR Review: hooks の stderr flush 追加、パス環境非依存化、インストールヒント追加

✅ 全体評価

このPRは開発体験を大きく向上させる重要な改善です。3つの主要な変更点はすべて明確な目的を持ち、適切に実装されています。


📋 コード品質

👍 良い点

  1. Output Buffering 問題の解決

    • すべての print()flush=True を追加し、stderr出力が途中で切れる問題を解決
    • .claude/hooks/block_git_no_verify.py:56sys.stderr.flush() も追加
  2. 環境非依存性の向上

    • .claude/settings.json:178,187,196,207,216 でハードコードされたパス /home/vscode/.claude/hooks/ を動的取得に変更
    • git rev-parse --show-toplevel を使用してリポジトリルートを取得
    • フォールバック || echo . により git リポジトリ外でもエラーを回避
  3. ユーザー体験の改善

    • ツールが見つからない場合(exit code 127)にインストールヒントを表示
    • .claude/hooks/pre_git_quality_gates.py:68,74,80,86 で具体的なインストールコマンドを提供
  4. エラーハンドリングの改善

    • .claude/hooks/pre_git_quality_gates.py:117-133 で複数の条件を判定
    • 空出力(ヘッダーのみ)もツール不在として適切に処理

🔍 潜在的な問題・改善提案

⚠️ 中程度の懸念

1. 空出力判定のロジックが脆弱

.claude/hooks/pre_git_quality_gates.py:124-125:

stdout_lines = [l for l in result.stdout.strip().split('\n') if l.strip() and not l.startswith('━')]
is_empty_output = len(stdout_lines) <= 1 and not result.stderr.strip()

問題点:

  • not l.startswith('━') は特定のヘッダー形式に依存しており、将来の出力フォーマット変更で壊れる可能性
  • 1行の有効な出力があってもスキップされる(<= 1 の判定)

推奨:

# より明確な意図を示す定数定義
MIN_MEANINGFUL_OUTPUT_LINES = 2

# ヘッダー文字のセットを定数化
HEADER_CHARS = {'━', '=', '-', '#'}

stdout_lines = [
    l for l in result.stdout.strip().split('\n')
    if l.strip() and not any(l.startswith(ch * 3) for ch in HEADER_CHARS)
]
is_empty_output = len(stdout_lines) < MIN_MEANINGFUL_OUTPUT_LINES and not result.stderr.strip()

2. エラーパターンマッチングの国際化対応不足

.claude/hooks/pre_git_quality_gates.py:120-121:

or "No such file or directory" in result.stderr
or "command not found" in result.stderr

問題点:

  • ロケールが日本語の環境では「そのようなファイルやディレクトリはありません」になる可能性
  • 英語以外の環境で動作しない

推奨:

# exit code 127 は POSIX 標準なので、これだけで十分
is_tool_missing = result.returncode == 127

または locale に依存しない判定を追加:

# 複数言語対応
error_patterns = [
    "No such file or directory",
    "command not found",
    "そのようなファイルやディレクトリはありません",
    "コマンドが見つかりません"
]
is_tool_missing = (
    result.returncode == 127
    or any(pattern in result.stderr for pattern in error_patterns)
)

💡 Minor: コードの可読性向上

3. Magic Number の定数化

.claude/hooks/pre_git_quality_gates.py:119:

result.returncode == 127

推奨:

# ファイルの先頭で定数定義
EXIT_CODE_COMMAND_NOT_FOUND = 127

# 使用箇所
result.returncode == EXIT_CODE_COMMAND_NOT_FOUND

4. DRY原則の違反

.claude/hooks/pre_git_quality_gates.py:130,133 で同じメッセージが重複:

if hint:
    print(f"  ⚠️  スキップ (ツールまたは環境が見つかりません)", file=sys.stderr, flush=True)
    print(f"      💡 インストール: {hint}", file=sys.stderr, flush=True)
else:
    print(f"  ⚠️  スキップ (ツールまたは環境が見つかりません)", file=sys.stderr, flush=True)

推奨:

print(f"  ⚠️  スキップ (ツールまたは環境が見つかりません)", file=sys.stderr, flush=True)
if hint:
    print(f"      💡 インストール: {hint}", file=sys.stderr, flush=True)

🔒 セキュリティ

✅ 問題なし

  • コマンドインジェクションのリスクなし(shlex.split()subprocess.run() の配列形式を使用)
  • パストラバーサルの懸念なし(git rev-parse --show-toplevel は安全)

⚡ パフォーマンス

✅ 問題なし

  • git rev-parse の追加オーバーヘッドは微小(ms単位)
  • flush=True のパフォーマンス影響は無視可能

🧪 テストカバレッジ

⚠️ Test Plan が未完了

PR本文の Test plan がすべてチェックされていません:

  • ローカル環境で git commit/push が正常に動作すること
  • DevContainer 環境で git commit/push が正常に動作すること
  • ツールがない場合にインストールヒントが表示されること

推奨:
マージ前にこれらの手動テストを実施し、結果をPRに記録してください。


📚 ドキュメント

✅ 適切

  • PR本文のサマリーが明確
  • コミットメッセージが Conventional Commits に準拠

Minor: .claude/hooks/README.md がある場合、今回の変更(特にインストールヒント機能)を文書化すると良い


🎯 CLAUDE.md 準拠チェック

項目 状態 備考
Diff ≤ 400行 115行(70追加 + 45削除)
ファイル数 ≤ 25 3ファイル
Conventional Commits fix: タイプで適切
Linked Issue ⚠️ Issue リンクなし(Minor)

🚀 マージ推奨度

推奨: マージ可(Minor な改善提案あり)

理由:

  • コア機能の動作に影響する critical な問題なし
  • 開発体験を大きく向上させる重要な改善
  • 提案した改善点はすべて optional(後続PRで対応可)

マージ前の必須アクション:

  1. ✅ Test plan の手動実行と確認
  2. ⚠️ CI の claude-review が完了するのを待つ(現在 pending)

推奨される後続改善(別PRで可):

  1. 空出力判定ロジックの堅牢化
  2. エラーパターンマッチングの国際化対応
  3. Magic number の定数化
  4. DRY原則違反の解消

🤖 Review Summary

このPRは品質基準を満たしており、開発体験向上に直結する価値ある変更です。提案した改善点は品質をさらに高めるものですが、現状のコードでもプロダクション投入可能です。

Next Action: Test plan 完了後、マージを推奨します。

🤖 Generated by Claude Code

@keito4
keito4 merged commit d2d9387 into main Feb 12, 2026
14 checks passed
@github-actions

Copy link
Copy Markdown
Contributor

🎉 This PR is included in version 1.69.3 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

@github-actions github-actions Bot added the released リリース済み label Feb 12, 2026
@keito4
keito4 deleted the fix/hooks-flush-and-portable-paths branch March 1, 2026 09:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

released リリース済み

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant