diff --git a/lib/kamal/cli/base.rb b/lib/kamal/cli/base.rb index 2065b8afb..448e01f96 100644 --- a/lib/kamal/cli/base.rb +++ b/lib/kamal/cli/base.rb @@ -99,6 +99,9 @@ def run_pre_configure_hook(config_file, destination) say message end + # Export remaining keys so the ERB in the config file can read them + output.except("KAMAL_DESTINATION", "KAMAL_MESSAGE").each { |key, value| ENV[key] = value } + output["KAMAL_DESTINATION"] rescue SSHKit::Command::Failed => e raise HookError.new("Hook `pre-configure` failed:\n#{e.message}") diff --git a/lib/kamal/cli/templates/sample_hooks/pre-configure.sample b/lib/kamal/cli/templates/sample_hooks/pre-configure.sample index 40e0406f9..55d3551f0 100755 --- a/lib/kamal/cli/templates/sample_hooks/pre-configure.sample +++ b/lib/kamal/cli/templates/sample_hooks/pre-configure.sample @@ -17,6 +17,8 @@ # # KAMAL_DESTINATION — sets or overwrites the destination for this deploy # KAMAL_MESSAGE — printed to the user after the hook runs -# Any other keys are accumulated and available to subsequent hooks +# Any other keys are exported as environment variables before the config file +# is rendered — so its ERB can read them, e.g. <%= ENV["MY_HOST"] %> — and are +# also available to subsequent hooks echo "pre-configure hook called for destination: ${KAMAL_DESTINATION:-}" diff --git a/test/cli/pre_configure_test.rb b/test/cli/pre_configure_test.rb index e986007b5..a30e79b8c 100644 --- a/test/cli/pre_configure_test.rb +++ b/test/cli/pre_configure_test.rb @@ -35,6 +35,36 @@ class CliPreConfigureTest < CliTestCase end end + test "pre-configure hook output is exported to ENV for config ERB" do + config_yaml = <<~YAML + service: app + image: dhh/app + registry: + username: dhh + password: secret + servers: + - <%= ENV["PRE_CONFIGURE_HOST"] %> + builder: + arch: amd64 + YAML + + with_pre_configure_hook({ "PRE_CONFIGURE_HOST" => "1.2.3.4" }, config_yaml: config_yaml) do + run_command("exec", "date", "-c", "config/deploy.yml") + + assert_includes KAMAL.config.all_hosts, "1.2.3.4" + end + ensure + ENV.delete("PRE_CONFIGURE_HOST") + end + + test "pre-configure hook does not export reserved keys to ENV" do + with_pre_configure_hook({ "KAMAL_MESSAGE" => "Deploying to beta2" }) do + run_command("exec", "date", "-c", config_file_path("deploy_with_accessories")) + + assert_nil ENV["KAMAL_MESSAGE"] + end + end + test "pre-configure hook failure raises HookError" do with_pre_configure_hook_that_fails do assert_raises(Kamal::Cli::HookError) do @@ -131,7 +161,7 @@ def config_file_path(fixture_name) "test/fixtures/#{fixture_name}.yml" end - def with_pre_configure_hook(output, hooks_path: nil, destination: nil) + def with_pre_configure_hook(output, hooks_path: nil, destination: nil, config_yaml: nil) Dir.mktmpdir do |tmpdir| original_pwd = Dir.pwd old_dest = ENV["KAMAL_DESTINATION"] @@ -150,6 +180,12 @@ def with_pre_configure_hook(output, hooks_path: nil, destination: nil) FileUtils.mkdir_p(hook_dir) File.write(File.join(hook_dir, "pre-configure"), "#!/bin/bash\n") + if config_yaml + config_dir = File.join(tmpdir, "config") + FileUtils.mkdir_p(config_dir) + File.write(File.join(config_dir, "deploy.yml"), config_yaml) + end + # If custom hooks_path, write a config that uses it (with raw ERB intact), # plus a destination overlay so config loads successfully after rewrite if hooks_path