template: make rename portable and add explicit otp_app dev flow

This commit is contained in:
2026-04-04 19:45:32 +02:00
parent 647d5537ff
commit 54d9bdd99c
5 changed files with 70 additions and 23 deletions

View File

@@ -27,15 +27,19 @@ mix test
For local development alongside a Tribes checkout:
```bash
# Build plugin code once (host loads BEAM from _build/dev/lib/<otp_app>/ebin)
cd /path/to/your-plugin
mix compile
# Symlink into the host plugins directory
cd /path/to/tribes
ln -s /path/to/your-plugin plugins/your_plugin
# Start Tribes dev server — your plugin loads automatically
# Start Tribes dev server
iex --sname dev -S mix phx.server
```
Edit your plugin source. Phoenix code reloader picks up changes.
When you change plugin Elixir code, re-run `mix compile` in the plugin repo.
## Project Structure
@@ -63,6 +67,9 @@ your_plugin/
```json
{
"name": "your_plugin",
"entry_module": "YourPlugin.Plugin",
"host_api": "1",
"otp_app": "your_plugin",
"provides": ["some_capability@1"],
"requires": ["ecto@1"],
"enhances_with": ["inference@1"]

View File

@@ -58,24 +58,44 @@ defmodule MyPlugin.Plugin do
end
defp manifest_path do
# In a release, manifest.json sits alongside ebin/ in the plugin directory.
# In dev mode (path dep), it's at the project root.
project_manifest = Path.join(__DIR__, "../../manifest.json") |> Path.expand()
candidates =
case :code.priv_dir(:my_plugin) do
{:error, :bad_name} ->
# Dev mode fallback: relative to project root
Path.join(__DIR__, "../../../manifest.json") |> Path.expand()
[project_manifest]
priv_dir ->
priv_dir |> to_string() |> Path.join("../manifest.json") |> Path.expand()
priv_dir = to_string(priv_dir)
[
Path.join(priv_dir, "../manifest.json") |> Path.expand(),
project_manifest
]
end
first_existing_path(candidates) || project_manifest
end
defp migrations_path(manifest) do
if manifest["migrations"] do
candidates =
case :code.priv_dir(:my_plugin) do
{:error, :bad_name} -> nil
priv_dir -> priv_dir |> to_string() |> Path.join("repo/migrations")
{:error, :bad_name} ->
[Path.join(__DIR__, "../../priv/repo/migrations") |> Path.expand()]
priv_dir ->
[
Path.join(to_string(priv_dir), "repo/migrations") |> Path.expand(),
Path.join(__DIR__, "../../priv/repo/migrations") |> Path.expand()
]
end
first_existing_path(candidates)
end
end
defp first_existing_path(paths) do
Enum.find(paths, &File.exists?/1)
end
end

View File

@@ -4,6 +4,7 @@
"description": "TODO: Describe what this plugin does",
"entry_module": "MyPlugin.Plugin",
"host_api": "1",
"otp_app": "my_plugin",
"provides": [],
"requires": ["ecto@1"],
"enhances_with": [],

View File

@@ -29,7 +29,7 @@ defmodule MyPlugin.MixProject do
# Host dependency — provides Tribes.Plugin behaviour, types, and test helpers.
#
# For local development alongside a tribes checkout:
{:tribes, path: "../tribes", only: [:dev, :test]},
{:tribes, path: "../tribes", only: [:dev, :test], runtime: false},
#
# For CI or standalone development (when not co-located with tribes):
# {:tribes, github: "your-org/tribes", branch: "master", only: [:dev, :test]},

View File

@@ -45,13 +45,32 @@ if [ -d "test/my_plugin" ]; then
mv "test/my_plugin" "test/$SNAKE"
fi
# Replace in all text files
find . -type f \( -name '*.ex' -o -name '*.exs' -o -name '*.json' -o -name '*.js' -o -name '*.css' -o -name '*.md' -o -name '*.yml' -o -name '*.yaml' -o -name '.formatter.exs' \) -exec \
# Replace in all text files (portable across GNU/BSD sed)
sed_in_place() {
file=$1
if sed --version >/dev/null 2>&1; then
sed -i \
-e "s/my_plugin/$SNAKE/g" \
-e "s/MyPlugin/$MODULE/g" \
-e "s/my-plugin/$SNAKE/g" \
"$file"
else
sed -i '' \
-e "s/my_plugin/$SNAKE/g" \
-e "s/MyPlugin/$MODULE/g" \
-e "s/my-plugin/$SNAKE/g" \
{} +
"$file"
fi
}
while IFS= read -r -d '' file; do
sed_in_place "$file"
done < <(
find . -type f \
\( -name '*.ex' -o -name '*.exs' -o -name '*.json' -o -name '*.js' -o -name '*.css' -o -name '*.md' -o -name '*.yml' -o -name '*.yaml' -o -name '.formatter.exs' \) \
-print0
)
# Rename asset files
for ext in js css; do