scrumninja-git-cli 0.0.2
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.
- data/.document +5 -0
- data/.gitignore +21 -0
- data/LICENSE +20 -0
- data/README.rdoc +17 -0
- data/Rakefile +57 -0
- data/VERSION +1 -0
- data/bin/scrumninja-git-cli +3 -0
- data/lib/git_wrapper.rb +164 -0
- data/lib/scrum_ninja.rb +2 -0
- data/lib/scrum_ninja/server.rb +34 -0
- data/lib/scrum_ninja/session.rb +87 -0
- data/lib/scrum_ninja/story.rb +25 -0
- data/lib/scrum_ninja_git_cli.rb +187 -0
- data/lib/shell_cmd.rb +16 -0
- data/test/helper.rb +14 -0
- data/test/scrum_ninja/test_scrum_ninja_server.rb +42 -0
- data/test/scrum_ninja/test_scrum_ninja_session.rb +163 -0
- data/test/scrum_ninja/test_scrum_ninja_story.rb +31 -0
- data/test/test_git_wrapper.rb +375 -0
- data/test/test_scrum_ninja_git_cli.rb +224 -0
- metadata +156 -0
@@ -0,0 +1,375 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), 'helper'))
|
2
|
+
require "git_wrapper"
|
3
|
+
|
4
|
+
class GitWrapperUnitTest < Test::Unit::TestCase
|
5
|
+
|
6
|
+
def branch(name)
|
7
|
+
stub('Grit::Head', :name => name)
|
8
|
+
end
|
9
|
+
def remote(name)
|
10
|
+
stub('Grit::Remote', :name => name)
|
11
|
+
end
|
12
|
+
|
13
|
+
def setup
|
14
|
+
# Holler if we ever inadvertently try to run a git command
|
15
|
+
GitWrapper.expects(:run_git).never
|
16
|
+
end
|
17
|
+
|
18
|
+
def expect_git_command(command, interactive=false)
|
19
|
+
if interactive
|
20
|
+
GitWrapper.expects(:run_git).with(command, true)
|
21
|
+
else
|
22
|
+
GitWrapper.expects(:run_git).with(command)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
context "#locate_git_repo_root" do
|
27
|
+
context "ENV['PWD'] is the root of a git repo" do
|
28
|
+
should 'return ENV["PWD"]' do
|
29
|
+
pwd = '/some/path/somedir'
|
30
|
+
dir = stub(:entries => %w(. .. .git foo))
|
31
|
+
Dir.expects(:new).with(pwd).returns(dir)
|
32
|
+
ENV.expects(:[]).with('PWD').returns(pwd)
|
33
|
+
assert_equal pwd, GitWrapper.locate_git_repo_root
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
context "ENV['PWD'] is a (grand)child directory of a git repo" do
|
38
|
+
should 'return first parent of ENV["PWD"] that contains a .git directory' do
|
39
|
+
repo_path = '/some/path/repo'
|
40
|
+
pwd = "#{repo_path}/child/grandchild"
|
41
|
+
ENV.expects(:[]).with('PWD').returns(pwd)
|
42
|
+
normal_dir = stub(:entries => %w(. .. foo))
|
43
|
+
repo_dir = stub(:entries => %w(. .. .git foo))
|
44
|
+
Dir.stubs(:new => normal_dir)
|
45
|
+
Dir.expects(:new).with(repo_path).returns(repo_dir)
|
46
|
+
assert_equal repo_path, GitWrapper.locate_git_repo_root
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
context "ENV['PWD'] is not part of a git repo" do
|
51
|
+
should 'return nil' do
|
52
|
+
pwd = "/some/dir/child/grandchild"
|
53
|
+
ENV.expects(:[]).with('PWD').returns(pwd)
|
54
|
+
dir = stub(:entries => %w(. .. foo))
|
55
|
+
Dir.stubs(:new => dir)
|
56
|
+
assert_nil GitWrapper.locate_git_repo_root
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
context "git_version" do
|
62
|
+
should 'use run_git to get the version and return the correct version and memoize the answer' do
|
63
|
+
GitWrapper.expects(:run_git).with('--version').returns('git version 1.7.0.2')
|
64
|
+
assert_equal [1,7,0,2], GitWrapper.git_version
|
65
|
+
assert_equal [1,7,0,2], GitWrapper.git_version
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
context "is_git_current_enough?" do
|
70
|
+
should "be false if version is < 1.7" do
|
71
|
+
GitWrapper.stubs(:git_version).returns([1,6,9])
|
72
|
+
deny GitWrapper.is_git_current_enough?
|
73
|
+
end
|
74
|
+
|
75
|
+
should "be true if version is = 1.7" do
|
76
|
+
GitWrapper.stubs(:git_version).returns([1,7])
|
77
|
+
assert GitWrapper.is_git_current_enough?
|
78
|
+
end
|
79
|
+
|
80
|
+
should "be true if version is = 1.7 with extra version info" do
|
81
|
+
GitWrapper.stubs(:git_version).returns([1,7,0])
|
82
|
+
assert GitWrapper.is_git_current_enough?
|
83
|
+
end
|
84
|
+
|
85
|
+
should "be true if version is > 1.7" do
|
86
|
+
GitWrapper.stubs(:git_version).returns([1,7,1])
|
87
|
+
assert GitWrapper.is_git_current_enough?
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
91
|
+
|
92
|
+
|
93
|
+
should "return current_branch_name" do
|
94
|
+
current_branch = stub('Grit::Head', :name => 'this-branch-right-here-yall')
|
95
|
+
GitWrapper.git.expects(:head).returns(current_branch)
|
96
|
+
assert_equal('this-branch-right-here-yall', GitWrapper.current_branch_name)
|
97
|
+
end
|
98
|
+
|
99
|
+
context "branches" do
|
100
|
+
should "return a list of local branches when called with no arguments" do
|
101
|
+
locals = [branch('master'), branch('hackery')]
|
102
|
+
GitWrapper.git.expects(:branches).returns(locals)
|
103
|
+
assert_equal(locals, GitWrapper.branches)
|
104
|
+
end
|
105
|
+
|
106
|
+
should "return a list of remote branches when called with a remote name as the first argument" do
|
107
|
+
remotes = [
|
108
|
+
remote('origin/master'),
|
109
|
+
remote('origin/some-topical-branch'),
|
110
|
+
remote('github/foo')
|
111
|
+
]
|
112
|
+
remotes_on_origin = remotes[0,2]
|
113
|
+
GitWrapper.git.expects(:remotes).returns(remotes)
|
114
|
+
assert_equal(remotes_on_origin, GitWrapper.branches('origin'))
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
should "track_remote_branch" do
|
119
|
+
expect_git_command 'branch --set-upstream my-story origin/my-story'
|
120
|
+
GitWrapper.track_remote_branch('my-story')
|
121
|
+
end
|
122
|
+
|
123
|
+
should "publish_remote_branch" do
|
124
|
+
expect_git_command 'push origin my-story:refs/heads/my-story'
|
125
|
+
GitWrapper.publish_remote_branch('my-story')
|
126
|
+
end
|
127
|
+
|
128
|
+
context "fetch" do
|
129
|
+
should "grab a specified remote" do
|
130
|
+
expect_git_command 'fetch my_crazy_remote'
|
131
|
+
GitWrapper.fetch('my_crazy_remote')
|
132
|
+
end
|
133
|
+
should "grab 'origin' with no parameters" do
|
134
|
+
expect_git_command 'fetch origin'
|
135
|
+
GitWrapper.fetch
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
context "checkout" do
|
140
|
+
should 'fetch' do
|
141
|
+
expect_git_command 'fetch origin'
|
142
|
+
expect_git_command 'branch my-story'
|
143
|
+
expect_git_command 'push origin my-story:refs/heads/my-story'
|
144
|
+
expect_git_command 'branch --set-upstream my-story origin/my-story'
|
145
|
+
expect_git_command 'checkout my-story'
|
146
|
+
|
147
|
+
GitWrapper.checkout('my-story')
|
148
|
+
end
|
149
|
+
|
150
|
+
should "take an optional 'remote' parameter" do
|
151
|
+
expect_git_command 'fetch nonstandard_remote'
|
152
|
+
expect_git_command 'branch my-story'
|
153
|
+
expect_git_command 'push nonstandard_remote my-story:refs/heads/my-story'
|
154
|
+
expect_git_command 'branch --set-upstream my-story nonstandard_remote/my-story'
|
155
|
+
expect_git_command 'checkout my-story'
|
156
|
+
|
157
|
+
GitWrapper.checkout('my-story', 'nonstandard_remote')
|
158
|
+
end
|
159
|
+
|
160
|
+
context "when remote branch 'my-story' does not exist" do
|
161
|
+
setup do
|
162
|
+
@branches, @remotes = [branch('master')], []
|
163
|
+
GitWrapper.git.stubs(:branches).returns(@branches)
|
164
|
+
GitWrapper.git.stubs(:remotes).returns(@remotes)
|
165
|
+
end
|
166
|
+
|
167
|
+
should "create local 'my-story' branch, check it out, publish it, and track it" do
|
168
|
+
expect_git_command 'fetch origin'
|
169
|
+
expect_git_command 'branch local-story-branch'
|
170
|
+
expect_git_command 'push origin local-story-branch:refs/heads/local-story-branch'
|
171
|
+
expect_git_command 'branch --set-upstream local-story-branch origin/local-story-branch'
|
172
|
+
expect_git_command 'checkout local-story-branch'
|
173
|
+
|
174
|
+
GitWrapper.checkout('local-story-branch')
|
175
|
+
end
|
176
|
+
|
177
|
+
context "and local branch 'my-story' exists" do
|
178
|
+
setup do
|
179
|
+
@branches << branch('my-story')
|
180
|
+
end
|
181
|
+
should "check out the remote branch and track it" do
|
182
|
+
expect_git_command 'fetch origin'
|
183
|
+
expect_git_command 'push origin my-story:refs/heads/my-story'
|
184
|
+
expect_git_command 'branch --set-upstream my-story origin/my-story'
|
185
|
+
expect_git_command 'checkout my-story'
|
186
|
+
|
187
|
+
GitWrapper.checkout('my-story')
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
context "when remote branch 'my-story' exists" do
|
193
|
+
setup do
|
194
|
+
@branches, @remotes = [branch('master')], [remote('origin/my-story')]
|
195
|
+
GitWrapper.git.stubs(:branches).returns(@branches)
|
196
|
+
GitWrapper.git.stubs(:remotes).returns(@remotes)
|
197
|
+
end
|
198
|
+
|
199
|
+
should "create local 'my-story' branch, make it track the remote branch, and check it out" do
|
200
|
+
expect_git_command 'fetch origin'
|
201
|
+
expect_git_command 'branch my-story'
|
202
|
+
expect_git_command 'branch --set-upstream my-story origin/my-story'
|
203
|
+
expect_git_command 'checkout my-story'
|
204
|
+
|
205
|
+
GitWrapper.checkout('my-story')
|
206
|
+
end
|
207
|
+
|
208
|
+
context "when local branch 'my-story' exists" do
|
209
|
+
setup do
|
210
|
+
@branches << branch('my-story')
|
211
|
+
end
|
212
|
+
should "make it track the remote branch, and check it out" do
|
213
|
+
expect_git_command 'fetch origin'
|
214
|
+
expect_git_command 'branch --set-upstream my-story origin/my-story'
|
215
|
+
expect_git_command 'checkout my-story'
|
216
|
+
|
217
|
+
GitWrapper.checkout('my-story')
|
218
|
+
end
|
219
|
+
end
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
context "#is_state_clean?" do
|
224
|
+
should "be true when it is" do
|
225
|
+
expect_git_command('status').returns <<-EOF
|
226
|
+
# On branch master
|
227
|
+
nothing to commit (working directory clean)
|
228
|
+
EOF
|
229
|
+
assert GitWrapper.is_state_clean?
|
230
|
+
end
|
231
|
+
|
232
|
+
context "unclean" do
|
233
|
+
should 'be false when there are unstaged changes' do
|
234
|
+
expect_git_command('status').returns <<-EOF
|
235
|
+
# On branch master
|
236
|
+
# Untracked files:
|
237
|
+
# (use "git add <file>..." to include in what will be committed)
|
238
|
+
#
|
239
|
+
# newfile
|
240
|
+
nothing added to commit but untracked files present (use "git add" to track)
|
241
|
+
EOF
|
242
|
+
deny GitWrapper.is_state_clean?
|
243
|
+
end
|
244
|
+
should 'be false when there are staged changes' do
|
245
|
+
expect_git_command('status').returns <<-EOF
|
246
|
+
# On branch master
|
247
|
+
# Changes to be committed:
|
248
|
+
# (use "git reset HEAD <file>..." to unstage)
|
249
|
+
#
|
250
|
+
# new file: newfile
|
251
|
+
#
|
252
|
+
EOF
|
253
|
+
deny GitWrapper.is_state_clean?
|
254
|
+
end
|
255
|
+
|
256
|
+
should 'be false when tehre are both staged and unstaged changes' do
|
257
|
+
expect_git_command('status').returns <<-EOF
|
258
|
+
# On branch master
|
259
|
+
# Changes to be committed:
|
260
|
+
# (use "git reset HEAD <file>..." to unstage)
|
261
|
+
#
|
262
|
+
# new file: somethingelse
|
263
|
+
#
|
264
|
+
# Changed but not updated:
|
265
|
+
# (use "git add <file>..." to update what will be committed)
|
266
|
+
# (use "git checkout -- <file>..." to discard changes in working directory)
|
267
|
+
#
|
268
|
+
# modified: newfile
|
269
|
+
#
|
270
|
+
# Untracked files:
|
271
|
+
# (use "git add <file>..." to include in what will be committed)
|
272
|
+
#
|
273
|
+
# something
|
274
|
+
EOF
|
275
|
+
deny GitWrapper.is_state_clean?
|
276
|
+
end
|
277
|
+
end
|
278
|
+
end
|
279
|
+
|
280
|
+
context "require_clean_story_branch" do
|
281
|
+
should "complain if working state is not clean" do
|
282
|
+
GitWrapper.expects(:is_state_clean?).returns(false)
|
283
|
+
GitWrapper.stubs(:current_branch_name).returns('master')
|
284
|
+
assert_raise(GitWrapper::WorkingFolderDirtyException) { GitWrapper.require_clean_story_branch }
|
285
|
+
end
|
286
|
+
|
287
|
+
should "complain if already on master" do
|
288
|
+
GitWrapper.stubs(:is_state_clean?).returns(true)
|
289
|
+
GitWrapper.expects(:current_branch_name).returns('master')
|
290
|
+
assert_raise(GitWrapper::WrongBranchException) { GitWrapper.require_clean_story_branch }
|
291
|
+
end
|
292
|
+
end
|
293
|
+
|
294
|
+
context "merge_from_master" do
|
295
|
+
should 'do a checkout of master, a pull, a checkout of the local branch, and a merge' do
|
296
|
+
GitWrapper.expects(:require_clean_story_branch)
|
297
|
+
GitWrapper.stubs(:current_branch_name).returns('99-bottles')
|
298
|
+
expect_git_command 'checkout master'
|
299
|
+
expect_git_command 'pull'
|
300
|
+
expect_git_command 'checkout 99-bottles'
|
301
|
+
expect_git_command 'merge master'
|
302
|
+
GitWrapper.merge_from_master
|
303
|
+
end
|
304
|
+
end
|
305
|
+
|
306
|
+
context "push_branch" do
|
307
|
+
should "do a pull/rebase, then a push" do
|
308
|
+
GitWrapper.expects(:require_clean_story_branch)
|
309
|
+
GitWrapper.stubs(:current_branch_name).returns('321-contact')
|
310
|
+
expect_git_command 'pull --rebase'
|
311
|
+
expect_git_command 'push origin 321-contact'
|
312
|
+
GitWrapper.push_branch
|
313
|
+
end
|
314
|
+
end
|
315
|
+
|
316
|
+
context 'merge_branch_into_master' do
|
317
|
+
should "do a checkout of master, a pull, and merge the story branch in" do
|
318
|
+
GitWrapper.expects(:require_clean_story_branch)
|
319
|
+
GitWrapper.stubs(:current_branch_name).returns('99-bottles')
|
320
|
+
expect_git_command 'checkout master'
|
321
|
+
expect_git_command 'pull'
|
322
|
+
expect_git_command 'merge 99-bottles'
|
323
|
+
GitWrapper.merge_branch_into_master
|
324
|
+
end
|
325
|
+
|
326
|
+
should 'accept a branch name, if called while on master' do
|
327
|
+
GitWrapper.expects(:require_clean_master_branch)
|
328
|
+
expect_git_command 'pull'
|
329
|
+
expect_git_command 'merge 99-bottles'
|
330
|
+
GitWrapper.merge_branch_into_master('99-bottles')
|
331
|
+
end
|
332
|
+
|
333
|
+
# To consider:
|
334
|
+
# should 'prefix the commit message with "Story #{nnn}: #{story name}"'
|
335
|
+
end
|
336
|
+
|
337
|
+
context 'require_clean_master_branch' do
|
338
|
+
context "require_clean_story_branch" do
|
339
|
+
should "complain if working state is not clean" do
|
340
|
+
GitWrapper.expects(:is_state_clean?).returns(false)
|
341
|
+
GitWrapper.stubs(:current_branch_name).returns('master')
|
342
|
+
assert_raise(GitWrapper::WorkingFolderDirtyException) { GitWrapper.require_clean_master_branch }
|
343
|
+
end
|
344
|
+
|
345
|
+
should "complain if not on master" do
|
346
|
+
GitWrapper.stubs(:is_state_clean?).returns(true)
|
347
|
+
GitWrapper.expects(:current_branch_name).returns('not_master')
|
348
|
+
assert_raise(GitWrapper::WrongBranchException) { GitWrapper.require_clean_master_branch }
|
349
|
+
end
|
350
|
+
end
|
351
|
+
end
|
352
|
+
|
353
|
+
context 'push_master' do
|
354
|
+
should "do a pull/rebase, then a push" do
|
355
|
+
GitWrapper.expects(:require_clean_master_branch)
|
356
|
+
expect_git_command 'pull --rebase'
|
357
|
+
expect_git_command 'push origin master'
|
358
|
+
GitWrapper.push_master
|
359
|
+
end
|
360
|
+
end
|
361
|
+
|
362
|
+
context "#add" do
|
363
|
+
should "add the specified paths to the index" do
|
364
|
+
expect_git_command 'add -A foo bar'
|
365
|
+
GitWrapper.add('-A foo bar')
|
366
|
+
end
|
367
|
+
end
|
368
|
+
|
369
|
+
context "#commit" do
|
370
|
+
should "commit changes with story number prepended to commit message" do
|
371
|
+
expect_git_command 'commit -m "Story 12345: " -e', true
|
372
|
+
GitWrapper.commit("Story 12345: ")
|
373
|
+
end
|
374
|
+
end
|
375
|
+
end
|
@@ -0,0 +1,224 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), 'helper'))
|
2
|
+
require 'scrum_ninja_git_cli'
|
3
|
+
|
4
|
+
class TestScrumNinjaGitCli < Test::Unit::TestCase
|
5
|
+
def story(project_id, name)
|
6
|
+
ScrumNinja::Story.new("Story", project_id, name)
|
7
|
+
end
|
8
|
+
|
9
|
+
def setup
|
10
|
+
@git = mock('git')
|
11
|
+
@git.stubs(:is_git_current_enough?).returns(true)
|
12
|
+
ScrumNinjaGitCli.stubs(:git_wrapper).returns(@git)
|
13
|
+
@session = mock('session')
|
14
|
+
ScrumNinjaGitCli.stubs(:session).returns(@session)
|
15
|
+
GitWrapper.expects(:run_command).never
|
16
|
+
end
|
17
|
+
|
18
|
+
def expect_output(message_name)
|
19
|
+
message = ScrumNinjaGitCli::Messages[message_name]
|
20
|
+
ScrumNinjaGitCli.expects(:output).with(message).returns(true)
|
21
|
+
end
|
22
|
+
|
23
|
+
context "help" do
|
24
|
+
should "output ScrumNinjaGitCli::HelpText" do
|
25
|
+
ScrumNinjaGitCli.expects(:output).with(ScrumNinjaGitCli::HelpText)
|
26
|
+
ScrumNinjaGitCli.help
|
27
|
+
end
|
28
|
+
|
29
|
+
should 'be displayed when the utility is run with no args' do
|
30
|
+
ScrumNinjaGitCli.expects(:help)
|
31
|
+
ScrumNinjaGitCli.run_command
|
32
|
+
end
|
33
|
+
|
34
|
+
should 'be run when a run_command gets an ArgumentError' do
|
35
|
+
ScrumNinjaGitCli.expects(:help)
|
36
|
+
ScrumNinjaGitCli.run_command(:start)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
context "info" do
|
41
|
+
should "make an API call and return a single Story object" do
|
42
|
+
the_story = story(99, "mmm... something...")
|
43
|
+
@session.expects(:get_story).with(99).returns(the_story)
|
44
|
+
ScrumNinjaGitCli.expects(:output).with(the_story)
|
45
|
+
ScrumNinjaGitCli.run_command(:info, 99)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
context "xml" do
|
50
|
+
should "make an API call and return the raw XML" do
|
51
|
+
xml = "<xml>bogus XML</xml>"
|
52
|
+
@session.expects(:get_story_xml).with(99).returns(xml)
|
53
|
+
ScrumNinjaGitCli.expects(:output).with(xml)
|
54
|
+
ScrumNinjaGitCli.run_command(:xml, 99)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
context 'list' do
|
59
|
+
should 'display a list of stories from ScrumNinja' do
|
60
|
+
stories = [story(999, "Do stuff"), story(42, "do something else")]
|
61
|
+
@session.expects(:get_stories).returns(stories)
|
62
|
+
ScrumNinjaGitCli.expects(:output).with(stories.map(&:to_s).join("\n"))
|
63
|
+
ScrumNinjaGitCli.run_command(:list)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
context "own" do
|
68
|
+
should "update the owner of the given story" do
|
69
|
+
@session.expects(:update_ownership).with(42, nil, {})
|
70
|
+
ScrumNinjaGitCli.run_command(:own, 42)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
context "start" do
|
75
|
+
should "join and own (nicely)" do
|
76
|
+
ScrumNinjaGitCli.expects(:join).with(42)
|
77
|
+
ScrumNinjaGitCli.expects(:own).with(42, nil, :abort_if_already_owned => true)
|
78
|
+
ScrumNinjaGitCli.run_command(:start, 42)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
context "dev-task" do
|
83
|
+
should 'start work on a branch named "dev-hyphenated-story-name"' do
|
84
|
+
ScrumNinjaGitCli.expects(:start_work_on_branch).with('dev-hyphenated-story-name')
|
85
|
+
ScrumNinjaGitCli.run_command(:dev_task, 'hyphenated STORY _nAmE')
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
|
90
|
+
context "rake" do
|
91
|
+
should "run rake" do
|
92
|
+
ShellCmd.expects(:run).with('rake').returns(0)
|
93
|
+
assert ScrumNinjaGitCli.rake
|
94
|
+
end
|
95
|
+
|
96
|
+
should 'print a message and return false in the event of a rake failure' do
|
97
|
+
ShellCmd.expects(:run).with('rake').returns(256)
|
98
|
+
expect_output :rake_failure
|
99
|
+
deny ScrumNinjaGitCli.rake
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
context "#commit" do
|
104
|
+
should "commit pending changes and add story number to commit message" do
|
105
|
+
@git.stubs(:current_branch_name).returns('12345-some-story-name')
|
106
|
+
@git.expects(:commit).with("Story 12345: Some Story Name")
|
107
|
+
ScrumNinjaGitCli.run_command(:commit)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
context "#add" do
|
112
|
+
should "add the specified paths to git" do
|
113
|
+
@git.expects(:add).with("foo bar baz")
|
114
|
+
ScrumNinjaGitCli.run_command(:add, 'foo bar baz')
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
context "deliver" do
|
119
|
+
actions = [
|
120
|
+
"push-branch",
|
121
|
+
"merge-from-master",
|
122
|
+
"rake",
|
123
|
+
"merge back into master",
|
124
|
+
"check out master and push it", # can't reuse GitWrapper#push_branch for this, though
|
125
|
+
]
|
126
|
+
should actions.join('; ') do
|
127
|
+
@git.stubs(:current_branch_name).returns('not_master')
|
128
|
+
@git.expects(:push_branch)
|
129
|
+
@git.expects(:merge_from_master)
|
130
|
+
ScrumNinjaGitCli.expects(:rake).returns(true)
|
131
|
+
@git.expects(:merge_branch_into_master)
|
132
|
+
@git.expects(:push_master)
|
133
|
+
ScrumNinjaGitCli.run_command(:deliver)
|
134
|
+
end
|
135
|
+
|
136
|
+
should 'not squash nor push master if rake fails' do
|
137
|
+
@git.stubs(:current_branch_name).returns('not_master')
|
138
|
+
@git.expects(:push_branch)
|
139
|
+
@git.expects(:merge_from_master)
|
140
|
+
ScrumNinjaGitCli.expects(:rake).returns(false)
|
141
|
+
ScrumNinjaGitCli.run_command(:deliver)
|
142
|
+
end
|
143
|
+
|
144
|
+
should 'not run if the current branch is master' do
|
145
|
+
@git.expects(:current_branch_name).returns('master')
|
146
|
+
expect_output(:wrong_branch)
|
147
|
+
ScrumNinjaGitCli.run_command(:deliver)
|
148
|
+
end
|
149
|
+
|
150
|
+
should_eventually "complain if any of the commit messages to be merged in don't have a story number prefix" do
|
151
|
+
# yeah, this'll be easy to mock...
|
152
|
+
flunk
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
context "join" do
|
157
|
+
setup do
|
158
|
+
@story = story(99, "bottles of beer")
|
159
|
+
@session.stubs(:get_story).returns(@story)
|
160
|
+
end
|
161
|
+
|
162
|
+
should "inform the user that Git 1.7 or newer is required" do
|
163
|
+
@git.expects(:is_git_current_enough?).returns(false)
|
164
|
+
expect_output :git_version
|
165
|
+
ScrumNinjaGitCli.run_command(:join, 99)
|
166
|
+
end
|
167
|
+
|
168
|
+
should "call #own, git fetch, and git checkout" do
|
169
|
+
@git.expects(:checkout).with(@story.branch_name)
|
170
|
+
@git.stubs(:is_state_clean?).returns(true)
|
171
|
+
@git.stubs(:current_branch_name).returns('master')
|
172
|
+
ScrumNinjaGitCli.run_command(:join, 99)
|
173
|
+
end
|
174
|
+
|
175
|
+
should 'give a nice warning message and/or error if the working state is not clean' do
|
176
|
+
@session.expects(:get_story).never
|
177
|
+
@git.expects(:is_state_clean?).returns(false)
|
178
|
+
@git.stubs(:current_branch_name).returns('master')
|
179
|
+
expect_output :clean_working_state
|
180
|
+
ScrumNinjaGitCli.run_command(:join, 99)
|
181
|
+
end
|
182
|
+
|
183
|
+
should 'give a nice warning message and/or error if the current branch is not master' do
|
184
|
+
@session.expects(:get_story).never
|
185
|
+
@git.stubs(:is_state_clean?).returns(true)
|
186
|
+
@git.stubs(:current_branch_name).returns('not-at-all-master')
|
187
|
+
expect_output :must_be_on_master
|
188
|
+
ScrumNinjaGitCli.run_command(:join, 99)
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
context "push-branch" do
|
193
|
+
should "call GitWrapper#push_branch" do
|
194
|
+
@git.expects(:push_branch)
|
195
|
+
ScrumNinjaGitCli.run_command('push-branch')
|
196
|
+
end
|
197
|
+
|
198
|
+
should "handle raised exceptions" do
|
199
|
+
@git.expects(:push_branch).raises(GitWrapper::WorkingFolderDirtyException)
|
200
|
+
expect_output :clean_working_state
|
201
|
+
assert_nothing_raised(Exception) { ScrumNinjaGitCli.run_command('push-branch') }
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
context "merge-from-master" do
|
206
|
+
should "call GitWrapper#push_branch" do
|
207
|
+
@git.expects(:merge_from_master)
|
208
|
+
ScrumNinjaGitCli.run_command('merge-from-master')
|
209
|
+
end
|
210
|
+
|
211
|
+
should "handle raised exceptions" do
|
212
|
+
@git.expects(:merge_from_master).raises(GitWrapper::WrongBranchException)
|
213
|
+
expect_output :wrong_branch
|
214
|
+
assert_nothing_raised(Exception) { ScrumNinjaGitCli.run_command('merge-from-master') }
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
context "#git" do
|
219
|
+
should "run git command with passed-through arguments" do
|
220
|
+
ScrumNinjaGitCli.expects(:exec).with("export I_AM_A_GIT_GURU=1; git arg1 arg2 arg3").returns('some output')
|
221
|
+
ScrumNinjaGitCli.run_command('git', 'arg1', 'arg2', 'arg3')
|
222
|
+
end
|
223
|
+
end
|
224
|
+
end
|