capistrano-strategy-copy-bundled 0.6.0 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format progress
data/LICENSE.txt CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2011 Rudolf Schmidt
1
+ Copyright (c) 2011-2012 Rudolf Schmidt
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
data/README.md ADDED
@@ -0,0 +1,58 @@
1
+ # Capistrano Strategy: Copy Bundled
2
+
3
+ This recipe for capistrano utilizes the regular copy strategy. However,
4
+ instead of bundling the gems on the remote servers, they are already
5
+ pre-bundled on the deploy machine and sent as one package.
6
+
7
+ In some networks, due to security reasons, production servers are not
8
+ allowed to access the internal company network. When that is the case,
9
+ you are not able access your internally written gems. Also, those kind
10
+ of servers usually, and intentionally, have no version control installed
11
+ or are behind a firewall with blocked access to rubygems, github, etc.
12
+
13
+ This capistrano recipe tries to help out with that.
14
+
15
+
16
+ ## Installation
17
+
18
+ System wide usage
19
+
20
+ ```console
21
+ gem install 'capistrano-strategy-copy-bundled'
22
+ ```
23
+
24
+ In your Gemfile
25
+
26
+ ```ruby
27
+ gem 'capistrano-strategy-copy-bundled'
28
+ ```
29
+
30
+
31
+ ## Usage
32
+
33
+ As this recipe does it's own bundling, there is not need to: `require 'bundler/capistrano'`.
34
+
35
+ All you have to do in your `config/deploy.rb`:
36
+
37
+ ```ruby
38
+ require 'capistrano-strategy-copy-bundled'
39
+ set :deploy_via, :copy_bundled # bundle gems locally and send them packed to all servers
40
+ ```
41
+
42
+ Additionally to that, you can set the usual options when using the regular :copy strategy for capistrano, like:
43
+
44
+ ```ruby
45
+ set :copy_dir, "/tmp/#{application}" # path where files are temporarily put before sending them to the servers
46
+ set :copy_exclude, ".git*" # we exclude the .git repo so that nobody is able to temper with the release
47
+
48
+ #Callback triggers to add your own steps within (in order)
49
+ on 'strategy:before:bundle', 'some:custom:task'
50
+ on 'strategy:after:bundle', 'some:custom:task'
51
+ on 'strategy:before:compression', 'some:custom:task'
52
+ on 'strategy:after:compression', 'some:custom:task'
53
+ on 'strategy:before:distribute', 'some:custom:task'
54
+ on 'strategy:after:distribute', 'some:custom:task'
55
+ ```
56
+
57
+ Copyright © 2011-2012 Rudolf Schmidt. Released under the MIT license.
58
+
@@ -1,12 +1,12 @@
1
1
  # -*- encoding: utf-8 -*-
2
2
  $:.push File.expand_path("../lib", __FILE__)
3
- require 'capistrano-strategy-copy-bundled'
3
+ require 'capistrano-strategy-copy-bundled/version'
4
4
 
5
5
  Gem::Specification.new do |s|
6
6
  s.name = "capistrano-strategy-copy-bundled"
7
7
  s.version = CapistranoStrategyCopyBundled::VERSION
8
- s.authors = ["Rudolf Schmidt"]
9
-
8
+ s.authors = ["Rudolf Schmidt", "Tom Meier"]
9
+
10
10
  s.homepage = "http://github.com/rudionrails/capistrano-strategy-copy-bundled"
11
11
  s.summary = %q{Capistrano copy recipe to transfer files already pre-bundled}
12
12
  s.description = %q{Bundle all gems in the copy directory and then send it to all servers}
@@ -19,6 +19,7 @@ Gem::Specification.new do |s|
19
19
  s.require_paths = ["lib"]
20
20
 
21
21
  # specify any dependencies here; for example:
22
- # s.add_development_dependency "rspec"
22
+ s.add_development_dependency "rspec"
23
23
  s.add_runtime_dependency "capistrano", "~> 2"
24
+ s.add_runtime_dependency "bundler", ">= 1.2" #Required for package --all
24
25
  end
