Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
91 changes: 76 additions & 15 deletions lib/mix/tasks/phx/install/dashboard.ex
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ defmodule Mix.Tasks.Phx.Install.Dashboard do
%Igniter.Mix.Task.Info{
group: :phoenix,
example: "mix phx.install.dashboard",
adds_deps: [{:phoenix_live_dashboard, "~> 0.8"}]
adds_deps: [{:phoenix_live_dashboard, "~> 0.8"}],
composes: ["phx.install.endpoint", "phx.install.live"]
}
end

Expand All @@ -43,18 +44,23 @@ defmodule Mix.Tasks.Phx.Install.Dashboard do
igniter
|> Igniter.Project.Deps.add_dep({:phoenix, "~> 1.7"})
|> Igniter.Project.Deps.add_dep({:phoenix_live_dashboard, "~> 0.8"})
|> Igniter.compose_task("phx.install.endpoint")
|> Igniter.compose_task("phx.install.live")
|> add_dashboard_route(app_name, router_module, telemetry_module)
end

defp add_dashboard_route(igniter, app_name, router_module, telemetry_module) do
dashboard_call =
~s|live_dashboard "/dashboard", metrics: #{inspect(telemetry_module)}|

dev_routes_code = """
if Application.compile_env(#{inspect(app_name)}, :dev_routes) do
import Phoenix.LiveDashboard.Router

scope "/dev" do
pipe_through :browser

live_dashboard "/dashboard", metrics: #{inspect(telemetry_module)}
#{dashboard_call}
end
end
"""
Expand All @@ -66,33 +72,88 @@ defmodule Mix.Tasks.Phx.Install.Dashboard do
[1, 2],
&Igniter.Code.Function.argument_equals?(&1, 0, "/dashboard")
) do
{:ok, _} -> {:ok, zipper}
:error -> insert_dashboard_route(zipper, app_name, dev_routes_code)
{:ok, _} ->
{:ok, zipper}

:error ->
insert_dashboard_route(zipper, dashboard_call, dev_routes_code)
end
end)
end

defp insert_dashboard_route(zipper, app_name, dev_routes_code) do
case find_dev_routes_block(zipper, app_name) do
{:ok, _} ->
defp insert_dashboard_route(zipper, dashboard_call, dev_routes_code) do
case find_dev_routes_block(zipper) do
{:ok, dev_routes_zipper} ->
add_dashboard_to_existing_dev_scope(dev_routes_zipper, dashboard_call, dev_routes_code)

:error ->
{:ok, Igniter.Code.Common.add_code(zipper, dev_routes_code)}
end
end

defp add_dashboard_to_existing_dev_scope(dev_routes_zipper, dashboard_call, dev_routes_code) do
with {:ok, body_zipper} <- Igniter.Code.Common.move_to_do_block(dev_routes_zipper),
{:ok, scope_zipper} <-
Igniter.Code.Function.move_to_function_call_in_current_scope(
body_zipper,
:scope,
[1, 2],
&Igniter.Code.Function.argument_equals?(&1, 0, "/dev")
) do
import_code = "import Phoenix.LiveDashboard.Router"
with_import = Igniter.Code.Common.add_code(scope_zipper, import_code, placement: :before)

fresh_zipper =
with_import
|> Sourceror.Zipper.root()
|> Sourceror.Zipper.zip()

with {:ok, dev_routes2} <- find_dev_routes_block(fresh_zipper),
{:ok, body2} <- Igniter.Code.Common.move_to_do_block(dev_routes2),
{:ok, scope2} <-
Igniter.Code.Function.move_to_function_call_in_current_scope(
body2,
:scope,
[1, 2],
&Igniter.Code.Function.argument_equals?(&1, 0, "/dev")
),
{:ok, scope_body2} <- Igniter.Code.Common.move_to_do_block(scope2) do
{:ok, Igniter.Code.Common.add_code(scope_body2, dashboard_call)}
else
_ ->
{:warning,
Igniter.Util.Warning.formatted_warning(
"Found existing dev_routes block but couldn't add dashboard route. Please add manually:",
dev_routes_code
)}
end
else
_ ->
{:warning,
Igniter.Util.Warning.formatted_warning(
"Found existing dev_routes block but couldn't add dashboard. Please add manually:",
"Found existing dev_routes block but couldn't add dashboard route. Please add manually:",
dev_routes_code
)}

:error ->
{:ok, Igniter.Code.Common.add_code(zipper, dev_routes_code)}
end
end

