Deploying to Heroku from TeamCity

Posted on by in Development

Previously I discussed our TeamCity configuration using RVM and mentioned that we often use git to deploy projects. Today I’ll share an example of how a TeamCity build agent can trigger deployments of a application hosted on Heroku and some of the challenges I found.

Add an ssh config entry for the project’s access to Heroku

Much like shared github access I need to be able to specify which ssh key a particular project’s connections to heroku should use. Since I want to use client side checkouts I can’t specify a private key within TeamCity but I do know that all my compatible build agents are local so I can add a new entry to `~/.ssh/config` and define a host which will allow me to connect to Heroku with a particular key.

# Heroku for #{new_project}
Host heroku-#{new_project}
User git
ForwardAgent yes
IdentityFile /home/teamcity/.ssh/teamcity_#{new_project}_rsa

Add a ssh key to the Heroku account
Now I need to add this new key to the Heroku account for this project by installing the heroku gem in my project’s gemset and using the `heroku` command line to add the key. Heroku stores the account credentials used in `~/.heroku` and the user account running my build agents might need to connect to many different heroku accounts. I could switch my heroku credentials, upload a key, and have different projects deploy using different accounts. However since I find it useful to be able to run the heroku command line (see below) I found it preferable to have a single `teamcity` heroku account added to every project as a collaborator.
If you find it necessary to switch between Heroku accounts frequently this tool from Aeonscope might be useful: managing multiple heroku accounts

Now I can add a key to the current project’s Heroku account.
heroku keys:add ~/.ssh/teamcity_#{new_project}_rsa

Deploying to Heroku
Now I can add a simple TeamCity build configuration which pushes code to Heroku once a particular revision passes the tests.

Command executable git
Command parameters push git@heroku-#{new_project}:#{new heroku project’s name}.git master

A project's deployment build configuration

Deploying and running database migrations
I don’t want my app trying to respond to requests while waiting for a database migration to finish so now it becomes necessary to put the app in maintenance mode before deploying and migrating.

Command executable sh
Command parameters -c heroku maintenance:on –app #{new_project} && sleep 60 && git push{new_project}.git master && heroku rake db:migrate –app #{new_project} && heroku maintenance:off –app #{new_project}

I found that I need to add a delay between turning on maintenance mode for the app and pushing to heroku. Attempting to push immediately fails with the error `Heroku push rejected, your slug is currently being compiled. Please try again later.` Even with a significant delay I still see this error occasionally and have to rerun the deploy build but at this point I don’t know of a way to make sure heroku can handle a new revision before attempting to push changes.

Now I can use TeamCity to automatically deploy changes to Heroku as soon as my project’s tests pass.