[Kamal] Hook実行時の出力制御機能を追加 - グローバルおよびフック単位での詳細設定が可能に
Context
Kamalではデプロイの各段階でカスタムフック(pre-deploy、post-deployなど)を実行できますが、これまでフックの出力をどのレベルで表示するかを制御する方法がありませんでした。#1243で指摘されていたように、フックの冗長な出力を抑制したい場合や、逆に詳細なデバッグ情報を確認したい場合に柔軟な制御ができませんでした。
この変更により、フックごとに出力レベルを設定できるようになり、デプロイプロセスのログをより適切に管理できるようになりました。
Technical Detail
設定方法
config/deploy.ymlにhooks_output設定を追加することで、フックの出力制御が可能になります。設定方法は2パターンあります。
グローバル設定 - すべてのフックに同じ出力レベルを適用:
hooks_output: :verbose
フック単位の設定 - フックごとに異なる出力レベルを指定:
hooks_output:
pre-deploy: :verbose
pre-build: :quiet
出力レベル
設定可能な出力レベルは2種類です:
-
:verbose- フックの実行コマンドと出力をすべて表示 -
:quiet- 「Running the X hook...」メッセージを含むすべての出力を非表示
設定がない場合(デフォルト)は、SSHKitのinfoレベルとなり、「Running...」と「Finished...」のメッセージのみが表示されます。
CLI フラグとの優先順位
CLIの冗長性フラグ(-v、-q)は設定ファイルのhooks_output設定よりも優先されます:
hook_verbosity = if KAMAL.verbosity == :info && hooks_output
VERBOSITY.fetch(hooks_output)
else
KAMAL.verbosity
end
-
-qフラグ指定時: すべてのフック出力を非表示 -
-vフラグ指定時: すべてのフック出力を表示 - フラグなし:
hooks_output設定に従う
実装の詳細
設定のバリデーションはKamal::Configurationで行われます:
HOOKS_OUTPUT_LEVELS = [ :quiet, :verbose ].freeze
def hooks_output_for(hook)
case raw_config.hooks_output
when Symbol, String
raw_config.hooks_output.to_sym
when Hash
raw_config.hooks_output[hook]&.to_sym
end
end
フック実行時は、設定された出力レベルに基づいてKAMAL.with_verbosityでコンテキストを切り替えます:
hook_verbosity = if KAMAL.verbosity == :info && hooks_output
VERBOSITY.fetch(hooks_output)
else
KAMAL.verbosity
end
KAMAL.with_verbosity(hook_verbosity) do
run_locally do
execute *KAMAL.hook.run(hook)
end
end
バリデーション
無効な出力レベルが指定された場合は、設定の読み込み時にエラーが発生します:
def validate_hooks_output_level!(level, hook = nil)
return if HOOKS_OUTPUT_LEVELS.include?(level)
context = hook ? " for hook '#{hook}'" : ""
raise Kamal::ConfigurationError, "Invalid hooks_output '#{level}'#{context}, must be one of: #{HOOKS_OUTPUT_LEVELS.join(', ')}"
end
エラーメッセージには、グローバル設定かフック単位設定かが明示されます。
テスト
統合テストでは、各出力レベルの動作が検証されています:
def assert_hook_output(output)
# pre-deploy hook (hooks_output: :verbose) shows everything
assert_match(/Running.*pre-deploy/, output)
assert_match(/Deployed!/, output)
# pre-build hook (hooks_output: :quiet) hides everything
assert_no_match(/Running.*pre-build/, output)
assert_no_match(/About to build and push/, output)
# post-deploy hook (no hooks_output setting) shows Running but hides output
assert_match(/Running.*post-deploy/, output)
assert_no_match(/Finished deploy!/, output)
end
利用シーン
-
詳細なデバッグが必要な場合:
pre-deploy: :verboseで該当フックの詳細ログを確認 -
ノイズを減らしたい場合:
pre-build: :quietでビルド関連の定型メッセージを非表示 -
CI/CDパイプライン: グローバルに
:quietを設定し、必要なフックのみ:verboseで出力
失敗したフックは、出力レベルの設定に関わらず、エラーメッセージ内に常に出力が含まれます。