engineyard-serverside 1.5.35.pre.2 → 1.6.0.pre

Sign up to get free protection for your applications and to get access to all the features.
Files changed (35) hide show
  1. data/lib/engineyard-serverside.rb +3 -1
  2. data/lib/engineyard-serverside/cli.rb +73 -38
  3. data/lib/engineyard-serverside/configuration.rb +38 -12
  4. data/lib/engineyard-serverside/deploy.rb +63 -51
  5. data/lib/engineyard-serverside/deploy_hook.rb +21 -18
  6. data/lib/engineyard-serverside/deprecation.rb +9 -17
  7. data/lib/engineyard-serverside/lockfile_parser.rb +1 -1
  8. data/lib/engineyard-serverside/rails_asset_support.rb +5 -5
  9. data/lib/engineyard-serverside/server.rb +8 -11
  10. data/lib/engineyard-serverside/shell.rb +101 -0
  11. data/lib/engineyard-serverside/shell/formatter.rb +70 -0
  12. data/lib/engineyard-serverside/shell/helpers.rb +29 -0
  13. data/lib/engineyard-serverside/strategies/git.rb +12 -15
  14. data/lib/engineyard-serverside/task.rb +28 -5
  15. data/lib/engineyard-serverside/version.rb +1 -1
  16. data/lib/vendor/open4/lib/open4.rb +432 -0
  17. data/spec/basic_deploy_spec.rb +9 -9
  18. data/spec/bundler_deploy_spec.rb +1 -1
  19. data/spec/custom_deploy_spec.rb +45 -4
  20. data/spec/deploy_hook_spec.rb +77 -78
  21. data/spec/deprecation_spec.rb +4 -26
  22. data/spec/git_strategy_spec.rb +6 -2
  23. data/spec/nodejs_deploy_spec.rb +2 -2
  24. data/spec/services_deploy_spec.rb +11 -10
  25. data/spec/shell_spec.rb +48 -0
  26. data/spec/spec_helper.rb +48 -25
  27. data/spec/sqlite3_deploy_spec.rb +1 -2
  28. data/spec/support/integration.rb +1 -13
  29. metadata +57 -97
  30. data/lib/engineyard-serverside/logged_output.rb +0 -91
  31. data/lib/vendor/systemu/LICENSE +0 -3
  32. data/lib/vendor/systemu/lib/systemu.rb +0 -363
  33. data/lib/vendor/systemu/systemu.gemspec +0 -45
  34. data/spec/fixtures/gitrepo/bar +0 -0
  35. data/spec/logged_output_spec.rb +0 -55
@@ -12,17 +12,17 @@ describe "Deploying an application without Bundler" do
12
12
 
13
13
  # run a deploy
14
14
  config = EY::Serverside::Deploy::Configuration.new({
15
- "strategy" => "IntegrationSpec",
16
- "deploy_to" => @deploy_dir.to_s,
17
- "group" => `id -gn`.strip,
18
- "stack" => 'nginx_passenger',
19
- "migrate" => nil,
20
- 'app' => 'foo',
21
- 'framework_env' => 'staging'
22
- })
15
+ "strategy" => "IntegrationSpec",
16
+ "deploy_to" => @deploy_dir.to_s,
17
+ "group" => `id -gn`.strip,
18
+ "stack" => 'nginx_passenger',
19
+ "migrate" => nil,
20
+ 'app' => 'foo',
21
+ 'framework_env' => 'staging'
22
+ })
23
23
 
24
24
  @binpath = File.expand_path(File.join(File.dirname(__FILE__), '..', 'bin', 'engineyard-serverside'))
25
- @deployer = FullTestDeploy.new(config)
25
+ @deployer = FullTestDeploy.new(config, test_shell)
26
26
  @deployer.deploy
27
27
  end
28
28
 
@@ -32,7 +32,7 @@ describe "Deploying an application that uses Bundler" do
32
32
  end
33
33
 
34
34
  @binpath = File.expand_path(File.join(File.dirname(__FILE__), '..', 'bin', 'engineyard-serverside'))
35
- @deployer = FullTestDeploy.new(config)
35
+ @deployer = FullTestDeploy.new(config, test_shell)
36
36
  @deployer.deploy
37
37
  end
38
38
 
@@ -11,7 +11,6 @@ describe "the EY::Serverside::Deploy API" do
11
11
  # cheat a bit; we don't actually want to do these things
