diff --git a/lib/tower/igniter.ex b/lib/tower/igniter.ex index 0cfca6f..83e3e5c 100644 --- a/lib/tower/igniter.ex +++ b/lib/tower/igniter.ex @@ -1,5 +1,10 @@ if Code.ensure_loaded?(Igniter) do defmodule Tower.Igniter do + @runtime_file_path "config/runtime.exs" + @default_runtime_file_content """ + import Config + """ + def reporters_list_append(igniter, module) do Igniter.Project.Config.configure( igniter, @@ -11,18 +16,93 @@ if Code.ensure_loaded?(Igniter) do ) end - def runtime_configure_reporter(igniter, application, items) do - items - |> Enum.reduce(igniter, fn {key, value}, igniter -> - Igniter.Project.Config.configure( - igniter, - "runtime.exs", - application, - [key], - value, - updater: &{:ok, &1} - ) - end) + def runtime_configure_reporter(igniter, application, items, opts \\ []) do + env = opts[:env] + + igniter + |> Igniter.include_or_create_file(@runtime_file_path, @default_runtime_file_content) + |> Igniter.update_elixir_file( + @runtime_file_path, + fn zipper -> + if Igniter.Project.Config.configures_root_key?(zipper, application) do + {:ok, zipper} + else + if env do + patterns = env_config_patterns(env) + + zipper + |> Igniter.Code.Common.move_to_cursor_match_in_scope(patterns) + |> case do + {:ok, zipper} -> + {:ok, zipper} + + :error -> + zipper + |> Igniter.Code.Common.add_code(""" + if config_env() == #{inspect(env)} do + end + """) + |> Igniter.Code.Common.move_to_cursor_match_in_scope(patterns) + end + else + {:ok, zipper} + end + |> case do + {:ok, zipper} -> + items + |> Enum.map(fn {key, value} -> + { + key, + case value do + {:code, code} -> + code + + other -> + other + |> Macro.escape() + |> Sourceror.to_string() + |> Sourceror.parse_string!() + end + } + end) + |> Enum.reduce_while( + {:ok, zipper}, + fn {key, value}, {:ok, zipper} -> + Igniter.Project.Config.modify_config_code( + zipper, + [key], + application, + value, + updater: &{:ok, &1} + ) + |> case do + {:ok, _} = ok_result -> {:cont, ok_result} + other_result -> {:halt, other_result} + end + end + ) + + :error -> + {:error, "Could not modify #{@runtime_file_path}"} + end + end + end + ) + end + + defp env_config_patterns(env) do + [ + """ + if config_env() == #{inspect(env)} do + __cursor__() + end + """, + """ + if #{inspect(env)} == config_env() do + __cursor__() + end + """ + ] end end end diff --git a/test/tower/igniter_test.exs b/test/tower/igniter_test.exs index 9863fdd..72446ee 100644 --- a/test/tower/igniter_test.exs +++ b/test/tower/igniter_test.exs @@ -92,6 +92,21 @@ defmodule TowerIgniterTest do ) end + test "from scratch with env" do + test_project() + |> Tower.Igniter.runtime_configure_reporter(:reporter, [api_key: "123"], env: :prod) + |> assert_creates( + "config/runtime.exs", + """ + import Config + + if config_env() == :prod do + config :reporter, api_key: "123" + end + """ + ) + end + test "appends to existing runtime config" do test_project( files: %{ @@ -100,46 +115,85 @@ defmodule TowerIgniterTest do """ } ) - |> Tower.Igniter.runtime_configure_reporter(:reporter, api_key: "123") + |> Tower.Igniter.runtime_configure_reporter(:reporter, [api_key: "123"], env: :prod) |> assert_has_patch( "config/runtime.exs", """ |import Config + | + + |if config_env() == :prod do + + | config :reporter, api_key: "123" + + |end + + | + """ + ) + end + + test "writes inside existing prod block if present" do + test_project( + files: %{ + "config/runtime.exs" => """ + import Config + + if config_env() == :prod do + IO.puts("hello") + end + """ + } + ) + |> Tower.Igniter.runtime_configure_reporter(:reporter, [api_key: "123"], env: :prod) + |> assert_has_patch( + "config/runtime.exs", + """ + |if config_env() == :prod do + | IO.puts("hello") + |config :reporter, api_key: "123" + |end + | """ ) end - test "does not append same config again" do + test "does not append same config again in existing env block" do test_project( files: %{ "config/runtime.exs" => """ import Config - config :reporter, api_key: "123" + if config_env() == :prod do + config :reporter, api_key: "123" + end """ } ) - |> Tower.Igniter.runtime_configure_reporter(:reporter, api_key: "123") + |> Tower.Igniter.runtime_configure_reporter(:reporter, [api_key: "123"], env: :prod) |> assert_unchanged() end - test "does not modify existing key value yet appends new key" do + test "does not modify existing key value yet appends new key in env block" do test_project( files: %{ "config/runtime.exs" => """ import Config - config :reporter, api_key: "123" + if config_env() == :prod do + config :reporter, api_key: "123" + end """ } ) - |> Tower.Igniter.runtime_configure_reporter(:reporter, api_key: "456", other_key: "789") + |> Tower.Igniter.runtime_configure_reporter( + :reporter, + [api_key: "456", other_key: "789"], + env: :prod + ) |> assert_has_patch( "config/runtime.exs", """ - - |config :reporter, api_key: "123" - + |config :reporter, api_key: "123", other_key: "789" + |if config_env() == :prod do + - | config :reporter, api_key: "123" + + | config :reporter, api_key: "123", other_key: "789" + |end """ ) end @@ -158,6 +212,20 @@ defmodule TowerIgniterTest do |> assert_unchanged() end + test "does not modify existing config in top level if configured for env" do + test_project( + files: %{ + "config/runtime.exs" => """ + import Config + + config :reporter, api_key: "123" + """ + } + ) + |> Tower.Igniter.runtime_configure_reporter(:reporter, [api_key: "123"], env: :prod) + |> assert_unchanged() + end + test "is idempotent" do test_project() |> Tower.Igniter.runtime_configure_reporter(:reporter, api_key: "123")