git-process 0.9.5 → 0.9.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -14,11 +14,13 @@ require 'git-process/git_lib'
14
14
  require 'git-process/git_process'
15
15
  require 'git-process/parked_changes_error'
16
16
  require 'git-process/uncommitted_changes_error'
17
+ require 'git-process/changed_file_helper'
17
18
 
18
19
 
19
20
  module GitProc
20
21
 
21
22
  class Sync < Process
23
+ include ChangeFileHelper
22
24
 
23
25
  def initialize(dir, opts)
24
26
  opts[:force] = true if opts[:rebase]
@@ -36,19 +38,32 @@ module GitProc
36
38
  end
37
39
 
38
40
 
39
- def runner
40
- raise UncommittedChangesError.new unless status.clean?
41
+ def verify_preconditions
42
+ super
43
+
44
+ if not status.clean?
45
+ offer_to_help_uncommitted_changes
46
+ end
47
+
41
48
  raise ParkedChangesError.new(self) if is_parked?
49
+ end
42
50
 
51
+
52
+ def cleanup
53
+ stash_pop if @stash_pushed
54
+ end
55
+
56
+
57
+ def runner
43
58
  @current_branch ||= branches.current
44
59
  @remote_branch ||= "#{server_name}/#{@current_branch}"
45
60
 
46
61
  fetch(server_name)
47
62
 
48
63
  if @do_rebase
49
- proc_rebase(remote_master_branch)
64
+ proc_rebase(integration_branch)
50
65
  else
51
- proc_merge(remote_master_branch)
66
+ proc_merge(integration_branch)
52
67
  end
53
68
 
54
69
  if @local
@@ -14,7 +14,7 @@ module GitProc
14
14
  module Version
15
15
  MAJOR = 0
16
16
  MINOR = 9
17
- PATCH = 5
17
+ PATCH = 6
18
18
  BUILD = nil
19
19
 
20
20
  STRING = [MAJOR, MINOR, PATCH, BUILD].compact.join('.')