@@ -1,4 +1,4 @@
1
- module CapistranoStrategyCopyBundled
2
- VERSION = '0.6.0'
3
-
4
- end
1
+ module CapistranoStrategyCopyBundled; end
2
+
3
+ require 'capistrano-strategy-copy-bundled/version'
4
+ require 'capistrano/recipes/deploy/strategy/copy_bundled'
@@ -0,0 +1,3 @@
1
+ module CapistranoStrategyCopyBundled
2
+ VERSION = '0.7.0'
3
+ end
@@ -1,3 +1,5 @@
1
+ require 'bundler/deployment'
2
+ require 'capistrano'
1
3
  require 'capistrano/recipes/deploy/strategy/copy'
2
4
 
3
5
  module Capistrano
@@ -6,121 +8,63 @@ module Capistrano
6
8
 
7
9
  class CopyBundled < Copy
8
10
 
9
- # @overload
11
+ def initialize(config = {})
12
+ super(config)
13
+
14
+ #Initialize with default bundler/capistrano tasks (bundle:install)
15
+ configuration.set :rake, lambda { "#{configuration.fetch(:bundle_cmd, "bundle")} exec rake" } unless configuration.exists?(:rake)
16
+ Bundler::Deployment.define_task(configuration, :task, :except => { :no_release => true })
17
+ end
18
+
10
19
  def deploy!
11
- if copy_cache
12
- if File.exists?(copy_cache)
13
- logger.debug "refreshing local cache to revision #{revision} at #{copy_cache}"
14
- system(source.sync(revision, copy_cache))
15
- else
16
- logger.debug "preparing local cache at #{copy_cache}"
17
- system(source.checkout(revision, copy_cache))
18
- end
19
-
20
- # Check the return code of last system command and rollback if not 0
21
- unless $? == 0
22
- raise Capistrano::Error, "shell command failed with return code #{$?}"
23
- end
24
-
25
- FileUtils.mkdir_p(destination)
26
-
27
- logger.debug "copying cache to deployment staging area #{destination}"
28
- Dir.chdir(copy_cache) do
29
- queue = Dir.glob("*", File::FNM_DOTMATCH)
30
- while queue.any?
31
- item = queue.shift
32
- name = File.basename(item)
33
-
34
- next if name == "." || name == ".."
35
- next if copy_exclude.any? { |pattern| File.fnmatch(pattern, item) }
36
-
37
- if File.symlink?(item)
38
- FileUtils.ln_s(File.readlink(item), File.join(destination, item))
39
- elsif File.directory?(item)
40
- queue += Dir.glob("#{item}/*", File::FNM_DOTMATCH)
41
- FileUtils.mkdir(File.join(destination, item))
42
- else
43
- FileUtils.ln(item, File.join(destination, item))
44
- end
45
- end
46
- end
47
- else
48
- logger.debug "getting (via #{copy_strategy}) revision #{revision} to #{destination}"
49
- system(command)
50
-
51
- if copy_exclude.any?
52
- logger.debug "processing exclusions..."
53
-
54
- copy_exclude.each do |pattern|
55
- delete_list = Dir.glob(File.join(destination, pattern), File::FNM_DOTMATCH)
56
- # avoid the /.. trap that deletes the parent directories
57
- delete_list.delete_if { |dir| dir =~ /\/\.\.$/ }
58
- FileUtils.rm_rf(delete_list.compact)
59
- end
60
- end
61
- end
20
+ logger.info "running :copy_bundled strategy"
21
+
22
+ copy_cache ? run_copy_cache_strategy : run_copy_strategy
62
23
 
63
- File.open(File.join(destination, "REVISION"), "w") { |f| f.puts(revision) }
24
+ create_revision_file
64
25
 
65
- # execute bundler
26
+ configuration.trigger('strategy:before:bundle')
27
+ #Bundle all gems
66
28
  bundle!
29
+ configuration.trigger('strategy:after:bundle')
67
30
 