12
12
  def require_custom_tasks() end
13
13
  def callback(*_) end
14
- def puts(*_) 'stfu' end
15
14
 
16
15
  attr_reader :call_order
17
16
  def initialize(*a)
@@ -34,7 +33,7 @@ describe "the EY::Serverside::Deploy API" do
34
33
  def disable_maintenance_page() @call_order << 'disable_maintenance_page' end
35
34
  end
36
35
 
37
- td = TestDeploy.new(EY::Serverside::Deploy::Configuration.new)
36
+ td = TestDeploy.new(EY::Serverside::Deploy::Configuration.new, test_shell)
38
37
  td.deploy
39
38
  td.call_order.should == %w(
40
39
  push_code
@@ -52,6 +51,48 @@ describe "the EY::Serverside::Deploy API" do
52
51
  cleanup_old_releases)
53
52
  end
54
53
 
54
+ describe "ey.yml loading" do
55
+ before(:each) do
56
+ @tempdir = `mktemp -d -t ey_yml_spec.XXXXX`.strip
57
+ @config = EY::Serverside::Deploy::Configuration.new('repository_cache' => @tempdir, 'environment_name' => 'env_name', 'account_name' => 'acc', 'migrate' => 'rake db:migrate', 'config' => {'branch' => 'branch_from_config'}.to_json)
58
+ @deploy = TestDeploy.new(@config, test_shell)
59
+ end
60
+
61
+ def write_ey_yml(relative_path, data = {'environments' => {'env_name' => {'copy_exclude' => ['.git'], 'migrate' => true, 'branch' => 'branch_from_ey_yaml'}}})
62
+ FileUtils.mkdir_p(File.join(
63
+ @tempdir,
64
+ File.dirname(relative_path)))
65
+
66
+ File.open(File.join(@tempdir, relative_path), 'w') do |f|
67
+ f.write data.to_yaml
68
+ end
69
+ end
70
+
71
+ it "requires 'ey.yml' and adds any defined methods to the deploy" do
72
+ write_ey_yml 'ey.yml'
73
+ @deploy.load_ey_yml
74
+ @deploy.config.copy_exclude.should == ['.git']
75
+ end
76
+
77
+ it "falls back to 'config/ey.yml'" do
78
+ write_ey_yml 'config/ey.yml'
79
+ @deploy.load_ey_yml
80
+ @deploy.config.copy_exclude.should == ['.git']
81
+ end
82
+
83
+ it "loads at lower priority than command line options" do
84
+ write_ey_yml 'ey.yml'
85
+ @deploy.load_ey_yml
86
+ @deploy.config.migration_command.should == 'rake db:migrate'
87
+ end
88
+
89
+ it "loads at lower priority than json config option" do
90
+ write_ey_yml 'ey.yml'
91
+ @deploy.load_ey_yml
92
+ @deploy.config.branch.should == 'branch_from_config'
93
+ end
94
+ end
95
+
55
96
  describe "task overrides" do
56
97
  class TestQuietDeploy < EY::Serverside::Deploy
57
98
  def puts(*_) 'quiet' end
@@ -60,7 +101,7 @@ describe "the EY::Serverside::Deploy API" do
60
101
  before(:each) do
61
102
  @tempdir = `mktemp -d -t custom_deploy_spec.XXXXX`.strip
62
103
  @config = EY::Serverside::Deploy::Configuration.new('repository_cache' => @tempdir)
63
- @deploy = TestQuietDeploy.new(@config)
104
+ @deploy = TestQuietDeploy.new(@config, test_shell)
64
105
  end
65
106
 
66
107
  def write_eydeploy(relative_path, contents = "def got_new_methods() 'from the file on disk' end")
@@ -92,7 +133,7 @@ describe "the EY::Serverside::Deploy API" do
92
133
  def value() 'base' end
93
134
  end
94
135
 
95
- deploy = TestDeploySuper.new(@config)
136
+ deploy = TestDeploySuper.new(@config, test_shell)
96
137
  deploy.require_custom_tasks.should be_true
97
138
  deploy.value.should == "base + derived"
98
139
  end