@@ -0,0 +1,143 @@
1
+ require 'git-process/sync'
2
+ require 'GitRepoHelper'
3
+
4
+ module GitProc
5
+
6
+ class CFHStub < Process
7
+ include ChangeFileHelper
8
+
9
+
10
+ def cleanup
11
+ stash_pop if @stash_pushed
12
+ end
13
+
14
+ end
15
+
16
+ end
17
+
18
+
19
+ describe GitProc::ChangeFileHelper do
20
+ include GitRepoHelper
21
+
22
+ before(:each) do
23
+ create_files(['.gitignore'])
24
+ gitprocess.commit('initial')
25
+ end
26
+
27
+
28
+ after(:each) do
29
+ rm_rf(tmpdir)
30
+ end
31
+
32
+
33
+ def log_level
34
+ Logger::ERROR
35
+ end
36
+
37
+
38
+ def create_process(dir, opts)
39
+ GitProc::CFHStub.new(dir, opts)
40
+ end
41
+
42
+
43
+ describe "uncommitted changes" do
44
+
45
+ it 'should fail when there are unmerged files' do
46
+ change_file_and_commit('modified file.txt', 'start')
47
+
48
+ gp = clone
49
+ change_file_and_commit('modified file.txt', 'changed', gp)
50
+ change_file_and_commit('modified file.txt', 'conflict', gitprocess)
51
+ gp.fetch
52
+
53
+ gp.merge('origin/master') rescue ''
54
+
55
+ expect {gp.offer_to_help_uncommitted_changes}.should raise_error GitProc::UncommittedChangesError
56
+ end
57
+
58
+
59
+ describe "using 'unknown' file" do
60
+
61
+ before(:each) do
62
+ change_file('unknown file.txt', '')
63
+ gitprocess.stub(:say)
64
+ end
65
+
66
+
67
+ it 'should then add it' do
68
+ gitprocess.stub(:ask).and_return('a')
69
+ gitprocess.should_receive(:add).with(['unknown file.txt'])
70
+
71
+ gitprocess.offer_to_help_uncommitted_changes
72
+ end
73
+
74
+
75
+ it 'should ignore the file' do
76
+ gitprocess.stub(:ask).and_return('i')
77
+ gitprocess.should_not_receive(:add)
78
+
79
+ gitprocess.offer_to_help_uncommitted_changes
80
+ end
81
+
82
+ end
83
+
84
+
85
+ describe "using changed files" do
86
+
87
+ before(:each) do
88
+ change_file_and_commit('modified file.txt', 'start')
89
+ change_file_and_commit('modified file2.txt', 'start')
90
+ change_file_and_commit('modified file3.txt', 'start')
91
+ change_file_and_commit('removed file.txt', 'content')
92
+ change_file_and_add('added file.txt', '')
93
+ change_file('modified file.txt', 'modified')
94
+ change_file_and_add('modified file2.txt', 'modified')
95
+ change_file_and_add('modified file3.txt', 'modified')
96
+ change_file('modified file2.txt', 'modified again')
97
+ change_file_and_add('removed file2.txt', 'content')
98
+ File.delete(File.join(gitprocess.workdir, 'removed file.txt'))
99
+ File.delete(File.join(gitprocess.workdir, 'removed file2.txt'))
100
+ File.delete(File.join(gitprocess.workdir, 'modified file3.txt'))
101
+
102
+ # End state of the above is:
103
+ # A "added file.txt"
104
+ # M "modified file.txt"
105
+ # MM "modified file2.txt"
106
+ # MD "modified file3.txt"
107
+ # D "removed file.txt"
108
+ # AD "removed file2.txt"
109
+
110
+ gitprocess.stub(:say)
111
+ end
112
+
113
+
114
+ it 'should ask about modified files, then commit them' do
115
+ gitprocess.stub(:ask).and_return('c')
116
+ gitprocess.should_receive(:add).with(["added file.txt", "modified file.txt", "modified file2.txt"])
117
+ gitprocess.should_receive(:remove).with(["modified file3.txt", "removed file.txt", "removed file2.txt"])
118
+ gitprocess.should_receive(:commit).with(nil)
119
+
120
+ gitprocess.offer_to_help_uncommitted_changes
121
+ end
122
+
123
+
124
+ it 'should ask about modified files, then stash them' do
125
+ gitprocess.stub(:ask).and_return('s')
126
+
127
+ gitprocess.offer_to_help_uncommitted_changes
128
+
129
+ gitprocess.status.clean?.should be_true
130
+
131
+ gitprocess.cleanup
132
+
133
+ stat = gitprocess.status
134
+ stat.added.should == ["added file.txt", "removed file2.txt"]
135
+ stat.modified.should == ["modified file.txt", "modified file2.txt"]
136
+ stat.deleted.should == ["modified file3.txt", "removed file.txt"]
137
+ end
138
+
139
+ end
140
+
141
+ end
142
+
143
+ end
@@ -5,6 +5,11 @@ require 'fileutils'
5
5
  describe GitProc::Process do
6
6
  include GitRepoHelper
7
7
 
8
+ def log_level
9
+ Logger::ERROR
10
+ end
11
+
12
+
8
13
  before(:each) do
9
14
  create_files(['.gitignore'])
10
15
  gitprocess.commit('initial')
@@ -33,4 +38,170 @@ describe GitProc::Process do
33
38
 
34
39
  end
35
40
 
