git-process 0.9.5 → 0.9.6

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.
@@ -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