@@ -1,67 +1,71 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe "the deploy-hook API" do
4
- before(:each) do
5
- @hook = EY::Serverside::DeployHook.new(options)
6
- @callback_context = EY::Serverside::DeployHook::CallbackContext.new(@hook.config)
7
- end
8
-
9
- def run_hook(options={}, &blk)
10
- raise ArgumentError unless block_given?
11
- options.each do |k, v|
12
- @callback_context.configuration[k] = v
13
- end
14
-
15
- # The hooks on the filesystem are run by passing a string to
16
- # context.instance_eval, not a block. However, using a block
17
- # should allow us to get the same degree of test coverage and
18
- # still let us have things like syntax checking work on this spec
19
- # file.
20
- @callback_context.instance_eval(&blk)
4
+ def deploy_hook(options={})
5
+ config = EY::Serverside::Deploy::Configuration.new(options)
6
+ EY::Serverside::DeployHook.new(config, test_shell)
21
7
  end
22
8
 
23
9
  context "#run" do
24
10
  it "is available" do
25
- run_hook { respond_to?(:run) }.should be_true
11
+ deploy_hook.eval_hook('respond_to?(:run)').should be_true
26
12
  end
27
13
 
28
14
  it "runs commands like the shell does" do
29
15
  ENV['COUNT'] = 'Chocula'
30
16
  File.unlink("/tmp/deploy_hook_spec.the_count") rescue nil
31
17
 
32
- run_hook { run("echo $COUNT > /tmp/deploy_hook_spec.the_count") }
18
+ deploy_hook.eval_hook('run("echo $COUNT > /tmp/deploy_hook_spec.the_count")')
33
19
 
34
20
  IO.read("/tmp/deploy_hook_spec.the_count").strip.should == "Chocula"
35
21
  end
36
22
 
37
23
  it "returns true/false to indicate the command's success" do
38
- run_hook { run("true") }.should be_true
39
- run_hook { run("false") }.should be_false
24
+ deploy_hook.eval_hook('run("true")').should be_true
25
+ deploy_hook.eval_hook('run("false")').should be_false
40
26
  end
41
27
  end
42
28
 
43
29
  context "#sudo" do
44
30
  it "is available" do
45
- run_hook { respond_to?(:sudo) }.should be_true
31
+ deploy_hook.eval_hook('respond_to?(:sudo)').should be_true
46
32
  end
47
33
 
48
34
  it "runs things with sudo" do
49
- @callback_context.should_receive(:system).with("sudo sh -l -c 'do it as root'").and_return(true)
50
-
51
- run_hook { sudo("do it as root") }
35
+ hook = deploy_hook
36
+ hook.callback_context.shell.should_receive(:logged_system).with("sudo sh -l -c 'do it as root'").and_return(true)
37
+ hook.eval_hook('sudo("do it as root")')
52
38
  end
53
39
  end
54
40
 
55
41
  context "capistrano-ish methods" do
56
42
  it "has them" do
57
- run_hook { respond_to?(:latest_release) }.should be_true
58
- run_hook { respond_to?(:previous_release) }.should be_true
59
- run_hook { respond_to?(:all_releases) }.should be_true
60
- run_hook { respond_to?(:current_path) }.should be_true
61
- run_hook { respond_to?(:shared_path) }.should be_true
62
- run_hook { respond_to?(:release_dir) }.should be_true
63
- run_hook { respond_to?(:failed_release_dir)}.should be_true
64
- run_hook { respond_to?(:release_path) }.should be_true
43
+ deploy_hook.eval_hook('respond_to?(:latest_release) ').should be_true
44
+ deploy_hook.eval_hook('respond_to?(:previous_release) ').should be_true
45
+ deploy_hook.eval_hook('respond_to?(:all_releases) ').should be_true
46
+ deploy_hook.eval_hook('respond_to?(:current_path) ').should be_true
47
+ deploy_hook.eval_hook('respond_to?(:shared_path) ').should be_true
48
+ deploy_hook.eval_hook('respond_to?(:release_dir) ').should be_true
49
+ deploy_hook.eval_hook('respond_to?(:failed_release_dir)').should be_true
50
+ deploy_hook.eval_hook('respond_to?(:release_path) ').should be_true
51
+ end
52
+ end
53
+
54
+ context "access to command line options that should be handed through to the config" do
55
+ before do
56
+ @hook = deploy_hook({'app' => 'app', 'environment_name' => 'env', 'account_name' => 'acc'})
57
+ end
58
+
59
+ it "has account_name" do
60
+ @hook.eval_hook('account_name').should == 'acc'
61
+ end
62
+
63
+ it "has environment_name" do
64
+ @hook.eval_hook('environment_name').should == 'env'
65
+ end
66
+
67
+ it "has app_name" do
68
+ @hook.eval_hook('app_name').should == 'app'
65
69
  end