68
- logger.trace "compressing #{destination} to #{filename}"
69
- Dir.chdir(copy_dir) { system(compress(File.basename(destination), File.basename(filename)).join(" ")) }
31
+ logger.info "compressing repository"
32
+ configuration.trigger('strategy:before:compression')
33
+ compress_repository
34
+ configuration.trigger('strategy:after:compression')
70
35
 
36
+
37
+ logger.info "distributing packaged repository"
38
+
39
+ configuration.trigger('strategy:before:distribute')
71
40
  distribute!
41
+ configuration.trigger('strategy:after:distribute')
72
42
  ensure
73
- FileUtils.rm filename rescue nil
74
- FileUtils.rm_rf destination rescue nil
43
+ rollback_changes
75
44
  end
76
45
 
77
-
78
46
  private
79
47
 
80
48
  def bundle!
81
- logger.trace "running bundler in #{destination}..."
82
-
83
- bundle_cmd = configuration[:bundle_cmd] || "bundle"
84
- bundle_flags = configuration[:bundle_flags] || "--deployment --quiet"
85
- bundle_dir = configuration[:bundle_dir] || File.join('vendor', 'bundle')
86
- bundle_gemfile = configuration[:bundle_gemfile] || File.join("Gemfile")
87
- bundle_without = [*(configuration[:bundle_without] || [:development, :test])].compact
49
+ bundle_cmd = configuration.fetch(:bundle_cmd, "bundle")
50
+ bundle_gemfile = configuration.fetch(:bundle_gemfile, "Gemfile")
51
+ bundle_dir = configuration.fetch(:bundle_dir, 'vendor/bundle')
52
+ bundle_flags = configuration.fetch(:bundle_flags, "--deployment --quiet")
53
+ bundle_without = [*configuration.fetch(:bundle_without, [:development, :test])].compact
88
54
 
89
- args = ["--gemfile #{bundle_gemfile}"]
55
+ args = ["--gemfile #{File.join(destination, bundle_gemfile)}"]
90
56
  args << "--path #{bundle_dir}" unless bundle_dir.to_s.empty?
91
- args << bundle_flags.to_s
57
+ args << bundle_flags.to_s unless bundle_flags.to_s.empty?
92
58
  args << "--without #{bundle_without.join(" ")}" unless bundle_without.empty?
93
59
 
94
- cmd = "#{bundle_cmd} install #{args.join(' ')}"
95
- Dir.chdir(destination) do
96
- defined?(Bundler) ? with_original_env { system(cmd) } : system(cmd)
60
+ Bundler.with_clean_env do
61
+ logger.info "installing gems to local cache : #{destination}..."
62
+ run_locally "cd #{destination} && #{bundle_cmd} install #{args.join(' ').strip}"
97
63
 
98
- # Check the return code of last system command and rollback if not 0
99
- raise Capistrano::Error, "shell command failed with return code #{$?}" unless $? == 0
64
+ logger.info "packaging gems for bundler in #{destination}..."
65
+ run_locally "cd #{destination} && #{bundle_cmd} package --all"
100
66
  end
101
67
  end
102
-
103
- # This method should be built-in to Bundler 1.1+
104
- def with_original_env
105
- original_env = ENV.to_hash
106
-
107
- begin
108
- # clean the ENV from Bundler settings
109
- ENV.delete( 'RUBYOPT' )
110
- ENV.keys.each { |k| ENV.delete(k) if k =~ /^bundle_/i } #remove any BUNDLE_* keys
111
-
112
- yield
113
- ensure
114
- ENV.replace( original_env )
115
- end
116
- end
117
-
118
- # Distributes the file to the remote servers
119
- def distribute!
120
- upload( filename, remote_filename, :via => configuration[:copy_via] || :sftp )
121
- run "cd #{configuration[:releases_path]} && #{decompress(remote_filename).join(" ")} && rm #{remote_filename}"
122
- end
123
-
124
68
  end
125
69
 
126
70
  end
