mirror of
https://github.com/capistrano/capistrano
synced 2023-03-27 23:21:18 -04:00
replace obsolete configuration tests with a failing one. Fix misnamed execution test class. Remove SCM and generator code (which will find its way into a separate package eventually)
git-svn-id: http://svn.rubyonrails.org/rails/tools/capistrano@6273 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
This commit is contained in:
parent
4c5597282d
commit
4789f87bf9
22 changed files with 26 additions and 1360 deletions
|
@ -27,8 +27,8 @@ module Capistrano
|
|||
# executed tasks.
|
||||
attr_reader :sessions
|
||||
|
||||
def initialize_with_connections #:nodoc:
|
||||
initialize_without_connections
|
||||
def initialize_with_connections(*args) #:nodoc:
|
||||
initialize_without_connections(*args)
|
||||
@sessions = {}
|
||||
end
|
||||
|
||||
|
|
|
@ -19,8 +19,8 @@ module Capistrano
|
|||
# A struct for representing a single instance of an invoked task.
|
||||
TaskCallFrame = Struct.new(:task, :rollback)
|
||||
|
||||
def initialize_with_execution #:nodoc:
|
||||
initialize_without_execution
|
||||
def initialize_with_execution(*args) #:nodoc:
|
||||
initialize_without_execution(*args)
|
||||
@task_call_frames = []
|
||||
end
|
||||
private :initialize_with_execution
|
||||
|
|
|
@ -30,8 +30,8 @@ module Capistrano
|
|||
# The load paths used for locating recipe files.
|
||||
attr_reader :load_paths
|
||||
|
||||
def initialize_with_loading #:nodoc:
|
||||
initialize_without_loading
|
||||
def initialize_with_loading(*args) #:nodoc:
|
||||
initialize_without_loading(*args)
|
||||
@load_paths = [".", File.expand_path(File.join(File.dirname(__FILE__), "../recipes"))]
|
||||
end
|
||||
private :initialize_with_loading
|
||||
|
|
|
@ -13,8 +13,8 @@ module Capistrano
|
|||
# role.
|
||||
attr_reader :roles
|
||||
|
||||
def initialize_with_roles #:nodoc:
|
||||
initialize_without_roles
|
||||
def initialize_with_roles(*args) #:nodoc:
|
||||
initialize_without_roles(*args)
|
||||
@roles = Hash.new { |h,k| h[k] = [] }
|
||||
end
|
||||
|
||||
|
|
|
@ -85,8 +85,8 @@ module Capistrano
|
|||
fetch(variable, nil)
|
||||
end
|
||||
|
||||
def initialize_with_variables #:nodoc:
|
||||
initialize_without_variables
|
||||
def initialize_with_variables(*args) #:nodoc:
|
||||
initialize_without_variables(*args)
|
||||
@variables = {}
|
||||
@original_procs = {}
|
||||
|
||||
|
|
|
@ -1,25 +0,0 @@
|
|||
class DeploymentGenerator < Rails::Generator::NamedBase
|
||||
attr_reader :recipe_file
|
||||
|
||||
def initialize(runtime_args, runtime_options = {})
|
||||
super
|
||||
@recipe_file = @args.shift || "deploy"
|
||||
end
|
||||
|
||||
def manifest
|
||||
record do |m|
|
||||
m.directory "config"
|
||||
m.template "deploy.rb", File.join("config", "#{recipe_file}.rb")
|
||||
m.directory "lib/tasks"
|
||||
m.template "capistrano.rake", File.join("lib", "tasks", "capistrano.rake")
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
# Override with your own usage banner.
|
||||
def banner
|
||||
"Usage: #{$0} deployment ApplicationName [recipe-name]\n" +
|
||||
" (recipe-name defaults to \"deploy\")"
|
||||
end
|
||||
end
|
|
@ -1,49 +0,0 @@
|
|||
# =============================================================================
|
||||
# A set of rake tasks for invoking the Capistrano automation utility.
|
||||
# =============================================================================
|
||||
|
||||
# Invoke the given actions via Capistrano
|
||||
def cap(*parameters)
|
||||
begin
|
||||
require 'rubygems'
|
||||
rescue LoadError
|
||||
# no rubygems to load, so we fail silently
|
||||
end
|
||||
|
||||
require 'capistrano/cli'
|
||||
|
||||
STDERR.puts "Capistrano/Rake integration is deprecated."
|
||||
STDERR.puts "Please invoke the 'cap' command directly: `cap #{parameters.join(" ")}'"
|
||||
|
||||
Capistrano::CLI.new(parameters.map { |param| param.to_s }).execute!
|
||||
end
|
||||
|
||||
namespace :remote do
|
||||
<%- config = Capistrano::Configuration.new
|
||||
config.load "standard"
|
||||
options = { :show_tasks => ", '-q'" }
|
||||
config.actor.each_task do |info| -%>
|
||||
<%- unless info[:desc].empty? -%>
|
||||
desc "<%= info[:desc].scan(/.*?(?:\. |$)/).first.strip.gsub(/"/, "\\\"") %>"
|
||||
<%- end -%>
|
||||
task(<%= info[:task].inspect %>) { cap <%= info[:task].inspect %><%= options[info[:task]] %> }
|
||||
|
||||
<%- end -%>
|
||||
desc "Execute a specific action using capistrano"
|
||||
task :exec do
|
||||
unless ENV['ACTION']
|
||||
raise "Please specify an action (or comma separated list of actions) via the ACTION environment variable"
|
||||
end
|
||||
|
||||
actions = ENV['ACTION'].split(",")
|
||||
actions.concat(ENV['PARAMS'].split(" ")) if ENV['PARAMS']
|
||||
|
||||
cap(*actions)
|
||||
end
|
||||
end
|
||||
|
||||
desc "Push the latest revision into production (delegates to remote:deploy)"
|
||||
task :deploy => "remote:deploy"
|
||||
|
||||
desc "Rollback to the release before the current release in production (delegates to remote:rollback)"
|
||||
task :rollback => "remote:rollback"
|
|
@ -1,122 +0,0 @@
|
|||
# This defines a deployment "recipe" that you can feed to capistrano
|
||||
# (http://manuals.rubyonrails.com/read/book/17). It allows you to automate
|
||||
# (among other things) the deployment of your application.
|
||||
|
||||
# =============================================================================
|
||||
# REQUIRED VARIABLES
|
||||
# =============================================================================
|
||||
# You must always specify the application and repository for every recipe. The
|
||||
# repository must be the URL of the repository you want this recipe to
|
||||
# correspond to. The deploy_to path must be the path on each machine that will
|
||||
# form the root of the application path.
|
||||
|
||||
set :application, "<%= singular_name %>"
|
||||
set :repository, "http://svn.yourhost.com/#{application}/trunk"
|
||||
|
||||
# =============================================================================
|
||||
# ROLES
|
||||
# =============================================================================
|
||||
# You can define any number of roles, each of which contains any number of
|
||||
# machines. Roles might include such things as :web, or :app, or :db, defining
|
||||
# what the purpose of each machine is. You can also specify options that can
|
||||
# be used to single out a specific subset of boxes in a particular role, like
|
||||
# :primary => true.
|
||||
|
||||
role :web, "www01.example.com", "www02.example.com"
|
||||
role :app, "app01.example.com", "app02.example.com", "app03.example.com"
|
||||
role :db, "db01.example.com", :primary => true
|
||||
role :db, "db02.example.com", "db03.example.com"
|
||||
|
||||
# =============================================================================
|
||||
# OPTIONAL VARIABLES
|
||||
# =============================================================================
|
||||
# set :deploy_to, "/path/to/app" # defaults to "/u/apps/#{application}"
|
||||
# set :user, "flippy" # defaults to the currently logged in user
|
||||
# set :scm, :darcs # defaults to :subversion
|
||||
# set :svn, "/path/to/svn" # defaults to searching the PATH
|
||||
# set :darcs, "/path/to/darcs" # defaults to searching the PATH
|
||||
# set :cvs, "/path/to/cvs" # defaults to searching the PATH
|
||||
# set :gateway, "gate.host.com" # default to no gateway
|
||||
|
||||
# =============================================================================
|
||||
# SSH OPTIONS
|
||||
# =============================================================================
|
||||
# ssh_options[:keys] = %w(/path/to/my/key /path/to/another/key)
|
||||
# ssh_options[:port] = 25
|
||||
|
||||
# =============================================================================
|
||||
# TASKS
|
||||
# =============================================================================
|
||||
# Define tasks that run on all (or only some) of the machines. You can specify
|
||||
# a role (or set of roles) that each task should be executed on. You can also
|
||||
# narrow the set of servers to a subset of a role by specifying options, which
|
||||
# must match the options given for the servers to select (like :primary => true)
|
||||
|
||||
desc <<DESC
|
||||
An imaginary backup task. (Execute the 'show_tasks' task to display all
|
||||
available tasks.)
|
||||
DESC
|
||||
task :backup, :roles => :db, :only => { :primary => true } do
|
||||
# the on_rollback handler is only executed if this task is executed within
|
||||
# a transaction (see below), AND it or a subsequent task fails.
|
||||
on_rollback { delete "/tmp/dump.sql" }
|
||||
|
||||
run "mysqldump -u theuser -p thedatabase > /tmp/dump.sql" do |ch, stream, out|
|
||||
ch.send_data "thepassword\n" if out =~ /^Enter password:/
|
||||
end
|
||||
end
|
||||
|
||||
# Tasks may take advantage of several different helper methods to interact
|
||||
# with the remote server(s). These are:
|
||||
#
|
||||
# * run(command, options={}, &block): execute the given command on all servers
|
||||
# associated with the current task, in parallel. The block, if given, should
|
||||
# accept three parameters: the communication channel, a symbol identifying the
|
||||
# type of stream (:err or :out), and the data. The block is invoked for all
|
||||
# output from the command, allowing you to inspect output and act
|
||||
# accordingly.
|
||||
# * sudo(command, options={}, &block): same as run, but it executes the command
|
||||
# via sudo.
|
||||
# * delete(path, options={}): deletes the given file or directory from all
|
||||
# associated servers. If :recursive => true is given in the options, the
|
||||
# delete uses "rm -rf" instead of "rm -f".
|
||||
# * put(buffer, path, options={}): creates or overwrites a file at "path" on
|
||||
# all associated servers, populating it with the contents of "buffer". You
|
||||
# can specify :mode as an integer value, which will be used to set the mode
|
||||
# on the file.
|
||||
# * render(template, options={}) or render(options={}): renders the given
|
||||
# template and returns a string. Alternatively, if the :template key is given,
|
||||
# it will be treated as the contents of the template to render. Any other keys
|
||||
# are treated as local variables, which are made available to the (ERb)
|
||||
# template.
|
||||
|
||||
desc "Demonstrates the various helper methods available to recipes."
|
||||
task :helper_demo do
|
||||
# "setup" is a standard task which sets up the directory structure on the
|
||||
# remote servers. It is a good idea to run the "setup" task at least once
|
||||
# at the beginning of your app's lifetime (it is non-destructive).
|
||||
setup
|
||||
|
||||
buffer = render("maintenance.rhtml", :deadline => ENV['UNTIL'])
|
||||
put buffer, "#{shared_path}/system/maintenance.html", :mode => 0644
|
||||
sudo "killall -USR1 dispatch.fcgi"
|
||||
run "#{release_path}/script/spin"
|
||||
delete "#{shared_path}/system/maintenance.html"
|
||||
end
|
||||
|
||||
# You can use "transaction" to indicate that if any of the tasks within it fail,
|
||||
# all should be rolled back (for each task that specifies an on_rollback
|
||||
# handler).
|
||||
|
||||
desc "A task demonstrating the use of transactions."
|
||||
task :long_deploy do
|
||||
transaction do
|
||||
update_code
|
||||
disable_web
|
||||
symlink
|
||||
migrate
|
||||
end
|
||||
|
||||
restart
|
||||
enable_web
|
||||
end
|
|
@ -1,20 +0,0 @@
|
|||
module Capistrano
|
||||
module Generators
|
||||
class RailsLoader
|
||||
def self.load!(options)
|
||||
require "#{options[:apply_to]}/config/environment"
|
||||
require "rails_generator"
|
||||
require "rails_generator/scripts/generate"
|
||||
|
||||
Rails::Generator::Base.sources << Rails::Generator::PathSource.new(
|
||||
:capistrano, File.dirname(__FILE__))
|
||||
|
||||
args = ["deployment"]
|
||||
args << (options[:application] || "Application")
|
||||
args << (options[:recipe_file] || "deploy")
|
||||
|
||||
Rails::Generator::Scripts::Generate.new.run(args)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,61 +0,0 @@
|
|||
module Capistrano
|
||||
module SCM
|
||||
|
||||
# The ancestor class of the various SCM module implementations.
|
||||
class Base
|
||||
attr_reader :configuration
|
||||
|
||||
def initialize(configuration) #:nodoc:
|
||||
@configuration = configuration
|
||||
end
|
||||
|
||||
def latest_revision
|
||||
nil
|
||||
end
|
||||
|
||||
def current_revision(actor)
|
||||
raise "#{self.class} doesn't support querying the deployed revision"
|
||||
end
|
||||
|
||||
def diff(actor, from=nil, to=nil)
|
||||
raise "#{self.class} doesn't support diff(from, to)"
|
||||
end
|
||||
|
||||
def update(actor)
|
||||
raise "#{self.class} doesn't support update(actor)"
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def run_checkout(actor, guts, &block)
|
||||
directory = File.basename(configuration.release_path)
|
||||
|
||||
command = <<-STR
|
||||
if [[ ! -d #{configuration.release_path} ]]; then
|
||||
#{guts}
|
||||
#{logging_commands(directory)}
|
||||
fi
|
||||
STR
|
||||
|
||||
actor.run(command, &block)
|
||||
end
|
||||
|
||||
def run_update(actor, guts, &block)
|
||||
command = <<-STR
|
||||
#{guts}
|
||||
#{logging_commands}
|
||||
STR
|
||||
|
||||
actor.run(command, &block)
|
||||
end
|
||||
|
||||
def logging_commands(directory = nil)
|
||||
log = "#{configuration.deploy_to}/revisions.log"
|
||||
|
||||
"(test -e #{log} || (touch #{log} && chmod 666 #{log})) && " +
|
||||
"echo `date +\"%Y-%m-%d %H:%M:%S\"` $USER #{configuration.revision} #{directory} >> #{log};"
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
|
@ -1,118 +0,0 @@
|
|||
require 'capistrano/scm/base'
|
||||
|
||||
module Capistrano
|
||||
module SCM
|
||||
|
||||
# An SCM module for using Bazaar as your source control tool. This
|
||||
# module is used by default, but you can explicitly specify it by
|
||||
# placing the following line in your configuration:
|
||||
#
|
||||
# set :scm, :baz
|
||||
#
|
||||
# Also, this module accepts a <tt>:baz</tt> configuration variable,
|
||||
# which (if specified) will be used as the full path to the svn
|
||||
# executable on the remote machine:
|
||||
#
|
||||
# set :baz, "/opt/local/bin/baz"
|
||||
#
|
||||
# Set the version you wish to deploy as the repository variable,
|
||||
# for example:
|
||||
#
|
||||
# set :repository, "you@example.com--dev/yourstuff--trunk--1.0"
|
||||
#
|
||||
# Ensure that you have already registered the archive on the target
|
||||
# machines.
|
||||
#
|
||||
# As bazaar keeps a great deal of extra information on a checkout,
|
||||
# you will probably want to use export instead:
|
||||
#
|
||||
# set :checkout, "export"
|
||||
#
|
||||
# TODO: provide setup recipe to register archive
|
||||
class Baz < Base
|
||||
# Return an integer identifying the last known revision in the baz
|
||||
# repository. (This integer is currently the revision number.)
|
||||
def latest_revision
|
||||
`#{baz} revisions #{configuration.repository}`.split.last =~ /\-(\d+)$/
|
||||
$1
|
||||
end
|
||||
|
||||
# Return the number of the revision currently deployed.
|
||||
def current_revision(actor)
|
||||
latest = actor.releases.last
|
||||
grep = %(grep " #{latest}$" #{configuration.deploy_to}/revisions.log)
|
||||
result = ""
|
||||
actor.run(grep, :once => true) do |ch, str, out|
|
||||
result << out if str == :out
|
||||
raise "could not determine current revision" if str == :err
|
||||
end
|
||||
|
||||
date, time, user, rev, dir = result.split
|
||||
raise "current revision not found in revisions.log" unless dir == latest
|
||||
rev.to_i
|
||||
end
|
||||
|
||||
# Return a string containing the diff between the two revisions. +from+
|
||||
# and +to+ may be in any format that bzr recognizes as a valid revision
|
||||
# identifier. If +from+ is +nil+, it defaults to the last deployed
|
||||
# revision. If +to+ is +nil+, it defaults to the last developed revision.
|
||||
def diff(actor, from=nil, to=nil)
|
||||
from ||= current_revision(actor)
|
||||
to ||= latest_revision
|
||||
from = baz_revision_name(from)
|
||||
to = baz_revision_name(to)
|
||||
`#{baz} delta --diffs -A #{baz_archive} #{baz_version}--#{from} #{baz_version}--#{to}`
|
||||
end
|
||||
|
||||
# Check out (on all servers associated with the current task) the latest
|
||||
# revision. Uses the given actor instance to execute the command.
|
||||
def checkout(actor)
|
||||
op = configuration[:checkout] || "get"
|
||||
from = baz_revision_name(configuration.revision)
|
||||
command = "#{baz} #{op} #{configuration.repository}--#{from} #{actor.release_path} &&"
|
||||
run_checkout(actor, command, &baz_stream_handler(actor))
|
||||
end
|
||||
|
||||
def update(actor)
|
||||
command = "cd #{actor.current_path} && #{baz} update &&"
|
||||
run_update(actor, command, &baz_stream_handler(actor))
|
||||
end
|
||||
|
||||
private
|
||||
def baz
|
||||
configuration[:baz] || "baz"
|
||||
end
|
||||
|
||||
def baz_revision_name(number)
|
||||
if number.to_i == 0 then
|
||||
"base-0"
|
||||
else
|
||||
"patch-#{number}"
|
||||
end
|
||||
end
|
||||
|
||||
def baz_archive
|
||||
configuration[:repository][/(.*)\//, 1]
|
||||
end
|
||||
|
||||
def baz_version
|
||||
configuration[:repository][/\/(.*)$/, 1]
|
||||
end
|
||||
|
||||
def baz_stream_handler(actor)
|
||||
Proc.new do |ch, stream, out|
|
||||
prefix = "#{stream} :: #{ch[:host]}"
|
||||
actor.logger.info out, prefix
|
||||
if out =~ /\bpassword.*:/i
|
||||
actor.logger.info "baz is asking for a password", prefix
|
||||
ch.send_data "#{actor.password}\n"
|
||||
elsif out =~ %r{passphrase}
|
||||
message = "baz needs your key's passphrase, sending empty string"
|
||||
actor.logger.info message, prefix
|
||||
ch.send_data "\n"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,70 +0,0 @@
|
|||
require 'capistrano/scm/base'
|
||||
|
||||
module Capistrano
|
||||
module SCM
|
||||
|
||||
# An SCM module for using Bazaar-NG (bzr) as your source control tool.
|
||||
# You can use it by placing the following line in your configuration:
|
||||
#
|
||||
# set :scm, :bzr
|
||||
#
|
||||
# Also, this module accepts a <tt>:bzr</tt> configuration variable,
|
||||
# which (if specified) will be used as the full path to the bzr
|
||||
# executable on the remote machine:
|
||||
#
|
||||
# set :bzr, "/opt/local/bin/bzr"
|
||||
class Bzr < Base
|
||||
# Return an integer identifying the last known revision in the bzr
|
||||
# repository. (This integer is currently the revision number.)
|
||||
def latest_revision
|
||||
`#{bzr} revno #{configuration.repository}`.to_i
|
||||
end
|
||||
|
||||
# Return the number of the revision currently deployed.
|
||||
def current_revision(actor)
|
||||
command = "#{bzr} revno #{actor.release_path} &&"
|
||||
run_update(actor, command, &bzr_stream_handler(actor))
|
||||
end
|
||||
|
||||
# Return a string containing the diff between the two revisions. +from+
|
||||
# and +to+ may be in any format that bzr recognizes as a valid revision
|
||||
# identifier. If +from+ is +nil+, it defaults to the last deployed
|
||||
# revision. If +to+ is +nil+, it defaults to the last developed revision.
|
||||
# Pay attention to the fact that as of now bzr does NOT support
|
||||
# diff on remote locations.
|
||||
def diff(actor, from=nil, to=nil)
|
||||
from ||= current_revision(actor)
|
||||
to ||= ""
|
||||
`#{bzr} diff -r #{from}..#{to} #{configuration.repository}`
|
||||
end
|
||||
|
||||
# Check out (on all servers associated with the current task) the latest
|
||||
# revision. Uses the given actor instance to execute the command. If
|
||||
# bzr asks for a password this will automatically provide it (assuming
|
||||
# the requested password is the same as the password for logging into the
|
||||
# remote server.)
|
||||
def checkout(actor)
|
||||
op = configuration[:checkout] || "branch"
|
||||
command = "#{bzr} #{op} -r#{configuration.revision} #{configuration.repository} #{actor.release_path} &&"
|
||||
run_checkout(actor, command, &bzr_stream_handler(actor))
|
||||
end
|
||||
|
||||
def update(actor)
|
||||
command = "cd #{actor.current_path} && #{bzr} pull -q &&"
|
||||
run_update(actor, command, &bzr_stream_handler(actor))
|
||||
end
|
||||
|
||||
private
|
||||
def bzr
|
||||
configuration[:bzr] || "bzr"
|
||||
end
|
||||
|
||||
def bzr_stream_handler(actor)
|
||||
Proc.new do |ch, stream, out|
|
||||
prefix = "#{stream} :: #{ch[:host]}"
|
||||
actor.logger.info out, prefix
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,129 +0,0 @@
|
|||
require 'time'
|
||||
require 'capistrano/scm/base'
|
||||
|
||||
module Capistrano
|
||||
module SCM
|
||||
|
||||
# An SCM module for using CVS as your source control tool. You can
|
||||
# specify it by placing the following line in your configuration:
|
||||
#
|
||||
# set :scm, :cvs
|
||||
#
|
||||
# Also, this module accepts a <tt>:cvs</tt> configuration variable,
|
||||
# which (if specified) will be used as the full path to the cvs
|
||||
# executable on the remote machine:
|
||||
#
|
||||
# set :cvs, "/opt/local/bin/cvs"
|
||||
#
|
||||
# You can specify the location of your local copy (used to query
|
||||
# the revisions, etc.) via the <tt>:local</tt> variable, which defaults to
|
||||
# ".".
|
||||
#
|
||||
# You may also specify a <tt>:branch</tt> configuration variable,
|
||||
# which (if specified) will be used in the '-r' option to the cvs
|
||||
# check out command. If it is not set, the module will determine if a
|
||||
# branch is being used in the CVS sandbox relative to
|
||||
# <tt>:local</tt> and act accordingly.
|
||||
#
|
||||
# set :branch, "prod-20060124"
|
||||
#
|
||||
# Also, you can specify the CVS_RSH variable to use on the remote machine(s)
|
||||
# via the <tt>:cvs_rsh</tt> variable. This defaults to the value of the
|
||||
# CVS_RSH environment variable locally, or if it is not set, to "ssh".
|
||||
class Cvs < Base
|
||||
def initialize(configuration)
|
||||
super(configuration)
|
||||
|
||||
if not @configuration.respond_to?(:local) then
|
||||
@configuration.set(:local,".")
|
||||
end
|
||||
|
||||
if not configuration.respond_to?(:branch) then
|
||||
configuration.set(:branch) { self.current_branch }
|
||||
else
|
||||
@current_branch = configuration[:branch]
|
||||
end
|
||||
end
|
||||
|
||||
# Return a string representing the date of the last revision (CVS is
|
||||
# seriously retarded, in that it does not give you a way to query when
|
||||
# the last revision was made to the repository, so this is a fairly
|
||||
# expensive operation...)
|
||||
def latest_revision
|
||||
return @latest_revision if @latest_revision
|
||||
configuration.logger.debug "querying latest revision..."
|
||||
@latest_revision = cvs_log(cvs_local, configuration.branch).
|
||||
split(/\r?\n/).
|
||||
grep(/^date: (.*?);/) { Time.parse($1).strftime("%Y-%m-%d %H:%M:%S") }.
|
||||
sort.
|
||||
last
|
||||
end
|
||||
|
||||
# Return a string representing the branch that the sandbox
|
||||
# relative to <tt>:local</tt> contains.
|
||||
def current_branch
|
||||
return @current_branch if @current_branch
|
||||
configuration.logger.debug "determining current_branch..."
|
||||
@current_branch = cvs_branch(cvs_local)
|
||||
end
|
||||
|
||||
# Check out (on all servers associated with the current task) the latest
|
||||
# revision, using a branch if necessary. Uses the given actor instance
|
||||
# to execute the command.
|
||||
def checkout(actor)
|
||||
cvs = configuration[:cvs] || "cvs"
|
||||
cvs_rsh = configuration[:cvs_rsh] || ENV['CVS_RSH'] || "ssh"
|
||||
|
||||
if "HEAD" == configuration.branch then
|
||||
branch_option = ""
|
||||
else
|
||||
branch_option = "-r #{configuration.branch}"
|
||||
end
|
||||
|
||||
command = <<-CMD
|
||||
cd #{configuration.releases_path};
|
||||
CVS_RSH="#{cvs_rsh}" #{cvs} -d #{configuration.repository} -Q co -D "#{configuration.revision}" #{branch_option} -d #{File.basename(actor.release_path)} #{actor.application};
|
||||
CMD
|
||||
|
||||
run_checkout(actor, command) do |ch, stream, out|
|
||||
prefix = "#{stream} :: #{ch[:host]}"
|
||||
actor.logger.info out, prefix
|
||||
if out =~ %r{password:}
|
||||
actor.logger.info "CVS is asking for a password", prefix
|
||||
ch.send_data "#{actor.password}\n"
|
||||
elsif out =~ %r{^Enter passphrase}
|
||||
message = "CVS needs your key's passphrase and cannot proceed"
|
||||
actor.logger.info message, prefix
|
||||
raise message
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Look for a 'CVS/Tag' file in the path. If this file exists
|
||||
# and contains a Line starting with 'T' then this CVS sandbox is
|
||||
# 'tagged' with a branch. In the default case return 'HEAD'
|
||||
def cvs_branch(path)
|
||||
branch = "HEAD"
|
||||
branch_file = File.join(path || ".", "CVS", "Tag")
|
||||
if File.exists?(branch_file) then
|
||||
File.open(branch_file) do |f|
|
||||
possible_branch = f.find { |l| l =~ %r{^T} }
|
||||
branch = possible_branch.strip[1..-1] if possible_branch
|
||||
end
|
||||
end
|
||||
branch
|
||||
end
|
||||
|
||||
def cvs_log(path,branch)
|
||||
`cd #{path || "."} && cvs -d #{configuration.repository} -q log -N -r#{branch}`
|
||||
end
|
||||
|
||||
def cvs_local
|
||||
configuration.local || "."
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
|
@ -1,27 +0,0 @@
|
|||
require 'capistrano/scm/base'
|
||||
|
||||
module Capistrano
|
||||
module SCM
|
||||
|
||||
# An SCM module for using darcs as your source control tool. Use it by
|
||||
# specifying the following line in your configuration:
|
||||
#
|
||||
# set :scm, :darcs
|
||||
#
|
||||
# Also, this module accepts a <tt>:darcs</tt> configuration variable,
|
||||
# which (if specified) will be used as the full path to the darcs
|
||||
# executable on the remote machine:
|
||||
#
|
||||
# set :darcs, "/opt/local/bin/darcs"
|
||||
class Darcs < Base
|
||||
# Check out (on all servers associated with the current task) the latest
|
||||
# revision. Uses the given actor instance to execute the command.
|
||||
def checkout(actor)
|
||||
darcs = configuration[:darcs] ? configuration[:darcs] : "darcs"
|
||||
revision = configuration[:revision] ? %(--to-match "#{configuration.revision}") : ""
|
||||
run_checkout(actor, "#{darcs} get -q --set-scripts-executable #{revision} #{configuration.repository} #{actor.release_path};")
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
|
@ -1,83 +0,0 @@
|
|||
require 'capistrano/scm/base'
|
||||
|
||||
module Capistrano
|
||||
module SCM
|
||||
|
||||
# An SCM module for using Mercurial as your source control tool.
|
||||
# You can use it by placing the following line in your configuration:
|
||||
#
|
||||
# set :scm, :mercurial
|
||||
#
|
||||
# Also, this module accepts a <tt>:mercurial</tt> configuration variable,
|
||||
# which (if specified) will be used as the full path to the hg
|
||||
# executable on the remote machine:
|
||||
#
|
||||
# set :mercurial, "/usr/local/bin/hg"
|
||||
class Mercurial < Base
|
||||
# Return a string identifying the tip changeset in the mercurial
|
||||
# repository. Note that this fetches the tip changeset from the
|
||||
# local repository, but capistrano will deploy from your _remote_
|
||||
# repository. So just make sure your local repository is synchronized
|
||||
# with your remote one.
|
||||
def latest_revision
|
||||
`#{mercurial} tip --template '{node|short}'`
|
||||
end
|
||||
|
||||
# Return the changeset currently deployed.
|
||||
def current_revision(actor)
|
||||
# NOTE:
|
||||
# copied almost verbatim from svn except its not cast into an int
|
||||
# this should be the same for almost _every_ scm can we take it out
|
||||
# of SCM-specific code?
|
||||
latest = actor.releases.last
|
||||
grep = %(grep " #{latest}$" #{configuration.deploy_to}/revisions.log)
|
||||
result = ""
|
||||
actor.run(grep, :once => true) do |ch, str, out|
|
||||
result << out if str == :out
|
||||
raise "could not determine current changeset" if str == :err
|
||||
end
|
||||
|
||||
date, time, user, changeset, dir = result.split
|
||||
raise "current changeset not found in revisions.log" unless dir == latest
|
||||
changeset
|
||||
end
|
||||
|
||||
# Return a string containing the diff between the two changesets. +from+
|
||||
# and +to+ may be in any format that mercurial recognizes as a valid
|
||||
# changeset. If +from+ is +nil+, it defaults to the last deployed
|
||||
# changeset. If +to+ is +nil+, it defaults to the current working
|
||||
# directory.
|
||||
def diff(actor, from = current_revision(actor), to = nil)
|
||||
cmd = "#{mercurial} diff -r #{from}"
|
||||
cmd << " -r #{to}" if to
|
||||
`#{cmd}`
|
||||
end
|
||||
|
||||
# Check out (on all servers associated with the current task) the latest
|
||||
# revision. Uses the given actor instance to execute the command. If
|
||||
# mercurial asks for a password this will automatically provide it
|
||||
# (assuming the requested password is the same as the password for
|
||||
# logging into the remote server.) If ssh repository method is used,
|
||||
# authorized keys must be setup.
|
||||
def checkout(actor)
|
||||
command = "#{mercurial} clone -U #{configuration.repository} " +
|
||||
"#{actor.release_path} && " +
|
||||
"#{mercurial} -R #{actor.release_path} update " +
|
||||
"-C #{configuration.revision} &&"
|
||||
run_checkout(actor, command, &hg_stream_handler(actor))
|
||||
end
|
||||
|
||||
private
|
||||
def mercurial
|
||||
configuration[:mercurial] || "hg"
|
||||
end
|
||||
|
||||
def hg_stream_handler(actor)
|
||||
Proc.new do |ch, stream, out|
|
||||
prefix = "#{stream} :: #{ch[:host]}"
|
||||
actor.logger.info out, prefix
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,139 +0,0 @@
|
|||
require 'capistrano/scm/base'
|
||||
|
||||
module Capistrano
|
||||
module SCM
|
||||
|
||||
# An SCM module for using perforce as your source control tool.
|
||||
# This module can explicitly selected by placing the following line
|
||||
# in your configuration:
|
||||
#
|
||||
# set :scm, :perforce
|
||||
#
|
||||
# Also, this module accepts a <tt>:p4</tt> configuration variable,
|
||||
# which (if specified) will be used as the full path to the p4
|
||||
# executable on the remote machine:
|
||||
#
|
||||
# set :p4, "/usr/local/bin/p4"
|
||||
#
|
||||
# This module accepts another <tt>:p4sync_flags</tt> configuration
|
||||
# variable, which (if specified) can add extra options. This setting
|
||||
# defaults to the value "-f" which forces resynchronization.
|
||||
#
|
||||
# set :p4sync_flags, "-f"
|
||||
#
|
||||
# This module accepts another <tt>:p4client_root</tt> configuration
|
||||
# variable to handle mapping adjustments. Perforce doesn't have the
|
||||
# ability to sync to a specific directory (e.g. the release_path); the
|
||||
# location being synced to is defined by the client-spec. As such, we
|
||||
# sync the client-spec (defined by <tt>p4client</tt> and then copy from
|
||||
# the determined root of the client-spec mappings to the release_path.
|
||||
# In the unlikely event that your client-spec mappings introduces
|
||||
# directory structure above the rails structure, you can override the
|
||||
# may need to specify the directory
|
||||
#
|
||||
# set :p4client_root, "/user/rmcmahon/project1/code"
|
||||
#
|
||||
# Finally, the module accepts a <tt>p4diff2_options</tt> configuration
|
||||
# variable. This can be used to manipulate the output when running a
|
||||
# diff between what is deployed, and another revision. This option
|
||||
# defaults to "-u". Run 'p4 help diff2' for other options.
|
||||
#
|
||||
class Perforce < Base
|
||||
|
||||
def latest_revision
|
||||
configuration.logger.debug "querying latest revision..." unless @latest_revision
|
||||
@latest_revision = `#{local_p4} counter change`.strip
|
||||
@latest_revision
|
||||
end
|
||||
|
||||
# Return the number of the revision currently deployed.
|
||||
def current_revision(actor)
|
||||
latest = actor.releases.last
|
||||
grep = %(grep " #{latest}$" #{configuration.deploy_to}/revisions.log)
|
||||
result = ""
|
||||
actor.run(grep, :once => true) do |ch, str, out|
|
||||
result << out if str == :out
|
||||
raise "could not determine current revision" if str == :err
|
||||
end
|
||||
|
||||
date, time, user, rev, dir = result.split
|
||||
raise "current revision not found in revisions.log" unless dir == latest
|
||||
rev.to_i
|
||||
end
|
||||
|
||||
# Return a string containing the diff between the two revisions. +from+
|
||||
# and +to+ may be in any format that p4 recognizes as a valid revision
|
||||
# identifiers. If +from+ is +nil+, it defaults to the last deployed
|
||||
# revision. If +to+ is +nil+, it defaults to #head.
|
||||
def diff(actor, from=nil, to=nil)
|
||||
from ||= "@#{current_revision(actor)}"
|
||||
to ||= "#head"
|
||||
p4client = configuration[:p4client]
|
||||
p4diff2_options = configuration[:p4diff2_options]||"-u -db"
|
||||
`#{local_p4} diff2 #{p4diff2_options} //#{p4client}/...#{from} //#{p4client}/...#{to}`
|
||||
end
|
||||
|
||||
# Syncronizes (on all servers associated with the current task) the head
|
||||
# revision of the code. Uses the given actor instance to execute the command.
|
||||
#
|
||||
def checkout(actor)
|
||||
p4sync_flags = configuration[:p4sync_flags] || "-f"
|
||||
p4client_root = configuration[:p4client_root] || "`#{remote_p4} client -o | grep ^Root | cut -f2`"
|
||||
command = "#{remote_p4} sync #{p4sync_flags} && cp -rf #{p4client_root} #{actor.release_path};"
|
||||
run_checkout(actor, command, &p4_stream_handler(actor))
|
||||
end
|
||||
|
||||
def update(actor)
|
||||
raise "#{self.class} doesn't support update(actor)"
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def local_p4
|
||||
add_standard_p4_options('p4')
|
||||
end
|
||||
|
||||
def remote_p4
|
||||
p4_cmd = configuration[:p4] || 'p4'
|
||||
add_standard_p4_options(p4_cmd)
|
||||
end
|
||||
|
||||
def add_standard_p4_options(p4_location)
|
||||
check_settings
|
||||
p4_cmd = p4_location
|
||||
p4_cmd = "#{p4_cmd} -p #{configuration[:p4port]}" if configuration[:p4port]
|
||||
p4_cmd = "#{p4_cmd} -u #{configuration[:p4user]}" if configuration[:p4user]
|
||||
p4_cmd = "#{p4_cmd} -P #{configuration[:p4passwd]}" if configuration[:p4passwd]
|
||||
p4_cmd = "#{p4_cmd} -c #{configuration[:p4client]}" if configuration[:p4client]
|
||||
p4_cmd
|
||||
end
|
||||
|
||||
def check_settings
|
||||
check_setting(:p4port, "Add set :p4port, <your perforce server details e.g. my.p4.server:1666> to deploy.rb")
|
||||
check_setting(:p4user, "Add set :p4user, <your production build username> to deploy.rb")
|
||||
check_setting(:p4passwd, "Add set :p4passwd, <your build user password> to deploy.rb")
|
||||
check_setting(:p4client, "Add set :p4client, <your client-spec name> to deploy.rb")
|
||||
end
|
||||
|
||||
def check_setting(p4setting, message)
|
||||
raise "#{p4setting} is not configured. #{message}" unless configuration[p4setting]
|
||||
end
|
||||
|
||||
def p4_stream_handler(actor)
|
||||
Proc.new do |ch, stream, out|
|
||||
prefix = "#{stream} :: #{ch[:host]}"
|
||||
actor.logger.info out, prefix
|
||||
if out =~ /\(P4PASSWD\) invalid or unset\./i
|
||||
raise "p4passwd is incorrect or unset"
|
||||
elsif out =~ /Can.t create a new user.*/i
|
||||
raise "p4user is incorrect or unset"
|
||||
elsif out =~ /Perforce client error\:/i
|
||||
raise "p4port is incorrect or unset"
|
||||
elsif out =~ /Client \'[\w\-\_\.]+\' unknown.*/i
|
||||
raise "p4client is incorrect or unset"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,127 +0,0 @@
|
|||
require 'capistrano/scm/base'
|
||||
|
||||
module Capistrano
|
||||
module SCM
|
||||
|
||||
# An SCM module for using subversion as your source control tool. This
|
||||
# module is used by default, but you can explicitly specify it by
|
||||
# placing the following line in your configuration:
|
||||
#
|
||||
# set :scm, :subversion
|
||||
#
|
||||
# Also, this module accepts a <tt>:svn</tt> configuration variable,
|
||||
# which (if specified) will be used as the full path to the svn
|
||||
# executable on the remote machine:
|
||||
#
|
||||
# set :svn, "/opt/local/bin/svn"
|
||||
class Subversion < Base
|
||||
# Return an integer identifying the last known revision in the svn
|
||||
# repository. (This integer is currently the revision number.)
|
||||
def latest_revision
|
||||
@latest_revision ||= begin
|
||||
configuration.logger.debug "querying latest revision..."
|
||||
match = svn_log(configuration.repository).scan(/r(\d+)/).first or
|
||||
raise "Could not determine latest revision"
|
||||
match.first
|
||||
end
|
||||
end
|
||||
|
||||
# Return the number of the revision currently deployed.
|
||||
def current_revision(actor)
|
||||
latest = actor.releases.last
|
||||
grep = %(grep " #{latest}$" #{configuration.deploy_to}/revisions.log)
|
||||
result = ""
|
||||
actor.run(grep, :once => true) do |ch, str, out|
|
||||
result << out if str == :out
|
||||
raise "could not determine current revision" if str == :err
|
||||
end
|
||||
|
||||
date, time, user, rev, dir = result.split
|
||||
raise "current revision not found in revisions.log" unless dir == latest
|
||||
|
||||
rev.to_i
|
||||
end
|
||||
|
||||
# Return a string containing the diff between the two revisions. +from+
|
||||
# and +to+ may be in any format that svn recognizes as a valid revision
|
||||
# identifier. If +from+ is +nil+, it defaults to the last deployed
|
||||
# revision. If +to+ is +nil+, it defaults to HEAD.
|
||||
def diff(actor, from=nil, to=nil)
|
||||
from ||= current_revision(actor)
|
||||
to ||= "HEAD"
|
||||
|
||||
`svn diff #{authorization} #{configuration.repository}@#{from} #{configuration.repository}@#{to}`
|
||||
end
|
||||
|
||||
# Check out (on all servers associated with the current task) the latest
|
||||
# revision. Uses the given actor instance to execute the command. If
|
||||
# svn asks for a password this will automatically provide it (assuming
|
||||
# the requested password is the same as the password for logging into the
|
||||
# remote server.)
|
||||
def checkout(actor)
|
||||
op = configuration[:checkout] || "co"
|
||||
command = "#{svn} #{op} #{authorization} -q -r#{configuration.revision} #{configuration.repository} #{actor.release_path} &&"
|
||||
run_checkout(actor, command, &svn_stream_handler(actor))
|
||||
end
|
||||
|
||||
# Update the current release in-place. This assumes that the original
|
||||
# deployment was made using checkout, and not something like export.
|
||||
def update(actor)
|
||||
command = "cd #{actor.current_path} && #{svn} up -q &&"
|
||||
run_update(actor, command, &svn_stream_handler(actor))
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def svn
|
||||
configuration[:svn] || "svn"
|
||||
end
|
||||
|
||||
def authorization
|
||||
username = configuration[:svn_username] ? "--username #{configuration[:svn_username]}" : ""
|
||||
password = configuration[:svn_password] ? "--password #{configuration[:svn_password]}" : ""
|
||||
"--no-auth-cache #{username} #{password}"
|
||||
end
|
||||
|
||||
def svn_log(path)
|
||||
`svn log #{authorization} -q --limit 1 #{path}`
|
||||
end
|
||||
|
||||
def svn_password
|
||||
configuration[:svn_password] || configuration[:password]
|
||||
end
|
||||
|
||||
def svn_passphrase
|
||||
configuration[:svn_passphrase] || svn_password
|
||||
end
|
||||
|
||||
def svn_stream_handler(actor)
|
||||
Proc.new do |ch, stream, out|
|
||||
prefix = "#{stream} :: #{ch[:host]}"
|
||||
actor.logger.info out, prefix
|
||||
if out =~ /\bpassword.*:/i
|
||||
actor.logger.info "subversion is asking for a password", prefix
|
||||
ch.send_data "#{svn_password}\n"
|
||||
elsif out =~ %r{\(yes/no\)}
|
||||
actor.logger.info "subversion is asking whether to connect or not",
|
||||
prefix
|
||||
ch.send_data "yes\n"
|
||||
elsif out =~ %r{passphrase}i
|
||||
message = "subversion needs your key's passphrase"
|
||||
actor.logger.info message, prefix
|
||||
ch.send_data "#{svn_passphrase}\n"
|
||||
elsif out =~ %r{The entry \'(\w+)\' is no longer a directory}
|
||||
message = "subversion can't update because directory '#{$1}' was replaced. Please add it to svn:ignore."
|
||||
actor.logger.info message, prefix
|
||||
raise message
|
||||
elsif out =~ %r{accept \(t\)emporarily}
|
||||
message = "accepting certificate temporarily"
|
||||
actor.logger.info message, prefix
|
||||
ch.send_data "t\n"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
|
@ -1,20 +1,15 @@
|
|||
begin
|
||||
require 'capistrano/version'
|
||||
require 'net/sftp'
|
||||
require 'net/sftp/version'
|
||||
sftp_version = [Net::SFTP::Version::MAJOR, Net::SFTP::Version::MINOR, Net::SFTP::Version::TINY]
|
||||
required_version = [1,1,0]
|
||||
if !Capistrano::Version.check(required_version, sftp_version)
|
||||
warn "You have Net::SFTP #{sftp_version.join(".")}, but you need at least #{required_version.join(".")}. Net::SFTP will not be used."
|
||||
Capistrano::SFTP = false
|
||||
else
|
||||
Capistrano::SFTP = true
|
||||
end
|
||||
rescue LoadError
|
||||
Capistrano::SFTP = false
|
||||
end
|
||||
require 'net/sftp'
|
||||
|
||||
module Capistrano
|
||||
unless ENV['SKIP_VERSION_CHECK']
|
||||
require 'capistrano/version'
|
||||
require 'net/sftp/version'
|
||||
sftp_version = [Net::SFTP::Version::MAJOR, Net::SFTP::Version::MINOR, Net::SFTP::Version::TINY]
|
||||
required_version = [1,1,0]
|
||||
if !Capistrano::Version.check(required_version, sftp_version)
|
||||
raise "You have Net::SFTP #{sftp_version.join(".")}, but you need at least #{required_version.join(".")}. Net::SFTP will not be used."
|
||||
end
|
||||
end
|
||||
|
||||
# This class encapsulates a single file transfer to be performed in parallel
|
||||
# across multiple machines, using the SFTP protocol.
|
||||
|
|
|
@ -2,10 +2,8 @@ require "#{File.dirname(__FILE__)}/../utils"
|
|||
require 'capistrano/configuration/execution'
|
||||
require 'capistrano/task_definition'
|
||||
|
||||
class ConfigurationNamespacesDSLTest < Test::Unit::TestCase
|
||||
class ConfigurationExecutionTest < Test::Unit::TestCase
|
||||
class MockConfig
|
||||
include Mocha::AutoVerify
|
||||
|
||||
attr_reader :tasks, :namespaces, :fully_qualified_name, :parent
|
||||
attr_reader :state, :original_initialize_called
|
||||
attr_accessor :logger
|
||||
|
@ -17,14 +15,14 @@ class ConfigurationNamespacesDSLTest < Test::Unit::TestCase
|
|||
@state = {}
|
||||
@fully_qualified_name = options[:fqn]
|
||||
@parent = options[:parent]
|
||||
@logger = stub(:debug => nil, :info => nil, :important => nil)
|
||||
@logger = options.delete(:logger)
|
||||
end
|
||||
|
||||
include Capistrano::Configuration::Execution
|
||||
end
|
||||
|
||||
def setup
|
||||
@config = MockConfig.new
|
||||
@config = MockConfig.new(:logger => stub(:debug => nil, :info => nil, :important => nil))
|
||||
end
|
||||
|
||||
def test_initialize_should_initialize_collections
|
||||
|
|
|
@ -1,35 +1,11 @@
|
|||
$:.unshift File.dirname(__FILE__) + "/../lib"
|
||||
|
||||
require 'test/unit'
|
||||
require 'capistrano/configuration'
|
||||
require "#{File.dirname(__FILE__)}/utils"
|
||||
|
||||
class ConfigurationTest < Test::Unit::TestCase
|
||||
def setup
|
||||
@config = Capistrano::Configuration.new
|
||||
end
|
||||
|
||||
def test_task_without_options
|
||||
block = Proc.new { }
|
||||
@config.task :hello, &block
|
||||
assert_equal 1, @config.actor.tasks.length
|
||||
assert_equal :hello, @config.actor.tasks[0][0]
|
||||
assert_equal({}, @config.actor.tasks[0][1])
|
||||
assert_equal block, @config.actor.tasks[0][2]
|
||||
end
|
||||
|
||||
def test_task_with_options
|
||||
block = Proc.new { }
|
||||
@config.task :hello, :roles => :app, &block
|
||||
assert_equal 1, @config.actor.tasks.length
|
||||
assert_equal :hello, @config.actor.tasks[0][0]
|
||||
assert_equal({:roles => :app}, @config.actor.tasks[0][1])
|
||||
assert_equal block, @config.actor.tasks[0][2]
|
||||
end
|
||||
|
||||
def test_task_description
|
||||
block = Proc.new { }
|
||||
@config.desc "A sample task"
|
||||
@config.task :hello, &block
|
||||
assert_equal "A sample task", @config.actor.tasks[0][1][:desc]
|
||||
def test_flunk
|
||||
flunk
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,196 +0,0 @@
|
|||
$:.unshift File.dirname(__FILE__) + "/../../lib"
|
||||
|
||||
require File.dirname(__FILE__) + "/../utils"
|
||||
require 'test/unit'
|
||||
require 'capistrano/scm/cvs'
|
||||
|
||||
class ScmCvsTest < Test::Unit::TestCase
|
||||
class CvsTest < Capistrano::SCM::Cvs
|
||||
attr_accessor :story
|
||||
attr_reader :last_path
|
||||
|
||||
def cvs_log(path,branch)
|
||||
@last_path = path
|
||||
story.shift
|
||||
end
|
||||
|
||||
def cvs_branch(path)
|
||||
"deploy-me"
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class MockChannel
|
||||
attr_reader :sent_data
|
||||
|
||||
def send_data(data)
|
||||
@sent_data ||= []
|
||||
@sent_data << data
|
||||
end
|
||||
|
||||
def [](name)
|
||||
"value"
|
||||
end
|
||||
end
|
||||
|
||||
class MockActor
|
||||
attr_reader :command
|
||||
attr_reader :channels
|
||||
attr_accessor :story
|
||||
|
||||
def initialize(config)
|
||||
@config = config
|
||||
end
|
||||
|
||||
def run(command)
|
||||
@command = command
|
||||
@channels ||= []
|
||||
@channels << MockChannel.new
|
||||
story.each { |stream, line| yield @channels.last, stream, line }
|
||||
end
|
||||
|
||||
def release_path
|
||||
(@config[:now] || Time.now.utc).strftime("%Y%m%d%H%M%S")
|
||||
end
|
||||
|
||||
def method_missing(sym, *args)
|
||||
@config.send(sym, *args)
|
||||
end
|
||||
end
|
||||
|
||||
def setup
|
||||
@config = MockConfiguration.new
|
||||
@config[:repository] = ":ext:joetester@rubyforge.org:/hello/world"
|
||||
@config[:cvs] = "/path/to/cvs"
|
||||
@config[:password] = "chocolatebrownies"
|
||||
@config[:now] = Time.utc(2005,8,24,12,0,0)
|
||||
@scm = CvsTest.new(@config)
|
||||
@actor = MockActor.new(@config)
|
||||
@log_msg = <<MSG.strip
|
||||
RCS file: /var/cvs/copland/copland/LICENSE,v
|
||||
Working file: LICENSE
|
||||
head: 1.1
|
||||
branch:
|
||||
locks: strict
|
||||
access list:
|
||||
keyword substitution: kv
|
||||
total revisions: 1; selected revisions: 1
|
||||
description:
|
||||
----------------------------
|
||||
revision 1.1
|
||||
date: 2004/08/29 04:23:36; author: minam; state: Exp;
|
||||
New implementation.
|
||||
=============================================================================
|
||||
|
||||
RCS file: /var/cvs/copland/copland/Rakefile,v
|
||||
Working file: Rakefile
|
||||
head: 1.7
|
||||
branch:
|
||||
locks: strict
|
||||
access list:
|
||||
keyword substitution: kv
|
||||
total revisions: 7; selected revisions: 1
|
||||
description:
|
||||
----------------------------
|
||||
revision 1.7
|
||||
date: 2004/09/15 16:35:01; author: minam; state: Exp; lines: +2 -1
|
||||
Rakefile now publishes package documentation from doc/packages instead of
|
||||
doc/packrat. Updated "latest updates" in manual.
|
||||
=============================================================================
|
||||
|
||||
RCS file: /var/cvs/copland/copland/TODO,v
|
||||
Working file: TODO
|
||||
head: 1.18
|
||||
branch:
|
||||
locks: strict
|
||||
access list:
|
||||
keyword substitution: kv
|
||||
total revisions: 18; selected revisions: 1
|
||||
description:
|
||||
----------------------------
|
||||
revision 1.18
|
||||
date: 2004/10/12 02:21:02; author: minam; state: Exp; lines: +4 -1
|
||||
Added RubyConf 2004 presentation.
|
||||
=============================================================================
|
||||
|
||||
RCS file: /var/cvs/copland/copland/Attic/build-gemspec.rb,v
|
||||
Working file: build-gemspec.rb
|
||||
head: 1.5
|
||||
branch:
|
||||
locks: strict
|
||||
access list:
|
||||
keyword substitution: kv
|
||||
total revisions: 5; selected revisions: 1
|
||||
description:
|
||||
----------------------------
|
||||
revision 1.5
|
||||
date: 2004/08/29 04:10:17; author: minam; state: dead; lines: +0 -0
|
||||
Here we go -- point of no return. Deleting existing implementation to make
|
||||
way for new implementation.
|
||||
=============================================================================
|
||||
|
||||
RCS file: /var/cvs/copland/copland/copland.gemspec,v
|
||||
Working file: copland.gemspec
|
||||
head: 1.12
|
||||
branch:
|
||||
locks: strict
|
||||
access list:
|
||||
keyword substitution: kv
|
||||
total revisions: 13; selected revisions: 1
|
||||
description:
|
||||
----------------------------
|
||||
revision 1.12
|
||||
date: 2004/09/11 21:45:58; author: minam; state: Exp; lines: +4 -4
|
||||
Minor change in how version is communicated to gemspec.
|
||||
=============================================================================
|
||||
MSG
|
||||
@scm.story = [ @log_msg ]
|
||||
end
|
||||
|
||||
def test_latest_revision
|
||||
@config[:local] = "/hello/world"
|
||||
@scm.story = [ @log_msg ]
|
||||
assert_equal "2004-10-12 02:21:02", @scm.latest_revision
|
||||
assert_equal "/hello/world", @scm.last_path
|
||||
end
|
||||
|
||||
def test_latest_with_default_local
|
||||
@config[:local] = nil
|
||||
@scm.story = [ @log_msg ]
|
||||
assert_equal "2004-10-12 02:21:02", @scm.latest_revision
|
||||
assert_equal ".", @scm.last_path
|
||||
end
|
||||
|
||||
def test_checkout
|
||||
@actor.story = []
|
||||
assert_nothing_raised { @scm.checkout(@actor) }
|
||||
assert_nil @actor.channels.last.sent_data
|
||||
assert_match %r{/path/to/cvs}, @actor.command
|
||||
end
|
||||
|
||||
def test_checkout_needs_ssh_password
|
||||
@actor.story = [[:out, "joetester@rubyforge.org's password: "]]
|
||||
assert_nothing_raised { @scm.checkout(@actor) }
|
||||
assert_equal ["chocolatebrownies\n"], @actor.channels.last.sent_data
|
||||
end
|
||||
|
||||
def test_current_branch
|
||||
assert_equal "deploy-me", @scm.current_branch
|
||||
end
|
||||
|
||||
def test_default_current_branch
|
||||
@config[:branch] = "default-branch"
|
||||
@scm = CvsTest.new(@config)
|
||||
assert_equal "default-branch", @scm.current_branch
|
||||
end
|
||||
|
||||
def test_default_local
|
||||
@config = MockConfiguration.new
|
||||
@config[:repository] = ":ext:joetester@rubyforge.org:/hello/world"
|
||||
@config[:cvs] = "/path/to/cvs"
|
||||
@config[:password] = "chocolatebrownies"
|
||||
@config[:now] = Time.utc(2005,8,24,12,0,0)
|
||||
@scm = CvsTest.new(@config)
|
||||
assert_equal ".", @scm.configuration.local
|
||||
end
|
||||
end
|
|
@ -1,137 +0,0 @@
|
|||
$:.unshift File.dirname(__FILE__) + "/../../lib"
|
||||
|
||||
require File.dirname(__FILE__) + "/../utils"
|
||||
require 'test/unit'
|
||||
require 'capistrano/scm/subversion'
|
||||
|
||||
class ScmSubversionTest < Test::Unit::TestCase
|
||||
class SubversionTest < Capistrano::SCM::Subversion
|
||||
attr_accessor :story
|
||||
attr_reader :last_path
|
||||
|
||||
def svn_log(path)
|
||||
@last_path = path
|
||||
story.shift
|
||||
end
|
||||
end
|
||||
|
||||
class MockChannel
|
||||
attr_reader :sent_data
|
||||
|
||||
def send_data(data)
|
||||
@sent_data ||= []
|
||||
@sent_data << data
|
||||
end
|
||||
|
||||
def [](name)
|
||||
"value"
|
||||
end
|
||||
end
|
||||
|
||||
class MockActor
|
||||
attr_reader :command
|
||||
attr_reader :channels
|
||||
attr_accessor :story
|
||||
|
||||
def initialize(config)
|
||||
@config = config
|
||||
end
|
||||
|
||||
def run(command)
|
||||
@command = command
|
||||
@channels ||= []
|
||||
@channels << MockChannel.new
|
||||
story.each { |stream, line| yield @channels.last, stream, line }
|
||||
end
|
||||
|
||||
def method_missing(sym, *args)
|
||||
@config.send(sym, *args)
|
||||
end
|
||||
end
|
||||
|
||||
def setup
|
||||
@config = MockConfiguration.new
|
||||
@config[:current_path] = "/mwa/ha/ha/current"
|
||||
@config[:repository] = "/hello/world"
|
||||
@config[:svn] = "/path/to/svn"
|
||||
@config[:password] = "chocolatebrownies"
|
||||
@scm = SubversionTest.new(@config)
|
||||
@actor = MockActor.new(@config)
|
||||
@log_msg = <<MSG.strip
|
||||
------------------------------------------------------------------------
|
||||
r1967 | minam | 2005-08-03 06:59:03 -0600 (Wed, 03 Aug 2005) | 2 lines
|
||||
|
||||
Initial commit of the new capistrano utility
|
||||
|
||||
------------------------------------------------------------------------
|
||||
MSG
|
||||
@scm.story = [ @log_msg ]
|
||||
end
|
||||
|
||||
def test_latest_revision
|
||||
@scm.story = [ @log_msg ]
|
||||
assert_equal "1967", @scm.latest_revision
|
||||
assert_equal "/hello/world", @scm.last_path
|
||||
end
|
||||
|
||||
def test_checkout
|
||||
@actor.story = []
|
||||
assert_nothing_raised { @scm.checkout(@actor) }
|
||||
assert_nil @actor.channels.last.sent_data
|
||||
assert_match %r{/path/to/svn\b.*\bco\b.* -q}, @actor.command
|
||||
end
|
||||
|
||||
def test_checkout_via_export
|
||||
@actor.story = []
|
||||
@config[:checkout] = "export"
|
||||
assert_nothing_raised { @scm.checkout(@actor) }
|
||||
assert_nil @actor.channels.last.sent_data
|
||||
assert_match %r{/path/to/svn\b.*\bexport\b.* -q}, @actor.command
|
||||
end
|
||||
|
||||
def test_update
|
||||
@actor.story = []
|
||||
assert_nothing_raised { @scm.update(@actor) }
|
||||
assert_nil @actor.channels.last.sent_data
|
||||
assert_match %r{/path/to/svn\b.*\bup\b}, @actor.command
|
||||
end
|
||||
|
||||
def test_checkout_needs_ssh_password
|
||||
@actor.story = [[:out, "Password: "]]
|
||||
assert_nothing_raised { @scm.checkout(@actor) }
|
||||
assert_equal ["chocolatebrownies\n"], @actor.channels.last.sent_data
|
||||
end
|
||||
|
||||
def test_checkout_needs_http_password
|
||||
@actor.story = [[:out, "Password for (something): "]]
|
||||
assert_nothing_raised { @scm.checkout(@actor) }
|
||||
assert_equal ["chocolatebrownies\n"], @actor.channels.last.sent_data
|
||||
end
|
||||
|
||||
def test_checkout_needs_https_certificate
|
||||
@actor.story = [[:out, "(R)eject, accept (t)emporarily or accept (p)ermanently? "]]
|
||||
assert_nothing_raised { @scm.checkout(@actor) }
|
||||
assert_equal ["t\n"], @actor.channels.last.sent_data
|
||||
end
|
||||
|
||||
def test_checkout_needs_alternative_ssh_password
|
||||
@actor.story = [[:out, "someone's password: "]]
|
||||
assert_nothing_raised { @scm.checkout(@actor) }
|
||||
assert_equal ["chocolatebrownies\n"], @actor.channels.last.sent_data
|
||||
end
|
||||
|
||||
def test_svn_password
|
||||
@config[:svn_password] = "butterscotchcandies"
|
||||
@actor.story = [[:out, "Password: "]]
|
||||
assert_nothing_raised { @scm.checkout(@actor) }
|
||||
assert_equal ["butterscotchcandies\n"], @actor.channels.last.sent_data
|
||||
end
|
||||
|
||||
def test_svn_username
|
||||
@actor.story = []
|
||||
@config[:svn_username] = "turtledove"
|
||||
assert_nothing_raised { @scm.checkout(@actor) }
|
||||
assert_nil @actor.channels.last.sent_data
|
||||
assert_match %r{/path/to/svn\b.*\bco\b.* --username turtledove}, @actor.command
|
||||
end
|
||||
end
|
Loading…
Add table
Reference in a new issue