41
+
42
+ describe "run lifecycle" do
43
+
44
+ it "should call the standard hooks" do
45
+ proc = GitProc::Process.new(tmpdir)
46
+ proc.should_receive(:verify_preconditions)
47
+ proc.should_receive(:runner)
48
+ proc.should_receive(:cleanup)
49
+ proc.should_not_receive(:exit)
50
+
51
+ proc.run
52
+ end
53
+
54
+
55
+ it "should call 'cleanup' even if there's an error" do
56
+ proc = GitProc::Process.new(tmpdir)
57
+ proc.should_receive(:verify_preconditions)
58
+ proc.should_receive(:runner).and_raise(GitProc::GitProcessError.new("Error!"))
59
+ proc.should_receive(:cleanup)
60
+ proc.should_receive(:exit)
61
+ proc.should_receive(:puts).with("Error!")
62
+
63
+ proc.run
64
+ end
65
+
66
+ end
67
+
68
+
69
+ describe "validate local integration branch" do
70
+
71
+ it "should use remove the int-branch if not on it and not blocked" do
72
+ gp = clone('master')
73
+ gp.checkout('fb', :new_branch => 'master')
74
+
75
+ gp.stub(:ask_about_removing_master).and_return(true)
76
+
77
+ gp.verify_preconditions
78
+
79
+ gp.branches.include?('master').should be_false
80
+ end
81
+
82
+
83
+ it "should ask use remove the int-branch if not on it and not blocked" do
84
+ gp = clone('master')
85
+ gp.checkout('fb', :new_branch => 'master')
86
+
87
+ gp.should_receive(:ask_about_removing_master).and_return(true)
88
+
89
+ gp.verify_preconditions
90
+
91
+ gp.branches.include?('master').should be_false
92
+ end
93
+
94
+
95
+ it "should ask use remove the int-branch if not on it and not blocked and not remove if answered no" do
96
+ gp = clone('master')
97
+ gp.checkout('fb', :new_branch => 'master')
98
+
99
+ gp.should_receive(:ask_about_removing_master).and_return(false)
100
+
101
+ gp.verify_preconditions
102
+
103
+ gp.branches.include?('master').should be_true
104
+ end
105
+
106
+
107
+ it "should not remove the int-branch if on it" do
108
+ gp = clone('master')
109
+
110
+ gp.verify_preconditions
111
+
112
+ gp.branches.include?('master').should be_true
113
+ end
114
+
115
+
116
+ it "should not remove the int-branch if blocked" do
117
+ gp = clone('master')
118
+ gp.config('gitProcess.keepLocalIntegrationBranch', 'true')
119
+ gp.checkout('fb', :new_branch => 'master')
120
+
121
+ gp.verify_preconditions
122
+
123
+ gp.branches.include?('master').should be_true
124
+ end
125
+
126
+
127
+ describe "local vs remote branch status" do
128
+
129
+ before(:each) do
130
+ change_file_and_commit('a.txt', 'a content', gitprocess)
131
+ change_file_and_commit('b.txt', 'b content', gitprocess)
132
+ end
133
+
134
+
135
+ it "should not remove if both have changes" do
136
+ gp = clone('master')
137
+
138
+ change_file_and_commit('c.txt', 'c on origin/master', gitprocess)
139
+ change_file_and_commit('d.txt', 'd on master', gp)
140
+
141
+ gp.checkout('fb', :new_branch => 'master')
142
+
143
+ gp.fetch
144
+ gp.verify_preconditions
145
+
146
+ gp.branches.include?('master').should be_true
147
+ end
148
+
149
+
150
+ it "should remove if server changed but not local" do
151
+ gp = clone('master')
152
+ gp.stub(:ask_about_removing_master).and_return(true)
153
+
154
+ change_file_and_commit('c.txt', 'c on origin/master', gitprocess)
155
+
156
+ gp.checkout('fb', :new_branch => 'master')
157
+
158
+ gp.fetch
159
+ gp.verify_preconditions
160
+
161
+ gp.branches.include?('master').should be_false
162
+ end
163
+
164
+
165
+ it "should not remove if server did not change but local did" do
166
+ gp = clone('master')
167
+
168
+ change_file_and_commit('c.txt', 'c on master', gp)
169
+
170
+ gp.checkout('fb', :new_branch => 'master')
171
+
172
+ gp.fetch
173
+ gp.verify_preconditions
174
+
175
+ gp.branches.include?('master').should be_true
176
+ end
177
+
178
+
179
+ it "should remove if server and local are the same" do
180
+ change_file_and_commit('c.txt', 'c on origin/master', gitprocess)
181
+
182
+ gp = clone('master')
183
+
184
+ gp.checkout('fb', :new_branch => 'master')
185
+ gp.stub(:ask_about_removing_master).and_return(true)
186
+
187
+ gp.fetch
188
+ gp.verify_preconditions
189
+
190
+ gp.branches.include?('master').should be_false
191
+ end
192
+
193
+ end
194
+
195
+
196
+ it "should not remove the int-branch if not a clone" do
197
+ gitprocess.config('gitProcess.keepLocalIntegrationBranch', 'false')
198
+ gitprocess.checkout('fb', :new_branch => 'master')
199
+
200
+ gitprocess.verify_preconditions
201
+
202
+ gitprocess.branches.include?('master').should be_true
203
+ end
204
+
205
+ end
206
+
36
207
  end