66
70
  end
67
71
 
@@ -79,34 +83,34 @@ describe "the deploy-hook API" do
79
83
  end
80
84
 
81
85
  it "is available" do
82
- run_hook { @node.nil? }.should be_false
86
+ deploy_hook.eval_hook('@node.nil?').should be_false
83
87
  end
84
88
 
85
89
  it "has indifferent access" do
86
- run_hook { @node[:instance_role] }.should == 'solo'
87
- run_hook { @node['instance_role'] }.should == 'solo'
90
+ deploy_hook.eval_hook('@node[:instance_role] ').should == 'solo'
91
+ deploy_hook.eval_hook('@node["instance_role"]').should == 'solo'
88
92
  end
89
93
 
90
94
  it "has deep indifferent access" do
91
- run_hook { @node['applications']['myapp']['type'] }.should == 'rails'
92
- run_hook { @node[:applications]['myapp'][:type] }.should == 'rails'
93
- run_hook { @node[:applications][:myapp][:type] }.should == 'rails'
95
+ deploy_hook.eval_hook('@node["applications"]["myapp"]["type"]').should == 'rails'
96
+ deploy_hook.eval_hook('@node[:applications]["myapp"][:type] ').should == 'rails'
97
+ deploy_hook.eval_hook('@node[:applications][:myapp][:type] ').should == 'rails'
94
98
  end
95
99
  end
96
100
 
97
101
  context "the @configuration ivar" do
98
102
  it "is available" do
99
- run_hook { @configuration.nil? }.should be_false
103
+ deploy_hook.eval_hook('@configuration.nil?').should be_false
100
104
  end
101
105
 
102
106
  it "has the configuration in it" do
103
- run_hook('bert' => 'ernie') { @configuration.bert }.should == 'ernie'
107
+ deploy_hook('bert' => 'ernie').eval_hook('@configuration.bert').should == 'ernie'
104
108
  end
105
109
 
106
110
  it "can be accessed with method calls, with [:symbols], or ['strings']" do
107
- run_hook('bert' => 'ernie') { @configuration.bert }.should == 'ernie'
108
- run_hook('bert' => 'ernie') { @configuration[:bert] }.should == 'ernie'
109
- run_hook('bert' => 'ernie') { @configuration['bert'] }.should == 'ernie'
111
+ deploy_hook('bert' => 'ernie').eval_hook('@configuration.bert ').should == 'ernie'
112
+ deploy_hook('bert' => 'ernie').eval_hook('@configuration[:bert] ').should == 'ernie'
113
+ deploy_hook('bert' => 'ernie').eval_hook('@configuration["bert"]').should == 'ernie'
110
114
  end
111
115
 
112
116
  [:repository_cache,
@@ -118,7 +122,7 @@ describe "the deploy-hook API" do
118
122
  :revision,
119
123
  :environment].each do |attribute|
120
124
  it "has the #{attribute.inspect} attribute for compatibility with chef-deploy" do
121
- run_hook { @configuration.has_key?(attribute) }.should be_true
125
+ deploy_hook.eval_hook("@configuration.has_key?(#{attribute.inspect})").should be_true
122
126
  end
123
127
  end
124
128
  end
@@ -126,62 +130,58 @@ describe "the deploy-hook API" do
126
130
  context "has methods to run code only on certain instances" do
127
131
  def scenarios
128
132
  [
129
- {:instance_role => 'solo'},
130
- {:instance_role => 'app_master'},
131
- {:instance_role => 'app'},
132
- {:instance_role => 'db_master'},
133
- {:instance_role => 'db_slave'},
134
- {:instance_role => 'multi_role,app'},
135
- {:instance_role => 'multi,util'},
136
- {:instance_role => 'util', :name => "alpha"},
137
- {:instance_role => 'util', :name => "beta"},
138
- {:instance_role => 'util', :name => "gamma"},
133
+ ['solo' ],
134
+ ['app_master' ],
135
+ ['app' ],
136
+ ['db_master' ],
137
+ ['db_slave' ],
138
+ ['multi_role,app'],
139
+ ['multi,util' ],
140
+ ['util', 'alpha' ],
141
+ ['util', 'beta' ],
142
+ ['util', 'gamma' ],
139
143
  ]
