capistrano-strategy-copy-bundled 0.6.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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.