@@ -1,9 +1,15 @@
1
1
  require 'git-process/git_status'
2
2
  require 'GitRepoHelper'
3
+ require 'fileutils'
3
4
 
4
5
  describe GitProc::GitStatus do
5
6
  include GitRepoHelper
6
7
 
8
+ def log_level
9
+ Logger::ERROR
10
+ end
11
+
12
+
7
13
  before(:each) do
8
14
  create_files(['.gitignore'])
9
15
  gitprocess.commit('initial')
@@ -16,9 +22,9 @@ describe GitProc::GitStatus do
16
22
 
17
23
 
18
24
  it "should handle added files" do
19
- create_files(['a', 'b', 'c'])
25
+ create_files(['a', 'b file.txt', 'c'])
20
26
 
21
- gitprocess.status.added.should == ['a', 'b', 'c']
27
+ gitprocess.status.added.should == ['a', 'b file.txt', 'c']
22
28
  end
23
29
 
24
30
 
@@ -90,6 +96,21 @@ describe GitProc::GitStatus do
90
96
  end
91
97
 
92
98
 
99
+ it "should handle a move/rename" do
100
+ FileUtils.cp __FILE__, File.join(gitprocess.workdir, 'a file.txt')
101
+ gitprocess.add('a file.txt')
102
+ gitprocess.commit('a with content')
103
+
104
+ FileUtils.cp __FILE__, File.join(gitprocess.workdir, 'b file.txt')
105
+ gitprocess.remove 'a file.txt'
106
+ gitprocess.add 'b file.txt'
107
+
108
+ status = gitprocess.status
109
+ status.deleted.should == ['a file.txt']
110
+ status.added.should == ['b file.txt']
111
+ end
112
+
113
+
93
114
  it "should return an empty result" do
94
115
  gitprocess.status.added.should == []
95
116
  gitprocess.status.deleted.should == []
data/spec/new_fb_spec.rb CHANGED
@@ -30,7 +30,7 @@ describe GitProc::NewFeatureBranch do
30
30
 
31
31
  it "should create the named branch against origin/master" do
32
32
  clone do |gp|
33
- new_branch = gp.run
33
+ new_branch = gp.runner
34
34
 
35
35
  new_branch.name.should == 'test_branch'
36
36
  new_branch.sha.should == gp.branches['origin/master'].sha
@@ -44,7 +44,7 @@ describe GitProc::NewFeatureBranch do
44
44
  change_file_and_commit('a', '')
45
45
  change_file_and_commit('b', '')
46
46
 
47
- new_branch = gitprocess.run
47
+ new_branch = gitprocess.runner
48
48
 
49
49
  new_branch.name.should == 'test_branch'
50
50
  Dir.chdir(gitprocess.workdir) do |dir|
@@ -59,7 +59,7 @@ describe GitProc::NewFeatureBranch do
59
59
  it "should use 'integration_branch' instead of 'remote_master_branch'" do
60
60
  change_file_and_commit('a', '')
61
61
 
62
- new_branch = gitprocess.run
62
+ new_branch = gitprocess.runner
63
63
 
64
64
  new_branch.name.should == 'test_branch'
65
65
  end
@@ -72,7 +72,7 @@ describe GitProc::NewFeatureBranch do
72
72
  change_file_and_add('b', '')
73
73
  change_file('c', '')
74
74
 
75
- new_branch = gitprocess.run
75
+ new_branch = gitprocess.runner
76
76
 
77
77
  new_branch.name.should == 'test_branch'
78
78
  Dir.chdir(gitprocess.workdir) do |dir|
@@ -6,6 +6,11 @@ require 'json'
6
6
  describe GitProc::RebaseToMaster do
7
7
  include GitRepoHelper
8
8
 