140
144
  end
141
145
 
142
- def where_code_runs_with(method, *args)
143
- scenarios.map do |s|
144
- @callback_context.configuration[:current_roles] = s[:instance_role].split(',')
145
- @callback_context.configuration[:current_name] = s[:name]
146
-
147
- if run_hook { send(method, *args) { 'ran!'} } == 'ran!'
148
- result = s[:instance_role]
149
- result << "_#{s[:name]}" if s[:name]
150
- result
151
- end
146
+ def where_code_runs_with(code)
147
+ scenarios.select do |role, name|
148
+ hook = deploy_hook(:current_roles => role.split(','), :current_name => name)
149
+ hook.eval_hook("#{code} { 'ran' } == 'ran'")
150
+ end.map do |scenario|
151
+ scenario.compact.join("_")
152
152
  end.compact
153
153
  end
154
154
 
155
155
  it "#on_app_master runs on app masters and solos" do
156
- where_code_runs_with(:on_app_master).should == %w(solo app_master)
156
+ where_code_runs_with("on_app_master").should == %w(solo app_master)
157
157
  end
158
158
 
159
159
  it "#on_app_servers runs on app masters, app slaves, and solos" do
160
- where_code_runs_with(:on_app_servers).should == %w(solo app_master app multi_role,app)
160
+ where_code_runs_with("on_app_servers").should == %w(solo app_master app multi_role,app)
161
161
  end
162
162
 
163
163
  it "#on_app_servers_and_utilities does what it says on the tin" do
164
- where_code_runs_with(:on_app_servers_and_utilities).should ==
164
+ where_code_runs_with("on_app_servers_and_utilities").should ==
165
165
  %w(solo app_master app multi_role,app multi,util util_alpha util_beta util_gamma)
166
166
  end
167
167
 
168
168
  it "#on_utilities() runs on all utility instances" do
169
- where_code_runs_with(:on_utilities).should ==
169
+ where_code_runs_with("on_utilities").should ==
170
170
  %w(multi,util util_alpha util_beta util_gamma)
171
171
  end
172
172
 
173
173
  it "#on_utilities('sometype') runs on only utilities of type 'sometype'" do
174
- where_code_runs_with(:on_utilities, 'alpha').should == %w(util_alpha)
174
+ where_code_runs_with("on_utilities('alpha')").should == %w(util_alpha)
175
175
  end
176
176
 
177
177
  it "#on_utilities('type1', 'type2') runs on utilities of both types" do
178
- where_code_runs_with(:on_utilities, 'alpha', 'beta').should ==
178
+ where_code_runs_with("on_utilities('alpha', 'beta')").should ==
179
179
  %w(util_alpha util_beta)
180
180
  end
181
181
 
182
182
  it "#on_utilities can be invoked with (['a', 'b']) or ('a', 'b')" do
183
- where_code_runs_with(:on_utilities, %w[alpha beta]).should ==
184
- where_code_runs_with(:on_utilities, 'alpha', 'beta')
183
+ where_code_runs_with("on_utilities(%w[alpha beta])").should ==
184
+ where_code_runs_with("on_utilities('alpha', 'beta')")
185
185
  end
186
186
 
187
187
  end
@@ -189,20 +189,19 @@ describe "the deploy-hook API" do
189
189
  context "#syntax_error" do
190
190
  it "returns nil for hook files containing valid Ruby syntax" do
191
191
  hook_path = File.expand_path('../fixtures/valid_hook.rb', __FILE__)
192
- @hook.syntax_error(hook_path).should be_nil
192
+ deploy_hook.syntax_error(hook_path).should be_nil
193
193
  end
194
194
 
195
195
  it "returns a brief problem description for hook files containing valid Ruby syntax" do
196
196
  hook_path = File.expand_path('../fixtures/invalid_hook.rb', __FILE__)
197
- desc = "spec/fixtures/invalid_hook.rb:1: syntax error, unexpected '^'"
198
- match = /#{Regexp.escape desc}/
199
- @hook.syntax_error(hook_path).should =~ match
197
+ error = Regexp.escape("spec/fixtures/invalid_hook.rb:1: syntax error, unexpected '^'")
198
+ deploy_hook.syntax_error(hook_path).should =~ /#{error}/
200
199
  end
