mirror of
https://github.com/ash-project/igniter.git
synced 2024-09-20 05:22:52 +12:00
improvement: use warnings instead of errors for better UX
improvement: move proejct related things to `Project` namespace
This commit is contained in:
parent
310efa55b7
commit
46fc43a8cc
7 changed files with 165 additions and 47 deletions
|
@ -20,7 +20,7 @@ defmodule Mix.Tasks.YourLib.Gen.YourThing do
|
||||||
...some_code
|
...some_code
|
||||||
end
|
end
|
||||||
""")
|
""")
|
||||||
|> Igniter.Config.configure(
|
|> Igniter.Project.Config.configure(
|
||||||
"config.exs",
|
"config.exs",
|
||||||
app_name,
|
app_name,
|
||||||
[:list_of_things],
|
[:list_of_things],
|
||||||
|
|
|
@ -43,7 +43,7 @@ defmodule Igniter.Install do
|
||||||
|
|
||||||
{igniter, [install | install_list]}
|
{igniter, [install | install_list]}
|
||||||
else
|
else
|
||||||
{Igniter.Deps.add_dependency(igniter, install, requirement,
|
{Igniter.Project.Deps.add_dependency(igniter, install, requirement,
|
||||||
error?: true,
|
error?: true,
|
||||||
yes?: "--yes" in argv
|
yes?: "--yes" in argv
|
||||||
), [install | install_list]}
|
), [install | install_list]}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
defmodule Igniter.Application do
|
defmodule Igniter.Project.Application do
|
||||||
@moduledoc "Codemods and tools for working with Application modules."
|
@moduledoc "Codemods and tools for working with Application modules."
|
||||||
|
|
||||||
require Igniter.Code.Common
|
require Igniter.Code.Common
|
||||||
|
@ -83,11 +83,14 @@ defmodule Igniter.Application do
|
||||||
zipper
|
zipper
|
||||||
|> Zipper.down()
|
|> Zipper.down()
|
||||||
|> Zipper.rightmost()
|
|> Zipper.rightmost()
|
||||||
|> Igniter.Code.List.append_new_to_list(to_supervise, diff_checker)
|
|> Igniter.Code.List.append_new_to_list(Macro.escape(to_supervise), diff_checker)
|
||||||
else
|
else
|
||||||
_ ->
|
_ ->
|
||||||
{:error,
|
{:warning,
|
||||||
"Expected `#{path}` to be an Application with a `start` function that has a `children = [...]` assignment"}
|
"""
|
||||||
|
Could not find a `children = [...]` assignment in the `start` function of the `#{application}` module.
|
||||||
|
Please ensure that #{inspect(to_supervise)} is added started by the application `#{application}` manually.
|
||||||
|
"""}
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
@ -137,7 +140,19 @@ defmodule Igniter.Application do
|
||||||
end
|
end
|
||||||
|
|
||||||
_ ->
|
_ ->
|
||||||
{:error, "Required a module using `Mix.Project` to exist in `mix.exs`"}
|
{:warning,
|
||||||
|
"""
|
||||||
|
No module in `mix.exs` using `Mix.Project` was found. Please update your `mix.exs`
|
||||||
|
to point to the application module `#{inspect(application)}`.
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
def application do
|
||||||
|
[
|
||||||
|
mod: {#{inspect(application)}, []}
|
||||||
|
]
|
||||||
|
end
|
||||||
|
"""}
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
end
|
end
|
|
@ -1,26 +1,47 @@
|
||||||
defmodule Igniter.Config do
|
defmodule Igniter.Project.Config do
|
||||||
@moduledoc "Codemods and utilities for modifying Elixir config files."
|
@moduledoc "Codemods and utilities for modifying Elixir config files."
|
||||||
|
|
||||||
require Igniter.Code.Function
|
require Igniter.Code.Function
|
||||||
alias Igniter.Code.Common
|
alias Igniter.Code.Common
|
||||||
alias Sourceror.Zipper
|
alias Sourceror.Zipper
|
||||||
|
|
||||||
@doc "Sets a config value in the given configuration file, if it is not already set."
|
@doc """
|
||||||
@spec configure_new(Igniter.t(), Path.t(), atom(), list(atom), term()) :: Igniter.t()
|
Sets a config value in the given configuration file, if it is not already set.
|
||||||
def configure_new(igniter, file_path, app_name, config_path, value) do
|
|
||||||
configure(igniter, file_path, app_name, config_path, value, &{:ok, &1})
|
## Opts
|
||||||
|
|
||||||
|
* `failure_message` - A message to display to the user if the configuration change is unsuccessful.
|
||||||
|
"""
|
||||||
|
@spec configure_new(Igniter.t(), Path.t(), atom(), list(atom), term(), opts :: Keyword.t()) ::
|
||||||
|
Igniter.t()
|
||||||
|
def configure_new(igniter, file_path, app_name, config_path, value, opts \\ []) do
|
||||||
|
configure(
|
||||||
|
igniter,
|
||||||
|
file_path,
|
||||||
|
app_name,
|
||||||
|
config_path,
|
||||||
|
value,
|
||||||
|
Keyword.put(opts, :updater, &{:ok, &1})
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
@doc "Sets a config value in the given configuration file, updating it with `updater` if it is already set."
|
@doc """
|
||||||
|
Sets a config value in the given configuration file, updating it with `updater` if it is already set.
|
||||||
|
|
||||||
|
## Opts
|
||||||
|
|
||||||
|
* `:updater` - A function that takes a zipper at a currently configured value and returns a new zipper with the value updated.
|
||||||
|
* `failure_message` - A message to display to the user if the configuration change is unsuccessful.
|
||||||
|
"""
|
||||||
@spec configure(
|
@spec configure(
|
||||||
Igniter.t(),
|
Igniter.t(),
|
||||||
Path.t(),
|
Path.t(),
|
||||||
atom(),
|
atom(),
|
||||||
list(atom),
|
list(atom),
|
||||||
term(),
|
term(),
|
||||||
(Zipper.t() -> {:ok, Zipper.t()} | :error) | nil
|
opts :: Keyword.t()
|
||||||
) :: Igniter.t()
|
) :: Igniter.t()
|
||||||
def configure(igniter, file_name, app_name, config_path, value, updater \\ nil) do
|
def configure(igniter, file_name, app_name, config_path, value, opts \\ []) do
|
||||||
file_contents = "import Config\n"
|
file_contents = "import Config\n"
|
||||||
|
|
||||||
file_path = Path.join("config", file_name)
|
file_path = Path.join("config", file_name)
|
||||||
|
@ -32,7 +53,7 @@ defmodule Igniter.Config do
|
||||||
value -> Macro.escape(value)
|
value -> Macro.escape(value)
|
||||||
end
|
end
|
||||||
|
|
||||||
updater = updater || fn zipper -> {:ok, Common.replace_code(zipper, value)} end
|
updater = opts[:updater] || fn zipper -> {:ok, Common.replace_code(zipper, value)} end
|
||||||
|
|
||||||
igniter
|
igniter
|
||||||
|> ensure_default_configs_exist(file_name)
|
|> ensure_default_configs_exist(file_name)
|
||||||
|
@ -49,7 +70,7 @@ defmodule Igniter.Config do
|
||||||
false
|
false
|
||||||
end) do
|
end) do
|
||||||
nil ->
|
nil ->
|
||||||
{:error, "No call to `import Config` found in configuration file"}
|
{:warning, bad_config_message(app_name, file_path, config_path, value, opts)}
|
||||||
|
|
||||||
zipper ->
|
zipper ->
|
||||||
modify_configuration_code(zipper, config_path, app_name, value, updater)
|
modify_configuration_code(zipper, config_path, app_name, value, updater)
|
||||||
|
@ -79,6 +100,44 @@ defmodule Igniter.Config do
|
||||||
""")
|
""")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp bad_config_message(app_name, file_path, config_path, value, opts) do
|
||||||
|
path =
|
||||||
|
config_path
|
||||||
|
|> keywordify(value)
|
||||||
|
|
||||||
|
code =
|
||||||
|
quote do
|
||||||
|
config unquote(app_name), unquote(path)
|
||||||
|
end
|
||||||
|
|
||||||
|
message =
|
||||||
|
if opts[:failure_message] do
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
#{opts[:failure_message]}
|
||||||
|
"""
|
||||||
|
else
|
||||||
|
""
|
||||||
|
end
|
||||||
|
|
||||||
|
or_update =
|
||||||
|
if opts[:updater] do
|
||||||
|
" or update"
|
||||||
|
else
|
||||||
|
""
|
||||||
|
end
|
||||||
|
|
||||||
|
"""
|
||||||
|
Please set#{or_update} the following config in #{file_path}:
|
||||||
|
|
||||||
|
#{Macro.to_string(code)}#{String.trim_trailing(message)}
|
||||||
|
"""
|
||||||
|
end
|
||||||
|
|
||||||
|
defp keywordify([], value), do: value
|
||||||
|
defp keywordify([key | rest], value), do: [{key, keywordify(rest, value)}]
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
Modifies elixir configuration code starting at the configured zipper.
|
Modifies elixir configuration code starting at the configured zipper.
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
defmodule Igniter.Deps do
|
defmodule Igniter.Project.Deps do
|
||||||
@moduledoc "Codemods and utilities for managing dependencies declared in mix.exs"
|
@moduledoc "Codemods and utilities for managing dependencies declared in mix.exs"
|
||||||
require Igniter.Code.Common
|
require Igniter.Code.Common
|
||||||
alias Igniter.Code.Common
|
alias Igniter.Code.Common
|
||||||
|
@ -100,7 +100,12 @@ defmodule Igniter.Deps do
|
||||||
Igniter.Code.List.remove_index(zipper, current_declaration_index)
|
Igniter.Code.List.remove_index(zipper, current_declaration_index)
|
||||||
else
|
else
|
||||||
_ ->
|
_ ->
|
||||||
{:error, "Failed to remove dependency #{inspect(name)}"}
|
{:warning,
|
||||||
|
"""
|
||||||
|
Failed to remove dependency #{inspect(name)} from `mix.exs`.
|
||||||
|
|
||||||
|
Please remove the old dependency manually.
|
||||||
|
"""}
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
end
|
end
|
|
@ -1,4 +1,4 @@
|
||||||
defmodule Igniter.Formatter do
|
defmodule Igniter.Project.Formatter do
|
||||||
@moduledoc "Codemods and utilities for interacting with `.formatter.exs` files"
|
@moduledoc "Codemods and utilities for interacting with `.formatter.exs` files"
|
||||||
alias Igniter.Code.Common
|
alias Igniter.Code.Common
|
||||||
alias Sourceror.Zipper
|
alias Sourceror.Zipper
|
||||||
|
@ -43,7 +43,14 @@ defmodule Igniter.Formatter do
|
||||||
zipper
|
zipper
|
||||||
|
|
||||||
:error ->
|
:error ->
|
||||||
zipper
|
{:warning,
|
||||||
|
"""
|
||||||
|
Could not import dependency #{inspect(dep)} into `.formatter.exs`.
|
||||||
|
|
||||||
|
Please add the import manually, i.e
|
||||||
|
|
||||||
|
import_deps: [#{inspect(dep)}]
|
||||||
|
"""}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
@ -87,7 +94,14 @@ defmodule Igniter.Formatter do
|
||||||
zipper
|
zipper
|
||||||
|
|
||||||
_ ->
|
_ ->
|
||||||
zipper
|
{:warning,
|
||||||
|
"""
|
||||||
|
Could not add formatter plugin #{inspect(plugin)} into `.formatter.exs`.
|
||||||
|
|
||||||
|
Please add the import manually, i.e
|
||||||
|
|
||||||
|
plugins: [#{inspect(plugin)}]
|
||||||
|
"""}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end)
|
end)
|
|
@ -1,4 +1,4 @@
|
||||||
defmodule Igniter.ConfigTest do
|
defmodule Igniter.Project.ConfigTest do
|
||||||
use ExUnit.Case
|
use ExUnit.Case
|
||||||
|
|
||||||
alias Rewrite.Source
|
alias Rewrite.Source
|
||||||
|
@ -6,7 +6,7 @@ defmodule Igniter.ConfigTest do
|
||||||
describe "configure/6" do
|
describe "configure/6" do
|
||||||
test "it creates the config file if it does not exist" do
|
test "it creates the config file if it does not exist" do
|
||||||
%{rewrite: rewrite} =
|
%{rewrite: rewrite} =
|
||||||
Igniter.Config.configure(Igniter.new(), "fake.exs", :fake, [:foo, :bar], "baz")
|
Igniter.Project.Config.configure(Igniter.new(), "fake.exs", :fake, [:foo, :bar], "baz")
|
||||||
|
|
||||||
config_file = Rewrite.source!(rewrite, "config/fake.exs")
|
config_file = Rewrite.source!(rewrite, "config/fake.exs")
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@ defmodule Igniter.ConfigTest do
|
||||||
|
|
||||||
config :fake, buz: [:blat]
|
config :fake, buz: [:blat]
|
||||||
""")
|
""")
|
||||||
|> Igniter.Config.configure("fake.exs", :fake, [:foo, :bar], "baz")
|
|> Igniter.Project.Config.configure("fake.exs", :fake, [:foo, :bar], "baz")
|
||||||
|
|
||||||
config_file = Rewrite.source!(rewrite, "config/fake.exs")
|
config_file = Rewrite.source!(rewrite, "config/fake.exs")
|
||||||
|
|
||||||
|
@ -41,18 +41,20 @@ defmodule Igniter.ConfigTest do
|
||||||
test "it merges the spark formatter plugins" do
|
test "it merges the spark formatter plugins" do
|
||||||
%{rewrite: rewrite} =
|
%{rewrite: rewrite} =
|
||||||
Igniter.new()
|
Igniter.new()
|
||||||
|> Igniter.Config.configure(
|
|> Igniter.Project.Config.configure(
|
||||||
"fake.exs",
|
"fake.exs",
|
||||||
:spark,
|
:spark,
|
||||||
[:formatter, :"Ash.Resource"],
|
[:formatter, :"Ash.Resource"],
|
||||||
[],
|
[],
|
||||||
fn x ->
|
updater: fn x ->
|
||||||
x
|
x
|
||||||
end
|
end
|
||||||
)
|
)
|
||||||
|> Igniter.Config.configure("fake.exs", :spark, [:formatter, :"Ash.Domain"], [], fn x ->
|
|> Igniter.Project.Config.configure("fake.exs", :spark, [:formatter, :"Ash.Domain"], [],
|
||||||
|
updater: fn x ->
|
||||||
x
|
x
|
||||||
end)
|
end
|
||||||
|
)
|
||||||
|
|
||||||
config_file = Rewrite.source!(rewrite, "config/fake.exs")
|
config_file = Rewrite.source!(rewrite, "config/fake.exs")
|
||||||
|
|
||||||
|
@ -70,7 +72,7 @@ defmodule Igniter.ConfigTest do
|
||||||
|
|
||||||
config :fake, buz: [:blat]
|
config :fake, buz: [:blat]
|
||||||
""")
|
""")
|
||||||
|> Igniter.Config.configure("fake.exs", :fake, [:foo], "baz")
|
|> Igniter.Project.Config.configure("fake.exs", :fake, [:foo], "baz")
|
||||||
|
|
||||||
config_file = Rewrite.source!(rewrite, "config/fake.exs")
|
config_file = Rewrite.source!(rewrite, "config/fake.exs")
|
||||||
|
|
||||||
|
@ -87,7 +89,7 @@ defmodule Igniter.ConfigTest do
|
||||||
|> Igniter.create_new_elixir_file("config/fake.exs", """
|
|> Igniter.create_new_elixir_file("config/fake.exs", """
|
||||||
import Config
|
import Config
|
||||||
""")
|
""")
|
||||||
|> Igniter.Config.configure("fake.exs", :fake, [Foo.Bar, :bar], "baz")
|
|> Igniter.Project.Config.configure("fake.exs", :fake, [Foo.Bar, :bar], "baz")
|
||||||
|
|
||||||
config_file = Rewrite.source!(rewrite, "config/fake.exs")
|
config_file = Rewrite.source!(rewrite, "config/fake.exs")
|
||||||
|
|
||||||
|
@ -103,8 +105,8 @@ defmodule Igniter.ConfigTest do
|
||||||
|> Igniter.create_new_elixir_file("config/fake.exs", """
|
|> Igniter.create_new_elixir_file("config/fake.exs", """
|
||||||
import Config
|
import Config
|
||||||
""")
|
""")
|
||||||
|> Igniter.Config.configure("fake.exs", :fake, [Foo.Bar, :bar], "baz")
|
|> Igniter.Project.Config.configure("fake.exs", :fake, [Foo.Bar, :bar], "baz")
|
||||||
|> Igniter.Config.configure("fake.exs", :fake, [Foo.Bar, :buz], "biz")
|
|> Igniter.Project.Config.configure("fake.exs", :fake, [Foo.Bar, :buz], "biz")
|
||||||
|
|
||||||
config_file = Rewrite.source!(rewrite, "config/fake.exs")
|
config_file = Rewrite.source!(rewrite, "config/fake.exs")
|
||||||
|
|
||||||
|
@ -122,7 +124,7 @@ defmodule Igniter.ConfigTest do
|
||||||
|
|
||||||
config :fake, :buz, [:blat]
|
config :fake, :buz, [:blat]
|
||||||
""")
|
""")
|
||||||
|> Igniter.Config.configure("fake.exs", :fake, [:foo, :bar], "baz")
|
|> Igniter.Project.Config.configure("fake.exs", :fake, [:foo, :bar], "baz")
|
||||||
|
|
||||||
config_file = Rewrite.source!(rewrite, "config/fake.exs")
|
config_file = Rewrite.source!(rewrite, "config/fake.exs")
|
||||||
|
|
||||||
|
@ -142,7 +144,7 @@ defmodule Igniter.ConfigTest do
|
||||||
|
|
||||||
config :fake, :buz, [:blat]
|
config :fake, :buz, [:blat]
|
||||||
""")
|
""")
|
||||||
|> Igniter.Config.configure("fake.exs", :fake, [:foo], "baz")
|
|> Igniter.Project.Config.configure("fake.exs", :fake, [:foo], "baz")
|
||||||
|
|
||||||
config_file = Rewrite.source!(rewrite, "config/fake.exs")
|
config_file = Rewrite.source!(rewrite, "config/fake.exs")
|
||||||
|
|
||||||
|
@ -162,9 +164,11 @@ defmodule Igniter.ConfigTest do
|
||||||
|
|
||||||
config :fake, :buz, [:blat]
|
config :fake, :buz, [:blat]
|
||||||
""")
|
""")
|
||||||
|> Igniter.Config.configure("fake.exs", :fake, [:buz], "baz", fn list ->
|
|> Igniter.Project.Config.configure("fake.exs", :fake, [:buz], "baz",
|
||||||
|
updater: fn list ->
|
||||||
Igniter.Code.List.prepend_new_to_list(list, "baz")
|
Igniter.Code.List.prepend_new_to_list(list, "baz")
|
||||||
end)
|
end
|
||||||
|
)
|
||||||
|
|
||||||
config_file = Rewrite.source!(rewrite, "config/fake.exs")
|
config_file = Rewrite.source!(rewrite, "config/fake.exs")
|
||||||
|
|
||||||
|
@ -183,7 +187,7 @@ defmodule Igniter.ConfigTest do
|
||||||
|
|
||||||
config :fake, :buz, [:blat]
|
config :fake, :buz, [:blat]
|
||||||
""")
|
""")
|
||||||
|> Igniter.Config.configure("fake.exs", :fake, [:buz], 12)
|
|> Igniter.Project.Config.configure("fake.exs", :fake, [:buz], 12)
|
||||||
|
|
||||||
config_file = Rewrite.source!(rewrite, "config/fake.exs")
|
config_file = Rewrite.source!(rewrite, "config/fake.exs")
|
||||||
|
|
||||||
|
@ -202,13 +206,15 @@ defmodule Igniter.ConfigTest do
|
||||||
|
|
||||||
config :fake, foo: %{"a" => ["a", "b"]}
|
config :fake, foo: %{"a" => ["a", "b"]}
|
||||||
""")
|
""")
|
||||||
|> Igniter.Config.configure("fake.exs", :fake, [:foo], %{"b" => ["c", "d"]}, fn zipper ->
|
|> Igniter.Project.Config.configure("fake.exs", :fake, [:foo], %{"b" => ["c", "d"]},
|
||||||
|
updater: fn zipper ->
|
||||||
Igniter.Code.Map.set_map_key(zipper, "b", ["c", "d"], fn zipper ->
|
Igniter.Code.Map.set_map_key(zipper, "b", ["c", "d"], fn zipper ->
|
||||||
with {:ok, zipper} <- Igniter.Code.List.prepend_new_to_list(zipper, "c") do
|
with {:ok, zipper} <- Igniter.Code.List.prepend_new_to_list(zipper, "c") do
|
||||||
Igniter.Code.List.prepend_new_to_list(zipper, "d")
|
Igniter.Code.List.prepend_new_to_list(zipper, "d")
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
end)
|
end
|
||||||
|
)
|
||||||
|
|
||||||
config_file = Rewrite.source!(rewrite, "config/fake.exs")
|
config_file = Rewrite.source!(rewrite, "config/fake.exs")
|
||||||
|
|
||||||
|
@ -218,5 +224,24 @@ defmodule Igniter.ConfigTest do
|
||||||
config :fake, foo: %{"a" => ["a", "b"], "b" => ["c", "d"]}
|
config :fake, foo: %{"a" => ["a", "b"], "b" => ["c", "d"]}
|
||||||
"""
|
"""
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "it presents users with instructions on how to update a malformed config" do
|
||||||
|
%{warnings: [warning]} =
|
||||||
|
Igniter.new()
|
||||||
|
|> Igniter.create_new_elixir_file("config/fake.exs", """
|
||||||
|
config :fake, foo: %{"a" => ["a", "b"]}
|
||||||
|
""")
|
||||||
|
|> Igniter.Project.Config.configure("fake.exs", :fake, [:foo], %{"b" => ["c", "d"]},
|
||||||
|
failure_message: "A failure message!"
|
||||||
|
)
|
||||||
|
|
||||||
|
assert warning == """
|
||||||
|
Please set the following config in config/fake.exs:
|
||||||
|
|
||||||
|
config :fake, foo: %{"b" => ["c", "d"]}
|
||||||
|
|
||||||
|
A failure message!
|
||||||
|
"""
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
Loading…
Reference in a new issue