9
+ def log_level
10
+ Logger::ERROR
11
+ end
12
+
13
+
9
14
  before(:each) do
10
15
  create_files(['.gitignore'])
11
16
  gitprocess.commit('initial')
@@ -24,11 +29,6 @@ describe GitProc::RebaseToMaster do
24
29
 
25
30
  describe "rebase to master" do
26
31
 
27
- def log_level
28
- Logger::ERROR
29
- end
30
-
31
-
32
32
  it "should work easily for a simple rebase" do
33
33
  gitprocess.checkout('fb', :new_branch => 'master')
34
34
  change_file_and_commit('a', '')
@@ -98,61 +98,58 @@ describe GitProc::RebaseToMaster do
98
98
  gitprocess.checkout('_parking_', :new_branch => 'master')
99
99
  change_file_and_commit('a', '')
100
100
 
101
- expect {gitprocess.runner}.should raise_error GitProc::ParkedChangesError
101
+ expect {gitprocess.verify_preconditions}.should raise_error GitProc::ParkedChangesError
102
102
  end
103
103
  end
104
104
 
105
105
 
106
106
  describe "closing the pull request" do
107
107
 
108
- def log_level
109
- Logger::ERROR
110
- end
111
-
112
-
113
108
  it "should work for an existing pull request" do
109
+ stub_request(:get, /test_repo\/pulls\?access_token=/).
110
+ to_return(:status => 200, :body => JSON([{:number => 987, :state => 'open', :html_url => 'test_url', :head => {:ref => 'fb'}, :base => {:ref => 'master'}}]))
111
+ stub_request(:patch, /test_repo\/pulls\/987\?access_token=/).
112
+ with(:body => JSON({:state => 'closed'})).
113
+ to_return(:status => 200, :body => JSON([{:number => 987, :state => 'closed', :html_url => 'test_url', :head => {:ref => 'fb'}, :base => {:ref => 'master'}}]))
114
+
114
115
  gitprocess.branch('fb', :base_branch => 'master')
115
- clone('fb') do |gp|
116
- stub_request(:get, /test_repo\/pulls\?access_token=/).
117
- to_return(:status => 200, :body => JSON([{:number => 987, :state => 'open', :html_url => 'test_url', :head => {:ref => 'fb'}, :base => {:ref => 'master'}}]))
118
- stub_request(:patch, /test_repo\/pulls\/987\?access_token=/).
119
- with(:body => JSON({:state => 'closed'})).
120
- to_return(:status => 200, :body => JSON([{:number => 987, :state => 'closed', :html_url => 'test_url', :head => {:ref => 'fb'}, :base => {:ref => 'master'}}]))
121
- gp.config('gitProcess.github.authToken', 'test-token')
122
- gp.config('remote.origin.url', 'git@github.com:test_repo.git')
123
- gp.config('github.user', 'test_user')
124
- gp.stub(:fetch)
125
- gp.stub(:push)
126
-
127
- gp.runner
128
- end
116
+
117
+ gp = clone('fb')
118
+ gp.config('gitProcess.github.authToken', 'test-token')
119
+ gp.config('remote.origin.url', 'git@github.com:test_repo.git')
120
+ gp.config('github.user', 'test_user')
121
+
122
+ rtm = GitProc::RebaseToMaster.new(gp.workdir, {:log_level => log_level})
123
+ rtm.stub(:fetch)
124
+ rtm.stub(:push)
125
+ rtm.runner
129
126
  end
130
127
 
131
128
 
132
129
  it "should not try when there is no auth token" do
133
130
  gitprocess.branch('fb', :base_branch => 'master')
134
- clone('fb') do |gp|
135
- gp.config('gitProcess.github.authToken', '')
136
- gp.config('remote.origin.url', 'git@github.com:test_repo.git')
137
- gp.config('github.user', 'test_user')
138
- gp.stub(:fetch)
139
- gp.stub(:push)
140
-
141
- gp.runner
142
- end
131
+ gp = clone('fb')
132
+ gp.config('gitProcess.github.authToken', '')
133
+ gp.config('remote.origin.url', 'git@github.com:test_repo.git')
134
+ gp.config('github.user', 'test_user')
135
+
136
+ rtm = GitProc::RebaseToMaster.new(gp.workdir, {:log_level => log_level})
137
+ rtm.stub(:fetch)
138
+ rtm.stub(:push)
139
+ rtm.runner
143
140
  end
