A few weeks ago, we rolled out preliminary support for automatic code coverage collection and custom post-build tasks.
Over the coming weeks, we’re rolling out better UIs in front of these features, but if you’re impatient, and you’re up for using our sample rake task, read on for end-to-end continuous deployment.
I’ll describe how we use post-build tasks and environment variables to implement continuous deployment of one of our own apps into Heroku, including running migrations.
Note: If you currently use Tddium’s push-on-pass functionality, this approach replaces it.
Step 1: Setup Environment Variables
The first step is to set ephemeral environment variables in Tddium containing sensitive parameters, like your Heroku app name and credentials.
1 2 3 |
$ tddium config:add account HEROKU_EMAIL my_heroku_login_email@example.com $ tddium config:add account HEROKU_API_KEY my_heroku_api_key $ tddium config:add account HEROKU_APP_NAME my_heroku_app_name |
Tddium’s environment variables allow you to pass this sensitive information to your tests and the post-build hook that we’ll create – without having to check these in to your repository.
You can find your Heroku API key by logging in to your Heroku Account page.
Step 2: Install the Post Build Task
We’ve written up a sample post-build task that will push to Heroku automatically (gist). You can customize this task as you need. Over the next few weeks, we’ll be rolling out a more streamlined UI to make post-build configuration much simpler.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
def cmd(c) system c end namespace :tddium do desc "post_build_hook" task :post_build_hook do # This build hook should only run after CI builds. # # There are other cases where we’d want to run something after every build, # or only after manual builds. return unless ENV["TDDIUM_MODE"] == "ci" return unless ENV["TDDIUM_BUILD_STATUS"] == "passed" dir = File.expand_path("~/.heroku/") heroku_email = ENV["HEROKU_EMAIL"] heroku_api_key = ENV["HEROKU_API_KEY"] current_branch = `git symbolic-ref HEAD 2>/dev/null | cut -d"/" -f 3-`.strip app_name = ENV["HEROKU_APP_NAME"] push_target = "git@heroku.com:#{app_name}.git" abort "invalid current branch" unless current_branch FileUtils.mkdir_p(dir) or abort "Could not create #{dir}" puts "Writing Heroku Credentials" File.open(File.join(dir, "credentials"), "w") do |f| f.write([heroku_email, heroku_api_key].join("n")) f.write("n") end File.open(File.expand_path("~/.netrc"), "a+") do |f| [‘api’, ‘code’].each do |host f.puts "machine #{host}.heroku.com" f.puts " login #{heroku_email}" f.puts " password #{heroku_api_key}" end end puts "Pushing to Heroku: #{push_target}…" cmd "git push #{push_target} HEAD:master –force" or abort "could not push to #{push_target}" Bundler.with_clean_env do puts "Running Heroku Migrations…" cmd "heroku run rake db:migrate –app #{app_name}" or abort "aborted migrations" puts "Restarting Heroku…" cmd "heroku restart –app #{app_name}" or abort "aborted heroku restart" end end end |
Step 3: Authorize Tddium’s Worker Key
Run tddium account
to get the Tddium worker key you need to authorize with Heroku.
Save the key in a file: tddium-worker-key.pub
.
Then run heroku keys:add tddium-worker-key.pub
Step 4: Trigger A Build
That’s it! Push to your git repo to trigger Tddium CI, or trigger a build manually on your Tddium Dashboard.
When the push and migration completes, you’ll see a post_build_hook.log.
If you haven’t configured Tddium CI, read our getting started guide for more information.
If you don’t yet have a Tddium account, sign up now for a free trial!
Don’t hesitate to contact us at support@tddium.com for more information.
Update (10/25/2012):
Our awesome customers have pointed out a few gotchas and solutions:
- Make sure you have the ‘heroku’ gem in your Gemfile, or the above Heroku commands won’t work. We’ll soon be automatically including the heroku toolbelt in our workers, but until then…
- If you’re using Rails 3.1+ and the asset pipeline, make sure you enable the heroku user-env-compile labs feature.
Update (6/21/2013):
The Heroku toolbelt package has been installed in test VMs for some time now so it is safe to use instead of the gem.
Update (7/15/2013):
If you are using Ruby 2.0, you will need to use Bundler.with_clean_env to run the Heroku toolbelt command.
14 Comments
This was working, but seems like it broke with some of the latest changes.
Miguel, in your case it looks as though there is an authentication problem — i.e. you need to authorize the proper key in Heroku. Some users also have had excessively long running post-build hooks and the default timeout is now enforced.
Wiiliam, How do you increase the timeout duration?
Geoff, there is a hard cap at the moment, but you can increase the timeout up to that cap by setting the {:tddium => {:timeout_hook => seconds } } (as YAML) in tddium.yml.
William, what’s the hard cap as of now?
Dharampal,
The hard cap is long enough that it should not pose a problem unless you are doing significant computation in the hook, which you really shouldn’t be doing. If you have trouble and are hitting the cap, please contact support for now. We’ll be improving the hook infrastructure and the associated documentation in the short term.
What’s the hard cap on build hook timeouts as of now?
Couple of observations –
1.) The post-build task link in the first paragraph is dead – http://docs.tddium.com/getting-started/post-build-tasks
2.) It would be cool if you had one gist that contained the rake task in Step 2.) embedded in this page. Currently there are several on github, which is the official & most current? https://gist.github.com/search?q=tddium_post_build.rake
Why not use revision history?
Geoff — thanks for pointing out the broken link! We’ve fixed it. There is a link in the post to the current gist; we’ll be updating it.
In a rails app where should the tddium_post_build.rake file go?
@James: If you commit it as
$RAILS_ROOT/lib/tddium_post_build.rake
, it should get picked up automatically.Thanks, also I get an error of no directory ‘credentials’ for the line:
File.open(File.join(dir, “credentials”)
If I’m not using a Rails app, where do I put this file and how do I reference it from tddium.yml, if this is necessary?
https://gist.github.com/nvreynolds/5ad0c78582d9b0eeee08
2 Trackbacks
[…] 5/2012: Read our latest blog post about Continuous Deployment for Heroku […]
[…] Here’s an example of how to set up deploy notifications for a repo that’s already set up with Heroku, Tddium and NewRelic, and configured for Heroku auto-deployment using the procedure described in this earlier post. […]