201
200
  end
202
201
 
203
202
  context "is compatible with older deploy hook scripts" do
204
203
  it "#current_role returns the first role" do
205
- run_hook(:current_roles => %w(a b)) { current_role.should == 'a' }
204
+ deploy_hook(:current_roles => %w(a b)).eval_hook('current_role').should == 'a'
206
205
  end
207
206
  end
208
207
  end
@@ -12,34 +12,12 @@ describe EY::Serverside do
12
12
  $stderr = @original_stderr
13
13
  end
14
14
 
15
- def check_deprecation(new_const, prints_warning = true)
16
- old_name = new_const.to_s.gsub('EY::Serverside::', 'EY::')
17
- eval(old_name).should == new_const
18
- @warnings.string.should include(old_name) if prints_warning
19
- end
20
-
21
- it "preserves the old constants" do
22
- names = %w[CLI Deploy DeployBase Deploy::Configuration
23
- DeployHook LockfileParser LoggedOutput Server Task
24
- Strategies Strategies::Git]
25
-
26
- names.map do |name|
27
- const = eval("::EY::Serverside::#{name}")
28
- # The way deprecations are implemented currently, we don't print
29
- # warning messages for constants that aren't directly under EY::
30
- prints_warning = name.include?('::') ? false : true
31
- check_deprecation(const, prints_warning)
32
- end
33
- end
34
-
35
- it "deprecates EY.dna_json and EY.node" do
36
- EY.dna_json.should == EY::Serverside.dna_json
37
- @warnings.string.should include("EY.dna_json")
38
- EY.node.should == EY::Serverside.node
39
- @warnings.string.should include("EY.node")
15
+ it "deprecates EY::Serverside::LoggedOutput for EY::Serverside::Shell::Helpers" do
16
+ EY::Serverside::LoggedOutput.should == EY::Serverside::Shell::Helpers
17
+ @warnings.string.should include("EY::Serverside::LoggedOutput")
40
18
  end
41
19
 
42
20
  it "doesn't interfere with unrelated constants" do
43
- lambda{ EY::WTFNotDefined }.should raise_error(NameError, /uninitialized constant.*EY::WTFNotDefined/)
21
+ lambda{ EY::Serverside::WTFNotDefined }.should raise_error(NameError, /uninitialized constant.*WTFNotDefined/)
44
22
  end
45
23
  end
@@ -2,8 +2,12 @@ require 'spec_helper'
2
2
 
3
3
  describe "the git deploy strategy" do
4
4
  subject do
5
- EY::Serverside::Strategies::Git.new(:repo => File.join(GITREPO_DIR, 'git'),
6
- :repository_cache => GITREPO_DIR, :ref => "master")
5
+ EY::Serverside::Strategies::Git.new(
6
+ test_shell,
7
+ :repo => File.join(GITREPO_DIR, 'git'),
8
+ :repository_cache => GITREPO_DIR,
9
+ :ref => "master"
10
+ )
7
11
  end
8
12
 
9
13
  before { subject.checkout }
@@ -2,7 +2,7 @@ require 'spec_helper'
2
2
 
3
3
  describe "Deploying an application that uses Node.js and NPM" do
4
4
  def deploy_test_application
5
- @deploy_dir = File.join(Dir.tmpdir, "serverside-deploy-#{Time.now.to_i}-#{$$}")
5
+ @deploy_dir = Pathname.new(Dir.tmpdir).join("serverside-deploy-#{Time.now.to_i}-#{$$}")
6
6
 
7
7
  # set up EY::Serverside::Server like we're on a solo
8
8
  EY::Serverside::Server.reset
@@ -19,7 +19,7 @@ describe "Deploying an application that uses Node.js and NPM" do
19
19
  })
20
20
 
21
21
  @binpath = File.expand_path(File.join(File.dirname(__FILE__), '..', 'bin', 'engineyard-serverside'))
22
- @deployer = FullTestDeploy.new(config)
22
+ @deployer = FullTestDeploy.new(config, test_shell)
23
23
  @deployer.deploy do
24
24
  FileUtils.mkdir_p(config.repository_cache) # block runs before deploy
25
25
  @deployer.generate_package_json_in(config.repository_cache)