I talked about this at the Sydney Meteor meetup. The slides for the talk are available here.


I have been using an amazing tool called Meteor Up to deploy my app to a virtual server. But as the app grew, the deployment took longer and became more bandwidth-consuming.

That meant that I couldn’t deploy if I didn’t have a decent Internet connection. This is a problem because I usually work in places with not-so-fast Internet speed (cafe, library, etc.).

So I set up a continuous delivery with TravisCI. This way, I can simply push my code to the GitHub repository, and TravisCI will deploy it using Meteor Up as long as my tests pass.

In this article I would like to share how I set it up. You can find a demo app at GitHub with a step-by-step instruction. Also, I did a presentation on this topic at Meteor Sydney, and the slides can be viewed here.

I am using Mocha and Velocity to run my tests.

Build Meteor app with TravisCI

Before setting up a continuous delivery, we need to tell TravisCI to build our app. This is quite simply done by enabling the app on TravisCI, and adding .travis.yml to our repo.

.travis.yml

sudo: required
language: node_js
node_js:
- '0.12'
before_install:
- curl https://install.meteor.com/ | sh
services: mongodb
script:
- meteor --test --release velocity:[email protected]_3

In before_install, we are installing meteor. And in services, we are specifying mongodb as our test database. In script, we are specifying the script to run our test as per the instruction from Velocity.

You need to add console-reporter in you app because CIs use exit status of the test command to determine if the build passed.

This works, but what if you want to specify --settings option, perhaps with your settings.json?

You can encrypt settings.json with TravisCI, and add --settings option to the test script in .travis.yml. Do not check the raw settings.json into your source control! We will take a further look at this below.

Setup deployment on successful builds

We will tell TravisCI to deploy the app using Meteor Up. We do this in after_success in our .travis.yml (See build lifecycle in the official doc for more info about what after_success means).

But we have a problem: Meteor Up needs to use mup.json, settings.json, and perhaps our pem file for server authentication.

We want to encrypt them rather than committing them. But doing so is not simple because encrypting only works with one file.

In the offical doc, TravisCI suggests an alternative way of encrypting multiple files. Let us try that way.

We can compress our files into a .tar file, and encrypt that file. When the build runs, we will need to decrypt, and decompress the file to get mup.json, settings.json, and pem file back.

Let’s compress those files into secrets.tar:

tar cvf secrets.tar mup.json settings.json private_key

And ecrypt it:

travis encrypt-file secrets.tar --add

--add flag simply adds the decryption process to .travis.yml so you don’t have to do it manually.

The above command creates secrets.tar.enc. You need to commit this into your source control.

We need to tell TravisCI to decompress secrets.tar.enc once decrypted. Also, let’s install mup before the test runs.

Having done those, our before_install script in .travis.yml should look like this:

before_install:
- curl https://install.meteor.com/ | sh
- npm install -g mup # Add this line to install mup

- openssl ... in secrets.tar.enc -out secrets.tar -d
- tar xvf secrets.tar # Add this line to decompress secrets.tar

Now add after_success and run mup deploy.

after_success:
- mup deploy

We are done here. But an improvement can be made. Obviously, we would not want to deploy all branches. Let us customize branches for deployment.

Only deploy for certain branches

Typically, we want to deploy only certain branches to our production. We wouldn’t want to release the code in a feature branch into the wild.

While TravisCI lets you specify branch under deploy key in .travis.yml, it does not allow us to do that for after_success.

My solution is to use TRAVIS_BRANCH environment variable provided by TravisCI to see the current branch and conditionally execute mup deploy. Here is a simple script I wrote, also hosted on GitHub.

#!/bin/bash
echo "On branch '$TRAVIS_BRANCH'."

if [ "$TRAVIS_BRANCH" == "prod" ]; then
  echo "Triggering Mup deployment..."
  mup deploy
else
  echo "Not deploying. Use 'prod' branch to deploy."
fi

Make an executable .sh file in your app like the above, and simply execute it in after_success.

To use the above script, you can simply add the following to your .travis.yml and curl the script straight from GitHub:

after_success:
- curl -L http://git.io/vqbln | sh

Conclusion

There are some things to note:

  1. We are assuming our settings.json, mup.json, and the pem file are in our app root directory. Configure mup.json to use the correct path.

  2. Also, if any of those files change, you need to make a new secret.tar, encrypt it to overwrite the old secret.tar.enc.

Now you can just push to a particular branch to deploy your app, rather than running mup deploy locally and waiting for the result.

As mentioned, you can find the demo app with instructions on GitHub. Have fun!