Posts tagged #mix

How to keep mix tasks private to your hex packages

A few days ago I created a mix task for one of my hex packages. This package was just a wrapper around the awesome shipit package. Now, this task is specific to my hex package and isn’t going to be used by apps which depend on my hex package. However, today I found my mix task happily listed in the host apps’ list of tasks. This is not a good thing :)

I initially tried changing the extension of the mix task to .exs but that didn’t help. The mix task was not even listed in my hex package now.

After a lot of digging I found two useful pieces of info which helped me get around this.

  1. Mix deps have an :env key which defaults to :prod. This means, when mix compiles a dependency, the value of Mix.env inside that dependency is set to :prod.

  2. Mix compiler has an :elixirc_paths flag which tells the compiler where to look for elixir source code.

Knowing this, all I had to do was:

  1. Move the mix tasks from ./lib/mix/tasks to ./mix/tasks so that it is not picked up by default.
  2. Change mix.exs by adding the following to the project, so that in the :dev env of the hex package our mix task is loaded/compiled.
# mix.exs
def project do
  [app: :honeybadger,
  # ...
   elixirc_paths: elixirc_paths(Mix.env),
  # ...

defp elixirc_paths(:dev), do: ["lib", "mix"]
defp elixirc_paths(_), do: ["lib"]

Now my hex specific mix tasks are loaded only when I am working on my hex package. And the users of my hex package don’t see my mix utility tasks.

Treat your elixir warnings as errors in your non dev environments

One of the bittersweet things about Go is its relentlessness with warnings. You cannot compile your Go code which has warnings in it. This is great for the long term health of the project. However, it is not so pleasant while writing the code. Elixir takes an opposite approach to this where even errors which should break your build are treated as warnings. One such instance are Behaviours. If you have a module which implements a behaviour and does not implement a non optional callback, all elixir does is emit a warning! It should really throw an error and stop the compilation. However, all hope is not lost! You can use an elixir compiler flag to treat warnings as errors. All you need to do is add the following to your mix.exs:

  def project do
    [app: :awesome_possum,
     # treat warnings as errors in non dev environments
     elixirc_options: [warnings_as_errors: Mix.env != :dev],

You can even hard code it to true and it will always treat warnings as errors. However, non dev is the sweet spot for me, as I may be testing incomplete code with warnings in dev.

You can also pass these options to via the cli like so:

# using elixirc
elixirc --warnings-as-errors awesome_possum.ex
# using mix
mix compile --warnings-as-errors