144
141
 
145
142
 
146
143
  it "should not try when there is a file:// origin url" do
147
144
  gitprocess.branch('fb', :base_branch => 'master')
148
- clone('fb') do |gp|
149
- gp.config('gitProcess.github.authToken', 'test-token')
150
- gp.config('github.user', 'test_user')
151
- gp.stub(:fetch)
152
- gp.stub(:push)
153
-
154
- gp.runner
155
- end
145
+ gp = clone('fb')
146
+ gp.config('gitProcess.github.authToken', 'test-token')
147
+ gp.config('github.user', 'test_user')
148
+
149
+ rtm = GitProc::RebaseToMaster.new(gp.workdir, {:log_level => log_level})
150
+ rtm.stub(:fetch)
151
+ rtm.stub(:push)
152
+ rtm.runner
156
153
  end
157
154
 
158
155
  end
@@ -162,41 +159,35 @@ describe GitProc::RebaseToMaster do
162
159
 
163
160
  describe "custom integration branch" do
164
161
 
165
- def log_level
166
- Logger::ERROR
167
- end
162
+ it "should use the 'gitProcess.integrationBranch' configuration" do
163
+ gitprocess.checkout('int-br', :new_branch => 'master')
164
+ change_file_and_commit('a', '')
168
165
 
166
+ gitprocess.checkout('fb', :new_branch => 'master')
167
+ change_file_and_commit('b', '')
169
168
 
170
- it "should use the 'gitProcess.integrationBranch' configuration" do
171
- gitprocess.checkout('int-br', :new_branch => 'master') do
172
- change_file_and_commit('a', '')
173
- end
174
- gitprocess.checkout('fb', :new_branch => 'master') do
175
- change_file_and_commit('b', '')
176
- end
177
- gitprocess.branches['master'].delete
169
+ gitprocess.branches['master'].delete!
178
170
 
179
- clone('int-br') do |gl|
180
- gl.config('gitProcess.integrationBranch', 'int-br')
171
+ gl = clone('int-br')
172
+ gl.config('gitProcess.integrationBranch', 'int-br')
181
173
 
182
- gl.checkout('ab', :new_branch => 'origin/int-br')
174
+ gl.checkout('ab', :new_branch => 'origin/int-br')
183
175
 
184
- branches = gl.branches
185
- branches.include?('origin/master').should be_false
186
- branches['ab'].sha.should == branches['origin/int-br'].sha
176
+ my_branches = gl.branches
177
+ my_branches.include?('origin/master').should be_false
178
+ my_branches['ab'].sha.should == my_branches['origin/int-br'].sha
187
179
 
188
- gl.stub(:repo_name).and_return('test_repo')
180
+ gl.stub(:repo_name).and_return('test_repo')
189
181
 
190
- change_file_and_commit('c', '', gl)
182
+ change_file_and_commit('c', '', gl)
191
183
 
192
- branches = gl.branches
193
- branches['ab'].sha.should_not == branches['origin/int-br'].sha
184
+ my_branches = gl.branches
185
+ my_branches['ab'].sha.should_not == my_branches['origin/int-br'].sha
194
186
 
195
- gl.run
187
+ GitProc::RebaseToMaster.new(gl.workdir, {:log_level => log_level}).runner
196
188
 
197
- branches = gl.branches
198
- branches['HEAD'].sha.should == branches['origin/int-br'].sha
199
- end
189
+ my_branches = gl.branches
190
+ my_branches['HEAD'].sha.should == my_branches['origin/int-br'].sha
200
191
  end
201
192
 
202
193
  end
@@ -204,11 +195,6 @@ describe GitProc::RebaseToMaster do
204
195
 
205
196
  describe "remove current feature branch" do
206
197
 
207
- def log_level
208
- Logger::ERROR
209
- end
210
-
211
-
212
198
  describe "when handling the parking branch" do
213
199
 
214
200
  it "should create it based on origin/master" do