Capistrano With Git Shared Repository

Update: A newer version of this article exists for Capistrano 2.0, go here if you’re using 2.0 or above.

I just wrote a simple Capistrano SCM module for git. It assumes you are using a shared repo. I recall when searching for something like this that someone may have starting writing one, but I couldn’t find it. So here’s my (perhaps only) version:

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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
require 'capistrano/scm/base'

module Capistrano
  module SCM

    # An SCM module for using git as your source control tool. Assumes you
    # are using a shared git repository. Use it by specifying the following
    # line in your configuration:
    #
    #   set :scm, :git
    #
    # You must set <tt>:branch</tt>, which is the reference to the branch
    # you are deploying, for example:
    # 
    #   set :branch, "remotes/origin/master"
    #
    # Also, this module accepts a <tt>:git</tt> configuration variable,
    # which (if specified) will be used as the full path to the git
    # executable on the remote machine:
    #
    #   set :git, "/opt/local/bin/git"
    #
    # Remember to set <tt>:repository</tt> to the path of your git repo:
    #
    #   set :repository, "someuser@somehost:/home/myproject"
    class Git < Base
      def current_revision(actor)
        git  = configuration[:git] ? configuration[:git] : "git"
        exec = "cd #{actor.current_path} && git rev-parse HEAD"

        result = ""
        actor.run(exec, :once => true) do |ch, str, out|
          result = out if str == :out
          raise "Could not determine current revision" if str == :err
        end

        result
      end

      def checkout(actor)
        git      = configuration[:git] ? configuration[:git] : "git"
        branch   = configuration[:branch]

        fail "No branch specified, use for example 'set :branch, \"remotes/origin/master\"' in your deploy.rb" unless branch

        execute  = "#{git} clone #{configuration.repository} #{actor.release_path}; "
        execute += "cd #{actor.release_path} ; #{git} checkout -b deploy #{branch}; "

        run_checkout(actor, execute, &git_stream_handler(actor))
      end

      private

      def git_stream_handler(actor)
        Proc.new do |ch, stream, out|
          prefix = "#{stream} :: #{ch[:host]}"
          actor.logger.info out, prefix
          if out =~ %r{password:}
            actor.logger.info "git is asking for a password", prefix
            ch.send_data "#{actor.password}\n"
          elsif out =~ %r{\(yes/no\)}
            actor.logger.info "git is asking whether to connect or not", prefix
            ch.send_data "yes\n"
          elsif out =~ %r{passphrase}
            message = "git needs your key's passphrase, sending empty string"
            actor.logger.info message, prefix
            ch.send_data "\n"
          end
        end
      end
    end

  end
end

You can download the module here: git.rb. Put it in the ‘lib/capistrano/scm’ directory of your main Capistrano install.

This will allow deploying by checking out a specified branch of a remote shared git repo. There are a lot of other features in git that I did not add hooks for. Exercise for the reader. :) If you add on, please do drop me a note so I can improve my version also.

Comments