Claude CodeでMavenビルドを回す — -q -Bで出力を絞りverifyで完了を確かめる
Claude CodeにMavenビルドを任せるときの出力の絞り方を整理しました。-q・-B・-ntpの役割、-Dtestでのテスト絞り込み、mvn verifyを完了条件にするCLAUDE.mdとStop hookの書き方まで扱います。
Claude CodeにMavenを回させるなら、mvn -q -B -ntp verifyを基本形にします。-qでエラー以外の出力を止め、-Bで色と対話を切り、-ntpでダウンロードの進捗表示を消します。verifyまで走らせれば、コンパイル・単体テスト・パッケージ・統合テスト・品質チェックが一度に通ったかを終了コードで判断できます。この記事では、各オプションの効き方と、テストの絞り込み、CLAUDE.mdとStop hookへの書き方を順に扱います。
出力を絞る3つのオプションは役割が別
Mavenのコマンドライン一覧では、出力まわりのオプションは次のように説明されています。
| オプション | 一覧での説明 | 効くもの |
|---|---|---|
-q / --quiet | 一覧での説明Quiet output - only show errors | 効くもの出力の量 |
-B / --batch-mode | 一覧での説明非対話(バッチ)モードで実行し、出力の色を無効にする | 効くもの色と入力待ち |
-ntp / --no-transfer-progress | 一覧での説明ダウンロード・アップロードの進捗を表示しない | 効くもの進捗の行 |
-qは出力するメッセージの種類を減らします。-Bは表示の形を変えます。-ntpは依存ライブラリの取得中に流れる進捗行だけを止めます。
-qと-B・-ntpの違い
-q
エラーだけを出します。成功したビルドはほとんど何も出力しません。
-B と -ntp
色の制御文字と、転送進捗の行を止めます。メッセージの種類は変わりません。
-qだけでは足りない場面もあります。-qを付けずに-B -ntpだけにすると、各プラグインの実行ログは残りつつ、色と進捗だけが消えます。失敗の原因を探るときは、この形が中間になります。
-l(--log-file)を使うと、ビルドの出力をすべてファイルに書き出せます。このオプションも色を無効にします。出力をコンテキストに入れずにファイルに残す用途は、後の二段運用で使います。
Claude Codeが受け取る出力には上限がある
絞る理由は、Claude CodeのBashツールが出力を受け取る仕組みにあります。ツールのリファレンスによると、コマンドの結果は成功と失敗で扱いが変わります。
| 結果 | Claudeに渡るもの |
|---|---|
| 成功 | Claudeに渡るもの約30,000字までインライン。超えるとファイルのパスと、先頭2,000字までのプレビュー |
| 失敗 | Claudeに渡るもの約10,000字までインライン。超えると先頭と末尾の抜粋で、ファイルのパスは付かない |
Mavenのビルドが落ちて終了コード1を返せば、後者の扱いです。落ちたときに限って、詳しいログの途中が切れます。依存ライブラリの取得ログやテストの標準出力が先に積み上がっていると、肝心のエラー箇所が抜粋から外れかねません。
出力の読み戻し範囲を広げる環境変数もあります。ただしインラインの上限そのものは上がらないので、設定で補うより先にログを減らすほうが筋の良い順序です。設定の詳細はbashOutputMaxCharsの解説を参照してください。
なぜ完了条件はverifyなのか
Mavenのライフサイクルでは、validateからdeployまでのフェーズが順に実行されます。最後のフェーズを指定すれば、そこまでの全フェーズが走ります。ガイドには、何を呼べばよいか迷うときはmvn verifyが推奨のフェーズだと書かれています。
verifyの位置づけは次のとおりです。
test: コンパイル済みのコードを単体テストするpackage: JARなどの配布形式にまとめるverify: 統合テストの結果に対して、品質基準を満たすかのチェックを走らせる
多くの場合、verifyの効果はpackageと同じです。ただし統合テストがあるプロジェクトでは、それも実行されます。checkstyleのような追加チェックをverifyに束ねていれば、規約違反もここで見つかります。
Claudeに「ビルドを通して」と頼むだけだと、mvn compileで止まっても本人は完了と受け取れます。完了条件をmvn verifyの終了コード0と決めておけば、判定が曖昧になりません。
逆に、integration-testフェーズを直接呼ぶのは避けます。ガイドによれば、FailsafeやJaCoCoのようなプラグインはverifyでレポートを集め、pre-integration-testやpost-integration-testでテスト環境の起動と片付けをします。integration-testを単独で呼ぶとレポートが作られず、TomcatやDockerが起動したまま残ることもあります。
繰り返し回すときはテストを絞る
verifyは毎回すべてのテストを回します。実装の途中で、直した箇所のテストだけを見たいときは、Surefireの-Dtestで絞れます。
# テストクラス1つ
mvn -q -B -ntp -Dtest=OrderServiceTest test
# クラス内のメソッドを絞る(JUnit 4とTestNGが対象)
mvn -q -B -ntp -Dtest='OrderServiceTest#create*' test
# パターンと除外
mvn -q -B -ntp '-Dtest=*ServiceTest, !Unstable*' test指定の書き方は、Surefireのドキュメントにある次の規則です。
- クラス名は拡張子なしで書く。拡張子を付けても外される
*と?のパターン、カンマ区切りの複数指定が使える#の後ろでメソッドを絞る。メソッドの絞り込みはJUnit 4とTestNGが対象と明記されている!で除外する
ここで落とし穴が1つあります。-Dtestで指定したテストが1件も実行されないと、既定ではビルドが失敗します。surefire.failIfNoSpecifiedTestsの既定値がtrueだからです。綴りを間違えたときに失敗してくれるのは都合がよく、わざわざfalseにする理由は通常ありません。
また-Dtestで絞ったあとの成功は、プロジェクト全体の成功を意味しません。絞り込みは作業中の確認用と割り切り、最後は絞らないmvn verifyで締める運用にします。
テストの出力量を減らす設定
Surefireには、テスト自体が吐く出力を減らす設定もあります。
| ユーザープロパティ | 既定値 | 内容 |
|---|---|---|
maven.test.redirectTestOutputToFile | 既定値false | 内容テストの標準出力をreportsDirectory/<テスト名>-output.txtに出す |
surefire.skipAfterFailureCount | 既定値0 | 内容指定した数の失敗・エラーが出たら残りのテストを飛ばす |
trimStackTrace | 既定値false | 内容レポートのスタックトレースをテスト内の行だけに切り詰める |
surefire.rerunFailingTestsCount | 既定値0 | 内容失敗したテストを指定回数まで再実行する |
テストがSystem.outに大量に書き出すプロジェクトでは、redirectTestOutputToFileが効きます。ログがコンソールからファイルへ移るので、必要なテストの分だけClaudeに読ませられます。
skipAfterFailureCount=1は、最初の失敗で止めたいときの選択肢です。ドキュメントには、並列実行やフォーク実行では競合のために完全には保証されないとあります。
rerunFailingTestsCountは不安定なテストの再実行用です。再実行して通ったテストは「不安定なテスト」として数えられ、ビルド自体は成功します。つまり終了コード0でも不安定なテストが混じる場合があります。完了条件に使うなら、この設定は入れたままにするか外すかをチームで決めておきます。
-DskipTestsや-Dmaven.test.skip=trueでテストを飛ばす方法もあります。後者はテストのコンパイルも飛ばします。ただし「テストを通した」ことにはならないので、完了条件の確認には使えません。Claudeが詰まったときに、これらでビルドだけ通す方向へ逃げないよう、CLAUDE.mdで禁止しておくのが安全です。
マルチモジュールでは対象と失敗の扱いを決める
複数モジュールのプロジェクトでは、出力量はモジュール数に比例します。次のオプションで範囲を絞れます。
| オプション | 内容 |
|---|---|
-pl <モジュール> | 内容指定したモジュールだけをビルドする。[groupId]:artifactIdか相対パスで指定 |
-am | 内容-plで指定したモジュールが必要とするモジュールも一緒にビルドする |
-amd | 内容-plで指定したモジュールに依存するモジュールも一緒にビルドする |
-rf <モジュール> | 内容指定したモジュールからリアクターを再開する |
-fae | 内容失敗したモジュールに依存しない部分は最後まで進め、失敗は最後に報告する |
-ff | 内容最初の失敗で止める |
直したモジュールの影響を見たいなら-pl core -amではなく、-pl core -amdが合います。-amは上流、-amdは下流を足すオプションなので、向きを取り違えないでください。
失敗の調べ方は2通りです。1回の実行で全体の失敗を見渡したいなら-faeを付けます。逆にログを短くしたいなら-ffで最初の失敗で止め、直してから-rfで続きから再開します。
# coreを直した影響をcoreと下流で確かめる
mvn -q -B -ntp -pl core -amd verify
# 失敗したモジュールから再開する
mvn -q -B -ntp -rf :api verify失敗したときだけ詳しく読む二段運用
毎回-qだと、失敗時に原因が足りません。毎回詳細だと、成功のたびにコンテキストを消費します。通常は静かに回し、失敗したときだけ詳細を読む運用を、1つのコマンドにまとめられます。
mvn -B -ntp verify -l target/mvn-verify.log; \
echo "exit code: $?"; \
grep -n -E 'ERROR|FAIL' target/mvn-verify.log | head -n 40-lでログ全量をファイルに残し、画面には終了コードと、エラーを含む行の先頭40件だけを返します。続きが必要なら、Claudeがそのファイルをgrepや範囲指定で読めます。ログの置き場は、.gitignore済みのtarget/にしておけば差分に混じりません。
成功のときも出力は終了コードの1行だけです。-qと違い、ログファイルには全量が残るので、後から調べる手段を失いません。
CLAUDE.mdに完了条件を書く
オプションを毎回指示するのは手間です。プロジェクトのCLAUDE.mdに、判断の基準ごと書いておきます。次は一例です。
## Mavenビルド
- 完了の条件は `mvn -q -B -ntp verify` が終了コード0で終わること
- 作業中の確認は `-Dtest=<クラス名>` でテストを絞ってよい。最後は絞らずに verify を通す
- 失敗したら `-q` を外し、`-l target/mvn-verify.log` でログを残して ERROR の行を読む
- 複数モジュールでは `-pl <モジュール> -amd` で影響範囲を確かめる
- `-DskipTests` と `-Dmaven.test.skip=true` は完了の確認に使わない
- ログ全文を貼り直さないポイントは、絞る場面と絞らない場面を条件つきで書くことです。「常に-q」と書くと、失敗の調査でも情報を絞ったままにしかねません。同じ考え方は、テストコマンドの書き方を扱ったVitestのCLAUDE.mdや、Gradleのビルド出力の記事にも通じます。
Stop hookでverifyを強制する
CLAUDE.mdは指示であり、守られる保証はありません。完了条件を確実に効かせたいなら、Stop hookを使えます。hooksのリファレンスによると、Stopイベントで終了コード2を返すと、Claudeは作業を続けます。標準エラー出力の内容が、続けるための理由として渡されます。
.claude/settings.jsonに次のように登録します。
{
"hooks": {
"Stop": [
{
"hooks": [
{ "type": "command", "command": ".claude/hooks/verify-maven.sh" }
]
}
]
}
}呼ばれるスクリプトは、たとえば次の形です。
#!/bin/bash
input=$(cat)
# すでにStop hookの結果で続行中なら、無限に差し戻さない
if echo "$input" | grep -q '"stop_hook_active": *true'; then
exit 0
fi
log="${TMPDIR:-/tmp}/mvn-verify.log"
if mvn -q -B -ntp verify > "$log" 2>&1; then
exit 0
fi
grep -n -E 'ERROR|FAIL' "$log" | head -n 40 >&2
exit 2Stop hookには、続行中かどうかを示すstop_hook_activeが入力のJSONで渡されます。リファレンスでは、解決しない条件でブロックし続けるのを避けるために、この値を確認するよう案内されています。上の例ではこの値がtrueなら素通りさせています。つまり差し戻しは1回までです。複数回の差し戻しが要るなら、判定をスクリプトに足します。
差し戻しの上限そのものを調整する環境変数については、CLAUDE_CODE_STOP_HOOK_BLOCK_CAPの解説にあります。hooks全体の仕組みはClaude Code Hooks完全ガイドにまとめています。
注意点が1つあります。verifyはテストの量に応じて時間がかかり、Claudeの応答のたびに走ります。小さな会話の度に数分待たされるようなら、Stop hookでは-Dtestなしの全体実行ではなく、変更したモジュールに絞るなど、プロジェクトに合わせて軽くしてください。
実行時間とつまずきの切り分け
初回のビルドがタイムアウトする: Bashツールの前面実行の既定タイムアウトは2分です。依存ライブラリの初回取得は時間がかかることがあります。Claudeがtimeoutを指定して延ばせ、上限は既定で10分です。BASH_DEFAULT_TIMEOUT_MSとBASH_MAX_TIMEOUT_MSの環境変数で変更できます。
ビルドが静かすぎて成否が分からない: -qは成功時に出力をほとんど出しません。終了コードをecho $?で読むよう、CLAUDE.mdに書きます。
-Dtestで指定したのに「テストがない」と失敗する: クラス名の綴りを確認します。メソッドの絞り込みは、ドキュメントの記載がJUnit 4とTestNGまでです。JUnit 5での扱いは記載がないので、まずクラス単位で絞ります。
ネットワークがない環境で失敗する: -o(--offline)でオフライン実行に切り替えられます。ローカルリポジトリに依存ライブラリが揃っているときに使います。
SNAPSHOTの更新確認で遅い: -nsu(--no-snapshot-updates)でSNAPSHOTの更新を抑えられます。一方で-Uは更新を強制するので、依存が古いままのときの切り分けに使います。
ビルドを待ちながら別の作業を進めたい: Claude側でrun_in_backgroundによる実行が使えます。
まとめ
出力の量は-q、色は-B、進捗行は-ntpと、効く軸が別々です。完了条件はmvn verifyの終了コード0に置き、作業中だけ-Dtestと-pl -amdで範囲を絞ります。確実に守らせたい箇所はStop hookに寄せ、判断の基準はCLAUDE.mdに書く、という分担がいちばん噛み合います。
Spring Bootのアプリを作る具体的な流れは、Spring BootのREST API開発で扱っています。テストランナーの出力を絞る発想は、Rustのnextestでの長い出力の絞り方にも共通します。