diff --git a/lib/kamal/cli/base.rb b/lib/kamal/cli/base.rb index e648281f..0710c088 100644 --- a/lib/kamal/cli/base.rb +++ b/lib/kamal/cli/base.rb @@ -25,12 +25,17 @@ module Kamal::Cli def initialize(*) super @original_env = ENV.to_h.dup - load_envs + load_env initialize_commander(options_with_subcommand_class_options) end private - def load_envs + def reload_env + reset_env + load_env + end + + def load_env if destination = options[:destination] Dotenv.load(".env.#{destination}", ".env") else @@ -38,10 +43,27 @@ module Kamal::Cli end end - def reload_envs + def reset_env + replace_env @original_env + end + + def replace_env(env) ENV.clear - ENV.update(@original_env) - load_envs + ENV.update(env) + end + + def with_original_env + keeping_current_env do + reset_env + yield + end + end + + def keeping_current_env + current_env = ENV.to_h.dup + yield + ensure + replace_env(current_env) end def options_with_subcommand_class_options diff --git a/lib/kamal/cli/main.rb b/lib/kamal/cli/main.rb index 7f35da95..598d6c42 100644 --- a/lib/kamal/cli/main.rb +++ b/lib/kamal/cli/main.rb @@ -191,10 +191,12 @@ class Kamal::Cli::Main < Kamal::Cli::Base end if Pathname.new(File.expand_path(env_template_path)).exist? - File.write(env_path, ERB.new(File.read(env_template_path), trim_mode: "-").result, perm: 0600) + # Ensure existing env doesn't pollute template evaluation + content = with_original_env { ERB.new(File.read(env_template_path), trim_mode: "-").result } + File.write(env_path, content, perm: 0600) unless options[:skip_push] - reload_envs + reload_env invoke "kamal:cli:env:push", options end else diff --git a/test/cli/main_test.rb b/test/cli/main_test.rb index 4db97aaf..6436947c 100644 --- a/test/cli/main_test.rb +++ b/test/cli/main_test.rb @@ -1,6 +1,9 @@ require_relative "cli_test_case" class CliMainTest < CliTestCase + setup { @original_env = ENV.to_h.dup } + teardown { ENV.clear; ENV.update @original_env } + test "setup" do invoke_options = { "config_file" => "test/fixtures/deploy_simple.yml", "version" => "999", "skip_hooks" => false } @@ -434,7 +437,7 @@ class CliMainTest < CliTestCase end test "envify" do - with_test_dot_env_erb(contents: "HELLO=<%= 'world' %>") do + with_test_dotenv(".env.erb": "HELLO=<%= 'world' %>") do run_command("envify") assert_equal("HELLO=world", File.read(".env")) end @@ -448,14 +451,14 @@ class CliMainTest < CliTestCase <% end -%> EOF - with_test_dot_env_erb(contents: file) do + with_test_dotenv(".env.erb": file) do run_command("envify") assert_equal("HELLO=world\nKEY=value\n", File.read(".env")) end end test "envify with destination" do - with_test_dot_env_erb(contents: "HELLO=<%= 'world' %>", file: ".env.world.erb") do + with_test_dotenv(".env.world.erb": "HELLO=<%= 'world' %>") do run_command("envify", "-d", "world", config_file: "deploy_for_dest") assert_equal "HELLO=world", File.read(".env.world") end @@ -470,6 +473,13 @@ class CliMainTest < CliTestCase run_command("envify", "--skip-push") end + test "envify with clean env" do + with_test_dotenv(".env": "HELLO=already", ".env.erb": "HELLO=<%= ENV.fetch 'HELLO', 'never' %>") do + run_command("envify", "--skip-push") + assert_equal "HELLO=never", File.read(".env") + end + end + test "remove with confirmation" do run_command("remove", "-y", config_file: "deploy_with_accessories").tap do |output| assert_match /docker container stop traefik/, output @@ -522,14 +532,16 @@ class CliMainTest < CliTestCase stdouted { Kamal::Cli::Main.start([ *command, "-c", "test/fixtures/#{config_file}.yml" ]) } end - def with_test_dot_env_erb(contents:, file: ".env.erb") + def with_test_dotenv(**files) Dir.mktmpdir do |dir| fixtures_dup = File.join(dir, "test") FileUtils.mkdir_p(fixtures_dup) FileUtils.cp_r("test/fixtures/", fixtures_dup) Dir.chdir(dir) do - File.write(file, contents) + files.each do |filename, contents| + File.binwrite(filename.to_s, contents) + end yield end end