git-process-lib 2.0.0

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