Skip to content

Commit b697114

Browse files
author
Jason S
authored
Create a process that runs migrations and then shuts down (#482)
1 parent 6dd7df5 commit b697114

File tree

2 files changed

+77
-0
lines changed

2 files changed

+77
-0
lines changed

lib/ecto/migrator.ex

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,21 @@ defmodule Ecto.Migrator do
7777
$ bin/my_app eval "MyApp.Release.migrate"
7878
$ bin/my_app eval "MyApp.Release.rollback(MyApp.Repo, 20190417140000)"
7979
80+
## Example: Running migrations on application startup
81+
82+
Add the following to the top of your application children spec:
83+
84+
{Ecto.Migrator,
85+
repos: Application.fetch_env!(:my_app, :ecto_repos),
86+
skip: System.get_env("SKIP_MIGRATIONS") == "true"}
87+
88+
To skip migrations you can also pass `skip: true` or as in the example
89+
set the environment variable `SKIP_MIGRATIONS` to a truthy value.
90+
91+
To roll back you'd do it normally:
92+
93+
$ mix ecto.rollback
94+
8095
"""
8196

8297
require Logger
@@ -451,6 +466,38 @@ defmodule Ecto.Migrator do
451466
|> collect_migrations(directories)
452467
|> Enum.sort_by(fn {_, version, _} -> version end)
453468
end
469+
470+
use GenServer
471+
472+
@doc """
473+
Runs migrations as part of your supervision tree.
474+
475+
## Options
476+
477+
* `:repos` - Required option to tell the migrator which Repo's to
478+
migrate. Example: `repos: [MyApp.Repo]`
479+
* `:skip` - Option to skip migrations.
480+
Defaults to `false`.
481+
"""
482+
def start_link(opts) do
483+
GenServer.start_link(__MODULE__, opts, name: __MODULE__)
484+
end
485+
486+
@impl true
487+
def init(opts) do
488+
repos = Keyword.fetch!(opts, :repos)
489+
490+
skip? = Keyword.get(opts, :skip, false)
491+
migrator = Keyword.get(opts, :migrator, &Ecto.Migrator.run/3)
492+
493+
unless skip? do
494+
for repo <- repos do
495+
{:ok, _, _} = with_repo(repo, &migrator.(&1, :up, all: true))
496+
end
497+
end
498+
499+
:ignore
500+
end
454501

455502
defp collect_migrations(versions, migration_source) do
456503
ups_with_file =

test/ecto/migrator_test.exs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -861,5 +861,35 @@ defmodule Ecto.MigratorTest do
861861
end
862862
end
863863

864+
describe "gen_server" do
865+
test "runs the migrator with repos config" do
866+
migrator = fn repo, _, _ ->
867+
assert TestRepo == repo
868+
[]
869+
end
870+
871+
assert {:ok, :undefined} = start_supervised({Ecto.Migrator, [repos: [TestRepo], migrator: migrator]})
872+
end
873+
874+
test "skip is set" do
875+
migrator = fn repo, _, _ ->
876+
refute TestRepo == repo
877+
[]
878+
end
879+
880+
assert {:ok, :undefined} = start_supervised({Ecto.Migrator, [repos: [TestRepo], migrator: migrator, skip: true]})
881+
end
882+
883+
test "migrations fail" do
884+
migrator = fn repo, _, _ ->
885+
assert TestRepo == repo
886+
raise "boom"
887+
[]
888+
end
889+
890+
assert {:error, {{%RuntimeError{message: "boom"}, _}, _}} = start_supervised({Ecto.Migrator, [repos: [TestRepo], migrator: migrator]})
891+
end
892+
end
893+
864894
defp last_command(), do: Process.get(:last_command)
865895
end

0 commit comments

Comments
 (0)