statistrano 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (72) hide show
  1. checksums.yaml +7 -0
  2. data/changelog.md +161 -0
  3. data/doc/config/file-permissions.md +33 -0
  4. data/doc/config/log-files.md +32 -0
  5. data/doc/config/task-definitions.md +88 -0
  6. data/doc/getting-started.md +96 -0
  7. data/doc/strategies/base.md +38 -0
  8. data/doc/strategies/branches.md +82 -0
  9. data/doc/strategies/releases.md +110 -0
  10. data/doc/strategies.md +17 -0
  11. data/lib/statistrano/config/configurable.rb +53 -0
  12. data/lib/statistrano/config/rake_task_with_context_creation.rb +43 -0
  13. data/lib/statistrano/config.rb +52 -0
  14. data/lib/statistrano/deployment/log_file.rb +44 -0
  15. data/lib/statistrano/deployment/manifest.rb +88 -0
  16. data/lib/statistrano/deployment/rake_tasks.rb +74 -0
  17. data/lib/statistrano/deployment/registerable.rb +11 -0
  18. data/lib/statistrano/deployment/releaser/revisions.rb +163 -0
  19. data/lib/statistrano/deployment/releaser/single.rb +48 -0
  20. data/lib/statistrano/deployment/releaser.rb +2 -0
  21. data/lib/statistrano/deployment/strategy/base.rb +132 -0
  22. data/lib/statistrano/deployment/strategy/branches/index/template.html.erb +78 -0
  23. data/lib/statistrano/deployment/strategy/branches/index.rb +40 -0
  24. data/lib/statistrano/deployment/strategy/branches/release.rb +73 -0
  25. data/lib/statistrano/deployment/strategy/branches.rb +198 -0
  26. data/lib/statistrano/deployment/strategy/check_git.rb +43 -0
  27. data/lib/statistrano/deployment/strategy/invoke_tasks.rb +58 -0
  28. data/lib/statistrano/deployment/strategy/releases.rb +76 -0
  29. data/lib/statistrano/deployment/strategy.rb +37 -0
  30. data/lib/statistrano/deployment.rb +10 -0
  31. data/lib/statistrano/log/default_logger.rb +105 -0
  32. data/lib/statistrano/log.rb +33 -0
  33. data/lib/statistrano/remote/file.rb +79 -0
  34. data/lib/statistrano/remote.rb +111 -0
  35. data/lib/statistrano/shell.rb +17 -0
  36. data/lib/statistrano/util/file_permissions.rb +34 -0
  37. data/lib/statistrano/util.rb +27 -0
  38. data/lib/statistrano/version.rb +3 -0
  39. data/lib/statistrano.rb +55 -0
  40. data/readme.md +247 -0
  41. data/spec/integration_tests/base_integration_spec.rb +103 -0
  42. data/spec/integration_tests/branches_integration_spec.rb +189 -0
  43. data/spec/integration_tests/releases/deploy_integration_spec.rb +116 -0
  44. data/spec/integration_tests/releases/list_releases_integration_spec.rb +38 -0
  45. data/spec/integration_tests/releases/prune_releases_integration_spec.rb +86 -0
  46. data/spec/integration_tests/releases/rollback_release_integration_spec.rb +46 -0
  47. data/spec/lib/statistrano/config/configurable_spec.rb +88 -0
  48. data/spec/lib/statistrano/config/rake_task_with_context_creation_spec.rb +73 -0
  49. data/spec/lib/statistrano/config_spec.rb +34 -0
  50. data/spec/lib/statistrano/deployment/log_file_spec.rb +75 -0
  51. data/spec/lib/statistrano/deployment/manifest_spec.rb +171 -0
  52. data/spec/lib/statistrano/deployment/rake_tasks_spec.rb +107 -0
  53. data/spec/lib/statistrano/deployment/registerable_spec.rb +19 -0
  54. data/spec/lib/statistrano/deployment/releaser/revisions_spec.rb +486 -0
  55. data/spec/lib/statistrano/deployment/releaser/single_spec.rb +59 -0
  56. data/spec/lib/statistrano/deployment/strategy/base_spec.rb +158 -0
  57. data/spec/lib/statistrano/deployment/strategy/branches_spec.rb +19 -0
  58. data/spec/lib/statistrano/deployment/strategy/check_git_spec.rb +39 -0
  59. data/spec/lib/statistrano/deployment/strategy/invoke_tasks_spec.rb +66 -0
  60. data/spec/lib/statistrano/deployment/strategy/releases_spec.rb +257 -0
  61. data/spec/lib/statistrano/deployment/strategy_spec.rb +76 -0
  62. data/spec/lib/statistrano/deployment_spec.rb +4 -0
  63. data/spec/lib/statistrano/log/default_logger_spec.rb +172 -0
  64. data/spec/lib/statistrano/log_spec.rb +36 -0
  65. data/spec/lib/statistrano/remote/file_spec.rb +166 -0
  66. data/spec/lib/statistrano/remote_spec.rb +226 -0
  67. data/spec/lib/statistrano/util/file_permissions_spec.rb +25 -0
  68. data/spec/lib/statistrano/util_spec.rb +23 -0
  69. data/spec/lib/statistrano_spec.rb +52 -0
  70. data/spec/spec_helper.rb +86 -0
  71. data/spec/support/given.rb +39 -0
  72. metadata +223 -0
