Elixir - Mix


Mix assumes that we are in the development environment unless we tell it otherwise with MIX_ENV= mix some_task.

common tasks

Phoenix tasks

mix.exs

  1. http://blog.plataformatec.com.br/2016/07/understanding-deps-and-applications-in-your-mixfile/

tips

(how to) run multiple tasks at once

$ mix do deps.get, compile

which is equivalent to:

$ mix deps.get && mix compile

(how to) set default environment for any task

  1. https://hexdocs.pm/mix/Mix.Task.html#preferred_cli_env/1
  2. https://elixirforum.com/t/how-do-i-set-the-env-at-alias/16304

https://hexdocs.pm/mix/Mix.Task.html#module-attributes

@preferred_cli_env - recommends environment to run task. It is used in absence of a Mix project recommendation, or explicit MIX_ENV, and it only works for tasks in the current project.

# mix.exs

def project do
  [
    # ...
    preferred_cli_env: [
      deploy: :prod
    ]
  ]
end

troubleshooting

Mix doesn’t allow to run the same task twice in alias

Rake has the same behaviour - task must be reenabled explicitly before it can be run again.

thus it’s impossible to create alias in mix.exs for the list of tasks in which the same task is run multiple times with different arguments:

defp aliases do
  [
    # works
    "ecto.reset": ["ecto.drop", "ecto.setup"],
    # doesn't work (the 2nd task is not run)
    "deploy.prod": [
      "edeliver build release",
      "edeliver deploy release production"
    ]
  ]
end

alternating between 2 tasks doesn’t reenable the 1st task:

defp aliases do
  [
    "edeliver.all": [
      "edeliver build release",
      "deps.get",
      # edeliver task is not reenabled
      "edeliver deploy release production"
    ]
  ]
end

solution

  1. https://stackoverflow.com/questions/36846041
  2. https://hexdocs.pm/mix/Mix.Task.html#rerun/2
  3. https://hexdocs.pm/mix/Mix.html#module-aliases
  4. https://github.com/elixir-lang/elixir/blob/master/lib/mix/test/mix/task_test.exs#L138

it’s possible to pass function instead of a string with task name and task arguments - that function would need to use Mix.Task.rerun/2 to run the same task multiple times (it reenables the task before running it):

defp aliases do
  [
    "deploy.stage": [
      &deploy_stage/1,
      "cmd ssh devops@billing sudo systemctl restart billing_stage"
    ]
  ]
end

defp deploy_stage(_) do
  Mix.shell().info("[billing staging]")
  Mix.Task.run(:edeliver, ["update", "staging", "--mix-env=stage"])
  Mix.Task.rerun(:edeliver, ["migrate", "staging"])
end

for some reason it’s required to define function with arity of 1 - otherwise Mix complains:

(FunctionClauseError) no function clause matching in Mix.Task.run_alias/3