defmodule Mix.Tasks.Agentix.Gen.Migration do
@shortdoc "Copies Agentix's Ecto migration into your repo's migrations directory"
@moduledoc """
Copies the Agentix tables migration into your repo so the Ecto/Postgres persistence
adapter (`Agentix.Persistence.Ecto`) has its schema.
mix agentix.gen.migration
mix agentix.gen.migration priv/repo/migrations --repo MyApp.Repo
Writes a timestamped `*_create_agentix_tables.exs` under the given directory (default
`priv/repo/migrations`); then run `mix ecto.migrate`. The migration module is namespaced
under your repo — inferred from the host app name, or set explicitly with `--repo`. The
Ecto-backed suspension expiry additionally needs Oban's own migration (see Oban's docs).
"""
use Mix.Task
@template "priv/templates/migration/create_agentix_tables.exs"
@default_dir Path.join(~w(priv repo migrations))
@impl Mix.Task
def run(args) do
{opts, paths} = OptionParser.parse!(args, strict: [repo: :string])
dir = List.first(paths) || @default_dir
case Path.wildcard(Path.join(dir, "*_create_agentix_tables.exs")) do
[existing | _] ->
# The migration's module name is fixed, so a second copy (a re-run) would clash on
# compile and break `mix ecto.migrate`. Skip rather than write a conflicting file.
Mix.shell().info([:yellow, "* skipping ", :reset, "#{existing} already exists"])
existing
[] ->
contents =
:agentix
|> Application.app_dir(@template)
# Land the migration under the host's repo namespace, not Agentix's.
|> File.read!()
|> String.replace("Agentix.Repo.Migrations", "#{migrations_namespace(opts[:repo])}")
File.mkdir_p!(dir)
target = Path.join(dir, "#{timestamp()}_create_agentix_tables.exs")
File.write!(target, contents)
Mix.shell().info([:green, "* creating ", :reset, target])
target
end
end
# The host's migrations module namespace (e.g. `MyApp.Repo.Migrations`): from `--repo`,
# else inferred from the host app name.
defp migrations_namespace(nil) do
app = Mix.Project.config()[:app] || :my_app
"#{app |> to_string() |> Macro.camelize()}.Repo.Migrations"
end
defp migrations_namespace(repo), do: "#{repo}.Migrations"
# Ecto's migration timestamp format: UTC, second resolution, zero-padded.
defp timestamp, do: Calendar.strftime(DateTime.utc_now(), "%Y%m%d%H%M%S")
end