chore(husky): pre-commit/pre-push を Docker/host 両対応にし重い解析を pre-push へ分離 - #6900
Conversation
- 実行環境を自動判定(ec-cube コンテナ稼働中は `docker compose exec`、 無ければ host の vendor/bin、どちらも無ければ握り潰さず明示スキップ) - pre-commit: php-cs-fixer を staged のみ auto-fix(lint-staged 非依存= コンテナに node が無くても動作。約0.5秒) - pre-push: rector --dry-run + phpstan を project-wide 実行(重い解析は 「人に渡す境界」である push へ寄せ、commit のテンポを保つ) - キャッシュ削除(rm -rf var/rector_cache /tmp/phpstan)を廃止し incremental キャッシュを活かす(pre-push 初回~35s→以降~4.5s) - ECCUBE_HOOK_RUNNER=docker|host|skip で強制切替、HUSKY=0 でバイパス可 Refs #6761 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
📝 WalkthroughWalkthrough
ChangesHusky フック更新
Estimated code review effort: 2 (Simple) | ~10 minutes Sequence Diagram(s)sequenceDiagram
participant Developer as 開発者
participant PreCommit as pre-commit
participant PrePush as pre-push
participant Runner as ECCUBE_HOOK_RUNNER
participant Tools as lint-staged/php-cs-fixer/rector/phpstan
Developer->>PreCommit: git commit
PreCommit->>Runner: 実行環境を選択
PreCommit->>Tools: staged PHP を検査・修正
Tools-->>PreCommit: 結果
Developer->>PrePush: git push
PrePush->>Runner: 実行環境を選択
PrePush->>Tools: cache:clear、rector、phpstan を実行
Tools-->>PrePush: 結果
Suggested reviewers: Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 4
🧹 Nitpick comments (4)
.husky/pre-commit (2)
1-32: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win
package.jsonのlint-staged設定が未使用になっている可能性
package.jsonには同一のphp-cs-fixer --config=.php-cs-fixer.dist.php --path-mode=intersection fixを呼ぶlint-staged設定が残っています。本PRでnpx lint-stagedの直接利用をシェルベースの実行に置き換えたのであれば、package.json側の該当設定は死んだ設定として整理対象になり得ます(本ファイルの変更範囲外のため要確認)。🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In @.husky/pre-commit around lines 1 - 32, The package.json lint-staged entry for php-cs-fixer may now be dead config because .husky/pre-commit runs php-cs-fixer directly via RUN/xargs instead of npx lint-staged. Verify whether any other hook or workflow still uses that lint-staged task; if not, remove or consolidate the redundant package.json setting so there is a single source of truth for the php-cs-fixer invocation.
14-24: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winpre-push と重複する実行環境判定ロジック
Line 14-24 の Docker/host 判定ロジックは
.husky/pre-pushの Line 11-21 とほぼ同一です。共通スクリプト(例:.husky/lib/detect-runner.sh)に切り出して両フックからsourceすると、今後の変更漏れやドリフトを防げます。🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In @.husky/pre-commit around lines 14 - 24, The Docker/host execution environment detection in the pre-commit hook is duplicated with the pre-push hook, so extract the shared runner selection logic into a common helper script and have both hooks source it. Move the current case-based detection from the pre-commit hook into a reusable script (for example, a shared Husky library), then update the pre-commit and pre-push hooks to call that shared logic instead of maintaining separate copies..husky/pre-push (2)
11-21: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win実行環境判定ロジックの重複
PR概要によると
pre-commitにも同様の docker/host 判定ロジックが実装される想定です。この判定処理(DC/SVC定義、auto判定、RUN組み立て)を共通シェルスクリプト(例:.husky/_/runner.sh)に切り出し、両フックからsourceする形にすると保守性が向上します。🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In @.husky/pre-push around lines 11 - 21, The docker/host execution environment detection in the pre-push hook is duplicated and should be shared with pre-commit. Extract the DC/SVC setup, ECCUBE_HOOK_RUNNER auto/host/docker/skip branching, and RUN construction into a common shell helper such as a sourced runner script, then update the pre-push hook and the matching pre-commit hook to load that shared logic instead of duplicating the case block.
17-17: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick winDocker疎通確認にタイムアウトが無い
$DC exec -T "$SVC" trueがDocker daemon無応答時に無期限にハングする可能性があります。ローカル開発フローが固まるのを防ぐため、timeoutコマンドでラップすることを推奨します。🛠️ 修正案
- if $DC exec -T "$SVC" true >/dev/null 2>&1; then RUN="$DC exec -T $SVC" + if timeout 5 $DC exec -T "$SVC" true >/dev/null 2>&1; then RUN="$DC exec -T $SVC"🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In @.husky/pre-push at line 17, The Docker connectivity check in the pre-push hook can hang indefinitely when the daemon is unresponsive; update the conditional check in the pre-push script around the $DC exec -T "$SVC" true probe to run under a timeout wrapper. Keep the existing RUN assignment flow, but ensure the Docker sanity check fails fast instead of blocking the local workflow.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.husky/pre-commit:
- Around line 26-32: The pre-commit hook in the staged PHP fix flow is re-adding
whole files with git add, which can pull in unstaged edits from the same file.
Update the .husky/pre-commit logic around the php-cs-fixer and git add steps so
it only operates on the indexed content, using a stash/restore approach such as
git stash --keep-index before running the fix and restoring afterward. Keep the
fix localized to the existing STAGED_PHP handling and the php-cs-fixer
invocation so only staged changes are committed.
- Around line 11-24: The pre-commit hook in .husky/pre-commit should reject
unsupported ECCUBE_HOOK_RUNNER values instead of silently falling through to
host execution, so update the case handling around RUN to fail explicitly on
unknown input. Also, wherever STAGED_PHP is piped into xargs for php-cs-fixer
and git add, switch to a NUL-safe file list flow so filenames with spaces are
preserved; adjust the hook’s STAGED_PHP processing and the php-cs-fixer/git add
invocation together.
In @.husky/pre-push:
- Line 18: The host check in the pre-push hook only verifies vendor/bin/phpstan,
so it can pass even when vendor/bin/rector is missing and later fail at
execution time instead of showing the intended skip message. Update the
conditional in .husky/pre-push to also require rector’s executable presence
alongside phpstan, matching the later rector invocation path and keeping the
host detection in sync with the commands that actually run.
- Around line 12-21: The ECCUBE_HOOK_RUNNER switch in .husky/pre-push has no
default branch, so invalid values fall through with RUN unset and the hook
continues ambiguously. Update the case handling around ECCUBE_HOOK_RUNNER to add
an explicit default path that rejects unknown values with a clear error message
and non-zero exit, using the existing RUN selection logic for docker, host,
skip, and auto as the valid symbols to anchor the change.
---
Nitpick comments:
In @.husky/pre-commit:
- Around line 1-32: The package.json lint-staged entry for php-cs-fixer may now
be dead config because .husky/pre-commit runs php-cs-fixer directly via
RUN/xargs instead of npx lint-staged. Verify whether any other hook or workflow
still uses that lint-staged task; if not, remove or consolidate the redundant
package.json setting so there is a single source of truth for the php-cs-fixer
invocation.
- Around line 14-24: The Docker/host execution environment detection in the
pre-commit hook is duplicated with the pre-push hook, so extract the shared
runner selection logic into a common helper script and have both hooks source
it. Move the current case-based detection from the pre-commit hook into a
reusable script (for example, a shared Husky library), then update the
pre-commit and pre-push hooks to call that shared logic instead of maintaining
separate copies.
In @.husky/pre-push:
- Around line 11-21: The docker/host execution environment detection in the
pre-push hook is duplicated and should be shared with pre-commit. Extract the
DC/SVC setup, ECCUBE_HOOK_RUNNER auto/host/docker/skip branching, and RUN
construction into a common shell helper such as a sourced runner script, then
update the pre-push hook and the matching pre-commit hook to load that shared
logic instead of duplicating the case block.
- Line 17: The Docker connectivity check in the pre-push hook can hang
indefinitely when the daemon is unresponsive; update the conditional check in
the pre-push script around the $DC exec -T "$SVC" true probe to run under a
timeout wrapper. Keep the existing RUN assignment flow, but ensure the Docker
sanity check fails fast instead of blocking the local workflow.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 80f9a8ba-6b5d-4cd8-896b-fe0ba7d1e3a5
📒 Files selected for processing (2)
.husky/pre-commit.husky/pre-push
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## 4.4 #6900 +/- ##
==========================================
+ Coverage 75.32% 77.10% +1.78%
==========================================
Files 519 546 +27
Lines 25483 27133 +1650
==========================================
+ Hits 19196 20922 +1726
+ Misses 6287 6211 -76
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
…ctor 存在確認 - pre-push: rector が参照する dev コンテナ XML が無い cold 状態で push がブロックされる問題に対し、 実行前に XML の存在を確認し無ければ cache:clear --env=dev で生成(cache:warmup では再生成されないため) - pre-commit: lint-staged が使える環境では優先利用し部分ステージ(git add -p)の未ステージ差分巻き込みを防止。 node/lint-staged が無い環境では従来の php-cs-fixer 直実行にフォールバック(部分ステージ非保護を明示) - 両フック: ECCUBE_HOOK_RUNNER の不正値を case の *) で明示的に exit 1(host への暗黙フォールスルーを防止) - pre-push: host 判定に rector の存在確認を追加(先に実行される rector 欠落時の実行時エラーを回避) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
.husky/pre-commit (1)
37-46:⚠️ Potential issue | 🟠 MajorDocker フォールバックは部分ステージと特殊なパスを破壊します。
Line 38-39 の注意書きどおり、部分ステージ済みファイルを整形して Line 46 で再ステージすると、未ステージの hunk までコミットされます。さらに Lines 41/46 の改行区切り
xargsは空白を含む PHP パスを分割します。未ステージ差分を退避・復元するか、少なくとも該当状態では中断し、git diff -zとxargs -0でパスを渡してください。🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In @.husky/pre-commit around lines 37 - 46, Update the pre-commit fallback around STAGED_PHP so it does not commit unstaged hunks: either stash and restore unstaged changes or abort when partially staged files are detected. Also replace newline-delimited xargs usage in the php-cs-fixer and git add commands with null-delimited paths from git diff -z and xargs -0, preserving filenames containing spaces or special characters.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.husky/pre-commit:
- Around line 31-34: Update the lint-staged branch condition in the pre-commit
hook to require both node_modules/.bin/lint-staged and available node and npx
commands via command -v. Keep the existing lint-staged execution and exit
behavior, allowing the php-cs-fixer fallback when either command is unavailable.
---
Outside diff comments:
In @.husky/pre-commit:
- Around line 37-46: Update the pre-commit fallback around STAGED_PHP so it does
not commit unstaged hunks: either stash and restore unstaged changes or abort
when partially staged files are detected. Also replace newline-delimited xargs
usage in the php-cs-fixer and git add commands with null-delimited paths from
git diff -z and xargs -0, preserving filenames containing spaces or special
characters.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 40328e90-553e-449c-892d-c3978dc9337a
📒 Files selected for processing (2)
.husky/pre-commit.husky/pre-push
| if [ -z "$RUN" ] && [ -x node_modules/.bin/lint-staged ]; then | ||
| echo "pre-commit: lint-staged" | ||
| npx lint-staged -q | ||
| exit $? |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "## pre-commit lines"
sed -n '1,80p' .husky/pre-commit 2>/dev/null || true
echo
echo "## repository files of interest"
git ls-files | grep -E '^(package\.json|compose.*|Dockerfile|bin/php-cs-fixer|\.php-cs-fixer|ci|scripts|vendor|tools|install)' | head -100Repository: EC-CUBE/ec-cube
Length of output: 2074
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "## search lint-staged and pre-commit related docs/configs"
rg -n "lint-staged|pre-commit|php-cs-fixer|npm|command -v node|command -v npx|node_modules" -S . --glob '!node_modules/**' --glob '!vendor/**' --glob '!dist/**' --glob '!build/**' | head -200Repository: EC-CUBE/ec-cube
Length of output: 17893
🏁 Script executed:
#!/bin/bash
set -euo pipefail
python3 - <<'PY'
from pathlib import Path
p=Path('.husky/pre-commit')
if not p.exists():
print("missing")
raise SystemExit
lines=p.read_text().splitlines()
for i,l in enumerate(lines,1):
if 25<=i<=40: print(f"{i:03}: {l}")
PYRepository: EC-CUBE/ec-cube
Length of output: 807
lint-staged の実行可否も確認してください。
node_modules/.bin/lint-staged があっても host に node/npx がない場合は Line 33 で失敗し、その後の php-cs-fixer フォールバックへ進みません。command -v node と command -v npx も分岐条件に含めてください。
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.husky/pre-commit around lines 31 - 34, Update the lint-staged branch
condition in the pre-commit hook to require both node_modules/.bin/lint-staged
and available node and npx commands via command -v. Keep the existing
lint-staged execution and exit behavior, allowing the php-cs-fixer fallback when
either command is unavailable.
レビュー指摘への対応(
|
| 指摘 | 対応 |
|---|---|
| pre-push: rector が dev コンテナ XML を要求し cold 状態で push ブロック(nanasess・必須) | rector 前に XML 存在ガード → 無ければ cache:clear --env=dev で生成。cache:warmup では再生成されないことを実測したため cache:clear を採用 |
pre-commit: git add が部分ステージ外の未ステージ差分を巻き込む(nanasess / CodeRabbit) |
lint-staged を残して優先利用(stash で部分ステージ安全)、node が無い環境のみ php-cs-fixer 直実行にフォールバック(非保護を明示) |
両フック: ECCUBE_HOOK_RUNNER 不正値の暗黙フォールスルー(CodeRabbit) |
case に *) を追加し不正値を exit 1 |
| pre-push: host 判定で rector の存在確認漏れ(CodeRabbit) | [ -x vendor/bin/rector ] && [ -x vendor/bin/phpstan ] に |
今回は見送った指摘
| 指摘 | 理由 |
|---|---|
| 環境判定ロジックの共通スクリプト化(CodeRabbit nitpick ×2) | 対象は短いフック 2 本で、実行コマンド・存在確認対象が異なる。共通化はパラメータ化が必要で、複製許容の範囲と判断 |
package.json の lint-staged が死に設定(CodeRabbit nitpick) |
上記対応で lint-staged を優先利用する構成にしたため、設定は現役として保持 |
Docker 疎通確認に timeout ラップ(CodeRabbit nitpick) |
timeout は POSIX 非保証(coreutils の無い macOS 等で不在)で、移植性をかえって損なうため見送り |
| 空白入りファイル名の NUL 区切り対応(CodeRabbit) | 本リポジトリに空白入り .php は存在せず、開発フックでの実害が低いため見送り |
運用上の注意(本 PR とは別件)
検証中、本ブランチが 4.4 より 246 コミット遅れであることが判明しました(composer.lock の DBAL が本ブランチ 3.10.5 に対し 4.4 は 4.4.3)。ローカルの pre-push は stale な vendor の影響で誤失敗し得ます(今回の push は HUSKY=0 でバイパスしています)。CI を正しく通すには 4.4 のマージ(追従)が必要と思われます。
nanasess
left a comment
There was a problem hiding this comment.
LGTM 👍 指摘した 2 点とも fb235a2a55 で妥当に対応いただけていることを、最新の hook を取得して確認しました。
- pre-commit(部分ステージ混入): host + lint-staged 優先で未ステージ差分を stash 保護し、node/lint-staged が無い環境のみ php-cs-fixer 直実行にフォールバック(非保護の旨も明示出力)。合意した方針どおりで、部分コミット運用の安全性が保たれています。旧
|| node -e ''の握り潰しがexit $?に変わり、cs-fixer の実エラーが commit をブロックするようになった点も良い改善です。 - pre-push(rector の dev container XML 要求): cold 状態での push ブロックを退避 XML で再現確認のうえ、XML 不在時に
cache:clear --env=dev(cache:warmupでは再生成されないという実機知見込み)で生成する分岐を追加。host 判定の rector 存在確認漏れも解消されています。
環境両対応・commit/push の役割分離という設計も含めて良い変更だと思います。approve します。
(follow-up として、フォールバック経路の部分ステージ非保護を完全に閉じたい場合は、staged な .php が同時に未ステージ変更も持つケースを検出して fail させるガードが低リスクかと思います。今回のマージをブロックするものではありません。)
概要(Overview・Refs Issue)
Git フック(husky)を Docker 環境・host 環境のどちらでも動くようにし、あわせて 重い静的解析を pre-commit から pre-push へ分離します。
docker-composeで開発している環境では、host に PHP / node を持たない構成が一般的です。現行および #6761 の hook はvendor/bin/*/npxを host 実行前提にしているため、そうした環境では hook が失敗、または握り潰し(|| node -e '')によって無音で素通りし「掛けているつもりで実は掛かっていない」状態になりがちでした。Refs #6761(pre-commit 強化の提案。本 PR はその Docker/host 両対応版・別案です)
方針(Policy)
実行環境を自動判定する
RUNプレフィックスを導入:ec-cubeコンテナ稼働中 →docker compose exec -T ec-cube …php+vendor/bin→ host 実行command -v phpまで見て「phar は在るが php ランタイム無し」の誤判定も回避)ECCUBE_HOOK_RUNNER=docker|host|skipで強制切替、HUSKY=0でバイパスフックを役割で分離(commit は頻繁=軽く、push は「人に渡す境界」= CI と同じ役割):
pre-commitpre-pushsrc全体)npx lint-stagedを直接php-cs-fixer --path-mode=intersection+git addに置換:コンテナに node/lint-staged が無くても動くようにするため(host でも同じ経路)。キャッシュ削除(
rm -rf var/rector_cache//tmp/phpstan)を廃止:commit/push ごとに消すと毎回コールドで遅い。incremental キャッシュを活かし、pre-push は 2 回目以降 ~4.5 秒に収まります。実装に関する補足(Appendix)
npm install時に.husky/_/配下へ全 git フックのラッパを生成するため、.husky/pre-pushを追加するだけで push 時に発火します(追加設定不要)。package.jsonのlint-staged設定は今回のフックからは呼ばれなくなります(残置しても無害。整理は follow-up 可)。テスト(Test)
手元の Docker 環境(
ec-cubeサービス)で end-to-end 確認済み:pre-commit: staged .php 1 件 → php-cs-fixer 実行、約 0.5 秒で完了(exit 0)。.php 未 staged の commit は即素通り。pre-push:rector --dry-run(OK)→phpstan analyze src/(No errors, 611 files)まで完走(exit 0)。初回 ~35 秒、キャッシュ維持で 2 回目以降 ~4.5 秒。running in Docker (ec-cube)に解決することを確認。ECCUBE_HOOK_RUNNER=hostで host 実行にも切替可能(host に PHP 8.3 + vendor がある環境で確認)。shell フックのため PHPUnit のテスト追加対象はありません。
相談(Discussion)
マイナーバージョン互換性保持のための制限事項チェックリスト
Summary by CodeRabbit