@@ -0,0 +1,116 @@
1
+ require 'spec_helper'
2
+
3
+ describe Capistrano::Deploy::Strategy::CopyBundled do
4
+
5
+ let(:source) { mock('source') }
6
+ let(:logger) { mock('logger', :info => true, :debug => true) }
7
+ let(:trigger) { mock('ConfTrigger') }
8
+ let(:destination) { '/some/where/here/' }
9
+ let(:config) { mock('Config', :application => "captest",
10
+ :releases_path => "/u/apps/test/releases",
11
+ :release_path => "/u/apps/test/releases/1234567890",
12
+ :real_revision => "154",
13
+ :trigger => trigger,
14
+ :exists? => false,
15
+ :set => true,
16
+ :[] => 'hello',
17
+ :logger => logger,
18
+ :fetch => ''
19
+ )}
20
+ let(:strategy) { Capistrano::Deploy::Strategy::CopyBundled.new(config) }
21
+
22
+ before do
23
+ #Initialisation
24
+ Bundler::Deployment.should_receive(:define_task).once
25
+
26
+ [:copy_cache, :run_copy_strategy, :run_locally, :run].each do |method_call|
27
+ Capistrano::Deploy::Strategy::CopyBundled.any_instance.stub(method_call) { nil }
28
+ end
29
+
30
+ # #Key base class copy commands
31
+ [:create_revision_file, :compress_repository, :distribute!, :rollback_changes].each do |main_call|
32
+ Capistrano::Deploy::Strategy::CopyBundled.any_instance.should_receive(main_call).once
33
+ end
34
+ end
35
+
36
+ context 'rake definition' do
37
+ it 'sets rake command by default' do
38
+ config.stub(:exists?).with(:rake) { false }
39
+ config.should_receive(:set).with(:rake, anything).once { true }
40
+ end
41
+
42
+ it 'uses any existing rake command if already exists' do
43
+ config.stub(:exists?).with(:rake) { true }
44
+ config.should_not_receive(:set).with(:rake, anything)
45
+ end
46
+
47
+ after do
48
+ Capistrano::Deploy::Strategy::CopyBundled.new(config).deploy!
49
+ end
50
+ end
51
+
52
+ context 'with existing copy cache' do
53
+ let(:copy_cache_dir) { '/u/tmp/copy-cache' }
54
+ before do
55
+ strategy.stub!(:copy_cache => copy_cache_dir)
56
+ end
57
+
58
+ it 'utilises existing copy cache strategy' do
59
+ strategy.should_receive(:run_copy_cache_strategy).once
60
+ strategy.should_not_receive(:run_copy_strategy)
61
+ strategy.deploy!
62
+ end
63
+ end
64
+
65
+ context 'with new copy cache' do
66
+ before do
67
+ strategy.stub!(:copy_cache => nil)
68
+ end
69
+
70
+ it 'initialises copy strategy' do
71
+ strategy.should_receive(:run_copy_strategy).once
72
+ strategy.should_not_receive(:run_copy_cache_strategy)
73
+ strategy.deploy!
74
+ end
75
+ end
76
+
77
+ context 'triggers' do
78
+ it 'custom calls during actions' do
79
+ expected_triggers = [ "strategy:before:bundle",
80
+ "strategy:after:bundle",
81
+ "strategy:before:compression",
82
+ "strategy:after:compression",
83
+ "strategy:before:distribute",
84
+ "strategy:after:distribute"]
85
+
86
+ expected_triggers.each do |trigger_name|
87
+ config.should_receive(:trigger).with(trigger_name).once
88
+ end
89
+ strategy.deploy!
90
+ end
91
+ end
92
+
93
+ context 'bundle!' do
94
+ let(:custom_bundle_cmd) { 'ANY_VAR=true bundle' }
95
+
96
+ before do
97
+ strategy.stub(:run_copy_cache_strategy => true, :run => true, :destination => destination)
98
+
99
+ config.stub(:fetch).with(:bundle_dir, 'vendor/bundle') { 'vendor/bundle' }
100
+ config.stub(:fetch).with(:bundle_gemfile, 'Gemfile') { 'Gemfile' }
101
+ config.stub(:fetch).with(:bundle_cmd, 'bundle' ) { custom_bundle_cmd }
102
+ config.stub(:fetch).with(:bundle_without, [:development, :test]) { [:development, :test, :staging] }
103
+
104
+ Bundler.should_receive(:with_clean_env).once.and_yield
105
+ end
106
+
107
+ it 'runs bundle install locally and package' do
108
+ strategy.should_receive(:run_locally).with("cd #{destination} && #{custom_bundle_cmd} install --gemfile #{File.join(destination, 'Gemfile')} --path vendor/bundle --without development test staging").once
109
+ strategy.should_receive(:run_locally).with("cd #{destination} && ANY_VAR=true bundle package --all").once
110
+ end
111
+
112
+ after do
113
+ strategy.deploy!
114
+ end
115
+ end
116
+ end
@@ -0,0 +1,13 @@
1
+ require 'capistrano-strategy-copy-bundled'
2
+
3
+ RSpec.configure do |config|
4
+ config.treat_symbols_as_metadata_keys_with_true_values = true
5
+ config.run_all_when_everything_filtered = true
6
+ config.filter_run :focus
7
+
8
+ # Run specs in random order to surface order dependencies. If you find an
9
+ # order dependency and want to debug it, you can fix the order by providing
10
+ # the seed, which is printed after each run.
11
+ # --seed 1234
12
+ config.order = 'random'
13
+ end
metadata CHANGED
@@ -1,73 +1,108 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: capistrano-strategy-copy-bundled
3
- version: !ruby/object:Gem::Version
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.7.0
4
5
  prerelease:
