diff --git a/README.md b/README.md index 257f250..9fea7a7 100644 --- a/README.md +++ b/README.md @@ -67,7 +67,7 @@ your_plugin/ ```json { "name": "your_plugin", - "entry_module": "YourPlugin.Plugin", + "entry_module": "Tribes.Plugins.YourPlugin.Plugin", "host_api": "1", "otp_app": "your_plugin", "provides": ["some_capability@1"], @@ -76,6 +76,8 @@ your_plugin/ } ``` +- **entry_module** — must be `Tribes.Plugins.*.Plugin` +- **otp_app** — required and must match `name` - **provides** — capabilities this plugin makes available - **requires** — hard dependencies (build fails without them) - **enhances_with** — optional dependencies (plugin degrades gracefully) diff --git a/lib/tribes/plugins/my_plugin/plugin.ex b/lib/tribes/plugins/my_plugin/plugin.ex new file mode 100644 index 0000000..c2a6ee6 --- /dev/null +++ b/lib/tribes/plugins/my_plugin/plugin.ex @@ -0,0 +1,5 @@ +defmodule Tribes.Plugins.MyPlugin.Plugin do + @moduledoc false + + defdelegate register(context), to: MyPlugin.Plugin +end diff --git a/manifest.json b/manifest.json index 274851e..0d40f12 100644 --- a/manifest.json +++ b/manifest.json @@ -2,7 +2,7 @@ "name": "my_plugin", "version": "0.1.0", "description": "TODO: Describe what this plugin does", - "entry_module": "MyPlugin.Plugin", + "entry_module": "Tribes.Plugins.MyPlugin.Plugin", "host_api": "1", "otp_app": "my_plugin", "provides": [], diff --git a/test/contract_test.exs b/test/contract_test.exs index 1038b2a..22b476a 100644 --- a/test/contract_test.exs +++ b/test/contract_test.exs @@ -8,7 +8,7 @@ defmodule MyPlugin.ContractTest do defmodule MyPlugin.ContractTest do use Tribes.Plugin.ContractTest, - plugin: MyPlugin.Plugin, + plugin: Tribes.Plugins.MyPlugin.Plugin, otp_app: :my_plugin end @@ -17,7 +17,7 @@ defmodule MyPlugin.ContractTest do use ExUnit.Case, async: true - @plugin MyPlugin.Plugin + @plugin Tribes.Plugins.MyPlugin.Plugin @manifest_path Path.join(__DIR__, "../manifest.json") |> Path.expand() setup_all do diff --git a/test/my_plugin/manifest_test.exs b/test/my_plugin/manifest_test.exs index d789aad..93e8a60 100644 --- a/test/my_plugin/manifest_test.exs +++ b/test/my_plugin/manifest_test.exs @@ -15,7 +15,15 @@ defmodule MyPlugin.ManifestTest do end test "has required fields", %{manifest: manifest} do - required = ["name", "version", "entry_module", "host_api", "provides", "requires"] + required = [ + "name", + "version", + "entry_module", + "host_api", + "otp_app", + "provides", + "requires" + ] for field <- required do assert Map.has_key?(manifest, field), @@ -25,12 +33,17 @@ defmodule MyPlugin.ManifestTest do test "name matches OTP app name", %{manifest: manifest} do assert manifest["name"] == "my_plugin" + assert manifest["otp_app"] == manifest["name"] end - test "entry_module is a valid Elixir module name", %{manifest: manifest} do + test "entry_module uses Tribes.Plugins namespace and Plugin suffix", %{manifest: manifest} do module_name = manifest["entry_module"] assert is_binary(module_name) - assert String.starts_with?(module_name, "Elixir.") or not String.contains?(module_name, " ") + + assert Regex.match?( + ~r/^Tribes\.Plugins\.[A-Z][A-Za-z0-9_]*(\.[A-Z][A-Za-z0-9_]*)*\.Plugin$/, + module_name + ) end test "provides contains valid capability identifiers", %{manifest: manifest} do @@ -53,7 +66,9 @@ defmodule MyPlugin.ManifestTest do test "entry_module matches actual plugin module", %{manifest: manifest} do module = String.to_atom("Elixir.#{manifest["entry_module"]}") - assert Code.ensure_loaded?(module), "entry_module #{manifest["entry_module"]} must be loadable" + + assert Code.ensure_loaded?(module), + "entry_module #{manifest["entry_module"]} must be loadable" end end end