defp find_dev_routes_block(zipper, app_name) do
defp find_dev_routes_block(zipper) do
Igniter.Code.Common.move_to(zipper, fn z ->
case Sourceror.Zipper.node(z) do
{:if, _, [{:compile_env, _, [_, ^app_name, :dev_routes | _]} | _]} -> true
{:if, _, [{:compile_env, _, [:erlang, :binary_to_atom, [^app_name | _], _]} | _]} -> true
_ -> false
{:if, _,
[
{{:., _, [{:__aliases__, _, [:Application]}, :compile_env]}, _, args}
| _
]} ->
args_contain_dev_routes?(args)

_ ->
false
end
end)
end

defp args_contain_dev_routes?([_, {:__block__, _, [:dev_routes]} | _]), do: true
defp args_contain_dev_routes?([_, :dev_routes | _]), do: true
defp args_contain_dev_routes?(_), do: false
end
4 changes: 3 additions & 1 deletion lib/mix/tasks/phx/install/router.ex
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ defmodule Mix.Tasks.Phx.Install.Router do
def info(_argv, _composing_task) do
%Igniter.Mix.Task.Info{
group: :phoenix,
example: "mix phx.install.router"
example: "mix phx.install.router",
composes: ["phx.install.core"]
}
end

Expand All @@ -33,6 +34,7 @@ defmodule Mix.Tasks.Phx.Install.Router do

igniter
|> Igniter.Project.Deps.add_dep({:phoenix, "~> 1.7"})
|> Igniter.compose_task("phx.install.core")
|> create_router(web_module)
|> create_error_json(web_module)
|> create_conn_case(web_module, endpoint_module)
Expand Down
52 changes: 52 additions & 0 deletions test/mix/tasks/phx/install/dashboard_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -113,5 +113,57 @@ defmodule Mix.Tasks.Phx.Install.DashboardTest do

assert result.issues == []
end

test "standalone invocation composes prerequisites and adds browser pipeline" do
igniter =
test_project()
|> Igniter.compose_task("phx.install.dashboard", ["--session-signing-salt", "sessionsalt"])
|> apply_igniter!()

source = Rewrite.source!(igniter.rewrite, "lib/test_web/router.ex")
content = Rewrite.Source.get(source, :content)

assert content =~ "pipeline :browser"
assert content =~ "pipe_through" and content =~ ":browser"
assert content =~ "live_dashboard"
end

test "adds live_dashboard into existing dev_routes block" do
dev_routes_block = """
if Application.compile_env(:test, :dev_routes) do
scope "/dev" do
pipe_through :browser
end
end
"""

igniter =
test_project()
|> Igniter.compose_task("phx.install.endpoint", ["--session-signing-salt", "sessionsalt"])
|> Igniter.compose_task("phx.install.router")
|> apply_igniter!()
|> Igniter.Project.Module.find_and_update_module!(
TestWeb.Router,
fn zipper ->
{:ok, Igniter.Code.Common.add_code(zipper, dev_routes_block)}
end
)
|> apply_igniter!()
|> Igniter.compose_task("phx.install.dashboard")
|> apply_igniter!()

source = Rewrite.source!(igniter.rewrite, "lib/test_web/router.ex")
content = Rewrite.Source.get(source, :content)

assert content =~ "live_dashboard"
assert content =~ "import Phoenix.LiveDashboard.Router"

occurrences =
content
|> String.split("dev_routes")
|> length()

assert occurrences == 2, "expected exactly one dev_routes block, found #{occurrences - 1}"
end
end
end
6 changes: 3 additions & 3 deletions test/mix/tasks/phx/install/router_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ defmodule Mix.Tasks.Phx.Install.RouterTest do
test "creates error_json module" do
test_project()
|> Igniter.compose_task("phx.install.router")
|> assert_creates("lib/test_web/error_json.ex")
|> assert_creates("lib/test_web/controllers/error_json.ex")
end

test "error_json has correct structure" do
Expand All @@ -38,7 +38,7 @@ defmodule Mix.Tasks.Phx.Install.RouterTest do
|> Igniter.compose_task("phx.install.router")
|> apply_igniter!()

source = Rewrite.source!(igniter.rewrite, "lib/test_web/error_json.ex")
source = Rewrite.source!(igniter.rewrite, "lib/test_web/controllers/error_json.ex")
content = Rewrite.Source.get(source, :content)

assert content =~ "defmodule TestWeb.ErrorJSON"
Expand Down Expand Up @@ -77,7 +77,7 @@ defmodule Mix.Tasks.Phx.Install.RouterTest do
|> apply_igniter!()

assert igniter.rewrite.sources["lib/my_app_web/router.ex"]
assert igniter.rewrite.sources["lib/my_app_web/error_json.ex"]
assert igniter.rewrite.sources["lib/my_app_web/controllers/error_json.ex"]
assert igniter.rewrite.sources["lib/my_app_web/conn_case.ex"]

router_content =
Expand Down
Loading