5
- version: 0.6.0
6
6
  platform: ruby
7
- authors:
8
- - Rudolf Schmidt
7
+ authors:
8
+ - Rudolf Schmidt
9
+ - Tom Meier
9
10
  autorequire:
10
11
  bindir: bin
11
12
  cert_chain: []
12
-
13
- date: 2011-10-19 00:00:00 +02:00
14
- default_executable:
15
- dependencies:
16
- - !ruby/object:Gem::Dependency
17
- name: capistrano
18
- prerelease: false
19
- requirement: &id001 !ruby/object:Gem::Requirement
20
- none: false
21
- requirements:
22
- - - ~>
23
- - !ruby/object:Gem::Version
24
- version: "2"
25
- type: :runtime
26
- version_requirements: *id001
13
+ date: 2013-02-26 00:00:00.000000000 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: rspec
17
+ requirement: !ruby/object:Gem::Requirement
18
+ none: false
19
+ requirements:
20
+ - - ! '>='
21
+ - !ruby/object:Gem::Version
22
+ version: '0'
23
+ type: :development
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ none: false
27
+ requirements:
28
+ - - ! '>='
29
+ - !ruby/object:Gem::Version
30
+ version: '0'
31
+ - !ruby/object:Gem::Dependency
32
+ name: capistrano
33
+ requirement: !ruby/object:Gem::Requirement
34
+ none: false
35
+ requirements:
36
+ - - ~>
37
+ - !ruby/object:Gem::Version
38
+ version: '2'
39
+ type: :runtime
40
+ prerelease: false
41
+ version_requirements: !ruby/object:Gem::Requirement
42
+ none: false
43
+ requirements:
44
+ - - ~>
45
+ - !ruby/object:Gem::Version
46
+ version: '2'
47
+ - !ruby/object:Gem::Dependency
48
+ name: bundler
49
+ requirement: !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '1.2'
55
+ type: :runtime
56
+ prerelease: false
57
+ version_requirements: !ruby/object:Gem::Requirement
58
+ none: false
59
+ requirements:
60
+ - - ! '>='
61
+ - !ruby/object:Gem::Version
62
+ version: '1.2'
27
63
  description: Bundle all gems in the copy directory and then send it to all servers
28
64
  email:
29
65
  executables: []
30
-
31
66
  extensions: []
32
-
33
67
  extra_rdoc_files: []
