Sal's Blog

Deploying a Rails API app with Heroku Pipelines

Introduction

user

Sal Lara

Sal is a senior web developer specializing in dev/design workflows, frontend and devops. He also enjoys robotics, making music, and puppies. He doesn't have any free time, but he does have a wife and two babies who make him very happy.


Featured

DevOps

Deploying a Rails API app with Heroku Pipelines

Posted by Sal Lara on .

I recently started using Heroku’s pipelines on a Rails API project, and found that, unfortunately, it still doesn’t support post-deploy scripting. Since running migrations automatically is pretty important (especially in production), I wrapped Heroku CLI commands in a couple of handy Bash functions:

The project actually had multiple instances of the same app in production—basically, branded and configured for various organizations, but sharing the same codebase. This made it a particularly good candidate for Heroku’s pipelines.

In this example of a pipeline on Heroku, the pipeline has been linked to a GitHub repository, and there's one app in staging, and three apps in production.
Example Heroku Pipeline

In this example of a pipeline on Heroku, the pipeline has been linked to a GitHub repository, and there's one app in staging, and three apps in production.

The first caveat—and in my opinion the biggest—is actually obtaining the names of the apps, according to their environment. Luckily, the Heroku CLI will give you all the info for a pipeline in JSON format, and the fantastic jq JSON-querying utility takes care of the rest.

Here it is, wrapped in a Bash function:

function heroku_pipe_apps() {
  COUPLING_STAGE=$2

  if [[ -z $2 ]]; then
    heroku pipelines:info $1 --json | jq -r '.apps[].name'
  fi

  heroku pipelines:info $1 --json | jq -r ".apps[] | select(.coupling.stage==\"${COUPLING_STAGE}\") | .name"
}

Note the use of jq in this function. On a Mac, you can get it with Homebrew by doing brew install jq.

Finally, this function, given a pipeline name (e.g. pipelinedeploy myrails-api) will do the following:

  • Put all the pipeline’s production apps in maintenance mode
  • Promote the (first) staging app to production. In the case on multiple production apps (as was my case here), the staging app is promoted to all of them.
  • Run migrations for all of the production apps
  • Take all production apps in the pipeline out of maintenance mode
pipelinedeploy() {
  PIPELINE=$1

  # Put the production apps in maintenance mode
  heroku_pipe_apps $PIPELINE production | xargs -I% heroku maintenance:on -a %

  # Promote the first staging app to all production apps
  heroku_pipe_apps $PIPELINE staging | head -n1 | xargs -I% heroku pipelines:promote -a %

  # Run migrations for all production apps in the pipeline
  heroku_pipe_apps $PIPELINE production | xargs -I% heroku run rake db:migrate -a %

  # Take all prod apps out of maintenance mode
  heroku_pipe_apps $PIPELINE production | xargs -I% heroku maintenance:off -a %
}
user

Sal Lara

http://natchiketa.com

Sal is a senior web developer specializing in dev/design workflows, frontend and devops. He also enjoys robotics, making music, and puppies. He doesn't have any free time, but he does have a wife and two babies who make him very happy.