git-process-lib 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (69) hide show
  1. data/CHANGELOG.md +123 -0
  2. data/Gemfile +21 -0
  3. data/Gemfile.lock +57 -0
  4. data/LICENSE +193 -0
  5. data/README.md +342 -0
  6. data/Rakefile +32 -0
  7. data/bin/git-new-fb +39 -0
  8. data/bin/git-pull-request +63 -0
  9. data/bin/git-sync +38 -0
  10. data/bin/git-to-master +44 -0
  11. data/docs/git-new-fb.1.adoc +83 -0
  12. data/docs/git-process.1.adoc +227 -0
  13. data/docs/git-pull-request.1.adoc +166 -0
  14. data/docs/git-sync.1.adoc +120 -0
  15. data/docs/git-to-master.1.adoc +172 -0
  16. data/git-new-fb.gemspec +20 -0
  17. data/git-process-lib.gemspec +25 -0
  18. data/git-process.gemspec +22 -0
  19. data/git-pull-request.gemspec +20 -0
  20. data/git-sync.gemspec +20 -0
  21. data/git-to-master.gemspec +20 -0
  22. data/lib/git-process/abstract_error_builder.rb +53 -0
  23. data/lib/git-process/changed_file_helper.rb +115 -0
  24. data/lib/git-process/git_abstract_merge_error_builder.rb +130 -0
  25. data/lib/git-process/git_branch.rb +105 -0
  26. data/lib/git-process/git_branches.rb +81 -0
  27. data/lib/git-process/git_config.rb +135 -0
  28. data/lib/git-process/git_lib.rb +646 -0
  29. data/lib/git-process/git_logger.rb +84 -0
  30. data/lib/git-process/git_merge_error.rb +28 -0
  31. data/lib/git-process/git_process.rb +159 -0
  32. data/lib/git-process/git_process_error.rb +18 -0
  33. data/lib/git-process/git_process_options.rb +101 -0
  34. data/lib/git-process/git_rebase_error.rb +30 -0
  35. data/lib/git-process/git_remote.rb +222 -0
  36. data/lib/git-process/git_status.rb +108 -0
  37. data/lib/git-process/github_configuration.rb +298 -0
  38. data/lib/git-process/github_pull_request.rb +165 -0
  39. data/lib/git-process/new_fb.rb +49 -0
  40. data/lib/git-process/parked_changes_error.rb +41 -0
  41. data/lib/git-process/pull_request.rb +136 -0
  42. data/lib/git-process/pull_request_error.rb +25 -0
  43. data/lib/git-process/rebase_to_master.rb +148 -0
  44. data/lib/git-process/sync_process.rb +55 -0
  45. data/lib/git-process/syncer.rb +157 -0
  46. data/lib/git-process/uncommitted_changes_error.rb +23 -0
  47. data/lib/git-process/version.rb +22 -0
  48. data/local-build.rb +24 -0
  49. data/spec/FileHelpers.rb +19 -0
  50. data/spec/GitRepoHelper.rb +123 -0
  51. data/spec/changed_file_helper_spec.rb +127 -0
  52. data/spec/git_abstract_merge_error_builder_spec.rb +64 -0
  53. data/spec/git_branch_spec.rb +123 -0
  54. data/spec/git_config_spec.rb +45 -0
  55. data/spec/git_lib_spec.rb +176 -0
  56. data/spec/git_logger_spec.rb +66 -0
  57. data/spec/git_process_spec.rb +208 -0
  58. data/spec/git_remote_spec.rb +227 -0
  59. data/spec/git_status_spec.rb +122 -0
  60. data/spec/github_configuration_spec.rb +152 -0
  61. data/spec/github_pull_request_spec.rb +117 -0
  62. data/spec/github_test_helper.rb +49 -0
  63. data/spec/new_fb_spec.rb +126 -0
  64. data/spec/pull_request_helper.rb +94 -0
  65. data/spec/pull_request_spec.rb +137 -0
  66. data/spec/rebase_to_master_spec.rb +362 -0
  67. data/spec/spec_helper.rb +21 -0
  68. data/spec/sync_spec.rb +1474 -0
  69. metadata +249 -0
