fireproofsocks

fireproofsocks

Migration file not found during Github action

I’m missing something and I hope someone can point it out to me. Long story short, the first migration in my app needs to slurp up a dump file, e.g. init.sql. It sets does stuff like SET statement_timeout = 0 and CREATE SCHEMA core etc. (There are some historical reasons why we are using this).

Two things made this tricky:

  1. The Ecto repo didn’t use the normal name.
  2. The app that controls the repo is sometimes used as a dependency.

But we figured this out. The trick was a migration file that could point to the init.sql file, both when the app was used as the primary app OR when it gets used as a dependency. It boiled down to this (comments left in for transparency):

defmodule MyApp.PGRepo.Migrations.InitDb do
  use Ecto.Migration

  require Logger

  @doc """
  This is a "Mixless" way of running a custom migration.

  This migration must be flexible enough so we can run it from inside `my_app`
  or inside some other app that uses `my_app` as a dependency. We rely on
  `Ecto.Migration.repo/0` to tell us which repo is triggering the migration, and
  we use `:code.priv_dir/1` to infer the environment.
  """
  def change do
    # This magically knows which Repo is running the migrations
    # (it is important that we do not hard-code `MyApp.Repo`)
    repo = Ecto.Migration.repo()

    # [`c:Ecto.Adapter.Structure.structure_load/2`](https://hexdocs.pm/ecto_sql/Ecto.Adapter.Structure.html#c:structure_load/2)
    # REQUIRES the configuration to be broken out with individual keys
    # for username, password, etc.
    x = repo.__adapter__().structure_load(repo_path(), config(repo))
    Logger.debug(inspect(x))
  end

  # This migration must be flexible enough so we can run it from inside this app
  # or inside some other app that uses this as a dependency.
  defp repo_path do
    "#{:code.priv_dir(:my_app)}/pg_repo"
  end

  # This fetches the repo config and overrides the `:dump_path` to point to
  # the sql dump used to define the initial structure of the database.
  #
  # Do NOT use `Application.get_env(:my_app, Ecto.Migration.repo())`
  # because it will NOT parse out individual settings from a db URL!
  # Instead, use the [`c:Ecto.Repo.config/0`](https://hexdocs.pm/ecto/3.5.2/Ecto.Repo.html#c:config/0)
  # because this DOES parse out a db URL into its component parts (`:username`, `:password`, etc.).
  defp config(repo) do
    repo.config()
    |> Keyword.put(:dump_path, "#{repo_path()}/migrations/init.sql")
  end
end

The migrations get executed when we run tests on a PR on Github via Github actions. The github workflow is pretty straightforward, it contains (in part):

      - name: Compile
        run: mix compile

      - name: Create PostGres database
        run: mix ecto.create

      - name: Migrate PostGres database
        run: mix ecto.migrate

This has all been working fine.

Until… I copied this structure over to a new repo. And suddenly the init.sql file is not found when the Github workflow executes on the new repo. I added an inspection to the problematic line:

    x = repo.__adapter__().structure_load(repo_path(), config(repo))
    Logger.debug(inspect(x))

When I run tests etc. locally, it works fine. On Github, however, I get an error because the external file is not found:

_build/test/lib/my_app/priv/pg_repo/migrations/init.sql NOT FOUND

I’m not seeing anything between the 2 repos that would explain why the old app finds its init.sql file but the new app does not. Does anyone have any ideas of why the .sql file isn’t being found when the tests run externally in Github?

And, just to be thorough, I tried rewriting this first migration WITHOUT this weird .sql file, with something like this:

def change do
  # ...
  execute("CREATE SCHEMA core")
end

But this fails with a different error:

** (Postgrex.Error) ERROR 42P01 (undefined_table) relation "schema_migrations" does not exist

These are 2 different errors… I need to solve one of them to make migrations work (I don’t really care which one shakes out).

Thanks for any ideas!

Marked As Solved

christhekeele

christhekeele

Does your release configuration copy all /priv/migrations over? Or maybe just .exs one?

Also Liked

fireproofsocks

fireproofsocks

Ah, this was the reality check I needed. I had created a global gitignore file that for some reason was ignoring .sql files, so that thing never made it up to Github. As soon as I committed that, things worked as expected.

The problem was between the keyboard and the chair.

Where Next?

Popular in Questions Top

pmjoe
I have a relationship of love and hate with Elixir. Lots of things are just absolutely right, but there are some things that are kind of ...
New
ycv005
I have followed this StackOverflow post to install the specific version of Erlang. And When I am running mix ecto.setup then getting fol...
New
aadeshere1
I have a another noob question about loop. Since elixir is immutable, while loop is not directly possible. total = 10 while total != 0 ...
New
Fl4m3Ph03n1x
Background Let’s assume I have a typical GenServer that receives messages as requests, does some operation in a DB and returns responses....
New
fayddelight
I tried installing elixir 1.11.2 erlang 23.3.4 via asdf in my zsh shell. Enabled the versions locally and globally. When I list them ...
New
ovidiubadita
Hey all, I discovered Elixir and I love it. I always wanted to learn a functional programming and I intended to go for Haskell, but afte...
New
electic
Hi, I am new to Elixir. I am trying to use the DateTime component to insert a date into MySQL however the there seems to be no way to fo...
New
Exadra37
Sometimes I want to check if the input into a function is not a blank string. My first approach: defmodule Example do def do_stuff(s...
New
Qqwy
Original source of discussion: This topic on the Pragmatic Programmers' Functional Web Development with Elixir, OTP, and Phoenix forum. ...
New
idi527
I’ve been re-reading swift book again and noticed that multiline strings there don’t have a trailing line break, unlike in elixir iex(2)...
New

Other popular topics Top

JDanielMartinez
Hi! May someone helps me, please! I have two apps into an umbrella project: the first one is Database, which manages queries, and the se...
New
sorentwo
Hello! tl;dr Announcing Oban, an Ecto based job processing library with a focus on reliability and historical observability. After spen...
977 41022 311
New
Tee
can someone please explain to me how Enum.reduce works with maps
New
New
Jim
As a follow up to my earlier question: I have the code compiling and running but not getting a successful login from the rest server. ...
New
aadeshere1
I have a another noob question about loop. Since elixir is immutable, while loop is not directly possible. total = 10 while total != 0 ...
New
rms.mrcs
Hi, I need to transform a list of numbers into a map where the keys are the indexes and the values are the original values of the list....
New
alice
Hey, Just curious what are the main benefits of Elixir compared to Clojure? When is Elixir more useful than Clojure and vice versa? Th...
New
fireproofsocks
Forgive me if this is obvious, but how does one delete a database record WITHOUT selecting it first? https://hexdocs.pm/ecto/Ecto.Repo.h...
New
Nvim
Elixir appears to be a superior language to Python. I don’t see any advantage of Python over Elixir. Are there any?
New

We're in Beta

About us Mission Statement