@@ -0,0 +1,19 @@
1
+ require 'spec_helper'
2
+
3
+ describe Statistrano::Deployment::Registerable do
4
+
5
+ describe "::register_strategy" do
6
+ it "calls register strategy on Deployment" do
7
+ class Foo; end
8
+ expect( Statistrano::Deployment::Strategy ).to receive(:register)
9
+ .with( Foo, :foo )
10
+
11
+ class Foo
12
+ extend Statistrano::Deployment::Registerable
13
+
14
+ register_strategy :foo
15
+ end
16
+ end
17
+ end
18
+
19
+ end
@@ -0,0 +1,486 @@
1
+ require 'spec_helper'
2
+
3
+ describe Statistrano::Deployment::Releaser::Revisions do
4
+
5
+ let(:default_remote_config_responses) do
6
+ {
7
+ remote_dir: '/var/www/proj',
8
+ local_dir: 'build',
9
+ release_count: 5,
10
+ release_dir: 'releases',
11
+ public_dir: 'current',
12
+ log_file_path: nil
13
+ }
14
+ end
15
+
16
+ describe "#initialize" do
17
+ it "creates a release_name based on current time" do
18
+ allow( Time ).to receive(:now).and_return(12345)
19
+ subject = described_class.new
20
+ expect( subject.release_name ).to eq "12345"
21
+ end
22
+ end
23
+
24
+ describe "#setup_release_path" do
25
+ context "with an existing release" do
26
+ it "copies existing 'current' release to release_path" do
27
+ config = double("Statistrano::Config", default_remote_config_responses )
28
+ remote = instance_double("Statistrano::Remote", config: config )
29
+ subject = described_class.new
30
+ release_path = File.join( '/var/www/proj/releases', subject.release_name )
31
+ allow( remote ).to receive(:run)
32
+ .and_return( HereOrThere::Response.new("","",true) )
33
+
34
+ expect( remote ).to receive(:create_remote_dir)
35
+ .with( '/var/www/proj/releases' )
36
+ expect( remote ).not_to receive(:create_remote_dir)
37
+ .with( release_path )
38
+
39
+ allow( remote ).to receive(:run).with("readlink /var/www/proj/current")
40
+ .and_return( HereOrThere::Response.new("/var/www/proj/releases/1234","",true) )
41
+ expect( remote ).to receive(:run)
42
+ .with("cp -a /var/www/proj/releases/1234 #{release_path}")
43
+ subject.setup_release_path remote
44
+ end
45
+ end
46
+ context "with no existing releases" do
47
+ it "creates the release_path on the remote" do
48
+ config = double("Statistrano::Config", default_remote_config_responses )
49
+ remote = instance_double("Statistrano::Remote", config: config )
50
+ subject = described_class.new
51
+ allow( remote ).to receive(:run)
52
+ .and_return( HereOrThere::Response.new("","",true) )
53
+
54
+ expect( remote ).to receive(:create_remote_dir)
55
+ .with( '/var/www/proj/releases' )
56
+ expect( remote ).to receive(:create_remote_dir)
57
+ .with( File.join( '/var/www/proj/releases', subject.release_name ) )
58
+ subject.setup_release_path remote
59
+ end
60
+ end
61
+ end
62
+
63
+ describe "#rsync_to_remote" do
64
+ it "calls rsync_to_remote on the remote with the local_dir & release_path" do
65
+ config = double("Statistrano::Config", default_remote_config_responses )
66
+ remote = instance_double("Statistrano::Remote", config: config )
67
+ subject = described_class.new
68
+
69
+ allow( Dir ).to receive(:pwd).and_return('/local')
70
+ expect( remote ).to receive(:rsync_to_remote)
71
+ .with( '/local/build', File.join( '/var/www/proj/releases', subject.release_name ) )
72
+ .and_return( HereOrThere::Response.new("","",true) )
73
+ subject.rsync_to_remote remote
74
+ end
75
+ end
76
+
77
+ describe "#symlink_release" do
78
+ it "runs symlink command on remote" do
79
+ config = double("Statistrano::Config", default_remote_config_responses )
80
+ remote = instance_double("Statistrano::Remote", config: config )
81
+ subject = described_class.new
82
+ release_path = File.join( '/var/www/proj/releases', subject.release_name )
83
+
84
+ expect( remote ).to receive(:run)
85
+ .with( "ln -nfs #{release_path} /var/www/proj/current" )
86
+ subject.symlink_release remote
87
+ end
88
+ end
89
+
90
+ describe "#prune_releases" do
91
+ it "removes releases not tracked in manifest" do
92
+ config = double("Statistrano::Config", default_remote_config_responses )
93
+ remote = instance_double("Statistrano::Remote", config: config )
94
+ manifest = instance_double("Statistrano::Deployment::Manifest")
95
+ subject = described_class.new
96
+ releases = [ Time.now.to_i.to_s,
97
+ (Time.now.to_i + 1 ).to_s,
98
+ (Time.now.to_i + 2 ).to_s ]
99
+ extra_release = (Time.now.to_i + 3).to_s
100
+
101
+ allow(remote).to receive(:run)
102
+ .with("ls -m /var/www/proj/releases")
103
+ .and_return( HereOrThere::Response.new( (releases + [extra_release]).join(','), '', true ) )
104
+ allow(remote).to receive(:run)
105
+ .with("readlink /var/www/proj/current")
106
+ .and_return( HereOrThere::Response.new("",'',true) )
107
+ allow( Statistrano::Deployment::Manifest ).to receive(:new)
108
+ .and_return(manifest)
109
+ allow(manifest).to receive(:remove_if)
110
+ allow(manifest).to receive(:data)
111
+ .and_return(releases.map { |r| {release: r} })
112
+
113
+
114
+ expect(remote).to receive(:run)
115
+ .with("rm -rf /var/www/proj/releases/#{extra_release}")
116
+ expect(manifest).to receive(:save!)
117
+ subject.prune_releases remote
118
+ end
119
+
120
+ it "removes older releases beyond release count from remote & manifest" do
121
+ config = double("Statistrano::Config", default_remote_config_responses.merge(release_count: 2) )
122
+ remote = instance_double("Statistrano::Remote", config: config )
123
+ subject = described_class.new
124
+ manifest = Statistrano::Deployment::Manifest.new '/var/www/proj', remote
125
+ allow( Statistrano::Deployment::Manifest ).to receive(:new)
126
+ .with( '/var/www/proj', remote )
127
+ .and_return(manifest)
128
+ releases = [ Time.now.to_i.to_s,
129
+ (Time.now.to_i + 1 ).to_s,
130
+ (Time.now.to_i + 2 ).to_s ]
131
+
132
+ allow(remote).to receive(:run)
133
+ .with("ls -m /var/www/proj/releases")
134
+ .and_return( HereOrThere::Response.new( releases.join(','), '', true ) )
135
+ allow(remote).to receive(:run)
136
+ .with("readlink /var/www/proj/current")
137
+ .and_return( HereOrThere::Response.new("",'',true) )
138
+
139
+ # this is gnarly but we need to test against
140
+ # the manifest release data because of the block in
141
+ # Manifest#remove_if
142
+ allow(remote).to receive(:run)
143
+ .with("cat /var/www/proj/manifest.json")
144
+ .and_return( HereOrThere::Response.new("[#{ releases.map{ |r| "{\"release\": \"#{r}\"}" }.join(',') }]",'',true) )
145
+
146
+ expect(remote).to receive(:run)
147
+ .with("rm -rf /var/www/proj/releases/#{releases.first}")
148
+ expect(manifest).to receive(:save!)
149
+ subject.prune_releases remote
150
+
151
+ # our expectation is for manifest data to be missing
152
+ # the release that is to be removed
153
+ expect(manifest.data).to eq releases[1..-1].map {|r| {release: r}}
154
+ end
155
+
156
+ it "skips removing a release if it is currently symlinked" do
157
+ config = double("Statistrano::Config", default_remote_config_responses.merge(release_count: 2) )
158
+ remote = instance_double("Statistrano::Remote", config: config )
159
+ subject = described_class.new
160
+ manifest = Statistrano::Deployment::Manifest.new '/var/www/proj', remote
161
+ allow( Statistrano::Deployment::Manifest ).to receive(:new)
162
+ .with( '/var/www/proj', remote )
163
+ .and_return(manifest)
164
+ releases = [ Time.now.to_i.to_s,
165
+ (Time.now.to_i + 1 ).to_s,
166
+ (Time.now.to_i + 2 ).to_s ]
167
+
168
+ allow(remote).to receive(:run)
169
+ .with("ls -m /var/www/proj/releases")
170
+ .and_return( HereOrThere::Response.new( releases.join(','), '', true ) )
171
+
172
+ # this is gnarly but we need to test against
173
+ # the manifest release data because of the block in
174
+ # Manifest#remove_if
175
+ allow(remote).to receive(:run)
176
+ .with("cat /var/www/proj/manifest.json")
177
+ .and_return( HereOrThere::Response.new("[#{ releases.map{ |r| "{\"release\": \"#{r}\"}" }.join(',') }]",'',true) )
178
+
179
+ allow(remote).to receive(:run)
180
+ .with("readlink /var/www/proj/current")
181
+ .and_return( HereOrThere::Response.new("/var/www/proj/releases/#{releases.first}\n",'',true) )
182
+ expect(remote).not_to receive(:run)
183
+ .with("rm -rf /var/www/proj/releases/#{releases.first}")
184
+ expect(manifest).to receive(:save!)
185
+
186
+ subject.prune_releases remote
187
+ end
188
+ end
189
+
190
+ describe "#add_release_to_manifest" do
191
+ it "adds release to manifest & saves" do
192
+ config = double("Statistrano::Config", default_remote_config_responses )
193
+ remote = instance_double("Statistrano::Remote", config: config )
194
+ manifest = instance_double("Statistrano::Deployment::Manifest")
195
+ allow( Statistrano::Deployment::Manifest ).to receive(:new)
196
+ .and_return(manifest)
197
+ subject = described_class.new
198
+
199
+ expect(manifest).to receive(:push)
200
+ .with( release: subject.release_name )
201
+ expect(manifest).to receive(:save!)
202
+ subject.add_release_to_manifest remote
203
+ end
204
+
205
+ it "merges build_data to release in manifest" do
206
+ config = double("Statistrano::Config", default_remote_config_responses )
207
+ remote = instance_double("Statistrano::Remote", config: config )
208
+ manifest = instance_double("Statistrano::Deployment::Manifest")
209
+ allow( Statistrano::Deployment::Manifest ).to receive(:new)
210
+ .and_return(manifest)
211
+ subject = described_class.new
212
+
213
+ expect(manifest).to receive(:push)
214
+ .with( release: subject.release_name, arbitrary: 'data' )
215
+ expect(manifest).to receive(:save!)
216
+
217
+ subject.add_release_to_manifest remote, arbitrary: 'data'
218
+ end
219
+ end
220
+
221
+ describe "#create_release" do
222
+ it "runs through the pipeline" do
223
+ # stupid spec for now
224
+ remote = instance_double("Statistrano::Remote")
225
+ subject = described_class.new
226
+
227
+ expect(subject).to receive(:setup_release_path).with(remote)
228
+ expect(subject).to receive(:rsync_to_remote).with(remote)
229
+ expect(subject).to receive(:invoke_pre_symlink_task)
230
+ expect(subject).to receive(:symlink_release).with(remote)
231
+ expect(subject).to receive(:add_release_to_manifest).with(remote, arbitrary: 'data')
232
+ expect(subject).to receive(:prune_releases).with(remote)
233
+
234
+ subject.create_release remote, arbitrary: 'data'
235
+ end
236
+
237
+ it "aborts deploy if pre_symlink_task returns false or raises" do
238
+ config = double("Statistrano::Config", default_remote_config_responses.merge(
239
+ pre_symlink_task: lambda { false }
240
+ ))
241
+ remote = instance_double("Statistrano::Remote", config: config )
242
+ subject = described_class.new
243
+
244
+ expect(subject).to receive(:setup_release_path).with(remote)
245
+ expect(subject).to receive(:rsync_to_remote).with(remote)
246
+ expect(subject).to receive(:invoke_pre_symlink_task).and_call_original
247
+
248
+ expect(subject).not_to receive(:symlink_release)
249
+ expect(subject).not_to receive(:add_release_to_manifest)
250
+ expect(subject).not_to receive(:prune_releases)
251
+
252
+ expect {
253
+ subject.create_release remote
254
+ }.to raise_error SystemExit
255
+ end
256
+ end
257
+
258
+ describe "#list_releases" do
259
+ it "returns manifest data of releases" do
260
+ config = double("Statistrano::Config", default_remote_config_responses )
261
+ remote = instance_double("Statistrano::Remote", config: config )
262
+ subject = described_class.new
263
+ manifest = instance_double("Statistrano::Deployment::Manifest")
264
+ allow( Statistrano::Deployment::Manifest ).to receive(:new)
265
+ .and_return(manifest)
266
+
267
+ release_data = [{release:"one"},{release:"two"}]
268
+ allow(manifest).to receive(:data)
269
+ .and_return( release_data + [{not_release:"foo"}])
270
+
271
+ expect( subject.list_releases(remote) ).to match_array release_data
272
+ end
273
+ it "sorts releases by release data (newest first)" do
274
+ config = double("Statistrano::Config", default_remote_config_responses )
275
+ remote = instance_double("Statistrano::Remote", config: config )
276
+ subject = described_class.new
277
+ manifest = instance_double("Statistrano::Deployment::Manifest")
278
+ allow( Statistrano::Deployment::Manifest ).to receive(:new)
279
+ .and_return(manifest)
280
+
281
+ release_one = ( Time.now.to_i + 0 ).to_s
282
+ release_two = ( Time.now.to_i + 1 ).to_s
283
+ release_three = ( Time.now.to_i + 2 ).to_s
284
+
285
+ release_data = [{release:release_one},{release:release_three},{release:release_two}]
286
+ allow(manifest).to receive(:data)
287
+ .and_return( release_data + [{not_release:"foo"}])
288
+
289
+ expect( subject.list_releases(remote) ).to eq [{release:release_three},{release:release_two},{release:release_one}]
290
+ end
291
+ end
292
+
293
+ describe "#current_release_data" do
294
+ it "returns data from current release" do
295
+ config = double("Statistrano::Config", default_remote_config_responses )
296
+ remote = instance_double("Statistrano::Remote", config: config )
297
+ subject = described_class.new
298
+ manifest = instance_double("Statistrano::Deployment::Manifest")
299
+ allow( Statistrano::Deployment::Manifest ).to receive(:new)
300
+ .and_return(manifest)
301
+
302
+ manifest_data = [{release: 'first', foo: 'bar'},{release: 'current', random: 'data'}]
303
+ allow(manifest).to receive(:data)
304
+ .and_return(manifest_data)
305
+
306
+ expect( subject.current_release_data(remote) ).to eq release:'current', random:'data'
307
+ end
308
+
309
+ it "merges data from log if log_file_path given" do
310
+ config = double("Statistrano::Config", default_remote_config_responses.merge(log_file_path: '/var/log') )
311
+ remote = instance_double("Statistrano::Remote", config: config )
312
+ subject = described_class.new
313
+ manifest = instance_double("Statistrano::Deployment::Manifest")
314
+ log_file = instance_double("Statistrano::Deployment::LogFile")
315
+ allow( Statistrano::Deployment::Manifest ).to receive(:new)
316
+ .and_return(manifest)
317
+ allow( Statistrano::Deployment::LogFile ).to receive(:new)
318
+ .with('/var/log', remote)
319
+ .and_return(log_file)
320
+
321
+ manifest_data = [{release: 'first', foo: 'bar'},{release: 'current', random: 'data'}]
322
+ allow(manifest).to receive(:data)
323
+ .and_return(manifest_data)
324
+ allow(log_file).to receive(:last_entry)
325
+ .and_return name: 'current',
326
+ log: 'data-current',
327
+ nested: {
328
+ data: 'nested'
329
+ }
330
+
331
+ expect( subject.current_release_data(remote) ).to eq release:'current',
332
+ random: 'data',
333
+ name: 'current',
334
+ log: 'data-current',
335
+ nested: {
336
+ data: 'nested'
337
+ }
338
+ end
339
+
340
+ it "handles an empty log file if log_file_path is given" do
341
+ config = double("Statistrano::Config", default_remote_config_responses.merge(log_file_path: '/var/log') )
342
+ remote = instance_double("Statistrano::Remote", config: config )
343
+ subject = described_class.new
344
+ manifest = instance_double("Statistrano::Deployment::Manifest")
345
+ log_file = instance_double("Statistrano::Remote::File")
346
+ allow( Statistrano::Deployment::Manifest ).to receive(:new)
347
+ .and_return(manifest)
348
+ allow( Statistrano::Remote::File ).to receive(:new)
349
+ .with('/var/log', remote)
350
+ .and_return(log_file)
351
+
352
+ manifest_data = [{release: 'first', foo: 'bar'},{release: 'current', random: 'data'}]
353
+ allow(manifest).to receive(:data)
354
+ .and_return(manifest_data)
355
+ allow(log_file).to receive(:content)
356
+ .and_return ""
357
+
358
+ expect( subject.current_release_data(remote) ).to eq release:'current',
359
+ random: 'data'
360
+ end
361
+ end
362
+
363
+ describe "#rollback_release" do
364
+ it "symlinks the previous release" do
365
+ config = double("Statistrano::Config", default_remote_config_responses )
366
+ remote = instance_double("Statistrano::Remote", config: config )
367
+ subject = described_class.new
368
+ manifest = instance_double("Statistrano::Deployment::Manifest")
369
+ allow( Statistrano::Deployment::Manifest ).to receive(:new)
370
+ .with( '/var/www/proj', remote )
371
+ .and_return(manifest)
372
+
373
+
374
+ release_one = ( Time.now.to_i + 0 ).to_s
375
+ release_two = ( Time.now.to_i + 1 ).to_s
376
+ release_three = ( Time.now.to_i + 2 ).to_s
377
+
378
+ allow( manifest ).to receive(:data)
379
+ .and_return([
380
+ {release: release_one},
381
+ {release: release_two},
382
+ {release: release_three}
383
+ ])
384
+ allow( remote ).to receive(:run)
385
+ allow(remote).to receive(:run)
386
+ .with("readlink /var/www/proj/current")
387
+ .and_return( HereOrThere::Response.new("",'',true) )
388
+ allow( manifest ).to receive(:remove_if)
389
+ allow( manifest ).to receive(:save!)
390
+
391
+ expect( subject ).to receive(:symlink_release)
392
+ .with( remote, release_two )
393
+
394
+ subject.rollback_release remote
395
+ end
396
+
397
+ it "removes the newest release from disk on remote" do
398
+ config = double("Statistrano::Config", default_remote_config_responses )
399
+ remote = instance_double("Statistrano::Remote", config: config )
400
+ subject = described_class.new
401
+ manifest = instance_double("Statistrano::Deployment::Manifest")
402
+ allow( Statistrano::Deployment::Manifest ).to receive(:new)
403
+ .with( '/var/www/proj', remote )
404
+ .and_return(manifest)
405
+
406
+ release_one = ( Time.now.to_i + 0 ).to_s
407
+ release_two = ( Time.now.to_i + 1 ).to_s
408
+ release_three = ( Time.now.to_i + 2 ).to_s
409
+
410
+ allow( manifest ).to receive(:data)
411
+ .and_return([
412
+ {release: release_one},
413
+ {release: release_two},
414
+ {release: release_three}
415
+ ])
416
+
417
+
418
+ allow( subject ).to receive(:symlink_release)
419
+ .with( remote, release_two )
420
+ allow( manifest ).to receive(:remove_if)
421
+ allow( manifest ).to receive(:save!)
422
+
423
+ allow(remote).to receive(:run)
424
+ .with("readlink /var/www/proj/current")
425
+ .and_return( HereOrThere::Response.new("",'',true) )
426
+ expect( remote ).to receive(:run)
427
+ .with("rm -rf /var/www/proj/releases/#{release_three}")
428
+
429
+ subject.rollback_release remote
430
+ end
431
+
432
+ it "removes the newest release from the manifest" do
433
+ config = double("Statistrano::Config", default_remote_config_responses )
434
+ remote = instance_double("Statistrano::Remote", config: config )
435
+ subject = described_class.new
436
+ manifest = Statistrano::Deployment::Manifest.new '/var/www/proj', remote
437
+ allow( Statistrano::Deployment::Manifest ).to receive(:new)
438
+ .with( '/var/www/proj', remote )
439
+ .and_return(manifest)
440
+
441
+
442
+ release_one = ( Time.now.to_i + 0 ).to_s
443
+ release_two = ( Time.now.to_i + 1 ).to_s
444
+ release_three = ( Time.now.to_i + 2 ).to_s
445
+ releases = [release_three,release_two,release_one]
446
+ allow( remote ).to receive(:run)
447
+ allow(remote).to receive(:run)
448
+ .with("readlink /var/www/proj/current")
449
+ .and_return( HereOrThere::Response.new("",'',true) )
450
+
451
+
452
+ # this is gnarly but we need to test against
453
+ # the manifest release data because of the block in
454
+ # Manifest#remove_if
455
+ allow(remote).to receive(:run)
456
+ .with("cat /var/www/proj/manifest.json")
457
+ .and_return( HereOrThere::Response.new("[#{ releases.map{ |r| "{\"release\": \"#{r}\"}" }.join(',') }]",'',true) )
458
+
459
+ allow( subject ).to receive(:symlink_release)
460
+ .with( remote, release_two )
461
+
462
+ expect( manifest ).to receive(:save!)
463
+ subject.rollback_release remote
464
+ expect( manifest.data ).to eq releases[1..-1].map {|r| {release: r}}
465
+ end
466
+
467
+ it "errors if there is only one release" do
468
+ config = double("Statistrano::Config", default_remote_config_responses )
469
+ remote = instance_double("Statistrano::Remote", config: config )
470
+ subject = described_class.new
471
+ manifest = instance_double("Statistrano::Deployment::Manifest")
472
+ allow( Statistrano::Deployment::Manifest ).to receive(:new)
473
+ .and_return(manifest)
474
+
475
+ release_one = ( Time.now.to_i + 0 ).to_s
476
+ allow( manifest ).to receive(:data)
477
+ .and_return([
478
+ { release: release_one }
479
+ ])
480
+
481
+ expect( Statistrano::Log ).to receive(:error)
482
+ subject.rollback_release remote
483
+ end
484
+ end
485
+
486
+ end
@@ -0,0 +1,59 @@
1
+ require 'spec_helper'
2
+
3
+ describe Statistrano::Deployment::Releaser::Single do
4
+
5
+ let(:default_remote_config_responses) do
6
+ {
7
+ remote_dir: '/var/www/proj',
8
+ local_dir: 'build'
9
+ }
10
+ end
11
+
12
+ describe "#initialize" do
13
+ it "creates a release_name based on current time" do
14
+ allow( Time ).to receive(:now).and_return(12345)
15
+ subject = described_class.new
16
+ expect( subject.release_name ).to eq "12345"
17
+ end
18
+ end
19
+
20
+ describe "#create_release" do
21
+ it "runs through the pipeline" do
22
+ remote = instance_double("Statistrano::Remote")
23
+ subject = described_class.new
24
+
25
+ expect(subject).to receive(:setup).with(remote)
26
+ expect(subject).to receive(:rsync_to_remote).with(remote)
27
+
28
+ subject.create_release remote, {}
29
+ end
30
+ end
31
+
32
+ describe "#setup" do
33
+ it "creates the remote_dir on the target" do
34
+ config = double("Statistrano::Config", default_remote_config_responses)
35
+ remote = instance_double("Statistrano::Remote", config: config )
36
+ subject = described_class.new
37
+
38
+ expect( remote ).to receive(:run)
39
+ .with("mkdir -p /var/www/proj")
40
+ .and_return( HereOrThere::Response.new("","",true) )
41
+ subject.setup remote
42
+ end
43
+ end
44
+
45
+ describe "#rsync_to_remote" do
46
+ it "calls rsync_to_remote on the remote with the local_dir & remote_dir" do
47
+ config = double("Statistrano::Config", default_remote_config_responses )
48
+ remote = instance_double("Statistrano::Remote", config: config )
49
+ subject = described_class.new
50
+
51
+ allow( Dir ).to receive(:pwd).and_return('/local')
52
+ expect( remote ).to receive(:rsync_to_remote)
53
+ .with( '/local/build', '/var/www/proj' )
54
+ .and_return( HereOrThere::Response.new("","",true) )
55
+ subject.rsync_to_remote remote
56
+ end
57
+ end
58
+
59
+ end