@@ -0,0 +1,21 @@
1
+ $LOAD_PATH.unshift File.join(File.dirname(__FILE__), '../lib')
2
+
3
+ require 'GitRepoHelper'
4
+ require 'pull_request_helper'
5
+
6
+ RSpec.configure do |config|
7
+ config.treat_symbols_as_metadata_keys_with_true_values = true
8
+
9
+ config.include GitRepoHelper, :git_repo_helper
10
+
11
+ config.before(:each, :git_repo_helper) do
12
+ create_files(%w(.gitignore))
13
+ gitlib.commit('initial')
14
+ end
15
+
16
+
17
+ config.after(:each, :git_repo_helper) do
18
+ rm_rf(gitlib.workdir)
19
+ end
20
+
21
+ end
data/spec/sync_spec.rb ADDED
@@ -0,0 +1,1474 @@
1
+ require 'git-process/sync_process'
2
+ require 'GitRepoHelper'
3
+ require 'rugged'
4
+
5
+
6
+ describe Sync do
7
+ include GitRepoHelper
8
+
9
+ before(:each) do
10
+ create_files(%w(.gitignore))
11
+ gitlib.commit('initial')
12
+ end
13
+
14
+
15
+ after(:each) do
16
+ rm_rf(gitlib.workdir)
17
+ end
18
+
19
+
20
+ def log_level
21
+ Logger::ERROR
22
+ end
23
+
24
+
25
+ def create_process(base = gitlib, opts = {})
26
+ GitProc::Sync.new(base, opts.merge({:rebase => false, :force => false}))
27
+ end
28
+
29
+
30
+ def verify_start_state
31
+ # meant to overridden
32
+ end
33
+
34
+
35
+ it 'should work when pushing with fast-forward' do
36
+ Given do
37
+ origin 'fb', :new_branch => 'master'
38
+ create_commit :b
39
+ local 'fb', :new_branch => 'origin/fb'
40
+ create_commit :c
41
+ end
42
+
43
+ when_sync_is_run
44
+
45
+ Then do
46
+ local_and_remote_are_same
47
+ l_sha.should == @local.sha('origin/fb')
48
+ end
49
+ end
50
+
51
+
52
+ it 'should work with a different remote server name' do
53
+ Given do
54
+ origin 'fb', :new_branch => 'master'
55
+ create_commit :b
56
+ local 'fb', :new_branch => 'a_remote/fb', :remote_name => 'a_remote'
57
+ create_commit :c
58
+ end
59
+
60
+ when_sync_is_run
61
+
62
+ Then do
63
+ local_and_remote_are_same
64
+ l_sha.should == @local.sha('a_remote/fb')
65
+ end
66
+ end
67
+
68
+
69
+ describe 'when forcing the push with a merge' do
70
+
71
+ def create_process(gitlib, opts)
72
+ GitProc::Sync.new(gitlib, opts.merge({:rebase => false, :force => true}))
73
+ end
74
+
75
+
76
+ it 'should work when pushing with non-fast-forward' do
77
+ change_file_and_commit('a', '')
78
+
79
+ gitlib.branch('fb', :base_branch => 'master')
80
+
81
+ clone_repo('fb') do |gl|
82
+ gitlib.checkout('fb') do
83
+ change_file_and_commit('a', 'hello', gitlib)
84
+ end
85
+
86
+ GitProc::Sync.new(gl, :rebase => false, :force => true, :log_level => log_level).runner
87
+ end
88
+ end
89
+
90
+ end
91
+
92
+
93
+ describe 'when merging' do
94
+
95
+ def create_process(gitlib, opts = {})
96
+ GitProc::Sync.new(gitlib, opts.merge({:rebase => true, :force => false}))
97
+ end
98
+
99
+
100
+ context 'piece by piece' do
101
+ it 'should do the same as rebase, but with merge - HOLDER'
102
+ end
103
+
104
+ end
105
+
106
+
107
+ describe 'when rebasing' do
108
+
109
+ def create_process(gitlib, opts = {})
110
+ GitProc::Sync.new(gitlib, opts.merge({:rebase => true, :force => false}))
111
+ end
112
+
113
+
114
+ context 'piece by piece' do
115
+
116
+ #
117
+ # Legend for the symbols below:
118
+ # i - integration branch (i.e., 'origin/master')
119
+ # l - local/working feature branch (i.e., 'fb')
120
+ # r - remote feature branch (i.e., 'origin/fb')
121
+ #
122
+
123
+ before(:each) do
124
+ @origin = gitlib
125
+ @origin.config['receive.denyCurrentBranch'] = 'ignore'
126
+
127
+ @a_sha = rcreate_commit :origin, 'HEAD', :a
128
+
129
+ @local = clone_repo('master', 'origin')
130
+ end
131
+
132
+
133
+ after(:each) do
134
+ rm_rf(@origin.workdir)
135
+ rm_rf(@local.workdir)
136
+ end
137
+
138
+
139
+ # i
140
+ # /
141
+ # - A - C
142
+ # \
143
+ # B
144
+ # \
145
+ # l,r
146
+ #
147
+ # Steps to get to this state:
148
+ # 1. Changes have been applied to the integration branch
149
+ # 2. No work has happened on the feature branch since the last `sync`
150
+ #
151
+ describe 'if local/remote match' do
152
+
153
+ def verify_start_state
154
+ l_sha.should == @b_sha
155
+ r_sha.should == @b_sha
156
+ i_sha.should == @c_sha
157
+ treeish(origin_repo, "#{@c_sha}~1").should == @a_sha
158
+ treeish(origin_repo, "#{@b_sha}~1").should == @a_sha
159
+ end
160
+
161
+
162
+ # i
163
+ # /
164
+ # - A - C - B1
165
+ # /
166
+ # l,r
167
+ it 'should work if no conflict' do
168
+ Given do
169
+ rcreate_commit_on_new_branch :origin, 'fb', 'master', :b
170
+ rfetch local_repo, 'origin'
171
+ local_repo.create_branch('fb', 'origin/fb')
172
+ @local.write_sync_control_file('fb')
173
+ rcreate_commit :origin, 'master', :c
174
+ end
175
+
176
+ when_sync_is_run
177
+
178
+ Then do
179
+ local_and_remote_are_same
180
+ parent(l_sha).should == @c_sha
181
+ check_file_content :b
182
+ end
183
+ end
184
+
185
+
186
+ # i
187
+ # /
188
+ # - A - C - XX
189
+ # \ /
190
+ # B l
191
+ # \
192
+ # r
193
+ it 'should raise an error if there is a conflict' do
194
+ Given do
195
+ rcreate_commit_on_new_branch :origin, 'fb', 'master', :b, :file => 'a'
196
+ rfetch local_repo, 'origin'
197
+ local_repo.create_branch('fb', 'origin/fb')
198
+ @local.write_sync_control_file('fb')
199
+ rcreate_commit :origin, 'master', :c, :file => 'a'
200
+ end
201
+
202
+ expect { when_sync_is_run }.to raise_error(RebaseError, /'a' was modified in both branches/)
203
+ end
204
+
205
+ end
206
+
207
+ # i
208
+ # /
209
+ # - A - C
210
+ # \
211
+ # B - D
212
+ # \ \
213
+ # r l
214
+ #
215
+ # Steps to get to this state:
216
+ # 1. Changes have been applied to the integration branch
217
+ # 2. Work has happened locally only on the feature branch since the last `sync`
218
+ #
219
+ describe 'if local is a fast-forward of remote' do
220
+
221
+ def verify_start_state
222
+ l_sha.should == @d_sha
223
+ r_sha.should == @b_sha
224
+ i_sha.should == @c_sha
225
+ treeish(origin_repo, "#{@c_sha}~1").should == @a_sha
226
+ treeish(origin_repo, "#{@b_sha}~1").should == @a_sha
227
+ treeish(local_repo, "#{@d_sha}~1").should == @b_sha
228
+ end
229
+
230
+
231
+ # i
232
+ # /
233
+ # - A - C - B1 - D1
234
+ # /
235
+ # l,r
236
+ it 'should work if no conflict' do
237
+ Given do
238
+ rcreate_commit_on_new_branch :origin, 'fb', 'master', :b
239
+ rfetch local_repo, 'origin'
240
+ local_repo.create_branch('fb', 'origin/fb')
241
+ @local.write_sync_control_file('fb')
242
+ rcreate_commit :local, 'fb', :d
243
+ rcreate_commit :origin, 'master', :c
244
+ end
245
+
246
+ when_sync_is_run
247
+
248
+ Then do
249
+ local_and_remote_are_same
250
+ @local.sha("#{l_sha}~2").should == @c_sha
251
+ check_file_content :b
252
+ check_file_content :d
253
+ end
254
+ end
255
+
256
+
257
+ # i
258
+ # /
259
+ # - A - C - XX
260
+ # \ \
261
+ # B - D l
262
+ # \ \
263
+ # r ??
264
+ it 'should raise an error if there is a conflict' do
265
+ Given do
266
+ rcreate_commit_on_new_branch :origin, 'fb', 'master', :b, :file => 'a'
267
+ rfetch local_repo, 'origin'
268
+ local_repo.create_branch('fb', 'origin/fb')
269
+ @local.write_sync_control_file('fb')
270
+ rcreate_commit :local, 'fb', :d
271
+ rcreate_commit :origin, 'master', :c, :file => 'a'
272
+ end
273
+
274
+ expect { when_sync_is_run }.to raise_error(RebaseError, /'a' was modified in both branches/)
275
+ end
276
+
277
+ end
278
+
279
+
280
+ # i l
281
+ # / \
282
+ # - A - C - B1 - D
283
+ # \
284
+ # B
285
+ # \
286
+ # r
287
+ #
288
+ # Steps to get to this state:
289
+ # 1. Changes have been applied to the integration branch
290
+ # 2. The local feature branch is manually rebased with integration
291
+ # 2. Work has happened locally only on the feature branch since the last `sync`
292
+ #
293
+ describe 'if local has already been rebased onto integration' do
294
+
295
+ def verify_start_state
296
+ l_sha.should == @d_sha
297
+ r_sha.should == @b_sha
298
+ i_sha.should == @c_sha
299
+ treeish(origin_repo, "#{@c_sha}~1").should == @a_sha
300
+ treeish(origin_repo, "#{@b_sha}~1").should == @a_sha
301
+ treeish(local_repo, "#{@b1_sha}~1").should == @c_sha
302
+ treeish(local_repo, "#{@d_sha}~2").should == @c_sha
303
+ end
304
+
305
+
306
+ # i
307
+ # /
308
+ # - A - C - B1 - D
309
+ # /
310
+ # l,r
311
+ it 'should work' do
312
+ Given do
313
+ rcreate_commit_on_new_branch :origin, 'fb', 'master', :b
314
+ rcreate_commit :origin, 'master', :c
315
+ rfetch local_repo, 'origin'
316
+ rcreate_commit_on_new_branch :local, 'fb', 'origin/master', :b1, :file => 'b'
317
+ rcreate_commit :local, 'fb', :d
318
+ end
319
+
320
+ when_sync_is_run
321
+
322
+ Then do
323
+ local_and_remote_are_same
324
+ treeish(local_repo, "#{l_sha}~2").should == @c_sha
325
+ end
326
+ end
327
+
328
+ end
329
+
330
+
331
+ # i r
332
+ # / /
333
+ # - A - C - B1
334
+ # \
335
+ # B - D
336
+ # \
337
+ # l
338
+ #
339
+ # Steps to get to this state:
340
+ # 1. Changes have been applied to the integration branch
341
+ # 2. The remote feature branch is rebased with integration, but no new work
342
+ # 2. Work has happened locally on the feature branch
343
+ #
344
+ describe 'if remote has already been rebased onto integration' do
345
+
346
+ def verify_start_state
347
+ l_sha.should == @d_sha
348
+ r_sha.should == @b1_sha
349
+ i_sha.should == @c_sha
350
+ treeish(origin_repo, "#{@c_sha}~1").should == @a_sha
351
+ treeish(local_repo, "#{@b_sha}~1").should == @a_sha
352
+ treeish(origin_repo, "#{@b1_sha}~1").should == @c_sha
353
+ treeish(local_repo, "#{@d_sha}~1").should == @b_sha
354
+ end
355
+
356
+
357
+ # i
358
+ # /
359
+ # - A - C - B1 - D1
360
+ # /
361
+ # l,r
362
+ it 'should work' do
363
+ Given do
364
+ rcreate_commit_on_new_branch :local, 'fb', 'origin/master', :b
365
+ @local.write_sync_control_file('fb')
366
+ rcreate_commit :local, 'fb', :d
367
+ rcreate_commit :origin, 'master', :c
368
+ rcreate_commit_on_new_branch :origin, 'fb', 'master', :b1, :file => 'b'
369
+ end
370
+
371
+ when_sync_is_run
372
+
373
+ Then do
374
+ local_and_remote_are_same
375
+ l_sha.should_not == @d_sha
376
+ treeish(local_repo, "#{l_sha}~1").should == @b1_sha
377
+ treeish(local_repo, "#{l_sha}~2").should == @c_sha
378
+ end
379
+ end
380
+
381
+
382
+ # i r
383
+ # / /
384
+ # - A - C - B1 - XX
385
+ # \ /
386
+ # B - D l
387
+ # \
388
+ # ??
389
+ it 'should raise an error if there is a conflict' do
390
+ Given do
391
+ rcreate_commit_on_new_branch :local, 'fb', 'origin/master', :b
392
+ rcreate_commit :local, 'fb', :d, :file => 'a'
393
+ rcreate_commit :origin, 'master', :c, :file => 'a'
394
+ rcreate_commit_on_new_branch :origin, 'fb', 'master', :b1, :file => 'b'
395
+ end
396
+
397
+ expect { when_sync_is_run }.to raise_error(RebaseError, /'a' was modified in both branches/)
398
+ end
399
+
400
+ end
401
+
402
+
403
+ # i r
404
+ # / \
405
+ # - A - C - B1 - D
406
+ # \
407
+ # B
408
+ # \
409
+ # l
410
+ #
411
+ # Steps to get to this state:
412
+ # 1. Changes have been applied to the integration branch
413
+ # 2. The remote feature branch is rebased with integration, but with new work
414
+ # 2. Work has not happened locally on the feature branch
415
+ #
416
+ describe 'if remote is ahead of local' do
417
+
418
+ def verify_start_state
419
+ l_sha.should == @b_sha
420
+ r_sha.should == @d_sha
421
+ i_sha.should == @c_sha
422
+ treeish(origin_repo, "#{@c_sha}~1").should == @a_sha
423
+ treeish(local_repo, "#{@b_sha}~1").should == @a_sha
424
+ treeish(origin_repo, "#{@b1_sha}~1").should == @c_sha
425
+ treeish(origin_repo, "#{@d_sha}~1").should == @b1_sha
426
+ end
427
+
428
+
429
+ # i
430
+ # /
431
+ # - A - C - B1 - D
432
+ # /
433
+ # l,r
434
+ it 'should work' do
435
+ Given do
436
+ rcreate_commit_on_new_branch :origin, 'fb', 'master', :b
437
+ rfetch local_repo, 'origin'
438
+ local_repo.create_branch('fb', 'origin/fb')
439
+ @local.write_sync_control_file('fb')
440
+ rcreate_commit :origin, 'master', :c
441
+ rcreate_commit :origin, 'fb', :b1, :file => 'b', :parents => [@c_sha]
442
+ rcreate_commit :origin, 'fb', :d
443
+ end
444
+
445
+ when_sync_is_run
446
+
447
+ Then do
448
+ local_and_remote_are_same
449
+ l_sha.should == @d_sha
450
+ end
451
+ end
452
+
453
+
454
+ # i
455
+ # /
456
+ # - A - C - B1 - D
457
+ # /
458
+ # l,r
459
+ it 'should work without a control file' do
460
+ Given do
461
+ rcreate_commit_on_new_branch :origin, 'fb', 'master', :b
462
+ rfetch local_repo, 'origin'
463
+ local_repo.create_branch('fb', 'origin/fb')
464
+ rcreate_commit :origin, 'master', :c
465
+ rcreate_commit :origin, 'fb', :b1, :file => 'b', :parents => [@c_sha]
466
+ rcreate_commit :origin, 'fb', :d
467
+ end
468
+
469
+ when_sync_is_run
470
+
471
+ Then do
472
+ local_and_remote_are_same
473
+ l_sha.should == @d_sha
474
+ end
475
+ end
476
+
477
+ end
478
+
479
+
480
+ # i
481
+ # /
482
+ # - A - C
483
+ # \
484
+ # B - D
485
+ # \ \
486
+ # \ l
487
+ # E
488
+ # \
489
+ # r
490
+ #
491
+ # Steps to get to this state:
492
+ # 1. Changes have been applied to the integration branch
493
+ # 2. Work has happened locally
494
+ # 3. Work has happened remotely
495
+ #
496
+ describe 'if local and remote both have work done on them, and remote has not been rebased' do
497
+
498
+ def verify_start_state
499
+ l_sha.should == @d_sha
500
+ r_sha.should == @e_sha
501
+ i_sha.should == @c_sha
502
+ treeish(origin_repo, "#{@c_sha}~1").should == @a_sha
503
+ treeish(origin_repo, "#{@b_sha}~1").should == @a_sha
504
+ treeish(local_repo, "#{@d_sha}~1").should == @b_sha
505
+ treeish(origin_repo, "#{@e_sha}~1").should == @b_sha
506
+ end
507
+
508
+
509
+ # i l,r
510
+ # / \
511
+ # - A - C - B1 - E1 - D1
512
+ it 'should work if no conflict' do
513
+ Given do
514
+ rcreate_commit_on_new_branch :origin, 'fb', 'master', :b
515
+ rfetch local_repo, 'origin'
516
+ local_repo.create_branch('fb', 'origin/fb')
517
+ @local.write_sync_control_file('fb')
518
+ rcreate_commit :local, 'fb', :d
519
+ rcreate_commit :origin, 'master', :c
520
+ rcreate_commit :origin, 'fb', :e
521
+ end
522
+
523
+ when_sync_is_run
524
+
525
+ Then do
526
+ local_and_remote_are_same
527
+ treeish(origin_repo, "#{l_sha}~3").should == @c_sha
528
+ check_file_content :b
529
+ check_file_content :d
530
+ end
531
+ end
532
+
533
+
534
+ # i l
535
+ # / /
536
+ # - A - C - XX
537
+ # \
538
+ # B - D
539
+ # \ \
540
+ # \ ??
541
+ # E
542
+ # \
543
+ # r
544
+ it 'should raise an error if conflict applying B' do
545
+ Given do
546
+ rcreate_commit_on_new_branch :origin, 'fb', 'master', :b, :file => 'a'
547
+ rfetch local_repo, 'origin'
548
+ local_repo.create_branch('fb', 'origin/fb')
549
+ @local.write_sync_control_file('fb')
550
+ rcreate_commit :local, 'fb', :d
551
+ rcreate_commit :origin, 'master', :c, :file => 'a'
552
+ rcreate_commit :origin, 'fb', :e
553
+ end
554
+
555
+ expect { when_sync_is_run }.to raise_error(RebaseError, /'a' was modified in both branches/)
556
+ end
557
+
558
+
559
+ # i l
560
+ # / \
561
+ # - A - C - B1 - XX
562
+ # \
563
+ # B - D
564
+ # \ \
565
+ # \ ??
566
+ # E
567
+ # \
568
+ # r
569
+ it 'should raise an error if there is a conflict applying remote' do
570
+ Given do
571
+ rcreate_commit_on_new_branch :origin, 'fb', 'master', :b
572
+ rfetch local_repo, 'origin'
573
+ local_repo.create_branch('fb', 'origin/fb')
574
+ @local.write_sync_control_file('fb')
575
+ rcreate_commit :local, 'fb', :d
576
+ rcreate_commit :origin, 'master', :c, :file => 'a'
577
+ rcreate_commit :origin, 'fb', :e, :file => 'a'
578
+ end
579
+
580
+ expect { when_sync_is_run }.to raise_error(RebaseError, /'a' was modified in both branches/)
581
+ end
582
+
583
+
584
+ # i l
585
+ # / \
586
+ # - A - C - B1 - E1 - XX
587
+ # \
588
+ # B - D
589
+ # \ \
590
+ # \ ??
591
+ # E
592
+ # \
593
+ # r
594
+ it 'should raise an error if conflict applying local' do
595
+ Given do
596
+ rcreate_commit_on_new_branch :origin, 'fb', 'master', :b
597
+ rfetch local_repo, 'origin'
598
+ local_repo.create_branch('fb', 'origin/fb')
599
+ @local.write_sync_control_file('fb')
600
+ rcreate_commit :local, 'fb', :d, :file => 'a'
601
+ rcreate_commit :origin, 'master', :c, :file => 'a'
602
+ rcreate_commit :origin, 'fb', :e
603
+ end
604
+
605
+ expect { when_sync_is_run }.to raise_error(RebaseError, /'a' was modified in both branches/)
606
+ end
607
+
608
+ end
609
+
610
+
611
+ # i l
612
+ # / /
613
+ # - A - C - D
614
+ # \
615
+ # B
616
+ # \
617
+ # r
618
+ #
619
+ # Steps to get to this state:
620
+ # 1. Changes have been applied to the integration branch
621
+ # 2. Nothing has changed on the remote since the last sync
622
+ # 3. Work has happened locally on the feature branch, and it is no longer a "simple" addition to the remote
623
+ #
624
+ describe 'if local is based on integration but not a "simple" version of remote' do
625
+
626
+ def verify_start_state
627
+ l_sha.should == @d_sha
628
+ r_sha.should == @b_sha
629
+ i_sha.should == @c_sha
630
+ treeish(origin_repo, "#{@b_sha}~1").should == @a_sha
631
+ treeish(origin_repo, "#{@c_sha}~1").should == @a_sha
632
+ treeish(local_repo, "#{@d_sha}~1").should == @c_sha
633
+ end
634
+
635
+
636
+ # i
637
+ # /
638
+ # - A - C - D
639
+ # /
640
+ # l,r
641
+ it 'should override remote branch' do
642
+ Given do
643
+ rcreate_commit_on_new_branch :origin, 'fb', 'master', :b
644
+ rcreate_commit :origin, 'master', :c
645
+ rfetch local_repo, 'origin'
646
+ local_repo.create_branch('fb', 'origin/fb')
647
+ @local.write_sync_control_file('fb')
648
+ rcreate_commit :local, 'fb', :d, :parents => [@c_sha]
649
+ end
650
+
651
+ when_sync_is_run
652
+
653
+ Then do
654
+ local_and_remote_are_same
655
+ l_sha.should == @d_sha
656
+ end
657
+ end
658
+
659
+ end
660
+
661
+
662
+ # l
663
+ # /
664
+ # D
665
+ # /
666
+ # - A - C - E
667
+ # \ /
668
+ # B i
669
+ # \
670
+ # r
671
+ #
672
+ # Steps to get to this state:
673
+ # 1. Changes have been applied to the integration branch
674
+ # 2. Nothing has changed on the remote since the last sync
675
+ # 2. Work has happened locally based on a newer version of integration, and it is no longer
676
+ # a "simple" addition to the remote
677
+ #
678
+ describe 'if local is not based on integration and not a "simple" version of remote' do
679
+
680
+ def verify_start_state
681
+ l_sha.should == @d_sha
682
+ r_sha.should == @b_sha
683
+ i_sha.should == @e_sha
684
+ treeish(origin_repo, "#{@b_sha}~1").should == @a_sha
685
+ treeish(origin_repo, "#{@c_sha}~1").should == @a_sha
686
+ treeish(local_repo, "#{@d_sha}~1").should == @c_sha
687
+ treeish(origin_repo, "#{@e_sha}~1").should == @c_sha
688
+ end
689
+
690
+
691
+ # - A - C - E - D1
692
+ # / /
693
+ # i l,r
694
+ it 'should override remote branch' do
695
+ Given do
696
+ rcreate_commit_on_new_branch :origin, 'fb', 'master', :b
697
+ rcreate_commit :origin, 'master', :c
698
+ rfetch local_repo, 'origin'
699
+ local_repo.create_branch('fb', 'origin/fb')
700
+ @local.write_sync_control_file('fb')
701
+ rcreate_commit :local, 'fb', :d, :parents => [@c_sha]
702
+ rcreate_commit :origin, 'master', :e
703
+ end
704
+
705
+ when_sync_is_run
706
+
707
+ Then do
708
+ local_and_remote_are_same
709
+ treeish(origin_repo, "#{l_sha}~1").should == @e_sha
710
+ end
711
+ end
712
+
713
+
714
+ # ??
715
+ # /
716
+ # D
717
+ # /
718
+ # - A - C - E - XX
719
+ # \ / /
720
+ # B i l
721
+ # \
722
+ # r
723
+ it 'should raise an error with conflict on local content' do
724
+ Given do
725
+ rcreate_commit_on_new_branch :origin, 'fb', 'master', :b
726
+ rcreate_commit :origin, 'master', :c
727
+ rfetch local_repo, 'origin'
728
+ local_repo.create_branch('fb', 'origin/fb')
729
+ @local.write_sync_control_file('fb')
730
+ rcreate_commit :local, 'fb', :d, :parents => [@c_sha], :file => 'a'
731
+ rcreate_commit :origin, 'master', :e, :file => 'a'
732
+ end
733
+
734
+ expect { when_sync_is_run }.to raise_error(RebaseError, /'a' was modified in both branches/)
735
+ end
736
+
737
+ end
738
+
739
+
740
+ # i r
741
+ # / \
742
+ # - A - C - B1 - E
743
+ # \
744
+ # B - D
745
+ # \
746
+ # l
747
+ #
748
+ # Steps to get to this state:
749
+ # 1. Changes have been applied to the integration branch
750
+ # 2. Work has happened locally based on an older version of integration
751
+ # 3. Work has happened remotely based on rebasing against integration
752
+ #
753
+ describe 'if local and remote both have work done on them, and remote has been rebased with integration' do
754
+
755
+ def verify_start_state
756
+ l_sha.should == @d_sha
757
+ r_sha.should == @e_sha
758
+ i_sha.should == @c_sha
759
+ treeish(local_repo, "#{@b_sha}~1").should == @a_sha
760
+ treeish(origin_repo, "#{@b1_sha}~1").should == @c_sha
761
+ treeish(origin_repo, "#{@c_sha}~1").should == @a_sha
762
+ treeish(local_repo, "#{@d_sha}~1").should == @b_sha
763
+ treeish(origin_repo, "#{@e_sha}~1").should == @b1_sha
764
+ end
765
+
766
+
767
+ # - A - C - B1 - E - D1
768
+ # / /
769
+ # i l,r
770
+ it 'should work if no conflict' do
771
+ Given do
772
+ rcreate_commit_on_new_branch :origin, 'fb', 'master', :b
773
+ rcreate_commit :origin, 'master', :c
774
+ rfetch local_repo, 'origin'
775
+ local_repo.create_branch('fb', 'origin/fb')
776
+ @local.write_sync_control_file('fb')
777
+ rcreate_commit :local, 'fb', :d
778
+ rcreate_commit :origin, 'fb', :b1, :parents => [@c_sha], :file => 'b'
779
+ rcreate_commit :origin, 'fb', :e
780
+ end
781
+
782
+ when_sync_is_run
783
+
784
+ Then do
785
+ local_and_remote_are_same
786
+ treeish(origin_repo, "#{l_sha}~1").should == @e_sha
787
+ end
788
+ end
789
+
790
+
791
+ # i r l
792
+ # / \ \
793
+ # - A - C - B1 - E - XX
794
+ # \
795
+ # B - D
796
+ # \
797
+ # ??
798
+ it 'should raise an error if there is a conflict' do
799
+ Given do
800
+ rcreate_commit_on_new_branch :origin, 'fb', 'master', :b
801
+ rcreate_commit :origin, 'master', :c
802
+ rfetch local_repo, 'origin'
803
+ local_repo.create_branch('fb', 'origin/fb')
804
+ @local.write_sync_control_file('fb')
805
+ rcreate_commit :local, 'fb', :d, :file => 'a'
806
+ rcreate_commit :origin, 'fb', :b1, :parents => [@c_sha], :file => 'b'
807
+ rcreate_commit :origin, 'fb', :e, :file => 'a'
808
+ end
809
+
810
+ expect { when_sync_is_run }.to raise_error(RebaseError, /'a' was modified in both branches/)
811
+ end
812
+
813
+ end
814
+
815
+
816
+ # r
817
+ # \
818
+ # B1 - E
819
+ # /
820
+ # - A - C - F
821
+ # \ \
822
+ # B - D i
823
+ # \
824
+ # l
825
+ #
826
+ # Steps to get to this state:
827
+ # 1. Changes have been applied to the integration branch
828
+ # 2. Work has happened locally based on an older version of integration
829
+ # 3. Work has happened remotely based on rebasing against integration
830
+ # 4. More work happened on integration
831
+ #
832
+ describe 'if local and remote both have work done on them, remote has been rebased with integration, and more work has been done on integration' do
833
+
834
+ def verify_start_state
835
+ l_sha.should == @d_sha
836
+ r_sha.should == @e_sha
837
+ i_sha.should == @f_sha
838
+ treeish(local_repo, "#{@b_sha}~1").should == @a_sha
839
+ treeish(origin_repo, "#{@b1_sha}~1").should == @c_sha
840
+ treeish(origin_repo, "#{@c_sha}~1").should == @a_sha
841
+ treeish(local_repo, "#{@d_sha}~1").should == @b_sha
842
+ treeish(origin_repo, "#{@e_sha}~1").should == @b1_sha
843
+ treeish(origin_repo, "#{@f_sha}~1").should == @c_sha
844
+ end
845
+
846
+
847
+ # - A - C - F - B2 - E1 - D1
848
+ # / /
849
+ # i l,r
850
+ it 'should work if no conflict' do
851
+ Given do
852
+ rcreate_commit_on_new_branch :origin, 'fb', 'master', :b
853
+ rcreate_commit :origin, 'master', :c
854
+ rfetch local_repo, 'origin'
855
+ local_repo.create_branch('fb', 'origin/fb')
856
+ @local.write_sync_control_file('fb')
857
+ rcreate_commit :local, 'fb', :d
858
+ rcreate_commit :origin, 'fb', :b1, :parents => [@c_sha], :file => 'b'
859
+ rcreate_commit :origin, 'fb', :e
860
+ rcreate_commit :origin, 'master', :f
861
+ end
862
+
863
+ when_sync_is_run
864
+
865
+ Then do
866
+ local_and_remote_are_same
867
+ treeish(local_repo, "#{l_sha}~3").should == @f_sha
868
+ end
869
+ end
870
+
871
+
872
+ # r
873
+ # \
874
+ # B1 - E
875
+ # /
876
+ # - A - C - F - XX
877
+ # \ \ \
878
+ # B - D i l
879
+ # \
880
+ # ??
881
+ it 'should raise an error if conflict applying remote' do
882
+ Given do
883
+ rcreate_commit_on_new_branch :origin, 'fb', 'master', :b
884
+ rcreate_commit :origin, 'master', :c
885
+ rfetch local_repo, 'origin'
886
+ local_repo.create_branch('fb', 'origin/fb')
887
+ @local.write_sync_control_file('fb')
888
+ rcreate_commit :local, 'fb', :d
889
+ rcreate_commit :origin, 'fb', :b1, :parents => [@c_sha], :file => 'a'
890
+ rcreate_commit :origin, 'fb', :e
891
+ rcreate_commit :origin, 'master', :f, :file => 'a'
892
+ end
893
+
894
+ expect { when_sync_is_run }.to raise_error(RebaseError, /'a' was modified in both branches/)
895
+ end
896
+
897
+
898
+ # r
899
+ # \
900
+ # B1 - E
901
+ # /
902
+ # - A - C - F - B2 - E1 - XX
903
+ # \ \ /
904
+ # B - D i l
905
+ # \
906
+ # ??
907
+ it 'should raise an error if conflict applying local' do
908
+ Given do
909
+ rcreate_commit_on_new_branch :origin, 'fb', 'master', :b
910
+ rcreate_commit :origin, 'master', :c
911
+ rfetch local_repo, 'origin'
912
+ local_repo.create_branch('fb', 'origin/fb')
913
+ @local.write_sync_control_file('fb')
914
+ rcreate_commit :local, 'fb', :d, :file => 'a'
915
+ rcreate_commit :origin, 'fb', :b1, :parents => [@c_sha], :file => 'b'
916
+ rcreate_commit :origin, 'fb', :e, :file => 'a'
917
+ rcreate_commit :origin, 'master', :f
918
+ end
919
+
920
+ expect { when_sync_is_run }.to raise_error(RebaseError, /'a' was modified in both branches/)
921
+ end
922
+
923
+ end
924
+
925
+
926
+ describe 'with branch name' do
927
+
928
+ def create_process(gitlib, opts = {})
929
+ GitProc::Sync.new(gitlib, opts.merge({:branch_name => 'fb', :rebase => true, :force => false}))
930
+ end
931
+
932
+
933
+ # i
934
+ # /
935
+ # - A - C
936
+ # \
937
+ # B
938
+ # \
939
+ # r
940
+ #
941
+ # Steps to get to this state:
942
+ # 1. There is a remote feature branch ("fb")
943
+ # 2. The local repo does not have a feature branch by the same name
944
+ # 3. The integration branch has moved on since the remote branch was last synced
945
+ describe 'no local branch by the same name' do
946
+
947
+ def verify_start_state
948
+ Rugged::Branch.lookup(local_repo, 'fb').should be_nil
949
+ r_sha.should == @b_sha
950
+ i_sha.should == @c_sha
951
+ treeish(origin_repo, "#{@c_sha}~1").should == @a_sha
952
+ treeish(origin_repo, "#{@b_sha}~1").should == @a_sha
953
+ end
954
+
955
+
956
+ # i l,r
957
+ # / /
958
+ # - A - C - B1
959
+ #
960
+ it 'creates a local branch and rebases with integration' do
961
+ Given do
962
+ rcreate_commit_on_new_branch :origin, 'fb', 'master', :b
963
+ rfetch local_repo, 'origin'
964
+ rcreate_commit_on_new_branch :local, 'random', 'master', :z, :parents => []
965
+ rcreate_commit :origin, 'master', :c
966
+ end
967
+
968
+ when_sync_is_run(false)
969
+
970
+ Then do
971
+ local_and_remote_are_same
972
+ @local.config['branch.fb.remote'].should == 'origin'
973
+ @local.config['branch.fb.merge'].should == 'refs/heads/master'
974
+ parent(l_sha).should == @c_sha
975
+ end
976
+ end
977
+
978
+ end
979
+
980
+
981
+ # i
982
+ # /
983
+ # - A - C
984
+ # \
985
+ # B - l
986
+ # \
987
+ # D - r
988
+ #
989
+ # Steps to get to this state:
990
+ # 1. There is a remote feature branch ("fb")
991
+ # 2. The local repo has a feature branch by the same name that is fully within the remote's history
992
+ # 3. The integration branch has moved on since the feature branches were last synced
993
+ describe 'has local branch by same name subsumed by remote' do
994
+
995
+ def verify_start_state
996
+ Rugged::Branch.lookup(local_repo, 'fb').should_not be_nil
997
+ l_sha.should == @b_sha
998
+ r_sha.should == @d_sha
999
+ i_sha.should == @c_sha
1000
+ treeish(origin_repo, "#{@c_sha}~1").should == @a_sha
1001
+ treeish(origin_repo, "#{@b_sha}~1").should == @a_sha
1002
+ treeish(origin_repo, "#{@d_sha}~1").should == @b_sha
1003
+ end
1004
+
1005
+
1006
+ # i l,r
1007
+ # / /
1008
+ # - A - C - B1
1009
+ #
1010
+ it 'change to the remote and rebases with integration if it is subsumed by the remote' do
1011
+ Given do
1012
+ rcreate_commit_on_new_branch :origin, 'fb', 'master', :b
1013
+ rfetch local_repo, 'origin'
1014
+ local_repo.create_branch('fb', 'origin/fb')
1015
+ rcreate_commit :origin, 'fb', :d
1016
+ rcreate_commit :origin, 'master', :c
1017
+ end
1018
+
1019
+ when_sync_is_run(false)
1020
+
1021
+ Then do
1022
+ local_and_remote_are_same
1023
+ @local.config['branch.fb.remote'].should == 'origin'
1024
+ @local.config['branch.fb.merge'].should == 'refs/heads/master'
1025
+ parent(l_sha).should == @c_sha
1026
+ end
1027
+ end
1028
+
1029
+ end
1030
+
1031
+
1032
+ # i
1033
+ # /
1034
+ # - A - C
1035
+ # \
1036
+ # B
1037
+ # \
1038
+ # r
1039
+ #
1040
+ # Steps to get to this state:
1041
+ # 1. There is a remote feature branch ("fb")
1042
+ # 2. The local repo has a feature branch by the same name not fully in the remote's history
1043
+ # 3. The integration branch has moved on since the remote branch was last synced
1044
+ describe 'has local branch by same name not subsumed by remote' do
1045
+
1046
+ def verify_start_state
1047
+ Rugged::Branch.lookup(local_repo, 'fb').should_not be_nil
1048
+ r_sha.should == @b_sha
1049
+ i_sha.should == @c_sha
1050
+ treeish(origin_repo, "#{@c_sha}~1").should == @a_sha
1051
+ treeish(origin_repo, "#{@b_sha}~1").should == @a_sha
1052
+ end
1053
+
1054
+
1055
+ # i l,r
1056
+ # / /
1057
+ # - A - C - B1
1058
+ #
1059
+ it 'should fail if it is not subsumed by the remote' do
1060
+ Given do
1061
+ rcreate_commit_on_new_branch :origin, 'fb', 'master', :b
1062
+ rcreate_commit_on_new_branch :local, 'fb', 'master', :z, :parents => []
1063
+ rcreate_commit :origin, 'master', :c
1064
+ end
1065
+
1066
+ expect { when_sync_is_run(false) }.to raise_error(GitProcessError, /is not fully subsumed by origin\/fb/)
1067
+ end
1068
+
1069
+ end
1070
+
1071
+
1072
+ describe 'unknown branch name' do
1073
+
1074
+ def create_process(gitlib, opts = {})
1075
+ GitProc::Sync.new(gitlib, opts.merge({:branch_name => 'unknown', :rebase => true, :force => false}))
1076
+ end
1077
+
1078
+
1079
+ def verify_start_state
1080
+ Rugged::Branch.lookup(origin_repo, 'fb').should_not be_nil
1081
+ Rugged::Branch.lookup(local_repo, 'unknown').should be_nil
1082
+ Rugged::Branch.lookup(origin_repo, 'unknown').should be_nil
1083
+ end
1084
+
1085
+
1086
+ it 'should fail if it is not subsumed by the remote' do
1087
+ Given do
1088
+ rcreate_commit_on_new_branch :origin, 'fb', 'master', :b
1089
+ end
1090
+
1091
+ expect { when_sync_is_run(false) }.to raise_error(GitProcessError, /There is not a remote branch for 'unknown'/)
1092
+ end
1093
+
1094
+ end
1095
+
1096
+
1097
+ describe 'no remote' do
1098
+
1099
+ def create_process(gitlib, opts = {})
1100
+ GitProc::Sync.new(gitlib, opts.merge({:branch_name => 'no_remote', :rebase => true, :force => false}))
1101
+ end
1102
+
1103
+
1104
+ def verify_start_state
1105
+ Rugged::Branch.lookup(local_repo, 'no_remote').should be_nil
1106
+ end
1107
+
1108
+
1109
+ it 'should fail if it is not subsumed by the remote' do
1110
+ Given do
1111
+ @local.command(:remote, ['remove', 'origin'])
1112
+ end
1113
+
1114
+ expect { when_sync_is_run(false) }.to raise_error(GitProcessError, /Specifying 'no_remote' does not make sense without a remote/)
1115
+ end
1116
+
1117
+ end
1118
+
1119
+ end
1120
+
1121
+ end
1122
+
1123
+
1124
+ describe 'when forcing local-only' do
1125
+
1126
+ def create_process(dir, opts)
1127
+ GitProc::Sync.new(dir, opts.merge({:rebase => true, :force => false, :local => true}))
1128
+ end
1129
+
1130
+
1131
+ it 'should not try to push' do
1132
+ change_file_and_commit('a', '')
1133
+
1134
+ gitlib.branch('fb', :base_branch => 'master')
1135
+
1136
+ clone_repo('fb') do |gl|
1137
+ gitlib.checkout('fb')
1138
+ change_file_and_commit('a', 'hello', gitlib)
1139
+
1140
+ sp = GitProc::Sync.new(gl, :rebase => true, :force => false, :local => true, :log_level => log_level)
1141
+ gl.should_receive(:fetch).at_least(1) # want to get remote changes
1142
+ gl.should_not_receive(:push) # ...but not push any
1143
+
1144
+ sp.runner
1145
+ end
1146
+ end
1147
+
1148
+ end
1149
+ end
1150
+
1151
+
1152
+ describe 'when there is no remote' do
1153
+
1154
+ def create_process(base, opts)
1155
+ GitProc::Sync.new(base, opts.merge({:rebase => true, :force => false, :local => false}))
1156
+ end
1157
+
1158
+
1159
+ it 'should not try to fetch or push' do
1160
+ change_file_and_commit('a', '')
1161
+
1162
+ gitlib.branch('fb', :base_branch => 'master')
1163
+
1164
+ sp = GitProc::Sync.new(gitlib, :rebase => true, :force => false, :local => true, :log_level => log_level)
1165
+ gitlib.should_not_receive(:fetch)
1166
+ gitlib.should_not_receive(:push)
1167
+
1168
+ sp.runner
1169
+ end
1170
+
1171
+ end
1172
+
1173
+
1174
+ describe 'when default rebase flag is used' do
1175
+
1176
+ def create_process(base = gitlib, opts = {})
1177
+ GitProc::Sync.new(base, opts.merge({:rebase => false, :force => false, :local => false}))
1178
+ end
1179
+
1180
+
1181
+ it 'should try to rebase by flag' do
1182
+ change_file_and_commit('a', '', gitlib)
1183
+
1184
+ gitlib.branch('fb', :base_branch => 'master')
1185
+
1186
+ sp = GitProc::Sync.new(gitlib, :rebase => true, :force => false, :local => true, :log_level => log_level)
1187
+ gitlib.should_receive(:rebase)
1188
+ gitlib.should_not_receive(:merge)
1189
+
1190
+ sp.runner
1191
+ end
1192
+
1193
+
1194
+ it 'should try to rebase by config' do
1195
+ change_file_and_commit('a', '', gitlib)
1196
+
1197
+ gitlib.branch('fb', :base_branch => 'master')
1198
+ gitlib.config.default_rebase_sync = true
1199
+
1200
+ sp = GitProc::Sync.new(gitlib, :force => false, :local => true, :log_level => log_level)
1201
+ gitlib.should_receive(:rebase)
1202
+ gitlib.should_not_receive(:merge)
1203
+
1204
+ sp.runner
1205
+ end
1206
+
1207
+
1208
+ it 'should not try to rebase by false config' do
1209
+ change_file_and_commit('a', '', gitlib)
1210
+
1211
+ gitlib.branch('fb', :base_branch => 'master')
1212
+ gitlib.config.default_rebase_sync = false
1213
+
1214
+ sp = GitProc::Sync.new(gitlib, :rebase => false, :force => false, :local => true, :log_level => log_level)
1215
+ gitlib.should_not_receive(:rebase)
1216
+ gitlib.should_receive(:merge)
1217
+
1218
+ sp.runner
1219
+ end
1220
+
1221
+
1222
+ it 'should try to rebase by true flag config' do
1223
+ change_file_and_commit('a', '', gitlib)
1224
+
1225
+ gitlib.branch('fb', :base_branch => 'master')
1226
+ gitlib.config.default_rebase_sync = false
1227
+
1228
+ sp = GitProc::Sync.new(gitlib, :rebase => true, :force => false, :local => true, :log_level => log_level)
1229
+ gitlib.should_receive(:rebase)
1230
+ gitlib.should_not_receive(:merge)
1231
+
1232
+ sp.runner
1233
+ end
1234
+
1235
+
1236
+ it 'should not try to rebase by false flag config' do
1237
+ change_file_and_commit('a', '', gitlib)
1238
+
1239
+ gitlib.branch('fb', :base_branch => 'master')
1240
+ gitlib.config.default_rebase_sync = true
1241
+
1242
+ sp = GitProc::Sync.new(gitlib, :rebase => false, :force => false, :local => true, :log_level => log_level)
1243
+ gitlib.should_not_receive(:rebase)
1244
+ gitlib.should_receive(:merge)
1245
+
1246
+ sp.runner
1247
+ end
1248
+
1249
+ end
1250
+
1251
+
1252
+ it "should work with a different remote server name than 'origin'" do
1253
+ change_file_and_commit('a', '')
1254
+
1255
+ gitlib.branch('fb', :base_branch => 'master')
1256
+
1257
+ clone_repo('fb', 'a_remote') do |gl|
1258
+ change_file_and_commit('a', 'hello', gl)
1259
+ gl.branches.include?('a_remote/fb').should be_true
1260
+
1261
+ GitProc::Sync.new(gl, :rebase => false, :force => false, :log_level => log_level).runner
1262
+
1263
+ gl.branches.include?('a_remote/fb').should be_true
1264
+ gitlib.branches.include?('fb').should be_true
1265
+ end
1266
+ end
1267
+
1268
+
1269
+ it 'should fail when removing current feature while on _parking_' do
1270
+ gitlib.checkout('_parking_', :new_branch => 'master')
1271
+ change_file_and_commit('a', '')
1272
+
1273
+ expect { gitprocess.verify_preconditions }.to raise_error ParkedChangesError
1274
+ end
1275
+
1276
+
1277
+ ###########################################################################
1278
+ #
1279
+ # HELPER METHODS
1280
+ #
1281
+ ###########################################################################
1282
+
1283
+
1284
+ #noinspection RubyInstanceMethodNamingConvention
1285
+ def Given
1286
+ if block_given?
1287
+ yield
1288
+ verify_start_state
1289
+ else
1290
+ raise ArgumentError, 'No block given'
1291
+ end
1292
+ end
1293
+
1294
+
1295
+ def when_sync_is_run(do_checkout = true)
1296
+ @local.checkout('fb') if do_checkout
1297
+ create_process(@local).runner
1298
+ end
1299
+
1300
+
1301
+ #noinspection RubyInstanceMethodNamingConvention
1302
+ def Then
1303
+ if block_given?
1304
+ yield
1305
+ else
1306
+ raise ArgumentError, 'No block given'
1307
+ end
1308
+ end
1309
+
1310
+
1311
+ def origin(branchname = nil, opts={})
1312
+ unless @origin
1313
+ @origin = gitlib
1314
+ @origin.config['receive.denyCurrentBranch'] = 'ignore'
1315
+ end
1316
+ @current_lib = @origin
1317
+ @origin.checkout(branchname, opts) if branchname
1318
+ @origin
1319
+ end
1320
+
1321
+
1322
+ def local(branchname = nil, opts={})
1323
+ if @local.nil?
1324
+ remote_name = opts[:remote_name] || 'origin'
1325
+ @local ||= clone_repo('master', remote_name)
1326
+ end
1327
+ @current_lib = @local
1328
+ @local.fetch
1329
+ @local.checkout(branchname, opts) if branchname
1330
+ @local
1331
+ end
1332
+
1333
+
1334
+ def parent(sha, lib = @local)
1335
+ lib.fetch
1336
+ @local.sha("#{sha}~1")
1337
+ end
1338
+
1339
+
1340
+ def create_commit(commit_name, opts={})
1341
+ lib = opts[:lib] || @current_lib
1342
+ raise ArgumentError, 'missing lib' unless lib
1343
+
1344
+ filename = opts[:file] || commit_name.to_s
1345
+ change_file_and_commit(filename, "#{commit_name} contents", lib)
1346
+ instance_variable_set("@#{commit_name}_sha", lib.sha('HEAD'))
1347
+ end
1348
+
1349
+
1350
+ def check_file_content(commit_name, opts={})
1351
+ lib = opts[:lib] || @local
1352
+
1353
+ filename = opts[:file] || commit_name.to_s
1354
+ File.open(File.join(lib.workdir, filename)).read.should == "#{commit_name} contents\n"
1355
+ end
1356
+
1357
+
1358
+ #noinspection RubyInstanceMethodNamingConvention
1359
+ def create_feature_branch_on_origin
1360
+ @origin.checkout('fb', :new_branch => 'master')
1361
+ end
1362
+
1363
+
1364
+ def local_repo
1365
+ @local_repo ||= Rugged::Repository.new(@local.workdir)
1366
+ end
1367
+
1368
+
1369
+ def origin_repo
1370
+ @origin_repo ||= Rugged::Repository.new(@origin.workdir)
1371
+ end
1372
+
1373
+
1374
+ def l_sha
1375
+ branch_tip(local_repo, 'fb')
1376
+ end
1377
+
1378
+
1379
+ def i_sha
1380
+ branch_tip(origin_repo, 'master')
1381
+ end
1382
+
1383
+
1384
+ def r_sha
1385
+ branch_tip(origin_repo, 'fb')
1386
+ end
1387
+
1388
+
1389
+ def local_and_remote_are_same
1390
+ l_sha.should == r_sha
1391
+ end
1392
+
1393
+
1394
+ def branch_tip(repo, branch_name)
1395
+ Rugged::Branch.lookup(repo, branch_name).tip.oid
1396
+ end
1397
+
1398
+
1399
+ def rchange_file_and_commit(repo_name, branch, filename, contents, opts = {})
1400
+ repo = self.method("#{repo_name.to_s}_repo").call
1401
+
1402
+ content_oid = repo.write(contents, :blob)
1403
+ logger.debug { "\nwrote content '#{contents}' to #{content_oid}" }
1404
+
1405
+ if branch.nil?
1406
+ tree = Rugged::Tree::Builder.new
1407
+ tree.insert(:name => filename, :oid => content_oid, :filemode => 0100644)
1408
+ tree_oid = tree.write(repo)
1409
+ parents = opts[:parents] || []
1410
+ branch_name = 'HEAD'
1411
+ else
1412
+ tree = Rugged::Tree::Builder.new(branch.tip.tree)
1413
+ tree.insert(:name => filename, :oid => content_oid, :filemode => 0100644)
1414
+ tree_oid = tree.write(repo)
1415
+ parents = opts[:parents] || [branch.tip.oid]
1416
+ branch_name = branch.canonical_name
1417
+ end
1418
+
1419
+ tree = repo.lookup(tree_oid)
1420
+ logger.debug "tree:"
1421
+ tree.each { |entry| logger.debug " #{entry.inspect}" }
1422
+
1423
+ person = {:name => 'test user', :email => 'test.user@test.com', :time => Time.now, :time_offset => 3600}
1424
+ oid = Rugged::Commit.create(repo,
1425
+ :message => "#{filename} - #{contents}",
1426
+ :committer => person,
1427
+ :author => person,
1428
+ :parents => parents,
1429
+ :update_ref => branch_name,
1430
+ :tree => tree_oid)
1431
+
1432
+ new_branch = Rugged::Branch.lookup(repo, branch.nil? ? 'HEAD' : branch.name)
1433
+ new_tip = new_branch.nil? ? 'BUG' : new_branch.tip.oid
1434
+ logger.debug { "wrote commit #{oid} on #{repo_name} - #{branch_name} with #{parents} as the parent, making new branch tip #{new_tip}" }
1435
+ oid
1436
+ end
1437
+
1438
+
1439
+ def rcreate_commit(repo_name, branch_name, commit_name, opts={})
1440
+ repo = self.method("#{repo_name.to_s}_repo").call
1441
+ branch = Rugged::Branch.lookup(repo, branch_name)
1442
+ _create_commit(repo_name, branch, commit_name, opts)
1443
+ end
1444
+
1445
+
1446
+ def _create_commit(repo_name, branch, commit_name, opts)
1447
+ filename = opts[:file] || commit_name.to_s
1448
+ oid = rchange_file_and_commit(repo_name, branch, filename, "#{commit_name} contents\n", opts)
1449
+ instance_variable_set("@#{commit_name}_sha", oid)
1450
+ oid
1451
+ end
1452
+
1453
+
1454
+ def rcreate_commit_on_new_branch(repo_name, branch_name, base_branch_name, commit_name, opts={})
1455
+ repo = self.method("#{repo_name.to_s}_repo").call
1456
+ branch = repo.create_branch(branch_name, base_branch_name)
1457
+ _create_commit(repo_name, branch, commit_name, opts)
1458
+ end
1459
+
1460
+
1461
+ def rfetch(repo, remote_name)
1462
+ remote = Rugged::Remote.lookup(repo, remote_name)
1463
+ remote.connect(:fetch) do |r|
1464
+ r.download()
1465
+ r.update_tips!
1466
+ end
1467
+ end
1468
+
1469
+
1470
+ def treeish(repo, treeish)
1471
+ Rugged::Object.rev_parse(repo, treeish).oid
1472
+ end
1473
+
1474
+ end