34
-
35
- files:
36
- - .gitignore
37
- - Gemfile
38
- - LICENSE.txt
39
- - README.rdoc
40
- - Rakefile
41
- - capistrano-strategy-copy-bundled.gemspec
42
- - lib/capistrano-strategy-copy-bundled.rb
43
- - lib/capistrano/recipes/deploy/strategy/copy_bundled.rb
44
- has_rdoc: true
68
+ files:
69
+ - .gitignore
70
+ - .rspec
71
+ - Gemfile
72
+ - LICENSE.txt
73
+ - README.md
74
+ - Rakefile
75
+ - capistrano-strategy-copy-bundled.gemspec
76
+ - lib/capistrano-strategy-copy-bundled.rb
77
+ - lib/capistrano-strategy-copy-bundled/version.rb
78
+ - lib/capistrano/recipes/deploy/strategy/copy_bundled.rb
79
+ - spec/lib/capistrano/recipes/deploy/strategy/copy_bundled_spec.rb
80
+ - spec/spec_helper.rb
45
81
  homepage: http://github.com/rudionrails/capistrano-strategy-copy-bundled
46
82
  licenses: []
47
-
48
83
  post_install_message:
49
84
  rdoc_options: []
50
-
51
- require_paths:
52
- - lib
53
- required_ruby_version: !ruby/object:Gem::Requirement
85
+ require_paths:
86
+ - lib
87
+ required_ruby_version: !ruby/object:Gem::Requirement
54
88
  none: false
55
- requirements:
56
- - - ">="
57
- - !ruby/object:Gem::Version
58
- version: "0"
59
- required_rubygems_version: !ruby/object:Gem::Requirement
89
+ requirements:
90
+ - - ! '>='
91
+ - !ruby/object:Gem::Version
92
+ version: '0'
93
+ required_rubygems_version: !ruby/object:Gem::Requirement
60
94
  none: false
61
- requirements:
62
- - - ">="
63
- - !ruby/object:Gem::Version
64
- version: "0"
95
+ requirements:
96
+ - - ! '>='
97
+ - !ruby/object:Gem::Version
98
+ version: '0'
65
99
  requirements: []
66
-
67
100
  rubyforge_project: capistrano-strategy-copy-bundled
68
- rubygems_version: 1.5.1
101
+ rubygems_version: 1.8.25
69
102
  signing_key:
70
103
  specification_version: 3
71
104
  summary: Capistrano copy recipe to transfer files already pre-bundled
72
- test_files: []
73
-
105
+ test_files:
106
+ - spec/lib/capistrano/recipes/deploy/strategy/copy_bundled_spec.rb
107
+ - spec/spec_helper.rb
108
+ has_rdoc:
data/README.rdoc DELETED
@@ -1,33 +0,0 @@
1
- = Capistrano Strategy: Copy Bundled
2
- This recipe for capistrano utilizes the regular copy strategy. However, instead of bundling the gems on the remote servers,
3
- they are already pre-bundled on the deploy machine and sent as one package.
4
-
5
- In some networks, due to security reasons, production servers are not allowed to access the internal company network. When
6
- that is the case, you are not able access your internally written gems. Also, these kind of servers usually and intentionally
7
- know nothing about version control or are even behind a firewall with blocked access to runygems or github and the likes.
8
-
9
- This capistrano recipe tries to help out in these scenarios.
10
-
11
- == Installation
12
- # for system wide usage
13
- gem install 'capistrano-strategy-copy-bundled'
14
-
15
- # or just in your Gemfile
16
- gem 'capistrano-strategy-copy-bundled'
17
-
18
-
19
- == Usage
20
- As this recipe does it's own bundling, there is not need to: require 'bundler/capistrano'.
21
-
22
- All you have to do in your `config/deploy.rb`:
23
-
24
- require 'capistrano-strategy-copy-bundled'
25
- set :deploy_via, :copy_bundled # bundle gems locally and send them packed to all servers
26
-
27
- Additionally to that, you can set the usual options when using the regular :copy strategy for capistrano, like:
28
- set :copy_dir, "/tmp/#{application}" # path where files are temporarily put before sending them to the servers
29
- set :copy_exclude, ".git*" # we exclude the .git repo so that nobody is able to temper with the release
30
-
31
-
32
- == Copyright
33
- Copyright (c) 2011 Rudolf Schmidt See LICENSE.txt for details.