mirror of
https://github.com/capistrano/capistrano
synced 2023-03-27 23:21:18 -04:00
Git SCM module (closes #9635)
git-svn-id: http://svn.rubyonrails.org/rails/tools/capistrano@7695 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
This commit is contained in:
parent
d5ecc1caab
commit
3a2df2deb9
3 changed files with 305 additions and 0 deletions
|
@ -1,5 +1,7 @@
|
|||
*SVN*
|
||||
|
||||
* Git SCM module [Garry Dolley, Geoffrey Grosenbach, Scott Chacon]
|
||||
|
||||
* Use the --password switch for subversion by default, but add :scm_prefer_prompt variable (defaults to false) [Jamis Buck]
|
||||
|
||||
|
||||
|
|
191
lib/capistrano/recipes/deploy/scm/git.rb
Normal file
191
lib/capistrano/recipes/deploy/scm/git.rb
Normal file
|
@ -0,0 +1,191 @@
|
|||
require 'capistrano/recipes/deploy/scm/base'
|
||||
|
||||
module Capistrano
|
||||
module Deploy
|
||||
module SCM
|
||||
|
||||
# An SCM module for using Git as your source control tool with Capistrano
|
||||
# 2.0. If you are using Capistrano 1.x, use this plugin instead:
|
||||
#
|
||||
# http://scie.nti.st/2007/3/16/capistrano-with-git-shared-repository
|
||||
#
|
||||
# Assumes you are using a shared Git repository.
|
||||
#
|
||||
# Parts of this plugin borrowed from Scott Chacon's version, which I
|
||||
# found on the Capistrano mailing list but failed to be able to get
|
||||
# working.
|
||||
#
|
||||
# FEATURES:
|
||||
#
|
||||
# * Very simple, only requiring 2 lines in your deploy.rb.
|
||||
# * Can deploy different branches, tags, or any SHA1 easily.
|
||||
# * Supports prompting for password / passphrase upon checkout.
|
||||
# (I am amazed at how some plugins don't do this)
|
||||
# * Supports :scm_command, :scm_password, :scm_passphrase Capistrano
|
||||
# directives.
|
||||
#
|
||||
# REQUIREMENTS
|
||||
# ------------
|
||||
#
|
||||
# Git is required to be installed on your remote machine(s), because a
|
||||
# clone and checkout is done to get the code up there. This is the way
|
||||
# I prefer to deploy; there is no alternative to this, so :deploy_via
|
||||
# is ignored.
|
||||
#
|
||||
# CONFIGURATION
|
||||
# -------------
|
||||
#
|
||||
# Use this plugin by adding the following line in your config/deploy.rb:
|
||||
#
|
||||
# set :scm, :git
|
||||
#
|
||||
# Set <tt>:repository</tt> to the path of your Git repo:
|
||||
#
|
||||
# set :repository, "someuser@somehost:/home/myproject"
|
||||
#
|
||||
# The above two options are required to be set, the ones below are
|
||||
# optional.
|
||||
#
|
||||
# You may set <tt>:branch</tt>, which is the reference to the branch, tag,
|
||||
# or any SHA1 you are deploying, for example:
|
||||
#
|
||||
# set :branch, "origin/master"
|
||||
#
|
||||
# Otherwise, HEAD is assumed. I strongly suggest you set this. HEAD is
|
||||
# not always the best assumption.
|
||||
#
|
||||
# The <tt>:scm_command</tt> configuration variable, if specified, will
|
||||
# be used as the full path to the git executable on the *remote* machine:
|
||||
#
|
||||
# set :scm_command, "/opt/local/bin/git"
|
||||
#
|
||||
# For compatibility with deploy scripts that may have used the 1.x
|
||||
# version of this plugin before upgrading, <tt>:git</tt> is still
|
||||
# recognized as an alias for :scm_command.
|
||||
#
|
||||
# Set <tt>:scm_password</tt> to the password needed to clone your repo
|
||||
# if you don't have password-less (public key) entry:
|
||||
#
|
||||
# set :scm_password, "my_secret'
|
||||
#
|
||||
# Otherwise, you will be prompted for a password.
|
||||
#
|
||||
# <tt>:scm_passphrase</tt> is also supported.
|
||||
#
|
||||
# The remote cache strategy is also supported.
|
||||
#
|
||||
# set :repository_cache, "git_master"
|
||||
# set :deploy_via, :remote_cache
|
||||
#
|
||||
# For faster clone, you can also use shallow cloning. This will set the
|
||||
# '--depth' flag using the depth specified. This *cannot* be used
|
||||
# together with the :remote_cache strategy
|
||||
#
|
||||
# set :git_shallow_clone, 1
|
||||
#
|
||||
# AUTHORS
|
||||
# -------
|
||||
#
|
||||
# Garry Dolley http://scie.nti.st
|
||||
# Contributions by Geoffrey Grosenbach http://topfunky.com
|
||||
# and Scott Chacon http://jointheconversation.org
|
||||
|
||||
class Git < Base
|
||||
# Sets the default command name for this SCM on your *local* machine.
|
||||
# Users may override this by setting the :scm_command variable.
|
||||
default_command "git"
|
||||
|
||||
# When referencing "head", use the branch we want to deploy or, by
|
||||
# default, Git's reference of HEAD (the latest changeset in the default
|
||||
# branch, usually called "master").
|
||||
def head
|
||||
configuration[:branch] || 'HEAD'
|
||||
end
|
||||
|
||||
# Performs a clone on the remote machine, then checkout on the branch
|
||||
# you want to deploy.
|
||||
def checkout(revision, destination)
|
||||
git = command
|
||||
|
||||
branch = head
|
||||
|
||||
fail "No branch specified, use for example 'set :branch, \"origin/master\"' in your deploy.rb" unless branch
|
||||
|
||||
if depth = configuration[:git_shallow_clone]
|
||||
execute = "#{git} clone --depth #{depth} #{configuration[:repository]} #{destination} && "
|
||||
else
|
||||
execute = "#{git} clone #{configuration[:repository]} #{destination} && "
|
||||
end
|
||||
|
||||
execute += "cd #{destination} && #{git} checkout -b deploy #{branch}"
|
||||
|
||||
execute
|
||||
end
|
||||
|
||||
# Merges the changes to 'head' since the last fetch, for remote_cache
|
||||
# deployment strategy
|
||||
def sync(revision, destination)
|
||||
execute = "cd #{destination} && git fetch origin && "
|
||||
|
||||
if head == 'HEAD'
|
||||
execute += "git merge origin/HEAD"
|
||||
else
|
||||
execute += "git merge #{head}"
|
||||
end
|
||||
|
||||
execute
|
||||
end
|
||||
|
||||
# Returns a string of diffs between two revisions
|
||||
def diff(from, to=nil)
|
||||
from << "..#{to}" if to
|
||||
scm :diff, from
|
||||
end
|
||||
|
||||
# Returns a log of changes between the two revisions (inclusive).
|
||||
def log(from, to=nil)
|
||||
from << "..#{to}" if to
|
||||
scm :log, from
|
||||
end
|
||||
|
||||
# Getting the actual commit id, in case we were passed a tag
|
||||
# or partial sha or something - it will return the sha if you pass a sha, too
|
||||
def query_revision(revision)
|
||||
yield(scm('rev-parse', revision)).chomp
|
||||
end
|
||||
|
||||
def command
|
||||
# For backwards compatibility with 1.x version of this module
|
||||
configuration[:git] || super
|
||||
end
|
||||
|
||||
# Determines what the response should be for a particular bit of text
|
||||
# from the SCM. Password prompts, connection requests, passphrases,
|
||||
# etc. are handled here.
|
||||
def handle_data(state, stream, text)
|
||||
logger.info "[#{stream}] #{text}"
|
||||
case text
|
||||
when /\bpassword.*:/i
|
||||
# git is prompting for a password
|
||||
unless pass = configuration[:scm_password]
|
||||
pass = Capistrano::CLI.password_prompt
|
||||
end
|
||||
"#{pass}\n"
|
||||
when %r{\(yes/no\)}
|
||||
# git is asking whether or not to connect
|
||||
"yes\n"
|
||||
when /passphrase/i
|
||||
# git is asking for the passphrase for the user's key
|
||||
unless pass = configuration[:scm_passphrase]
|
||||
pass = Capistrano::CLI.password_prompt
|
||||
end
|
||||
"#{pass}\n"
|
||||
when /accept \(t\)emporarily/
|
||||
# git is asking whether to accept the certificate
|
||||
"t\n"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
112
test/deploy/scm/git_test.rb
Normal file
112
test/deploy/scm/git_test.rb
Normal file
|
@ -0,0 +1,112 @@
|
|||
require "#{File.dirname(__FILE__)}/../../utils"
|
||||
require 'capistrano/recipes/deploy/scm/git'
|
||||
|
||||
class DeploySCMGitTest < Test::Unit::TestCase
|
||||
class TestSCM < Capistrano::Deploy::SCM::Git
|
||||
default_command "git"
|
||||
end
|
||||
|
||||
def setup
|
||||
@config = { }
|
||||
def @config.exists?(name); key?(name); end
|
||||
|
||||
@source = TestSCM.new(@config)
|
||||
end
|
||||
|
||||
def test_head
|
||||
assert_equal "HEAD", @source.head
|
||||
@config[:branch] = "master"
|
||||
assert_equal "master", @source.head
|
||||
end
|
||||
|
||||
def test_checkout
|
||||
@config[:repository] = "git@somehost.com:project.git"
|
||||
dest = "/var/www"
|
||||
assert_equal "git clone git@somehost.com:project.git /var/www && cd /var/www && git checkout -b deploy HEAD", @source.checkout('Not used', dest)
|
||||
|
||||
# With branch
|
||||
@config[:branch] = "origin/foo"
|
||||
assert_equal "git clone git@somehost.com:project.git /var/www && cd /var/www && git checkout -b deploy origin/foo", @source.checkout('Not used', dest)
|
||||
end
|
||||
|
||||
def test_diff
|
||||
assert_equal "git diff master", @source.diff('master')
|
||||
assert_equal "git diff master..branch", @source.diff('master', 'branch')
|
||||
end
|
||||
|
||||
def test_log
|
||||
assert_equal "git log master", @source.log('master')
|
||||
assert_equal "git log master..branch", @source.log('master', 'branch')
|
||||
end
|
||||
|
||||
def test_query_revision
|
||||
assert_equal "git rev-parse HEAD", @source.query_revision('HEAD') { |o| o }
|
||||
end
|
||||
|
||||
def test_command_should_be_backwards_compatible
|
||||
# 1.x version of this module used ":git", not ":scm_command"
|
||||
@config[:git] = "/srv/bin/git"
|
||||
assert_equal "/srv/bin/git", @source.command
|
||||
end
|
||||
|
||||
def test_sync
|
||||
dest = "/var/www"
|
||||
assert_equal "cd #{dest} && git fetch origin && git merge origin/HEAD", @source.sync('Not used', dest)
|
||||
|
||||
# With branch
|
||||
@config[:branch] = "origin/foo"
|
||||
assert_equal "cd #{dest} && git fetch origin && git merge origin/foo", @source.sync('Not used', dest)
|
||||
end
|
||||
|
||||
def test_shallow_clone
|
||||
@config[:repository] = "git@somehost.com:project.git"
|
||||
@config[:git_shallow_clone] = 1
|
||||
dest = "/var/www"
|
||||
assert_equal "git clone --depth 1 git@somehost.com:project.git /var/www && cd /var/www && git checkout -b deploy HEAD", @source.checkout('Not used', dest)
|
||||
|
||||
# With branch
|
||||
@config[:branch] = "origin/foo"
|
||||
assert_equal "git clone --depth 1 git@somehost.com:project.git /var/www && cd /var/www && git checkout -b deploy origin/foo", @source.checkout('Not used', dest)
|
||||
end
|
||||
|
||||
# Tests from base_test.rb, makin' sure we didn't break anything up there!
|
||||
def test_command_should_default_to_default_command
|
||||
assert_equal "git", @source.command
|
||||
@source.local { assert_equal "git", @source.command }
|
||||
end
|
||||
|
||||
def test_command_should_use_scm_command_if_available
|
||||
@config[:scm_command] = "/opt/local/bin/git"
|
||||
assert_equal "/opt/local/bin/git", @source.command
|
||||
end
|
||||
|
||||
def test_command_should_use_scm_command_in_local_mode_if_local_scm_command_not_set
|
||||
@config[:scm_command] = "/opt/local/bin/git"
|
||||
@source.local { assert_equal "/opt/local/bin/git", @source.command }
|
||||
end
|
||||
|
||||
def test_command_should_use_local_scm_command_in_local_mode_if_local_scm_command_is_set
|
||||
@config[:scm_command] = "/opt/local/bin/git"
|
||||
@config[:local_scm_command] = "/usr/local/bin/git"
|
||||
assert_equal "/opt/local/bin/git", @source.command
|
||||
@source.local { assert_equal "/usr/local/bin/git", @source.command }
|
||||
end
|
||||
|
||||
def test_command_should_use_default_if_scm_command_is_default
|
||||
@config[:scm_command] = :default
|
||||
assert_equal "git", @source.command
|
||||
end
|
||||
|
||||
def test_command_should_use_default_in_local_mode_if_local_scm_command_is_default
|
||||
@config[:scm_command] = "/foo/bar/git"
|
||||
@config[:local_scm_command] = :default
|
||||
@source.local { assert_equal "git", @source.command }
|
||||
end
|
||||
|
||||
def test_local_mode_proxy_should_treat_messages_as_being_in_local_mode
|
||||
@config[:scm_command] = "/foo/bar/git"
|
||||
@config[:local_scm_command] = :default
|
||||
assert_equal "git", @source.local.command
|
||||
assert_equal "/foo/bar/git", @source.command
|
||||
end
|
||||
end
|
Loading…
Reference in a new issue