You've already forked tribes-plugin-new
1bced15358
Update plugin-new templates and install task to use the host-backed plugin test/precommit aliases. Keep framework dependencies under the host API foundation and add regression coverage for generated aliases.
254 lines
8.0 KiB
Elixir
254 lines
8.0 KiB
Elixir
if Code.ensure_loaded?(Igniter) and Code.ensure_loaded?(Igniter.Mix.Task) and
|
|
Code.ensure_loaded?(Igniter.Mix.Task.Info) do
|
|
defmodule Mix.Tasks.TribesPlugin.Install.Igniter do
|
|
@moduledoc """
|
|
Installs Tribes plugin files into the current Mix project.
|
|
|
|
This task is intended for converting a fresh `mix new` project or refreshing
|
|
missing generated files in an existing plugin project. Existing files are
|
|
preserved unless Igniter project patching is used for dependencies or aliases.
|
|
|
|
## Examples
|
|
|
|
mix tribes_plugin.install
|
|
mix tribes_plugin.install --config-demo
|
|
mix tribes_plugin.install --app billing_reports --module BillingReports
|
|
"""
|
|
|
|
use Igniter.Mix.Task
|
|
|
|
alias TribesPlugin.Naming
|
|
alias TribesPlugin.Options
|
|
alias TribesPlugin.Templates
|
|
|
|
alias Igniter.Code.Common
|
|
|
|
@shortdoc "Installs Tribes plugin files into the current Mix project"
|
|
|
|
@impl Igniter.Mix.Task
|
|
def info(_argv, _composing_task) do
|
|
%Igniter.Mix.Task.Info{
|
|
group: :tribes_plugin,
|
|
example: "mix tribes_plugin.install --config-demo",
|
|
positional: [],
|
|
schema: [
|
|
app: :string,
|
|
module: :string,
|
|
description: :string,
|
|
host_path: :string,
|
|
config_demo: :boolean,
|
|
no_live_view: :boolean,
|
|
no_assets: :boolean,
|
|
provides: :string,
|
|
requires: :string,
|
|
enhances_with: :string
|
|
],
|
|
aliases: [],
|
|
defaults: [
|
|
host_path: "../tribes",
|
|
config_demo: false,
|
|
no_live_view: false,
|
|
no_assets: false
|
|
]
|
|
}
|
|
end
|
|
|
|
@impl Igniter.Mix.Task
|
|
def igniter(igniter) do
|
|
opts = igniter.args.options
|
|
app = opts[:app] || current_app(igniter)
|
|
module = opts[:module] || current_module()
|
|
naming = Naming.resolve!(".", app: app, module: module)
|
|
|
|
generator_opts =
|
|
[
|
|
description: opts[:description],
|
|
repo_name: Path.basename(File.cwd!()),
|
|
host_path: opts[:host_path],
|
|
live_view?: !opts[:no_live_view],
|
|
assets?: !opts[:no_assets],
|
|
config_demo?: !!opts[:config_demo],
|
|
provides: Options.parse_capabilities(opts[:provides]),
|
|
requires: Options.parse_capabilities(opts[:requires]),
|
|
enhances_with: Options.parse_capabilities(opts[:enhances_with])
|
|
]
|
|
|> Enum.reject(fn {_key, value} -> is_nil(value) end)
|
|
|
|
igniter
|
|
|> create_missing_files(Templates.project_files(naming, generator_opts))
|
|
|> add_project_deps(opts[:host_path])
|
|
|> add_preferred_envs()
|
|
|> add_project_aliases()
|
|
|> add_alias_helpers()
|
|
end
|
|
|
|
defp create_missing_files(igniter, files) do
|
|
Enum.reduce(files, igniter, fn
|
|
{"mix.exs", _contents}, igniter ->
|
|
igniter
|
|
|
|
{path, contents}, igniter ->
|
|
Igniter.create_new_file(igniter, path, contents, on_exists: :skip)
|
|
end)
|
|
end
|
|
|
|
defp add_project_deps(igniter, host_path) do
|
|
host_path = host_path || "../tribes"
|
|
|
|
igniter
|
|
|> Igniter.Project.Deps.add_dep(
|
|
{:tribes_plugin_api, [path: "#{host_path}/tribes_plugin_api", runtime: false]},
|
|
on_exists: :skip
|
|
)
|
|
|> Igniter.Project.Deps.add_dep(
|
|
{:tribes_plugin, [path: "../tribes-plugin-new", only: [:dev, :test], runtime: false]},
|
|
on_exists: :skip
|
|
)
|
|
|> Igniter.Project.Deps.add_dep(
|
|
{:igniter, "~> 0.7", only: [:dev, :test], runtime: false},
|
|
on_exists: :skip
|
|
)
|
|
|> Igniter.Project.Deps.add_dep({:phoenix, "~> 1.8"}, on_exists: :skip)
|
|
|> Igniter.Project.Deps.add_dep({:phoenix_html, "~> 4.1"}, on_exists: :skip)
|
|
|> Igniter.Project.Deps.add_dep({:phoenix_live_view, "~> 1.1.0"}, on_exists: :skip)
|
|
|> Igniter.Project.Deps.add_dep(
|
|
{:credo, "~> 1.7", only: [:dev, :test], runtime: false},
|
|
on_exists: :skip
|
|
)
|
|
|> Igniter.Project.Deps.add_dep({:lazy_html, ">= 0.1.0", only: :test}, on_exists: :skip)
|
|
|> Igniter.Project.Deps.add_dep({:usage_rules, "~> 1.2", only: :dev}, on_exists: :skip)
|
|
end
|
|
|
|
defp add_preferred_envs(igniter) do
|
|
Enum.reduce([precommit: :test, raw_precommit: :test, raw_test: :test], igniter, fn
|
|
{task, env}, igniter ->
|
|
Igniter.Project.MixProject.update(igniter, :cli, [:preferred_envs, task], fn _ ->
|
|
{:ok, {:code, env}}
|
|
end)
|
|
end)
|
|
end
|
|
|
|
defp add_project_aliases(igniter) do
|
|
igniter
|
|
|> Igniter.Project.TaskAliases.add_alias(:test, {:code, quote(do: &plugin_test_message/1)})
|
|
|> replace_alias(:test, quote(do: &plugin_test_message/1))
|
|
|> Igniter.Project.TaskAliases.add_alias(:raw_test, {:code, quote(do: &raw_test/1)})
|
|
|> replace_alias(:raw_test, quote(do: &raw_test/1))
|
|
|> Igniter.Project.TaskAliases.add_alias(:lint, [
|
|
"format --check-formatted",
|
|
"credo"
|
|
])
|
|
|> Igniter.Project.TaskAliases.add_alias(
|
|
:precommit,
|
|
{:code, quote(do: &plugin_precommit_message/1)}
|
|
)
|
|
|> replace_alias(:precommit, quote(do: &plugin_precommit_message/1))
|
|
|> Igniter.Project.TaskAliases.add_alias(
|
|
:raw_precommit,
|
|
{:code, quote(do: &raw_precommit/1)}
|
|
)
|
|
|> replace_alias(:raw_precommit, quote(do: &raw_precommit/1))
|
|
end
|
|
|
|
defp replace_alias(igniter, name, quoted) do
|
|
Igniter.Project.TaskAliases.modify_existing_alias(igniter, name, fn zipper ->
|
|
{:ok, Common.replace_code(zipper, quoted)}
|
|
end)
|
|
end
|
|
|
|
defp add_alias_helpers(igniter) do
|
|
Igniter.update_file(igniter, "mix.exs", fn source ->
|
|
content = Rewrite.Source.get(source, :content)
|
|
|
|
if String.contains?(content, "defp plugin_test_message(") do
|
|
source
|
|
else
|
|
Rewrite.Source.update(source, :content, &insert_alias_helpers/1)
|
|
end
|
|
end)
|
|
end
|
|
|
|
defp insert_alias_helpers(content) do
|
|
helpers = """
|
|
|
|
defp plugin_test_message(_args) do
|
|
Mix.raise(\"\"\"
|
|
This plugin test suite is host-backed. Use `plugin test` or `scripts/plugin test`.
|
|
|
|
For low-level debugging only, set up the host environment yourself and run `mix raw_test`.
|
|
\"\"\")
|
|
end
|
|
|
|
defp plugin_precommit_message(_args) do
|
|
Mix.raise(\"\"\"
|
|
This plugin precommit is host-backed. Use `plugin precommit` or `scripts/plugin precommit`.
|
|
|
|
For low-level debugging only, set up the host environment yourself and run `mix raw_precommit`.
|
|
\"\"\")
|
|
end
|
|
|
|
defp raw_precommit(args) do
|
|
Mix.Task.run("format")
|
|
Mix.Task.run("compile", ["--warnings-as-errors"])
|
|
Mix.Task.run("credo", ["--strict", "--all"])
|
|
Mix.Task.run("deps.unlock", ["--unused"])
|
|
raw_test(args)
|
|
end
|
|
|
|
defp raw_test(args), do: Mix.Tasks.Test.run(args)
|
|
"""
|
|
|
|
String.replace_suffix(content, "\nend\n", helpers <> "\nend\n")
|
|
end
|
|
|
|
defp current_app(igniter) do
|
|
igniter
|
|
|> Igniter.Project.Application.app_name()
|
|
|> to_string()
|
|
end
|
|
|
|
defp current_module do
|
|
Mix.Project.get!()
|
|
|> Module.split()
|
|
|> Enum.drop(-1)
|
|
|> case do
|
|
[] -> nil
|
|
parts -> Module.concat(parts) |> inspect()
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
defmodule Mix.Tasks.TribesPlugin.Install do
|
|
@moduledoc """
|
|
Installs Tribes plugin files into the current Mix project.
|
|
"""
|
|
|
|
use Mix.Task
|
|
|
|
@shortdoc "Installs Tribes plugin files into the current Mix project"
|
|
|
|
@impl Mix.Task
|
|
def run(argv) do
|
|
Enum.each(
|
|
[TribesPlugin.Naming, TribesPlugin.Options, TribesPlugin.Templates],
|
|
&Code.ensure_loaded?/1
|
|
)
|
|
|
|
Mix.Task.run("deps.loadpaths", [])
|
|
|
|
if Code.ensure_loaded?(Mix.Tasks.TribesPlugin.Install.Igniter) and
|
|
Code.ensure_loaded?(Igniter.Mix.Task.Info) do
|
|
Mix.Tasks.TribesPlugin.Install.Igniter.run(argv)
|
|
else
|
|
Mix.shell().error("""
|
|
The task 'tribes_plugin.install' requires igniter. Please install igniter and try again.
|
|
|
|
For more information, see: https://hexdocs.pm/igniter/readme.html#installation
|
|
""")
|
|
|
|
exit({:shutdown, 1})
|
|
end
|
|
end
|
|
end
|