niku

niku

Deployment an elixir project with using TravisCI

I have published an elixir project with using Travis CI.
I would like to share some tips & thoughts that I was getting through this experience. I will be happy if it helps you.

.travis.yml

Here is an .travis.yml in an elixir project. You have to set HEX_ENCRYPTED_KEY and HEX_PASSPHRASE to environment variables in TravisCI.

  • Every time I push a commit
    • Execute mix credo as linter
    • Execute mix dialyzer as statical type checker
    • Execute mix test
  • Every time I push a tag
    • First, same as pushing a commit. When it pass the checkings, it will deploy project to hex.pm and its document to hexdocs.pm
    • No write key and passphrase to logs in TravisCI
  • To build faster
language: elixir
sudo: false
otp_release:
  - 19.3
elixir:
  - 1.4.2
env:
  global:
    - HEX_USERNAME=niku
    # Follow other language's environment
    # e.g.) `RACK_ENV=test` has been setted as Default Environment Variables
    # https://docs.travis-ci.com/user/environment-variables/#Default-Environment-Variables
    - MIX_ENV=test
cache:
  directories:
    - _build
    - deps
script:
  - mix credo --strict
  # https://github.com/jeremyjh/dialyxir#command-line-options
  # > exit immediately with same exit status as dialyzer. useful for CI
  - mix dialyzer --halt-exit-status
  - mix test
deploy:
   # https://docs.travis-ci.com/user/deployment/script/
   # > `script` must be a scalar pointing to an executable file or command.
   provider: script
   # http://yaml.org/spec/1.2/spec.html#id2779048
   # `>-` indicates the line folding.
   script: >-
     mix deps.get &&
     mix hex.config username "$HEX_USERNAME" &&
     (mix hex.config encrypted_key "$HEX_ENCRYPTED_KEY" > /dev/null 2>&1) &&
     (echo "$HEX_PASSPHRASE"\\nY | mix hex.publish) &&
     mix clean &&
     mix deps.clean --all
   on:
    tags: true

tips & thoughts

A package with a specific version in hex.pm could not be updated except for one hour since its creation. I didn’t realize it.

A ruby project on TravisCI, RAILS_ENV=test and RACK_ENV=test are available to all builds. To get a similar behavior at an elixir project on TravisCI, you should set MIX_ENV=test to the global environment variable.

You can write only a scalar variable a deploy - script section. You have to use multiline syntax for yaml if you want to write scripts which have multiple inline lines. When you use >, it doesn’t work well because it includes the last line feed ( \n ). Instead, you have to use >- to write it which doesn’t include the last line feed ( \n ).
Related YAML spec:
8.1.1.2. Block Chomping Indicator,
8.1.3. Folded Style

For security reasons, you mustn’t write any encrypted_key to the CI log which anyone can read. Hoyouver mix hex.config key value writes its value to STDOUT. So, I have redirected the result of the command to /dev/null.

mix hex.publish requires both an input passphrase and to confirm Code of Conduct. It means you need key input twice. First, It needs the input passphrase. Second, It needs to type Y. So I have to have handled them with STDIN like this: echo "$HEX_PASSPHRASE"\\nY | mix hex.publish.

You need execution mix clean && mix deps.clean --all because of TravisCI executes git stash after a script evaluates. You will get an error like: Could not restore untracked files from stash if you don’t clean up.

Most Liked

bitwalker

bitwalker

Leader

Nice work! I’m tempted to try this out on my projects, though I’m hesitant to have things auto published - that said, I’ve probably made more mistakes during publishing by hand than I would if I got this set up right. Have you considered modifying this to maybe only do this on a tag? Have you looked into GitHub releases at all? It’d be cool to automatically create a release from a tag and set the description to be some subset of a CHANGELOG file showing what was modified.

Thanks for sharing!

spencerdcarlson

spencerdcarlson

This post was very helpful, but I noticed a few things that can be updated.

Accounting for these changes, and using the git clean -f command to address the git stash issue my deploy section ended up being a lot smaller:

deploy:
  provider: script
  script: >-
    mix deps.get &&
    mix hex.publish --yes &&
    git clean -f
  on:
    tags: true

This approach requires that you generate an API key from hex and then set it as travis ci environment variable (HEX_API_KEY)

