Posts tagged capistrano

Feb 17, 2010

Co-op Capistrano deployment script

Co-op Harvest capistrano ruby | comments

Yesterday at Harvest we launched a little API-accessible robot for our team communication app, Co-op. There are many uses for this API hook, from deploy notices to code commits to fun daily team affirmations. You are only limited by your imagination!

Our first use of the Cobot was to get deployment messages right in our Co-op workstream, including git commit messages. This is what we see today:

Archive: Tuesday, Feb 16 at Team Iridesco @ Harvest Co-op

And our Capistrano deployment script (hat tip to John Nunemaker for the idea):

namespace :co_op do
  desc "Update Co-op with most recent deployment messages."
  task :update do
    require 'net/http'
    require 'base64'
    require 'cgi'
    require 'json'

    app = "Harvest"
    key = "withheld_for_your_protection"

    headers = {
      "Accept"        => "application/json",
      "Content-Type"  => "application/json; charset=utf-8",
      "User-Agent"    => "Co-op Deployment"

      connection ="", 80)
      connection.open_timeout = 10
      logs = (`git log #{previous_revision}..#{current_revision}`).
               map{|l| l.strip}.
               reject {|t| t.match(/^Merge branch \'/)}
      logs_size = logs.size
      logs = logs[0,6]
      logs << '...' if logs_size > 6
      msg = "- #{logs.join('<br />- ')}"
      who_am_i = `whoami`.chomp.capitalize'/groups/5/notes', 
                      {:status => "#{who_am_i} deployed #{app}: " + 
                                  "<br />#{msg}", 
                       :key => key}.to_json, 
      puts 'Deploy notice sent to Co-op'
    rescue Timeout::Error => e
      puts "Timeout after 10s: Seems like Co-op missed your update."
      puts "Use \"cap co_op:update\" to update Co-op " +
           "status later w/o deploying"

after  "deploy", "co_op:update"

Feb 28, 2008

Move server configuration files into your repository

capistrano rails ruby scm svn Ruby Rails SVN SCM Capistrano | comments

Dung repository
Photo by Chambo25

Are you a programmer? Do you hate any process that involves SSH’ing into a server and editing files directly in production? Would you like to get rid of this non-source controlled hackery? Damn right you would!

If you’re deploying an application to a server, get those app-specific configuration files in your source control system! I happen to be a Ruby on Rails programmer, so the two files I’m looking to control are the Apache and Mongrel configuration files. Here are two sample locations:

Maruku could not parse this XML/HTML: 


Via terminal, browse into your local Rails app directory. Then, create a couple directories to store this configuration:

mkdir ./config/apache
mkdir ./config/mongrel

Then copy the configuration files you have sitting on your server into the local directory (I’m using SCP and assuming you know the rest). Again, locally:

scp bjhess@server_or_ip:/usr/local/apache2/conf/apps/appname.conf ./config/apache/
scp bjhess@server_or_ip:/etc/mongrel_cluster/appname.yml ./config/mongrel/


Now you’re all ready to commit these configuration repositories to your SVN/git/mercurial repository. But wait, you also want to actually use these versions of the configuration files in production, no? Well, let’s do it. Rename the original configuration files on the remote server:

mv /usr/local/apache2/conf/apps/appname.conf /usr/local/apache2/conf/apps/appname.conf.bak
mv /etc/mongrel_cluster/appname.yml /etc/mongrel_cluster/appname.yml.bak

Then simply update your deployment script to create symlinks from the expected configuration file location to the new location. I’m using Capistrano (version OLD), so adjust accordingly:

desc "Tasks to complete after code update"
task :after_update_code do
  #            LINK TARGET                                   LINK SOURCE
  run "ln -nfs #{current_release}/config/apache/appname.conf /usr/local/apache2/conf/apps/appname.conf"
  run "ln -nfs #{current_release}/config/mongrel/appname.yml /etc/mongrel_cluster/appname.yml"


This is great, isn’t it? The programmer in you loves having limitless history of configuration changes, not to mention the ability to use whatever local editor you choose. Wonderful day!

But what about the whole-server configuration files? Unless you commit to one app per server, I don’t think base Apache config files or server-level logrotate config files should be in a specific app’s repository. Perhaps a new repository could be setup to deal with these files? I imagine Capistrano could even be used for the bare-bones deployment.

Or maybe just backing up these general files is enough to keep your mind at ease. Just be sure to think about it. That’ll put you one step ahead of the rest

Update: Be sure to deal with symlinks upon rollbacks, something I just got burnt by:

desc "Tasks to complete after code rollback"
task :after_rollback do
  run "ln -nfs #{previous_release}/config/apache/appname.conf /usr/local/apache2/conf/apps/appname.conf"