diff --git a/CHANGELOG.md b/CHANGELOG.md index d9224f22..fa21388e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,9 @@ * Added `PowInvitation` to the `mix pow.extension.phoenix.gen.templates` and `mix pow.extension.phoenix.mailer.gen.templates` tasks * Fixed issue in umbrella projects where extensions wasn't found in environment configuration * Shell instructions will only be printed if the configuration is missing +* Now requires that `:ecto` or `:phoenix` are included in the dependency list for the app to run respective mix tasks * Deprecated `Mix.Pow.context_app/0` +* Deprecated `Mix.Pow.ensure_dep!/3` ## v1.0.3 (2019-03-09) diff --git a/lib/mix/pow.ex b/lib/mix/pow.ex index 46a09f49..e3cd81de 100644 --- a/lib/mix/pow.ex +++ b/lib/mix/pow.ex @@ -16,13 +16,13 @@ defmodule Mix.Pow do :ok end - @doc """ - Raises an exception if the application doesn't have the dependency. - """ + # TODO: Remove by 1.1.0 + @doc false + @deprecated "Use `ensure_ecto!` or `ensure_phoenix!` instead" @spec ensure_dep!(binary(), atom(), OptionParser.argv()) :: :ok | no_return def ensure_dep!(task, dep, _args) do fetch_deps() - |> dep_in_deps?(dep) + |> top_level_dep_in_deps?(dep) |> case do true -> :ok @@ -32,6 +32,27 @@ defmodule Mix.Pow do end end + @doc """ + Raises an exception if application doesn't have Ecto as dependency. + """ + @spec ensure_ecto!(binary(), OptionParser.argv()) :: :ok | no_return + def ensure_ecto!(task, _args) do + deps = fetch_deps() + + cond do + top_level_dep_in_deps?(deps, :ecto) -> :ok + top_level_dep_in_deps?(deps, :ecto_sql) -> :ok + true -> Mix.raise("mix #{task} can only be run inside an application directory that has :ecto or :ecto_sql as dependency") + end + end + + defp top_level_dep_in_deps?(deps, dep) do + Enum.any?(deps, fn + %Mix.Dep{app: ^dep, top_level: true} -> true + _any -> false + end) + end + # TODO: Remove by 1.1.0 and only support Elixir 1.7 defp fetch_deps do System.version() @@ -42,22 +63,16 @@ defmodule Mix.Pow do end end - defp dep_in_deps?(deps, dep) do - Enum.any?(deps, fn - %Mix.Dep{app: ^dep} -> true - _any -> false - end) - end - - @doc """ - Raises an exception if application doesn't have Ecto as dependency. - """ - def ensure_ecto!(task, args), do: ensure_dep!(task, :ecto, args) - @doc """ Raises an exception if application doesn't have Phoenix as dependency. """ - def ensure_phoenix!(task, args), do: ensure_dep!(task, :phoenix, args) + @spec ensure_phoenix!(binary(), OptionParser.argv()) :: :ok | no_return + def ensure_phoenix!(task, _args) do + case top_level_dep_in_deps?(fetch_deps(), :phoenix) do + true -> :ok + false -> Mix.raise("mix #{task} can only be run inside an application directory that has :phoenix as dependency") + end + end @doc """ Parses argument options into a map. diff --git a/lib/mix/tasks/pow.install.ex b/lib/mix/tasks/pow.install.ex index 37bcaa64..b9587f37 100644 --- a/lib/mix/tasks/pow.install.ex +++ b/lib/mix/tasks/pow.install.ex @@ -48,7 +48,14 @@ defmodule Mix.Tasks.Pow.Install do defp no_umbrella! do if Project.umbrella?() do - Mix.raise("mix #{@mix_task} can't be used in umbrella apps. Run mix pow.ecto.install in your ecto app directory, and optionally mix pow.phoenix.install in your phoenix app directory.") + Mix.raise( + """ + mix #{@mix_task} has to be used inside an application directory, but this is an umbrella project. + + Run mix pow.ecto.install inside your Ecto application directory to create schema module and migrations. + + Run mix pow.phoenix.install in your Phoenix application directory for configuration instructions. + """) end :ok diff --git a/test/mix/tasks/ecto/pow.ecto.install_test.exs b/test/mix/tasks/ecto/pow.ecto.install_test.exs index 0a5fd19e..137706ac 100644 --- a/test/mix/tasks/ecto/pow.ecto.install_test.exs +++ b/test/mix/tasks/ecto/pow.ecto.install_test.exs @@ -66,16 +66,36 @@ defmodule Mix.Tasks.Pow.Ecto.InstallTest do use Mix.Project def project do - [] + [ + deps: [ + {:ecto_job, ">= 0.0.0"} + ] + ] end end """) Mix.Project.in_project(:my_app, ".", fn _ -> - assert_raise Mix.Error, "mix pow.ecto.install can only be run inside an application directory that has :ecto as dependency", fn -> + Mix.Tasks.Deps.Get.run([]) + + # Insurance that we do test for top level ecto inclusion + assert Enum.any?(deps(), fn + %{app: :phoenix} -> true + _ -> false + end), "Ecto not loaded by dependency" + + assert_raise Mix.Error, "mix pow.ecto.install can only be run inside an application directory that has :ecto or :ecto_sql as dependency", fn -> Install.run([]) end end) end) end + + # TODO: Refactor to just use Elixir 1.7 or higher by Pow 1.1.0 + defp deps() do + case Kernel.function_exported?(Mix.Dep, :load_on_environment, 1) do + true -> apply(Mix.Dep, :load_on_environment, [[]]) + false -> apply(Mix.Dep, :loaded, [[]]) + end + end end diff --git a/test/mix/tasks/phoenix/pow.phoenix.install_test.exs b/test/mix/tasks/phoenix/pow.phoenix.install_test.exs index aeb4a6b0..fe32227c 100644 --- a/test/mix/tasks/phoenix/pow.phoenix.install_test.exs +++ b/test/mix/tasks/phoenix/pow.phoenix.install_test.exs @@ -73,19 +73,31 @@ defmodule Mix.Tasks.Pow.Phoenix.InstallTest do end) end - test "raises error in app with no phoenix dep" do + test "raises error in app with no top level phoenix dep" do File.cd!(@tmp_path, fn -> File.write!("mix.exs", """ defmodule MyApp.MixProject do use Mix.Project def project do - [] + [ + deps: [ + {:phoenix_live_reload, ">= 0.0.0"} + ] + ] end end """) Mix.Project.in_project(:my_app, ".", fn _ -> + Mix.Tasks.Deps.Get.run([]) + + # Insurance that we do test for top level phoenix inclusion + assert Enum.any?(deps(), fn + %{app: :phoenix} -> true + _ -> false + end), "Phoenix not loaded by dependency" + assert_raise Mix.Error, "mix pow.phoenix.install can only be run inside an application directory that has :phoenix as dependency", fn -> Install.run([]) end @@ -151,4 +163,12 @@ defmodule Mix.Tasks.Pow.Phoenix.InstallTest do end) end) end + + # TODO: Refactor to just use Elixir 1.7 or higher by Pow 1.1.0 + defp deps() do + case Kernel.function_exported?(Mix.Dep, :load_on_environment, 1) do + true -> apply(Mix.Dep, :load_on_environment, [[]]) + false -> apply(Mix.Dep, :loaded, [[]]) + end + end end diff --git a/test/mix/tasks/pow.install_test.exs b/test/mix/tasks/pow.install_test.exs index ffdfe9a3..876cc9cc 100644 --- a/test/mix/tasks/pow.install_test.exs +++ b/test/mix/tasks/pow.install_test.exs @@ -46,7 +46,7 @@ defmodule Mix.Tasks.Pow.InstallTest do """) Mix.Project.in_project(:umbrella, ".", fn _ -> - assert_raise Mix.Error, "mix pow.install can't be used in umbrella apps. Run mix pow.ecto.install in your ecto app directory, and optionally mix pow.phoenix.install in your phoenix app directory.", fn -> + assert_raise Mix.Error, ~r/mix pow.install has to be used inside an application directory/, fn -> Install.run([]) end end)