spencerdcarlson

spencerdcarlson

MacOS Tips

Officially travis does not support elixir for osx (docs):

Elixir builds are not available on the macOS environment.

I was able to use asdf to install elixir on macOS to build and test my hex package.

Here is the link to my .travis.yml if anyone wants to see an example or suggest improvements.

I ended up making all my asdf commands conditional, so I could cache asdf, erlang, and elixir.

If asdf was loaded from cache and I executed an asdf command (i.e. asdf update) it would cause a git log file to get updated (i.e ~/.asdf/.git/logs/<HEAD | FETCH | etc>) which would trigger a patch and re-upload of the cache on every build. Checking for cache before executing asdf commands resolved this issue.

There is probably a better way to do this. Maybe only cache the required asdf directories (~/.asdf/<installs && plugins && shims>), or clone asdf in a way that doesn’t cause any git tracking to function (clone bare?). idk, I didn’t explore those options very much.

Another issue I ran into, was if my .tool-versions file had my erlang version on the first line and my elixir version on the second line, then asdf install would only install erlang, but fail to install elixir. I have no idea why, but switching the order resolved this. I also added a travis_wait to the asdf_install to avoid timeouts on the erlang install.

A cache miss build will take ~11 min while a build that uses the cache takes about ~1 min

Here is and example of my environment variable setup for Hex regarding the above post

Where Next?

Popular in Guides/Tuts Top

hauks96
Hello everyone, I created a deployment tutorial for Phoenix applications with Kubernetes (microk8s) a few months back with the goal of s...
New
eclark
I’ve been working on a phoenix project lately and I wanted to use the latest versions of everything. Webpack 5 had some breaking changes ...
New
sergio
Wrote this guide on how to integrate DropzoneJS with Phoenix Liveview. Hope it helps someone out! https://sergiotapia.com/dropzonejs-dir...
New
wfgilman
I'm writing up this quick "How to" because what I thought was going to be an easy implementation of a Plug to validate a webhook request ...
New
Zurga
In a quest to optimize the amount of data sent between the server and client I recently decided to try to use MessagePack instead of JSON...
New
malloryerik
Hi, this is for people who, like me, have had some friction using .html.heex templates in VSCode. The solution seems to be, in a hyphena...
New
Jskalc
Sorry if it’s a common knowledge, but it’s something I just learned and wanted to share. I’ve seen that mind-blowing demo of hot-reload ...
New
alejandroErik
POST IN CONSTRUCTION Process for compile erlang otp 20 with odbc-unix for Oracle connections on Solaris 11.3 for 64 bits: Introductio...
New
bitli
In case this is handy for other people, here is how you can run Elixir on Android: Install https://termux.com/ apt update; apt upgrad...
New
AstonJ
With a few questions relating to this recently, I wonder if it might help having a thread where we share how we’ve set up Elixir/Erlang/P...
New

Other popular topics Top

peerreynders
Manning 2016 Halloween weekend sale via Deal of the Day Friday, October 28 - Half off all MEAPs - code WM102816LT Saturday, October 29 ...
326 29600 154
New
vrod
I am using the Starship cross-shell prompt – it seems pretty nice, but I get some errors: [WARN] - (starship::utils): Executing command ...
New
sergio
In Ruby, I can go: User.find_by(email: "foobar@email.com").update(email: "hello@email.com") How can I do something similar in Elixir? ...
New
vonH
In asking this question I am more interested about the expressiveness of the language itself and less concerned about the availability of...
New
joaquinalcerro
Hi there, I am working with Ecto-Postgresql and I need to call all of the records from a specific table but the table has 40,000 record...
New
quazar
How to set Jason to encode all fields in ecto schema, I don’t care about security and implementing only is taking long list of attributes...
New
sacepums
Hey guys. I'm new to elixir and im really stocked about it. But I ran into a bit of problem - I need to convert a date sting, for examp...
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
msaraiva
Surface is an experimental library built on top of Phoenix LiveView and its new LiveComponent API that aims to provide a more declarative...
564 42633 214
New
AstonJ
by Lance Halvorsen Elixir and Phoenix are generating tremendous excitement as an unbeatable platform for building modern web application...
460 27162 124
New

We're in Beta

About us Mission Statement