Wednesday, December 17, 2014

Travis and Inch - Continuous Integration and Documentation Coverage in Elixir

The why...

Sure, it may compile locally for me but after working with a friend to install my previous version and realizing that so much of what I do is dependent upon my local mnesia schema and all that jazz it became clear to be I needed an "External View" of what my project would look like as a fresh install every time.

The way you do that is with "Continuous Integration" - a build environment which automatically builds and tests on every push you do to your repository.

Documentation?  I hate writing it but I service which bugs me when I don't document something is useful for drilling good habits.

Travis and Inch

Travis, travis-ci.org provides free Continuous Integration services for Open Source projects.  So, to start with a completely blank slate I pulled down Phoenix v0.7.2 and built a brand spanky new project called "pastenix" and uploaded it to github at https://github.com/redvers/pastenix

To add Travis support I stole^H^H^H^H^Hcopied the .travis.yml file from the Phoenix framework directory, registered myself on travis-ci.org and waited for the test result...

BOOM

red@nukefromorbit:pastenix$ MIX_ENV=docs mix inch.report
** (Mix.Config.LoadError) could not load config config/docs.exs
    ** (Code.LoadError) could not load /Users/red/projects/elixir/pastenix/config/docs.exs
    (mix) lib/mix/config.ex:141: Mix.Config.read!/1
    (mix) lib/mix/config.ex:153: anonymous fn/2 in Mix.Config.read_wildcard!/2
    (elixir) lib/enum.ex:1261: Enum."-reduce/3-lists^foldl/2-0-"/3
    (stdlib) erl_eval.erl:657: :erl_eval.do_apply/6
    (stdlib) erl_eval.erl:441: :erl_eval.expr/5
    (elixir) lib/code.ex:140: Code.eval_string/3
So, what's going on here?

The default config/config.exs file in a new phoenix application allows you to modify various settings at compile-time depending on which "Mix Environment" you're running in.  For example, your DEV environment will do automatic code-loading when it detects changes in the source-code - not behavior you want reflected in production!

The simplest fix certainly is to remove the include directive at the end of the file like so:
#import_config "#{Mix.env}.exs"
The biggest issue with doing this is that you've now lost that valuable functionality.

You can't just create an empty docs.exs as the import_config does an eval and it can't eval nil:

red@nukefromorbit:pastenix$ MIX_ENV=docs mix inch.report
** (Mix.Config.LoadError) could not load config config/docs.exs
    ** (ArgumentError) expected config file to return keyword list, got: nil
    (mix) lib/mix/config.ex:141: Mix.Config.read!/1
    (mix) lib/mix/config.ex:153: anonymous fn/2 in Mix.Config.read_wildcard!/2
    (elixir) lib/enum.ex:1261: Enum."-reduce/3-lists^foldl/2-0-"/3
    (stdlib) erl_eval.erl:657: :erl_eval.do_apply/6
    (stdlib) erl_eval.erl:441: :erl_eval.expr/5
    (elixir) lib/code.ex:140: Code.eval_string/3
The way that I chose to solve it was to copy the dev.exs file to docs.exs.  As this is only for the documentation build one can argue that there's no useable settings to be overridden.  If anyone has a suggestion for a cleaner solution, please comment below.

Lastly, you want to add:
{:ex_doc, "~> 0.6", only: :docs},  {:inch_ex, "~> 0.2", only: :docs},
to your deps to make sure the code that does the actual documentation publication and coverage testing is included.

Pushing this change, results in a clean build!

Getting the Perty Buttons on your github page.

Github renders your README.md (markdown) file on the front-page of your project's github page so to add the two buttons to your page add them to the top of your README.md

For pastenix, they looked like this:
[![Build Status](https://api.travis-ci.org/redvers/pastenix.svg)](https://travis-ci.org/redvers/pastenix)
[![Inline docs](http://inch-ci.org/github/redvers/pastenix.svg)](http://inch-ci.org/github/redvers/pastenix)

1 comment:

  1. For what it's worth, you can just wrap that in an if.

    if Mix.env != :docs do
    import_config "#{Mix.env}.exs"
    end

    Or wrap it in a try/rescue.

    ReplyDelete