whiskey_disk 0.6.17 → 0.6.20

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG CHANGED
@@ -1,4 +1,38 @@
1
1
 
2
+ 0.6.20 / 2011-04-06
3
+ ==================
4
+
5
+ * Output the entire command before running it when debugging.
6
+ * more anal git checkouts on clones to support older gits
7
+ * abort instead of raising in wd
8
+ * Neuter commandline output in wd command spec
9
+ * Make #changes work on setup
10
+ * Allow enabling debugger in specs w/ non-empty ENV['debug']
11
+ * Fix setup #changed? integration specs
12
+ * Improve example text for deployment #changed? integration specs
13
+ * Factor out snapshotting of git revision from WD.initialize_git_changes
14
+ * Fix the direction of the setup #changed? integration spec test
15
+ * Fixing jump_to_initial_commit spec helper
16
+ * Helper integration spec should use the correct branch when setting up.
17
+ * adjust env testing in integration specs
18
+ * update some specs to work with updated checkout/setup helpers
19
+ * use branches in integration checks so full checkouts will work
20
+ * when initializing git changes data, work from deployment path
21
+ * allow integration spec checkouts to switch to a specific branch
22
+ * record git changes for later use by #changed?
23
+ * capture rsync changes for later #changed? analysis
24
+ * capture initial git HEAD ref for later #changes comparisons
25
+ * clean out any prior git/rsync changes data before refreshing repos
26
+ * Add specs for version command-line argument
27
+ * Change spec helper run_command method set pwd to bin/
28
+ * integration spec for #changed? in post_setup tasks
29
+ * adding #changed? helper (and friends) to whiskey_disk/helpers
30
+ * spec_helper method to rewind a git repo to the beginning
31
+ * git project scenario changes to support integration testing of #changes helper
32
+ * refactor: splitting up WD.summarize method
33
+ * README updates for #changed? helper functionality
34
+
35
+
2
36
  0.6.17 / 2011-03-25
3
37
  ==================
4
38
 
data/README.markdown CHANGED
@@ -86,12 +86,14 @@ current local checkout.
86
86
 
87
87
  - You can deploy to multiple remote targets at once. Currently this is limited
88
88
  to one-after-the-other synchronous deployments, but we're thinking about
89
- doing them in parallel once we're happy with the stability of this (new)
90
- feature.
89
+ doing them in parallel once we're happy with the stability of this feature.
91
90
 
92
91
  - Assign hosts to roles (e.g., "web", "db", "app") and vary the shell or rake
93
92
  post-setup/post-deploy actions you run based on those roles.
94
93
 
94
+ - Limit the actions you run after deployment based on whether files of interest
95
+ *actually changed*.
96
+
95
97
  ### Assumptions ###
96
98
 
97
99
  - your project is managed via git
@@ -486,9 +488,37 @@ You can also define these tasks yourself if you want to eliminate the dependency
486
488
  deployment target system.
487
489
 
488
490
 
491
+ ### Doing things when files of interest change ###
492
+
493
+ Do you want to run database migrations when no migrations have been added? Why bother compressing front-end assets when none of them have changed? Why restart your application server if only the project README changed? Whiskey\_disk provides a `changed?` ruby helper method to allow you to decide whether to run expensive post deployment tasks, based on what files changed in the deployment. Typically this would happen in your rake tasks, but it could happen from regular ruby code as well.
494
+
495
+
496
+ require 'whiskey_disk/helpers'
497
+
498
+ namespace :deploy do
499
+
500
+ task :run_migrations do
501
+ if role?(:db) and changed?('db/migrate')
502
+ puts "Running database migrations..."
503
+ Rake::Task['db:migrate'].invoke
504
+ end
505
+ end
506
+
507
+ task :compress_assets do
508
+ if changed?('public/stylesheets') or changed?('public/javascripts')
509
+ puts "Getting my asset munge on..."
510
+ # do some expensive asset compression stuff
511
+ end
512
+ end
513
+
514
+ task :post_deploy => [ :run_migrations, :compress_assets ]
515
+ end
516
+
517
+
518
+
489
519
  ### Running via rake ###
490
520
 
491
- In your Rakefile:
521
+ You can use rake tasks to do everything possible with whiskey\_disk (the `wd` command is just a front-end to the whiskey\_disk rake tasks). In your Rakefile:
492
522
 
493
523
  require 'whiskey_disk/rake'
494
524
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.6.17
1
+ 0.6.20
data/bin/wd CHANGED
@@ -43,10 +43,10 @@ rescue
43
43
  abort op.to_s
44
44
  end
45
45
 
46
- raise op.to_s unless options[:target]
47
- raise op.to_s unless rest and rest.size == 1
46
+ abort op.to_s unless options[:target]
47
+ abort op.to_s unless rest and rest.size == 1
48
48
  command = rest.first
49
- raise op.to_s unless ['deploy', 'setup'].include?(command)
49
+ abort op.to_s unless ['deploy', 'setup'].include?(command)
50
50
 
51
51
  ENV['to'] = options[:target]
52
52
  ENV['path'] = options[:path]
data/lib/whiskey_disk.rb CHANGED
@@ -137,12 +137,14 @@ class WhiskeyDisk
137
137
  end
138
138
 
139
139
  def ssh(domain, cmd)
140
+ puts "Running command on [#{domain}]: [#{cmd}]" if Config.debug?
140
141
  args = [domain[:name], build_command(domain, cmd)]
141
142
  args.unshift '-v' if Config.debug?
142
143
  system('ssh', *args)
143
144
  end
144
145
 
145
146
  def shell(domain, cmd)
147
+ puts "Running command locally: [#{cmd}]" if Config.debug?
146
148
  system('bash', '-c', build_command(domain, cmd))
147
149
  end
148
150
 
@@ -160,22 +162,24 @@ class WhiskeyDisk
160
162
  @results ||= []
161
163
  @results << { :domain => domain, :status => status }
162
164
  end
165
+
166
+ def summarize_results(results)
167
+ successes = failures = 0
168
+ results.each do |result|
169
+ puts "#{result[:domain]} => #{result[:status] ? 'succeeded' : 'failed'}."
170
+ if result[:status]
171
+ successes += 1
172
+ else
173
+ failures += 1
174
+ end
175
+ end
176
+ [successes + failures, successes, failures]
177
+ end
163
178
 
164
179
  def summarize
165
- puts
166
- puts "Results:"
180
+ puts "\nResults:"
167
181
  if results and not results.empty?
168
- successes = failures = total = 0
169
- results.each do |result|
170
- total += 1
171
- if result[:status]
172
- successes += 1
173
- else
174
- failures += 1
175
- end
176
-
177
- puts "#{result[:domain]} => #{result[:status] ? 'succeeded' : 'failed'}."
178
- end
182
+ total, successes, failures = summarize_results(results)
179
183
  puts "Total: #{total} deployment#{total == 1 ? '' : 's'}, " +
180
184
  "#{successes} success#{successes == 1 ? '' : 'es'}, " +
181
185
  "#{failures} failure#{failures == 1 ? '' : 's'}."
@@ -198,7 +202,7 @@ class WhiskeyDisk
198
202
  end
199
203
 
200
204
  def safe_branch_checkout(path, my_branch)
