mirror of
https://github.com/capistrano/capistrano
synced 2023-03-27 23:21:18 -04:00
Merge pull request #828 from coffeeaddict/decapsulated-scm
Decapsulated scm
This commit is contained in:
commit
f4d2bfe358
9 changed files with 446 additions and 10 deletions
|
@ -5,6 +5,7 @@ Reverse Chronological Order:
|
|||
## master
|
||||
|
||||
* Add a command line option to control role filter (`--roles`) (@andytinycat)
|
||||
* Use an SCM object with a pluggable strategy
|
||||
|
||||
## `3.1.0` (not released)
|
||||
|
||||
|
|
|
@ -1 +1,36 @@
|
|||
load File.expand_path("../tasks/git.rake", __FILE__)
|
||||
|
||||
require 'capistrano/scm'
|
||||
|
||||
class Capistrano::Git < Capistrano::SCM
|
||||
|
||||
# execute git with argument in the context
|
||||
#
|
||||
def git(*args)
|
||||
args.unshift :git
|
||||
context.execute *args
|
||||
end
|
||||
|
||||
# The Capistrano default strategy for git. You should want to use this.
|
||||
module DefaultStrategy
|
||||
def test
|
||||
test! " [ -f #{repo_path}/HEAD ] "
|
||||
end
|
||||
|
||||
def check
|
||||
test! :git, :'ls-remote', repo_url
|
||||
end
|
||||
|
||||
def clone
|
||||
git :clone, '--mirror', repo_url, repo_path
|
||||
end
|
||||
|
||||
def update
|
||||
git :remote, :update
|
||||
end
|
||||
|
||||
def release
|
||||
git :archive, fetch(:branch), '| tar -x -C', release_path
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1 +1,33 @@
|
|||
load File.expand_path("../tasks/hg.rake", __FILE__)
|
||||
|
||||
require 'capistrano/scm'
|
||||
|
||||
class Capistrano::Hg < Capistrano::SCM
|
||||
# execute hg in context with arguments
|
||||
def hg(*args)
|
||||
args.unshift(:hg)
|
||||
context.execute *args
|
||||
end
|
||||
|
||||
module DefaultStrategy
|
||||
def test
|
||||
test! " [ -d #{repo_path}/.hg ] "
|
||||
end
|
||||
|
||||
def check
|
||||
hg "id", repo_url
|
||||
end
|
||||
|
||||
def clone
|
||||
hg "clone", "--noupdate", repo_url, repo_path
|
||||
end
|
||||
|
||||
def update
|
||||
hg "pull"
|
||||
end
|
||||
|
||||
def release
|
||||
hg "archive", release_path, "--rev", fetch(:branch)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
116
lib/capistrano/scm.rb
Normal file
116
lib/capistrano/scm.rb
Normal file
|
@ -0,0 +1,116 @@
|
|||
module Capistrano
|
||||
|
||||
# Base class for SCM strategy providers.
|
||||
#
|
||||
# @abstract
|
||||
#
|
||||
# @attr_reader [Rake] context
|
||||
#
|
||||
# @author Hartog de Mik
|
||||
#
|
||||
class SCM
|
||||
attr_reader :context
|
||||
|
||||
# Provide a wrapper for the SCM that loads a strategy for the user.
|
||||
#
|
||||
# @param [Rake] context The context in which the strategy should run
|
||||
# @param [Module] strategy A module to include into the SCM instance. The
|
||||
# module should provide the abstract methods of Capistrano::SCM
|
||||
#
|
||||
def initialize(context, strategy)
|
||||
@context = context
|
||||
singleton = class << self; self; end
|
||||
singleton.send(:include, strategy)
|
||||
end
|
||||
|
||||
# Call test in context
|
||||
def test!(*args)
|
||||
context.test *args
|
||||
end
|
||||
|
||||
# The repository URL accoriding to the context
|
||||
def repo_url
|
||||
context.repo_url
|
||||
end
|
||||
|
||||
# The repository path accoriding to the context
|
||||
def repo_path
|
||||
context.repo_path
|
||||
end
|
||||
|
||||
# The release path accoriding to the context
|
||||
def release_path
|
||||
context.release_path
|
||||
end
|
||||
|
||||
# Fetch a var from the context
|
||||
# @param [Symbol] variable The variable to fetch
|
||||
# @param [Object] default The default value if not found
|
||||
#
|
||||
def fetch(*args)
|
||||
context.fetch(*args)
|
||||
end
|
||||
|
||||
# @abstract
|
||||
#
|
||||
# Your implementation should check the existance of a cache repository on
|
||||
# the deployment target
|
||||
#
|
||||
# @return [Boolean]
|
||||
#
|
||||
def test
|
||||
raise NotImplementedError.new(
|
||||
"Your SCM strategy module should provide a #test method"
|
||||
)
|
||||
end
|
||||
|
||||
# @abstract
|
||||
#
|
||||
# Your implementation should check if the specified remote-repository is
|
||||
# available.
|
||||
#
|
||||
# @return [Boolean]
|
||||
#
|
||||
def check
|
||||
raise NotImplementedError.new(
|
||||
"Your SCM strategy module should provide a #check method"
|
||||
)
|
||||
end
|
||||
|
||||
# @abstract
|
||||
#
|
||||
# Create a (new) clone of the remote-repository on the deployment target
|
||||
#
|
||||
# @return void
|
||||
#
|
||||
def clone
|
||||
raise NotImplementedError.new(
|
||||
"Your SCM strategy module should provide a #clone method"
|
||||
)
|
||||
end
|
||||
|
||||
# @abstract
|
||||
#
|
||||
# Update the clone on the deployment target
|
||||
#
|
||||
# @return void
|
||||
#
|
||||
def update
|
||||
raise NotImplementedError.new(
|
||||
"Your SCM strategy module should provide a #update method"
|
||||
)
|
||||
end
|
||||
|
||||
# @abstract
|
||||
#
|
||||
# Copy the contents of the cache-repository onto the release path
|
||||
#
|
||||
# @return void
|
||||
#
|
||||
def release
|
||||
raise NotImplementedError.new(
|
||||
"Your SCM strategy module should provide a #release method"
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,5 +1,9 @@
|
|||
namespace :git do
|
||||
|
||||
def strategy
|
||||
@strategy ||= Capistrano::Git.new(self, fetch(:git_strategy, Capistrano::Git::DefaultStrategy))
|
||||
end
|
||||
|
||||
set :git_environmental_variables, ->() {
|
||||
{
|
||||
git_askpass: "/bin/echo",
|
||||
|
@ -21,7 +25,7 @@ namespace :git do
|
|||
fetch(:branch)
|
||||
on release_roles :all do
|
||||
with fetch(:git_environmental_variables) do
|
||||
exit 1 unless test :git, :'ls-remote', repo_url
|
||||
exit 1 unless strategy.check
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -29,12 +33,12 @@ namespace :git do
|
|||
desc 'Clone the repo to the cache'
|
||||
task clone: :'git:wrapper' do
|
||||
on release_roles :all do
|
||||
if test " [ -f #{repo_path}/HEAD ] "
|
||||
if strategy.test
|
||||
info t(:mirror_exists, at: repo_path)
|
||||
else
|
||||
within deploy_path do
|
||||
with fetch(:git_environmental_variables) do
|
||||
execute :git, :clone, '--mirror', repo_url, repo_path
|
||||
strategy.clone
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -46,7 +50,7 @@ namespace :git do
|
|||
on release_roles :all do
|
||||
within repo_path do
|
||||
capturing_revisions do
|
||||
execute :git, :remote, :update
|
||||
strategy.update
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -58,7 +62,7 @@ namespace :git do
|
|||
with fetch(:git_environmental_variables) do
|
||||
within repo_path do
|
||||
execute :mkdir, '-p', release_path
|
||||
execute :git, :archive, fetch(:branch), '| tar -x -C', release_path
|
||||
strategy.release
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,19 +1,23 @@
|
|||
namespace :hg do
|
||||
def strategy
|
||||
@strategy ||= Capistrano::Hg.new(self, fetch(:hg_strategy, Capistrano::Hg::DefaultStrategy))
|
||||
end
|
||||
|
||||
desc 'Check that the repo is reachable'
|
||||
task :check do
|
||||
on release_roles :all do
|
||||
execute "hg", "id", repo_url
|
||||
strategy.check
|
||||
end
|
||||
end
|
||||
|
||||
desc 'Clone the repo to the cache'
|
||||
task :clone do
|
||||
on release_roles :all do
|
||||
if test " [ -d #{repo_path}/.hg ] "
|
||||
if strategy.test
|
||||
info t(:mirror_exists, at: repo_path)
|
||||
else
|
||||
within deploy_path do
|
||||
execute "hg", "clone", "--noupdate", repo_url, repo_path
|
||||
strategy.clone
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -23,7 +27,7 @@ namespace :hg do
|
|||
task :update => :'hg:clone' do
|
||||
on release_roles :all do
|
||||
within repo_path do
|
||||
execute "hg", "pull"
|
||||
strategy.update
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -32,7 +36,7 @@ namespace :hg do
|
|||
task :create_release => :'hg:update' do
|
||||
on release_roles :all do
|
||||
within repo_path do
|
||||
execute "hg", "archive", release_path, "--rev", fetch(:branch)
|
||||
strategy.release
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
70
spec/lib/capistrano/git_spec.rb
Normal file
70
spec/lib/capistrano/git_spec.rb
Normal file
|
@ -0,0 +1,70 @@
|
|||
require 'spec_helper'
|
||||
|
||||
require 'capistrano/git'
|
||||
|
||||
module Capistrano
|
||||
describe Git do
|
||||
let(:context) { Class.new.new }
|
||||
subject { Capistrano::Git.new(context, Capistrano::Git::DefaultStrategy) }
|
||||
|
||||
describe "#git" do
|
||||
it "should call execute git in the context, with arguments" do
|
||||
context.expects(:execute).with(:git, :init)
|
||||
subject.git(:init)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe Git::DefaultStrategy do
|
||||
let(:context) { Class.new.new }
|
||||
subject { Capistrano::Git.new(context, Capistrano::Git::DefaultStrategy) }
|
||||
|
||||
describe "#test" do
|
||||
it "should call test for repo HEAD" do
|
||||
context.expects(:repo_path).returns("/path/to/repo")
|
||||
context.expects(:test).with " [ -f /path/to/repo/HEAD ] "
|
||||
|
||||
subject.test
|
||||
end
|
||||
end
|
||||
|
||||
describe "#check" do
|
||||
it "should test the repo url" do
|
||||
context.expects(:repo_url).returns(:url)
|
||||
context.expects(:test).with(:git, :'ls-remote', :url).returns(true)
|
||||
|
||||
subject.check
|
||||
end
|
||||
end
|
||||
|
||||
describe "#clone" do
|
||||
it "should run git clone" do
|
||||
context.expects(:repo_url).returns(:url)
|
||||
context.expects(:repo_path).returns(:path)
|
||||
|
||||
context.expects(:execute).with(:git, :clone, '--mirror', :url, :path)
|
||||
|
||||
subject.clone
|
||||
end
|
||||
end
|
||||
|
||||
describe "#update" do
|
||||
it "should run git update" do
|
||||
context.expects(:execute).with(:git, :remote, :update)
|
||||
|
||||
subject.update
|
||||
end
|
||||
end
|
||||
|
||||
describe "#release" do
|
||||
it "should run git archive" do
|
||||
context.expects(:fetch).returns(:branch)
|
||||
context.expects(:release_path).returns(:path)
|
||||
|
||||
context.expects(:execute).with(:git, :archive, :branch, '| tar -x -C', :path)
|
||||
|
||||
subject.release
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
70
spec/lib/capistrano/hg_spec.rb
Normal file
70
spec/lib/capistrano/hg_spec.rb
Normal file
|
@ -0,0 +1,70 @@
|
|||
require 'spec_helper'
|
||||
|
||||
require 'capistrano/hg'
|
||||
|
||||
module Capistrano
|
||||
describe Hg do
|
||||
let(:context) { Class.new.new }
|
||||
subject { Capistrano::Hg.new(context, Capistrano::Hg::DefaultStrategy) }
|
||||
|
||||
describe "#hg" do
|
||||
it "should call execute hg in the context, with arguments" do
|
||||
context.expects(:execute).with(:hg, :init)
|
||||
subject.hg(:init)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe Hg::DefaultStrategy do
|
||||
let(:context) { Class.new.new }
|
||||
subject { Capistrano::Hg.new(context, Capistrano::Hg::DefaultStrategy) }
|
||||
|
||||
describe "#test" do
|
||||
it "should call test for repo HEAD" do
|
||||
context.expects(:repo_path).returns("/path/to/repo")
|
||||
context.expects(:test).with " [ -d /path/to/repo/.hg ] "
|
||||
|
||||
subject.test
|
||||
end
|
||||
end
|
||||
|
||||
describe "#check" do
|
||||
it "should test the repo url" do
|
||||
context.expects(:repo_url).returns(:url)
|
||||
context.expects(:execute).with(:hg, "id", :url)
|
||||
|
||||
subject.check
|
||||
end
|
||||
end
|
||||
|
||||
describe "#clone" do
|
||||
it "should run hg clone" do
|
||||
context.expects(:repo_url).returns(:url)
|
||||
context.expects(:repo_path).returns(:path)
|
||||
|
||||
context.expects(:execute).with(:hg, "clone", '--noupdate', :url, :path)
|
||||
|
||||
subject.clone
|
||||
end
|
||||
end
|
||||
|
||||
describe "#update" do
|
||||
it "should run hg update" do
|
||||
context.expects(:execute).with(:hg, "pull")
|
||||
|
||||
subject.update
|
||||
end
|
||||
end
|
||||
|
||||
describe "#release" do
|
||||
it "should run hg archive" do
|
||||
context.expects(:fetch).returns(:branch)
|
||||
context.expects(:release_path).returns(:path)
|
||||
|
||||
context.expects(:execute).with(:hg, "archive", :path, "--rev", :branch)
|
||||
|
||||
subject.release
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
104
spec/lib/capistrano/scm_spec.rb
Normal file
104
spec/lib/capistrano/scm_spec.rb
Normal file
|
@ -0,0 +1,104 @@
|
|||
require 'spec_helper'
|
||||
|
||||
require 'capistrano/scm'
|
||||
|
||||
module RaiseNotImplementedMacro
|
||||
def raise_not_implemented_on(method)
|
||||
it "should raise NotImplemented on #{method}" do
|
||||
expect {
|
||||
subject.send(method)
|
||||
}.to raise_error(NotImplementedError)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
RSpec.configure do
|
||||
include RaiseNotImplementedMacro
|
||||
end
|
||||
|
||||
module DummyStrategy
|
||||
def test
|
||||
test!("you dummy!")
|
||||
end
|
||||
end
|
||||
|
||||
module BlindStrategy; end
|
||||
|
||||
module Capistrano
|
||||
describe SCM do
|
||||
let(:context) { Class.new.new }
|
||||
|
||||
describe "#initialize" do
|
||||
subject { Capistrano::SCM.new(context, DummyStrategy) }
|
||||
|
||||
it "should load the provided strategy" do
|
||||
context.expects(:test).with("you dummy!")
|
||||
subject.test
|
||||
end
|
||||
end
|
||||
|
||||
describe "Convenience methods" do
|
||||
subject { Capistrano::SCM.new(context, BlindStrategy) }
|
||||
|
||||
describe "#test!" do
|
||||
it "should return call test on the context" do
|
||||
context.expects(:test).with(:x)
|
||||
subject.test!(:x)
|
||||
end
|
||||
end
|
||||
|
||||
describe "#repo_url" do
|
||||
it "should return the repo url according to the context" do
|
||||
context.expects(:repo_url).returns(:url)
|
||||
subject.repo_url.should == :url
|
||||
end
|
||||
end
|
||||
|
||||
describe "#repo_path" do
|
||||
it "should return the repo path according to the context" do
|
||||
context.expects(:repo_path).returns(:path)
|
||||
subject.repo_path.should == :path
|
||||
end
|
||||
end
|
||||
|
||||
describe "#release_path" do
|
||||
it "should return the release path according to the context" do
|
||||
context.expects(:release_path).returns('/path/to/nowhere')
|
||||
subject.release_path.should == '/path/to/nowhere'
|
||||
end
|
||||
end
|
||||
|
||||
describe "#fetch" do
|
||||
it "should call fetch on the context" do
|
||||
context.expects(:fetch)
|
||||
subject.fetch(:branch)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "With a 'blind' strategy" do
|
||||
subject { Capistrano::SCM.new(context, BlindStrategy) }
|
||||
|
||||
describe "#test" do
|
||||
raise_not_implemented_on(:test)
|
||||
end
|
||||
|
||||
describe "#check" do
|
||||
raise_not_implemented_on(:check)
|
||||
end
|
||||
|
||||
describe "#clone" do
|
||||
raise_not_implemented_on(:clone)
|
||||
end
|
||||
|
||||
describe "#update" do
|
||||
raise_not_implemented_on(:update)
|
||||
end
|
||||
|
||||
describe "#release" do
|
||||
raise_not_implemented_on(:release)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
Loading…
Reference in a new issue