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}
HostName heroku.com
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 |
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 git@heroku.com:#{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.