201
- %Q(cd #{path} && git checkout -b #{my_branch} origin/#{my_branch} || git checkout #{my_branch})
205
+ %Q(cd #{path} && git checkout -b #{my_branch} origin/#{my_branch} || git checkout #{my_branch} origin/#{my_branch} || git checkout #{my_branch})
202
206
  end
203
207
 
204
208
  def clone_repository(repo, path, my_branch)
@@ -251,13 +255,44 @@ class WhiskeyDisk
251
255
  clone_repository(self[:config_repository], self[:deploy_config_to], config_branch)
252
256
  end
253
257
 
258
+ def snapshot_git_revision
259
+ needs(:deploy_to)
260
+ enqueue "cd #{self[:deploy_to]}"
261
+ enqueue %Q{ml=\`cat .git/refs/heads/#{branch}\`}
262
+ end
263
+
264
+ def initialize_git_changes
265
+ needs(:deploy_to)
266
+ enqueue "rm -f #{self[:deploy_to]}/.whiskey_disk_git_changes"
267
+ snapshot_git_revision
268
+ end
269
+
270
+ def initialize_rsync_changes
271
+ needs(:deploy_to)
272
+ enqueue "rm -f #{self[:deploy_to]}/.whiskey_disk_rsync_changes"
273
+ end
274
+
275
+ def initialize_all_changes
276
+ needs(:deploy_to)
277
+ initialize_git_changes
278
+ initialize_rsync_changes
279
+ end
280
+
281
+ def capture_git_changes
282
+ needs(:deploy_to)
283
+ enqueue "git diff --name-only ${ml}..HEAD > #{self[:deploy_to]}/.whiskey_disk_git_changes"
284
+ end
285
+
254
286
  def update_main_repository_checkout
255
287
  needs(:deploy_to)
288
+ initialize_git_changes
256
289
  refresh_checkout(self[:deploy_to], branch)
290
+ capture_git_changes
257
291
  end
258
292
 
259
293
  def update_configuration_repository_checkout
260
294
  needs(:deploy_config_to)
295
+ initialize_rsync_changes
261
296
  refresh_checkout(self[:deploy_config_to], config_branch)
262
297
  end
263
298
 
@@ -265,7 +300,9 @@ class WhiskeyDisk
265
300
  needs(:deploy_to, :deploy_config_to)
266
301
  raise "Must specify project name when using a configuration repository." unless project_name_specified?
267
302
  enqueue "echo Rsyncing configuration..."
268
- enqueue("rsync -a#{'v --progress' if Config.debug?} #{self[:deploy_config_to]}/#{self[:project]}/#{self[:config_target]}/ #{self[:deploy_to]}/")
303
+ enqueue("rsync -a#{'v --progress' if Config.debug?} " +
304
+ "--log-file=#{self[:deploy_to]}/.whiskey_disk_rsync_changes " +
305
+ "#{self[:deploy_config_to]}/#{self[:project]}/#{self[:config_target]}/ #{self[:deploy_to]}/")
269
306
  end
270
307
 
271
308
  def run_post_setup_hooks
@@ -3,4 +3,46 @@
3
3
  def role?(role)
4
4
  return false unless ENV['WD_ROLES'] and ENV['WD_ROLES'] != ''
5
5
  ENV['WD_ROLES'].split(':').include?(role.to_s)
6
+ end
7
+
8
+ # have files of interest changed on this deployment?
9
+ def changed?(path)
10
+ return true unless gc = git_changes
11
+ cleaned = Regexp.escape(path.sub(%r{/+$}, ''))
12
+ [ gc, rsync_changes ].flatten.compact.any? { |p| p =~ %r<^#{cleaned}(?:$|/)> }
13
+ end
14
+
15
+ # list of changed paths, according to git
16
+ def git_changes
17
+ changes = read_git_changes_file.split("\n").uniq
18
+ rescue Exception
19
+ nil
20
+ end
21
+
22
+ def rsync_changes
23
+ changes = read_rsync_changes_file.split("\n")
24
+ changes.map {|c| c.sub(/^[^ ]* [^ ]* [^ ]* [^ ]* /, '') }.grep(%r{/}).map {|s| s.sub(%r{/$}, '') } - ['.']
25
+ rescue Exception
26
+ nil
27
+ end
28
+
29
+ def read_git_changes_file
30
+ File.read(git_changes_path)
31
+ end
32
+
33
+ def read_rsync_changes_file
34
+ File.read(rsync_changes_path)
35
+ end
36
+
37
+ def changes_file_root
38
+ path = IO.popen("git rev-parse --show-toplevel").read
39
+ path == '' ? Dir.pwd : path.chomp
40
+ end
41
+
42
+ def git_changes_path
43
+ File.join(changes_file_root, '.whiskey_disk_git_changes')
44
+ end
45
+
46
+ def rsync_changes_path
47
+ File.join(changes_file_root, '.whiskey_disk_rsync_changes')
6
48
  end
@@ -11,6 +11,7 @@ namespace :deploy do
11
11
  WhiskeyDisk.update_main_repository_checkout
12
12
  WhiskeyDisk.update_configuration_repository_checkout if WhiskeyDisk.has_config_repo?
13
13
  WhiskeyDisk.refresh_configuration if WhiskeyDisk.has_config_repo?
14
+ WhiskeyDisk.initialize_all_changes
14
15
  WhiskeyDisk.run_post_setup_hooks
15
16
  WhiskeyDisk.flush
16
17
  WhiskeyDisk.summarize
data/spec/spec_helper.rb CHANGED
@@ -3,6 +3,13 @@ require 'bacon'
3
3
  require 'facon'
4
4
  require 'fileutils'
5
5
 
6
+ if ENV['DEBUG'] and ENV['DEBUG'] != ''
7
+ STDERR.puts "Enabling debugger for spec runs..."
8
+ require 'rubygems'
9
+ require 'ruby-debug'
10
+ Debugger.start
11
+ end
12
+
6
13
  $:.unshift(File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib')))
7
14
 
8
15
  # local target directory, integration spec workspace
@@ -50,9 +57,19 @@ def scenario_config(path)
50
57
  end
51
58
 
52
59
  # clone a git repository locally (as if a "wd setup" had been deployed)
53
- def checkout_repo(repo_name, name = '')
60
+ def checkout_repo(repo_name, branch = nil)
54
61
  repo_path = File.expand_path(File.join(File.dirname(__FILE__), '..', 'scenarios', 'git_repositories', "#{repo_name}.git"))
55
- system("cd #{deployment_root} && git clone #{repo_path} #{name} >/dev/null 2>/dev/null")
62
+ system("cd #{deployment_root} && git clone #{repo_path} >/dev/null 2>/dev/null")
63
+ checkout_branch(repo_name, branch)
64
+ end
65
+
66
+ def checkout_branch(repo_name, branch = nil)
67
+ return unless branch
68
+ system("cd #{deployment_root}/#{repo_name} && git checkout #{branch} >/dev/null 2>/dev/null")
69
+ end
70
+
71
+ def jump_to_initial_commit(path)
72
+ system(%Q(cd #{File.join(deployment_root, path)} && git reset --hard `git log --oneline | tail -1 | awk '{print $1}'` >/dev/null 2>/dev/null))
56
73
  end
57
74
 
58
75
  def run_log
@@ -2,13 +2,24 @@ require File.dirname(__FILE__) + '/spec_helper.rb'
2
2
  require 'rake'
3
3
 
4
4
  def run_command
5
- eval File.read(File.join(File.dirname(__FILE__), *%w[.. bin wd]))
5
+ cmd_path = File.expand_path(File.join(File.dirname(__FILE__), *%w[.. bin wd]))
6
+ path = File.expand_path(File.dirname(cmd_path))
7
+ file = File.read(cmd_path)
8
+
9
+ Dir.chdir(path) do |path|
10
+ eval(file)
11
+ end
6
12
  end
7
13
 
8
14
  describe 'wd command' do
9
15
  before do
16
+ @stderr, @stdout, $stderr, $stdout = $stderr, $stdout, StringIO.new, StringIO.new
10
17
  ENV['to'] = ENV['path'] = nil
11
18
  end
19
+
20
+ after do
21
+ @stderr, @stdout, $stderr, $stdout = $stderr, $stdout, @stderr, @stdout
22
+ end
12
23
 
13
24
  describe 'when no command-line arguments are specified' do
14
25
  before do
@@ -21,25 +32,56 @@ describe 'wd command' do
21
32
  lambda { run_command }
22
33
  end
23
34
 
24
- it 'should fail' do
25
- lambda { run_command }.should.raise
35
+ it 'should exit' do
36
+ lambda { run_command }.should.raise(SystemExit)
37
+ end
38
+
39
+ it 'should exit with a failure status' do
40
+ begin
41
+ run_command
42
+ rescue Exception => e
43
+ e.success?.should == false
44
+ end
26
45
  end
27
46
  end
28
47
 
29
48
  it 'should output usage without a backtrace when --help is specified' do
30
49
  Object.send(:remove_const, :ARGV)
31
50
  ARGV = ['--help']
32
- self.stub!(:abort).and_raise(SystemExit) # primarily to drop extraneous output
33
51
  lambda { run_command }.should.raise(SystemExit)
34
52
  end
35
53
 
36
54
  it 'should output usage without a backtrace when garbage options are specified' do
37
55
  Object.send(:remove_const, :ARGV)
38
56
  ARGV = ['--slkjfsdflkj']
39
- self.stub!(:abort).and_raise(SystemExit) # primarily to drop extraneous output
40
57
  lambda { run_command }.should.raise(SystemExit)
41
58
  end
42
59
 
60
+ describe 'when --version argument is specified' do
61
+ before do
62
+ Object.send(:remove_const, :ARGV)
63
+ ARGV = ['--version']
64
+ end
65
+
66
+ # it 'should output the version stored in the VERSION file' do
67
+ # version = File.read(File.expand_path(File.join(File.dirname(__FILE__), '..', 'VERSION'))).chomp
68
+ # # TODO: capture version output
69
+ # lambda{ run_command }
70
+ # end
71
+
72
+ it 'should exit' do
73
+ lambda { run_command }.should.raise(SystemExit)
74
+ end
75
+
76
+ it 'should exit successfully' do
77
+ begin
78
+ run_command
79
+ rescue SystemExit => e
80
+ e.success?.should == true
81
+ end
82
+ end
83
+ end
84
+
43
85
  describe "when the 'setup' command is specified" do
44
86
  before do
45
87
  Object.send(:remove_const, :ARGV)
@@ -51,9 +93,17 @@ describe 'wd command' do
51
93
  Rake::Application.should.receive(:new).never
52
94
  lambda { run_command }
53
95
  end
54
-
55
- it 'should fail' do
56
- lambda { run_command }.should.raise
96
+
97
+ it 'should exit when a target is specified' do
98
+ lambda { run_command }.should.raise(SystemExit)
99
+ end
100
+
101
+ it 'should exit with a failing status when a target is specified' do
102
+ begin
103
+ run_command
104
+ rescue SystemExit => e
105
+ e.success?.should == false
106
+ end
57
107
  end
58
108
  end
59
109
 
@@ -432,8 +482,16 @@ describe 'wd command' do
432
482
  lambda { run_command }
433
483
  end
434
484
 
435
- it 'should fail' do
436
- lambda { run_command }.should.raise
485
+ it 'should exit when a target is specified' do
486
+ lambda { run_command }.should.raise(SystemExit)
487
+ end
488
+
489
+ it 'should exit with a failing status when a target is specified' do
490
+ begin
491
+ run_command
492
+ rescue SystemExit => e
493
+ e.success?.should == false
494
+ end
437
495
  end
438
496
  end
439
497
 
@@ -854,13 +912,36 @@ describe 'wd command' do
854
912
  ARGV = ['frazzlebazzle', 'shizzlebizzle']
855
913
  end
856
914
 
857
- it 'should fail if no target is specified' do
858
- lambda { run_command }.should.raise
915
+ describe 'when no target is specified' do
916
+ it 'should exit when a target is specified' do
917
+ lambda { run_command }.should.raise(SystemExit)
918
+ end
919
+
920
+ it 'should exit with a failing status when a target is specified' do
921
+ begin
922
+ run_command
923
+ rescue SystemExit => e
924
+ e.success?.should == false
925
+ end
926
+ end
859
927
  end
860
-
861
- it 'should fail even if a target is specified' do
862
- ARGV.push('--to=foo')
863
- lambda { run_command }.should.raise
928
+
929
+ describe 'when a target is specified' do
930
+ before do
931
+ ARGV.push('--to=foo')
932
+ end
933
+
934
+ it 'should exit when a target is specified' do
935
+ lambda { run_command }.should.raise(SystemExit)
936
+ end
937
+
938
+ it 'should exit with a failing status when a target is specified' do
939
+ begin
940
+ run_command
941
+ rescue SystemExit => e
942
+ e.success?.should == false
943
+ end
944
+ end
864
945
  end
865
946
  end
866
947
 
@@ -870,13 +951,36 @@ describe 'wd command' do
870
951
  ARGV = ['frazzlebazzle']
871
952
  end
872
953
 
873
- it 'should fail when no target is specified' do
874
- lambda { run_command }.should.raise
954
+ describe 'when no target is specified' do
955
+ it 'should exit when a target is specified' do
956
+ lambda { run_command }.should.raise(SystemExit)
957
+ end
958
+
959
+ it 'should exit with a failing status when a target is specified' do
960
+ begin
961
+ run_command
962
+ rescue SystemExit => e
963
+ e.success?.should == false
964
+ end
965
+ end
875
966
  end
876
-
877
- it 'should fail when a target is specified' do
878
- ARGV.push('--to=foo')
879
- lambda { run_command }.should.raise
967
+
968
+ describe 'when a target is specified' do
969
+ before do
970
+ ARGV.push('--to=foo')
971
+ end
972
+
973
+ it 'should exit when a target is specified' do
974
+ lambda { run_command }.should.raise(SystemExit)
975
+ end
976
+
977
+ it 'should exit with a failing status when a target is specified' do
978
+ begin
979
+ run_command
980
+ rescue SystemExit => e
981
+ e.success?.should == false
982
+ end
983
+ end
880
984
  end
881
985
  end
882
986
  end
@@ -1,7 +1,7 @@
1
1
  require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper.rb'))
2
2
  require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'lib', 'whiskey_disk', 'helpers'))
3
3
 
4
- describe '#role?' do
4
+ describe 'when checking for a role during setup or deployment' do
5
5
  it 'should accept a role string' do
6
6
  lambda { role?('web') }.should.not.raise(ArgumentError)
7
7
  end
@@ -41,3 +41,401 @@ describe '#role?' do
41
41
  end
42
42
  end
43
43
 
44
+ def set_git_changes(changes)
45
+ self.stub!(:git_changes).and_return(changes)
46
+ end
47
+
48
+ def set_rsync_changes(changes)
49
+ self.stub!(:rsync_changes).and_return(changes)
50
+ end
51
+
52
+ describe 'when determining if certain files changed when a deployment was run' do
53
+ before do
54
+ @matching_file = '/path/to/file'
55
+ @matching_path = '/path/to'
56
+ @non_matching_file = '/nowhere/file'
57
+ @substring_file = '/nowhere/filething'
58
+ @random_file = '/random/path'
59
+
60
+ set_git_changes([])
61
+ set_rsync_changes([])
62
+ end
63
+
64
+ it 'should accept a path' do
65
+ lambda { changed?('foo') }.should.not.raise(ArgumentError)
66
+ end
67
+
68
+ it 'should require a path' do
69
+ lambda { changed? }.should.raise(ArgumentError)
70
+ end
71
+
72
+ it 'should be true when the specified file is in the list of git changes' do
73
+ set_git_changes([ @matching_file, @random_file])
74
+ changed?(@matching_file).should.be.true
75
+ end
76
+
77
+ it 'should ignore trailing "/"s in the provided path when doing an exact git change match' do
78
+ set_git_changes([ @matching_file, @random_file])
79
+ changed?(@matching_file + '///').should.be.true
80
+ end
81
+
82
+ it 'should be true when the specified path is a full path prefix in the list of git changes' do
83
+ set_git_changes([ @matching_file , @random_file])
84
+ changed?(@matching_path).should.be.true
85
+ end
86
+
87
+ it 'should ignore trailing "/"s in the provided path when doing a path git change match' do
88
+ set_git_changes([ @matching_file , @random_file])
89
+ changed?(@matching_path + '///').should.be.true
90
+ end
91
+
92
+ it 'should be true when the specified file is in the list of rsync changes' do
93
+ set_rsync_changes([ @matching_file, @random_file])
94
+ changed?(@matching_file).should.be.true
95
+ end
96
+
97
+ it 'should ignore trailing "/"s in the provided path when doing an exact rsync change match' do
98
+ set_rsync_changes([ @matching_file, @random_file])
99
+ changed?(@matching_file + "///").should.be.true
100
+ end
101
+
102
+ it 'should be true when the specified path is a full path prefix in the list of git changes' do
103
+ set_rsync_changes([ @matching_file , @random_file])
104
+ changed?(@matching_path).should.be.true
105
+ end
106
+
107
+ it 'should ignore trailing "/"s in the provided path when doing a path rsync change match' do
108
+ set_rsync_changes([ @matching_file , @random_file])
109
+ changed?(@matching_path + '///').should.be.true
110
+ end
111
+
112
+ it 'should ignore regex metacharacters when looking for a git match' do
113
+ set_git_changes([ '/path/to/somestring'])
114
+ changed?('/path/to/some.*').should.be.false
115
+ end
116
+
117
+ it 'should ignore regex metacharacters when looking for an rsync match' do
118
+ set_rsync_changes([ '/path/to/somestring'])
119
+ changed?('/path/to/some.*').should.be.false
120
+ end
121
+
122
+ it 'should be true when the git changes file cannot be found' do
123
+ set_git_changes(nil)
124
+ changed?(@matching_file).should.be.true
125
+ end
126
+
127
+ it 'should be false if not path or file matches the specified file' do
128
+ set_git_changes([@matching_file, @matching_path, @random_file, @substring_file])
129
+ set_rsync_changes([@matching_file, @matching_path, @random_file, @substring_file])
130
+ changed?(@non_matching_file).should.be.false
131
+ end
132
+ end
133
+
134
+ describe "when finding files changed by git in a deployment" do
135
+ before do
136
+ @contents = 'CHANGELOG
137
+ README.markdown
138
+ Rakefile
139
+ VERSION
140
+ lib/whiskey_disk.rb
141
+ lib/whiskey_disk/config.rb
142
+ lib/whiskey_disk/helpers.rb
143
+ scenarios/git_repositories/project.git/objects/04/26e152e66c8cd42974279bdcae09be9839c172
144
+ scenarios/git_repositories/project.git/objects/04/f4de85eaf72ef1631dc6d7424045c0a749b757
145
+ scenarios/git_repositories/project.git/refs/heads/bad_rakefile
146
+ scenarios/git_repositories/project.git/refs/heads/master
147
+ scenarios/remote/deploy.yml
148
+ spec/integration/deployment_failures_spec.rb
149
+ spec/integration/post_rake_tasks_spec.rb
150
+ spec/integration/staleness_checks_spec.rb
151
+ spec/spec_helper.rb
152
+ spec/whiskey_disk/config_spec.rb
153
+ spec/whiskey_disk/helpers_spec.rb
154
+ spec/whiskey_disk_spec.rb
155
+ whiskey_disk.gemspec
156
+ '
157
+ end
158
+
159
+ it 'should work without arguments' do
160
+ lambda { git_changes }.should.not.raise(ArgumentError)
161
+ end
162
+
163
+ it 'should not allow arguments' do
164
+ lambda { git_changes(:foo) }.should.raise(ArgumentError)
165
+ end
166
+
167
+ it 'should return nil when a git changes file cannot be found' do
168
+ self.stub!(:read_git_changes_file).and_raise
169
+ git_changes.should.be.nil
170
+ end
171
+
172
+ it 'should return an empty list if no files are found in the git changes file' do
173
+ self.stub!(:read_git_changes_file).and_return('')
174
+ git_changes.should == []
175
+ end
176
+
177
+ it 'should return a list of all filenames mentioned in the git changes file' do
178
+ self.stub!(:read_git_changes_file).and_return(@contents)
179
+ git_changes.should == @contents.split("\n")
180
+ end
181
+
182
+ it 'should strip duplicates from filenames mentioned in the git changes file' do
183
+ lines = @contents.split("\n")
184
+ duplicates = @contents + lines.first + "\n" + lines.last + "\n"
185
+ self.stub!(:read_git_changes_file).and_return(duplicates)
186
+ git_changes.sort.should == @contents.split("\n").sort
187
+ end
188
+ end
189
+
190
+ describe "when finding files changed by rsync in a deployment" do
191
+ before do
192
+ @contents = '2011/02/27 20:11:42 [36728] receiving file list
193
+ 2011/02/27 20:11:42 [36728] sent 24 bytes received 9 bytes total size 0
194
+ 2011/02/27 20:11:58 [36780] receiving file list
195
+ 2011/02/27 20:11:58 [36780] sent 24 bytes received 9 bytes total size 0
196
+ 2011/02/27 20:12:09 [36808] receiving file list
197
+ 2011/02/27 20:12:09 [36808] sent 24 bytes received 9 bytes total size 0
198
+ 2011/02/27 20:12:19 [36835] receiving file list
199
+ 2011/02/27 20:12:19 [36835] .d..t.... ./
200
+ 2011/02/27 20:12:19 [36835] cd+++++++ Application Support/
201
+ 2011/02/27 20:12:19 [36835] cd+++++++ Application Support/Google/
202
+ 2011/02/27 20:12:19 [36835] cd+++++++ Application Support/Google/GoogleTalkPlugin.app/
203
+ 2011/02/27 20:12:19 [36835] cd+++++++ Application Support/Google/GoogleTalkPlugin.app/Contents/
204
+ 2011/02/27 20:12:19 [36835] >f+++++++ Application Support/Google/GoogleTalkPlugin.app/Contents/Info.plist
205
+ 2011/02/27 20:12:19 [36835] cd+++++++ Application Support/Google/GoogleTalkPlugin.app/Contents/Frameworks/
206
+ 2011/02/27 20:12:19 [36835] cd+++++++ Application Support/Google/GoogleTalkPlugin.app/Contents/Frameworks/GoogleBreakpad.framework/
207
+ 2011/02/27 20:12:19 [36835] cL+++++++ Application Support/Google/GoogleTalkPlugin.app/Contents/Frameworks/GoogleBreakpad.framework/GoogleBreakpad -> Versions/Current/GoogleBreakpad
208
+ 2011/02/27 20:12:19 [36835] cL+++++++ Application Support/Google/GoogleTalkPlugin.app/Contents/Frameworks/GoogleBreakpad.framework/Resources -> Versions/Current/Resources
209
+ 2011/02/27 20:12:19 [36835] cd+++++++ Application Support/Google/GoogleTalkPlugin.app/Contents/Frameworks/GoogleBreakpad.framework/Versions/
210
+ 2011/02/27 20:12:19 [36835] cL+++++++ Application Support/Google/GoogleTalkPlugin.app/Contents/Frameworks/GoogleBreakpad.framework/Versions/Current -> A
211
+ 2011/02/27 20:12:19 [36835] cd+++++++ Application Support/Google/GoogleTalkPlugin.app/Contents/Frameworks/GoogleBreakpad.framework/Versions/A/
212
+ 2011/02/27 20:12:19 [36835] cd+++++++ Application Support/Google/GoogleTalkPlugin.app/Contents/Frameworks/GoogleBreakpad.framework/Versions/A/Resources/
213
+ 2011/02/27 20:12:19 [36835] cd+++++++ Application Support/Google/GoogleTalkPlugin.app/Contents/Frameworks/GoogleBreakpad.framework/Versions/A/Resources/Reporter.app/
214
+ 2011/02/27 20:12:19 [36835] cd+++++++ Application Support/Google/GoogleTalkPlugin.app/Contents/Frameworks/GoogleBreakpad.framework/Versions/A/Resources/Reporter.app/Contents/
215
+ 2011/02/27 20:12:19 [36835] cd+++++++ Application Support/Google/GoogleTalkPlugin.app/Contents/MacOS/
216
+ 2011/02/27 20:12:20 [36835] >f+++++++ Application Support/Google/GoogleTalkPlugin.app/Contents/MacOS/GoogleTalkPlugin
217
+ 2011/02/27 20:12:20 [36835] cd+++++++ Internet Plug-Ins/
218
+ 2011/02/27 20:12:20 [36835] cd+++++++ Internet Plug-Ins/googletalkbrowserplugin.plugin/
219
+ 2011/02/27 20:12:20 [36835] cd+++++++ Internet Plug-Ins/googletalkbrowserplugin.plugin/Contents/
220
+ 2011/02/27 20:12:20 [36835] cd+++++++ Internet Plug-Ins/googletalkbrowserplugin.plugin/Contents/MacOS/
221
+ 2011/02/27 20:12:20 [36835] >f+++++++ Internet Plug-Ins/googletalkbrowserplugin.plugin/Contents/MacOS/googletalkbrowserplugin
222
+ 2011/02/27 20:12:20 [36835] cd+++++++ Internet Plug-Ins/googletalkbrowserplugin.plugin/Contents/Resources/
223
+ 2011/02/27 20:12:20 [36835] cd+++++++ Internet Plug-Ins/npgtpo3dautoplugin.plugin/
224
+ 2011/02/27 20:12:20 [36835] cd+++++++ Internet Plug-Ins/npgtpo3dautoplugin.plugin/Contents/
225
+ 2011/02/27 20:12:20 [36835] >f+++++++ Internet Plug-Ins/npgtpo3dautoplugin.plugin/Contents/Info.plist
226
+ 2011/02/27 20:12:20 [36835] cd+++++++ Internet Plug-Ins/npgtpo3dautoplugin.plugin/Contents/Frameworks/
227
+ 2011/02/27 20:12:20 [36835] cd+++++++ Internet Plug-Ins/npgtpo3dautoplugin.plugin/Contents/Frameworks/Cg.framework/
228
+ 2011/02/27 20:12:20 [36835] cL+++++++ Internet Plug-Ins/npgtpo3dautoplugin.plugin/Contents/Frameworks/Cg.framework/Cg -> Versions/Current/Cg
229
+ 2011/02/27 20:12:20 [36835] cL+++++++ Internet Plug-Ins/npgtpo3dautoplugin.plugin/Contents/Frameworks/Cg.framework/Resources -> Versions/Current/Resources
230
+ 2011/02/27 20:12:20 [36835] cd+++++++ Internet Plug-Ins/npgtpo3dautoplugin.plugin/Contents/Frameworks/Cg.framework/Versions/
231
+ 2011/02/27 20:12:20 [36835] cL+++++++ Internet Plug-Ins/npgtpo3dautoplugin.plugin/Contents/Frameworks/Cg.framework/Versions/Current -> 1.0
232
+ 2011/02/27 20:12:20 [36835] cd+++++++ Internet Plug-Ins/npgtpo3dautoplugin.plugin/Contents/Frameworks/Cg.framework/Versions/1.0/
233
+ 2011/02/27 20:12:20 [36835] cd+++++++ Internet Plug-Ins/npgtpo3dautoplugin.plugin/Contents/MacOS/
234
+ 2011/02/27 20:12:20 [36835] cd+++++++ Internet Plug-Ins/npgtpo3dautoplugin.plugin/Contents/Resources/
235
+ 2011/02/27 20:12:20 [36835] cd+++++++ Internet Plug-Ins/npgtpo3dautoplugin.plugin/Contents/Resources/English.lproj/
236
+ 2011/02/27 20:12:20 [36835] cd+++++++ QuickTime/
237
+ 2011/02/27 20:12:20 [36835] cd+++++++ QuickTime/Google Camera Adapter 0.component/
238
+ 2011/02/27 20:12:20 [36835] cd+++++++ QuickTime/Google Camera Adapter 0.component/Contents/
239
+ 2011/02/27 20:12:20 [36835] cd+++++++ QuickTime/Google Camera Adapter 0.component/Contents/MacOS/
240
+ 2011/02/27 20:12:20 [36835] cd+++++++ QuickTime/Google Camera Adapter 0.component/Contents/Resources/
241
+ 2011/02/27 20:12:20 [36835] cd+++++++ QuickTime/Google Camera Adapter 1.component/
242
+ 2011/02/27 20:12:20 [36835] cd+++++++ QuickTime/Google Camera Adapter 1.component/Contents/
243
+ 2011/02/27 20:12:20 [36835] >f+++++++ QuickTime/Google Camera Adapter 1.component/Contents/Info.plist
244
+ 2011/02/27 20:12:20 [36835] cd+++++++ QuickTime/Google Camera Adapter 1.component/Contents/MacOS/
245
+ 2011/02/27 20:12:20 [36835] cd+++++++ QuickTime/Google Camera Adapter 1.component/Contents/Resources/
246
+ 2011/02/27 20:12:20 [36835] sent 386 bytes received 1431 bytes total size 5229466
247
+ '
248
+
249
+ @changes = [
250
+ "Application Support",
251
+ "Application Support/Google",
252
+ "Application Support/Google/GoogleTalkPlugin.app",
253
+ "Application Support/Google/GoogleTalkPlugin.app/Contents",
254
+ "Application Support/Google/GoogleTalkPlugin.app/Contents/Frameworks",
255
+ "Application Support/Google/GoogleTalkPlugin.app/Contents/Frameworks/GoogleBreakpad.framework",
256
+ "Application Support/Google/GoogleTalkPlugin.app/Contents/Frameworks/GoogleBreakpad.framework/GoogleBreakpad -> Versions/Current/GoogleBreakpad",
257
+ "Application Support/Google/GoogleTalkPlugin.app/Contents/Frameworks/GoogleBreakpad.framework/Resources -> Versions/Current/Resources",
258
+ "Application Support/Google/GoogleTalkPlugin.app/Contents/Frameworks/GoogleBreakpad.framework/Versions",
259
+ "Application Support/Google/GoogleTalkPlugin.app/Contents/Frameworks/GoogleBreakpad.framework/Versions/A",
260
+ "Application Support/Google/GoogleTalkPlugin.app/Contents/Frameworks/GoogleBreakpad.framework/Versions/A/Resources",
261
+ "Application Support/Google/GoogleTalkPlugin.app/Contents/Frameworks/GoogleBreakpad.framework/Versions/A/Resources/Reporter.app",
262
+ "Application Support/Google/GoogleTalkPlugin.app/Contents/Frameworks/GoogleBreakpad.framework/Versions/A/Resources/Reporter.app/Contents",
263
+ "Application Support/Google/GoogleTalkPlugin.app/Contents/Frameworks/GoogleBreakpad.framework/Versions/Current -> A",
264
+ "Application Support/Google/GoogleTalkPlugin.app/Contents/Info.plist",
265
+ "Application Support/Google/GoogleTalkPlugin.app/Contents/MacOS",
266
+ "Application Support/Google/GoogleTalkPlugin.app/Contents/MacOS/GoogleTalkPlugin",
267
+ "Internet Plug-Ins",
268
+ "Internet Plug-Ins/googletalkbrowserplugin.plugin",
269
+ "Internet Plug-Ins/googletalkbrowserplugin.plugin/Contents",
270
+ "Internet Plug-Ins/googletalkbrowserplugin.plugin/Contents/MacOS",
271
+ "Internet Plug-Ins/googletalkbrowserplugin.plugin/Contents/MacOS/googletalkbrowserplugin",
272
+ "Internet Plug-Ins/googletalkbrowserplugin.plugin/Contents/Resources",
273
+ "Internet Plug-Ins/npgtpo3dautoplugin.plugin",
274
+ "Internet Plug-Ins/npgtpo3dautoplugin.plugin/Contents",
275
+ "Internet Plug-Ins/npgtpo3dautoplugin.plugin/Contents/Frameworks",
276
+ "Internet Plug-Ins/npgtpo3dautoplugin.plugin/Contents/Frameworks/Cg.framework",
277
+ "Internet Plug-Ins/npgtpo3dautoplugin.plugin/Contents/Frameworks/Cg.framework/Cg -> Versions/Current/Cg",
278
+ "Internet Plug-Ins/npgtpo3dautoplugin.plugin/Contents/Frameworks/Cg.framework/Resources -> Versions/Current/Resources",
279
+ "Internet Plug-Ins/npgtpo3dautoplugin.plugin/Contents/Frameworks/Cg.framework/Versions",
280
+ "Internet Plug-Ins/npgtpo3dautoplugin.plugin/Contents/Frameworks/Cg.framework/Versions/1.0",
281
+ "Internet Plug-Ins/npgtpo3dautoplugin.plugin/Contents/Frameworks/Cg.framework/Versions/Current -> 1.0",
282
+ "Internet Plug-Ins/npgtpo3dautoplugin.plugin/Contents/Info.plist",
283
+ "Internet Plug-Ins/npgtpo3dautoplugin.plugin/Contents/MacOS",
284
+ "Internet Plug-Ins/npgtpo3dautoplugin.plugin/Contents/Resources",
285
+ "Internet Plug-Ins/npgtpo3dautoplugin.plugin/Contents/Resources/English.lproj",
286
+ "QuickTime",
287
+ "QuickTime/Google Camera Adapter 0.component",
288
+ "QuickTime/Google Camera Adapter 0.component/Contents",
289
+ "QuickTime/Google Camera Adapter 0.component/Contents/MacOS",
290
+ "QuickTime/Google Camera Adapter 0.component/Contents/Resources",
291
+ "QuickTime/Google Camera Adapter 1.component",
292
+ "QuickTime/Google Camera Adapter 1.component/Contents",
293
+ "QuickTime/Google Camera Adapter 1.component/Contents/Info.plist",
294
+ "QuickTime/Google Camera Adapter 1.component/Contents/MacOS",
295
+ "QuickTime/Google Camera Adapter 1.component/Contents/Resources",
296
+ ]
297
+ end
298
+
299
+ it 'should work without arguments' do
300
+ lambda { rsync_changes }.should.not.raise(ArgumentError)
301
+ end
302
+
303
+ it 'should not allow arguments' do
304
+ lambda { rsync_changes(:foo) }.should.raise(ArgumentError)
305
+ end
306
+
307
+ it 'should return nil when an rsync changes file cannot be found' do
308
+ self.stub!(:read_rsync_changes_file).and_raise
309
+ rsync_changes.should.be.nil
310
+ end
311
+
312
+ it 'should return an empty list if no files are found in the rsync changes file' do
313
+ self.stub!(:read_rsync_changes_file).and_return('')
314
+ rsync_changes.should == []
315
+ end
316
+
317
+ it 'should return a list of all changed filenames mentioned in the rsync changes file, excluding "."' do
318
+ self.stub!(:read_rsync_changes_file).and_return(@contents)
319
+ rsync_changes.sort.first.should == @changes.sort.first
320
+ end
321
+ end
322
+
323
+ describe 'when reading the git-related changes for a deployment' do
324
+ before do
325
+ @contents = 'git changes'
326
+ @changes_path = '/path/to/git/changes'
327
+ self.stub!(:git_changes_path).and_return(@changes_path)
328
+ File.stub!(:read).with(@changes_path).and_return(@contents)
329
+ end
330
+
331
+ it 'should work without arguments' do
332
+ lambda { read_git_changes_file }.should.not.raise(ArgumentError)
333
+ end
334
+
335
+ it 'should not allow arguments' do
336
+ lambda { read_git_changes_file(:foo) }.should.raise(ArgumentError)
337
+ end
338
+
339
+ it 'should read the git changes file' do
340
+ File.should.receive(:read) do |arg|
341
+ arg.should == @changes_path
342
+ @contents
343
+ end
344
+ read_git_changes_file
345
+ end
346
+
347
+ it 'should return the contents of the git changes file' do
348
+ read_git_changes_file.should == @contents
349
+ end
350
+
351
+ it 'should fail if the git changes file cannot be read' do
352
+ File.stub!(:read).with(@changes_path).and_raise(Errno::ENOENT)
353
+ lambda { read_git_changes_file }.should.raise(Errno::ENOENT)
354
+ end
355
+ end
356
+
357
+ describe 'when reading the rsync-related changes for a deployment' do
358
+ before do
359
+ @contents = 'rsync changes'
360
+ @changes_path = '/path/to/rsync/changes'
361
+ self.stub!(:rsync_changes_path).and_return(@changes_path)
362
+ File.stub!(:read).with(@changes_path).and_return(@contents)
363
+ end
364
+
365
+ it 'should work without arguments' do
366
+ lambda { read_rsync_changes_file }.should.not.raise(ArgumentError)
367
+ end
368
+
369
+ it 'should not allow arguments' do
370
+ lambda { read_rsync_changes_file(:foo) }.should.raise(ArgumentError)
371
+ end
372
+
373
+ it 'should read the rsync changes file' do
374
+ File.should.receive(:read) do |arg|
375
+ arg.should == @changes_path
376
+ @contents
377
+ end
378
+ read_rsync_changes_file
379
+ end
380
+
381
+ it 'should return the contents of the rsync changes file' do
382
+ read_rsync_changes_file.should == @contents
383
+ end
384
+
385
+ it 'should fail if the rsync changes file cannot be read' do
386
+ File.stub!(:read).with(@changes_path).and_raise(Errno::ENOENT)
387
+ lambda { read_rsync_changes_file }.should.raise(Errno::ENOENT)
388
+ end
389
+ end
390
+
391
+ describe 'computing the path to the git changes file' do
392
+ before do
393
+ @git_path = '/path/to/toplevel'
394
+ @io_handle = ''
395
+ IO.stub!(:popen).with("git rev-parse --show-toplevel").and_return(@io_handle)
396
+ @io_handle.stub!(:read).and_return(@git_path + "\n")
397
+ end
398
+
399
+ it 'should work without arguments' do
400
+ lambda { git_changes_path }.should.not.raise(ArgumentError)
401
+ end
402
+
403
+ it 'should not allow arguments' do
404
+ lambda { git_changes_path(:foo) }.should.raise(ArgumentError)
405
+ end
406
+
407
+ it 'should return the path to the .whiskey_disk_git_changes file in the git top-level path' do
408
+ git_changes_path.should == File.join(@git_path, '.whiskey_disk_git_changes')
409
+ end
410
+
411
+ it 'should return the path to the .whiskey_disk_git_changes file in the current directory of the git top-level cannot be found' do
412
+ @io_handle.stub!(:read).and_return('')
413
+ git_changes_path.should == File.join(Dir.pwd, '.whiskey_disk_git_changes')
414
+ end
415
+ end
416
+
417
+ describe 'computing the path to the rsync changes file' do
418
+ before do
419
+ @rsync_path = '/path/to/toplevel'
420
+ @io_handle = ''
421
+ IO.stub!(:popen).with("git rev-parse --show-toplevel").and_return(@io_handle)
422
+ @io_handle.stub!(:read).and_return(@rsync_path + "\n")
423
+ end
424
+
425
+ it 'should work without arguments' do
426
+ lambda { rsync_changes_path }.should.not.raise(ArgumentError)
427
+ end
428
+
429
+ it 'should not allow arguments' do
430
+ lambda { rsync_changes_path(:foo) }.should.raise(ArgumentError)
431
+ end
432
+
433
+ it 'should return the path to the .whiskey_disk_rsync_changes file in the git top-level path' do
434
+ rsync_changes_path.should == File.join(@rsync_path, '.whiskey_disk_rsync_changes')
435
+ end
436
+
437
+ it 'should return the path to the .whiskey_disk_rsync_changes file in the current directory of the git top-level cannot be found' do
438
+ @io_handle.stub!(:read).and_return('')
439
+ rsync_changes_path.should == File.join(Dir.pwd, '.whiskey_disk_rsync_changes')
440
+ end
441
+ end
@@ -24,6 +24,7 @@ describe 'rake tasks' do
24
24
  :update_main_repository_checkout,
25
25
  :update_configuration_repository_checkout,
26
26
  :refresh_configuration,
27
+ :initialize_all_changes,
27
28
  :run_post_setup_hooks,
28
29
  :flush,
29
30
  :summarize
@@ -87,6 +88,11 @@ describe 'rake tasks' do
87
88
  end
88
89
  end
89
90
 
91
+ it 'should clear any tracked git or rsync changes' do
92
+ WhiskeyDisk.should.receive(:initialize_all_changes)
93
+ @rake["deploy:setup"].invoke
94
+ end
95
+
90
96
  describe 'when no configuration repository is specified' do
91
97
  it 'should update the configuration repository checkout' do
92
98
  WhiskeyDisk.should.not.receive(:update_configuration_repository_checkout)
@@ -221,9 +221,14 @@ describe 'WhiskeyDisk' do
221
221
  WhiskeyDisk.buffer.join(' ').should.match(%r{git checkout -b master origin/master})
222
222
  end
223
223
 
224
+ it 'should fall back to a regular checkout of the master branch with origin branch when no branch is specified' do
225
+ WhiskeyDisk.checkout_main_repository
226
+ WhiskeyDisk.buffer.join(' ').should.match(%r{\|\| git checkout master origin/master})
227
+ end
228
+
224
229
  it 'should fall back to a regular checkout of the master branch when no branch is specified' do
225
230
  WhiskeyDisk.checkout_main_repository
226
- WhiskeyDisk.buffer.join(' ').should.match(%r{\|\| git checkout master})
231
+ WhiskeyDisk.buffer.join(' ').should.match(%r{\|\| git checkout master origin/master \|\| git checkout master})
227
232
  end
228
233
 
229
234
  it 'should do a branch creation checkout of the specified branch when a branch is specified' do
@@ -232,10 +237,16 @@ describe 'WhiskeyDisk' do
232
237
  WhiskeyDisk.buffer.join(' ').should.match(%r{git checkout -b production origin/production})
233
238
  end
234
239
 
240
+ it 'should fall back to a regular checkout of the specified branch with origin branch when a branch is specified' do
241
+ WhiskeyDisk.configuration = @parameters.merge({'branch' => 'production'})
242
+ WhiskeyDisk.checkout_main_repository
243
+ WhiskeyDisk.buffer.join(' ').should.match(%r{\|\| git checkout production origin/production})
244
+ end
245
+
235
246
  it 'should fall back to a regular checkout of the specified branch when a branch is specified' do
236
247
  WhiskeyDisk.configuration = @parameters.merge({'branch' => 'production'})
237
248
  WhiskeyDisk.checkout_main_repository
238
- WhiskeyDisk.buffer.join(' ').should.match(%r{\|\| git checkout production})
249
+ WhiskeyDisk.buffer.join(' ').should.match(%r{\|\| git checkout production origin/production \|\| git checkout production})
239
250
  end
240
251
 
241
252
  it 'should do branch checkouts from the repository path' do
@@ -280,11 +291,34 @@ describe 'WhiskeyDisk' do
280
291
  WhiskeyDisk.buffer.join(' ').should.match(%r{git checkout -b master origin/master})
281
292
  end
282
293
 
294
+ it 'should fall back to a regular checkout of the master branch with origin branch when no branch is specified' do
295
+ WhiskeyDisk.checkout_configuration_repository
296
+ WhiskeyDisk.buffer.join(' ').should.match(%r{\|\| git checkout master origin/master})
297
+ end
298
+
299
+ it 'should fall back to a regular checkout of the master branch when no branch is specified' do
300
+ WhiskeyDisk.checkout_configuration_repository
301
+ WhiskeyDisk.buffer.join(' ').should.match(%r{\|\| git checkout master origin/master \|\| git checkout master})
302
+ end
303
+
283
304
  it 'should do a branch creation checkout of the specified branch when a branch is specified' do
284
305
  WhiskeyDisk.configuration = @parameters.merge({'config_branch' => 'production'})
285
306
  WhiskeyDisk.checkout_configuration_repository
286
307
  WhiskeyDisk.buffer.join(' ').should.match(%r{git checkout -b production origin/production})
287
308
  end
309
+
310
+ it 'should fall back to a regular checkout of the specified branch with origin branch when a branch is specified' do
311
+ WhiskeyDisk.configuration = @parameters.merge({'config_branch' => 'production'})
312
+ WhiskeyDisk.checkout_configuration_repository
313
+ WhiskeyDisk.buffer.join(' ').should.match(%r{\|\| git checkout production origin/production})
314
+ end
315
+
316
+ it 'should fall back to a regular checkout of the specified branch when a branch is specified' do
317
+ WhiskeyDisk.configuration = @parameters.merge({'config_branch' => 'production'})
318
+ WhiskeyDisk.checkout_configuration_repository
319
+ WhiskeyDisk.buffer.join(' ').should.match(%r{\|\| git checkout production origin/production \|\| git checkout production})
320
+ end
321
+
288
322
  end
289
323
 
290
324
  describe 'updating the main repository checkout' do
@@ -303,15 +337,20 @@ describe 'WhiskeyDisk' do
303
337
  WhiskeyDisk.buffer.join(' ').should.match(%r{cd /path/to/main/repo})
304
338
  end
305
339
 
306
- it 'should work from the default branch if no branch is specified' do
340
+ it 'should clear out any existing git changes data' do
307
341
  WhiskeyDisk.update_main_repository_checkout
308
- WhiskeyDisk.buffer.join(' ').should.match(%r{git checkout master})
342
+ WhiskeyDisk.buffer.join(' ').should.match(%r{rm -f /path/to/main/repo/.whiskey_disk_git_changes})
309
343
  end
310
-
311
- it 'should work from the specified branch if one is specified' do
344
+
345
+ it 'should capture the current git HEAD ref for the specified branch' do
312
346
  WhiskeyDisk.configuration = @parameters.merge({'branch' => 'production'})
313
347
  WhiskeyDisk.update_main_repository_checkout
314
- WhiskeyDisk.buffer.join(' ').should.match(%r{git checkout production})
348
+ WhiskeyDisk.buffer.join(' ').should.match(%r{ml=\`cat .git/refs/heads/production\`})
349
+ end
350
+
351
+ it 'should capture the current git HEAD ref for the master branch if no branch is specified' do
352
+ WhiskeyDisk.update_main_repository_checkout
353
+ WhiskeyDisk.buffer.join(' ').should.match(%r{ml=\`cat .git/refs/heads/master\`})
315
354
  end
316
355
 
317
356
  it 'should attempt to fetch only the master branch from the origin if no branch is specified' do
@@ -325,6 +364,17 @@ describe 'WhiskeyDisk' do
325
364
  WhiskeyDisk.buffer.join(' ').should.match(%r{git fetch origin \+refs/heads/production:refs/remotes/origin/production})
326
365
  end
327
366
 
367
+ it 'should work from the default branch if no branch is specified' do
368
+ WhiskeyDisk.update_main_repository_checkout
369
+ WhiskeyDisk.buffer.join(' ').should.match(%r{git checkout master})
370
+ end
371
+
372
+ it 'should work from the specified branch if one is specified' do
373
+ WhiskeyDisk.configuration = @parameters.merge({'branch' => 'production'})
374
+ WhiskeyDisk.update_main_repository_checkout
375
+ WhiskeyDisk.buffer.join(' ').should.match(%r{git checkout production})
376
+ end
377
+
328
378
  it 'should attempt to reset the master branch from the origin if no branch is specified' do
329
379
  WhiskeyDisk.update_main_repository_checkout
330
380
  WhiskeyDisk.buffer.join(' ').should.match(%r{git reset --hard origin/master})
@@ -335,11 +385,16 @@ describe 'WhiskeyDisk' do
335
385
  WhiskeyDisk.update_main_repository_checkout
336
386
  WhiskeyDisk.buffer.join(' ').should.match(%r{git reset --hard origin/production})
337
387
  end
388
+
389
+ it 'should collect git changes data' do
390
+ WhiskeyDisk.update_main_repository_checkout
391
+ WhiskeyDisk.buffer.join(' ').should.match(%r{git diff --name-only \$\{ml\}\.\.HEAD > /path/to/main/repo/\.whiskey_disk_git_changes})
392
+ end
338
393
  end
339
394
 
340
395
  describe 'updating the configuration repository checkout' do
341
396
  before do
342
- @parameters = { 'deploy_config_to' => '/path/to/config/repo' }
397
+ @parameters = { 'deploy_config_to' => '/path/to/config/repo', 'deploy_to' => '/path/to/main/repo' }
343
398
  WhiskeyDisk.configuration = @parameters
344
399
  end
345
400
 
@@ -353,6 +408,11 @@ describe 'WhiskeyDisk' do
353
408
  WhiskeyDisk.buffer.join(' ').should.match(%r{cd /path/to/config/repo})
354
409
  end
355
410
 
411
+ it 'should clear out any existing rsync changes data' do
412
+ WhiskeyDisk.update_configuration_repository_checkout
413
+ WhiskeyDisk.buffer.join(' ').should.match(%r{rm -f /path/to/main/repo/.whiskey_disk_rsync_changes})
414
+ end
415
+
356
416
  it 'should attempt to fetch only the master branch from the origin if no configuration branch is specified' do
357
417
  WhiskeyDisk.update_configuration_repository_checkout
358
418
  WhiskeyDisk.buffer.join(' ').should.match(%r{git fetch origin \+refs/heads/master:refs/remotes/origin/master})
@@ -407,6 +467,11 @@ describe 'WhiskeyDisk' do
407
467
  WhiskeyDisk.refresh_configuration
408
468
  WhiskeyDisk.buffer.last.should.match(%r{rsync.* /path/to/config/repo/whiskey_disk/staging/ /path/to/main/repo/})
409
469
  end
470
+
471
+ it 'should capture rsync change data' do
472
+ WhiskeyDisk.refresh_configuration
473
+ WhiskeyDisk.buffer.last.should.match(%r{rsync.* --log-file=/path/to/main/repo/.whiskey_disk_rsync_changes })
474
+ end
410
475
  end
411
476
 
412
477
  describe 'running post setup hooks' do
@@ -931,6 +996,7 @@ describe 'WhiskeyDisk' do
931
996
  @domain = { :name => @domain_name }
932
997
  WhiskeyDisk.configuration = { 'domain' => [ @domain ] }
933
998
  WhiskeyDisk.stub!(:system)
999
+ WhiskeyDisk.stub!(:puts)
934
1000
  end
935
1001
 
936
1002
  it 'should accept a domain and a command string' do
@@ -980,6 +1046,7 @@ describe 'WhiskeyDisk' do
980
1046
  @domain = { :name => @domain_name }
981
1047
  WhiskeyDisk.configuration = { 'domain' => [ @domain ] }
982
1048
  WhiskeyDisk.stub!(:system)
1049
+ WhiskeyDisk.stub!(:puts)
983
1050
  end
984
1051
 
985
1052
  it 'should accept a domain and a command string' do
data/whiskey_disk.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{whiskey_disk}
8
- s.version = "0.6.17"
8
+ s.version = "0.6.20"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Rick Bradley"]
12
- s.date = %q{2011-03-25}
12
+ s.date = %q{2011-04-06}
13
13
  s.description = %q{Opinionated gem for doing fast git-based server deployments.}
14
14
  s.email = %q{rick@rickbradley.com}
15
15
  s.executables = ["wd_role", "wd"]
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: whiskey_disk
3
3
  version: !ruby/object:Gem::Version
4
- hash: 37
4
+ hash: 47
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
8
  - 6
9
- - 17
10
- version: 0.6.17
9
+ - 20
10
+ version: 0.6.20
11
11
  platform: ruby
12
12
  authors:
13
13
  - Rick Bradley
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-03-25 00:00:00 -05:00
18
+ date: 2011-04-06 00:00:00 -05:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency