hub 1.6.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of hub might be problematic. Click here for more details.

@@ -0,0 +1,41 @@
1
+ $LOAD_PATH.unshift File.dirname(__FILE__)
2
+ require 'helper'
3
+
4
+ class AliasTest < Test::Unit::TestCase
5
+ def test_alias
6
+ instructions = hub("alias")
7
+ assert_includes "bash", instructions
8
+ assert_includes "sh", instructions
9
+ assert_includes "csh", instructions
10
+ assert_includes "zsh", instructions
11
+ assert_includes "fish", instructions
12
+ end
13
+
14
+ def test_alias_silent
15
+ assert_equal "alias git=hub\n", hub("alias -s bash")
16
+ end
17
+
18
+ def test_alias_bash
19
+ assert_alias_command "bash", "alias git=hub"
20
+ end
21
+
22
+ def test_alias_sh
23
+ assert_alias_command "sh", "alias git=hub"
24
+ end
25
+
26
+ def test_alias_zsh
27
+ assert_alias_command "zsh", 'function git(){hub "$@"}'
28
+ end
29
+
30
+ def test_alias_csh
31
+ assert_alias_command "csh", "alias git hub"
32
+ end
33
+
34
+ def test_alias_fish
35
+ assert_alias_command "fish", "alias git hub"
36
+ end
37
+
38
+ def test_alias_blah
39
+ assert_alias_command "blah", "fatal: never heard of `blah'"
40
+ end
41
+ end
data/test/deps.rip ADDED
@@ -0,0 +1 @@
1
+ webmock 1.3.0
data/test/fakebin/git ADDED
@@ -0,0 +1,11 @@
1
+ #!/bin/sh
2
+ if [ "$1" = "--version" ]; then
3
+ echo "git version 1.7.0.4"
4
+ elif [ "$1" = "--exec-path" ]; then
5
+ echo "/usr/lib/git-core"
6
+ elif [ "$1" = "--html-path" ]; then
7
+ echo "/usr/share/doc/git-doc"
8
+ else
9
+ echo "ERROR: git was called, but wasn't supposed to:" git $*
10
+ exit 1
11
+ fi
data/test/fakebin/open ADDED
@@ -0,0 +1,3 @@
1
+ #!/bin/sh
2
+ echo "ERROR: open was called, but wasn't supposed to:" open $*
3
+ exit 1
data/test/helper.rb ADDED
@@ -0,0 +1,111 @@
1
+ require 'test/unit'
2
+
3
+ begin
4
+ require 'redgreen'
5
+ rescue LoadError
6
+ end
7
+
8
+ $LOAD_PATH.unshift File.dirname(__FILE__) + '/../lib'
9
+ require 'hub'
10
+ require 'hub/standalone'
11
+
12
+ # We're looking for `open` in the tests.
13
+ ENV['BROWSER'] = 'open'
14
+
15
+ # Setup path with fake executables in case a test hits them
16
+ fakebin_dir = File.expand_path('../fakebin', __FILE__)
17
+ ENV['PATH'] = "#{fakebin_dir}:#{ENV['PATH']}"
18
+
19
+ class Test::Unit::TestCase
20
+ # Shortcut for creating a `Hub` instance. Pass it what you would
21
+ # normally pass `hub` on the command line, e.g.
22
+ #
23
+ # shell: hub clone rtomayko/tilt
24
+ # test: Hub("clone rtomayko/tilt")
25
+ def Hub(args)
26
+ Hub::Runner.new(*args.split(' '))
27
+ end
28
+
29
+ # Shortcut for running the `hub` command in a subprocess. Returns
30
+ # STDOUT as a string. Pass it what you would normally pass `hub` on
31
+ # the command line, e.g.
32
+ #
33
+ # shell: hub clone rtomayko/tilt
34
+ # test: hub("clone rtomayko/tilt")
35
+ #
36
+ # If a block is given it will be run in the child process before
37
+ # execution begins. You can use this to monkeypatch or fudge the
38
+ # environment before running hub.
39
+ def hub(args, input = nil)
40
+ parent_read, child_write = IO.pipe
41
+ child_read, parent_write = IO.pipe if input
42
+
43
+ fork do
44
+ yield if block_given?
45
+ $stdin.reopen(child_read) if input
46
+ $stdout.reopen(child_write)
47
+ $stderr.reopen(child_write)
48
+ Hub(args).execute
49
+ end
50
+
51
+ if input
52
+ parent_write.write input
53
+ parent_write.close
54
+ end
55
+ child_write.close
56
+ parent_read.read
57
+ end
58
+
59
+ # Asserts that `hub` will run a specific git command based on
60
+ # certain input.
61
+ #
62
+ # e.g.
63
+ # assert_command "clone git/hub", "git clone git://github.com/git/hub.git"
64
+ #
65
+ # Here we are saying that this:
66
+ # $ hub clone git/hub
67
+ # Should in turn execute this:
68
+ # $ git clone git://github.com/git/hub.git
69
+ def assert_command(input, expected)
70
+ assert_equal expected, Hub(input).command, "$ git #{input}"
71
+ end
72
+
73
+ def assert_commands(*expected)
74
+ input = expected.pop
75
+ assert_equal expected, Hub(input).commands
76
+ end
77
+
78
+ # Asserts that the command will be forwarded to git without changes
79
+ def assert_forwarded(input)
80
+ cmd = Hub(input)
81
+ assert !cmd.args.changed?, "arguments were not supposed to change: #{cmd.args.inspect}"
82
+ end
83
+
84
+ # Asserts that `hub` will show a specific alias command for a
85
+ # specific shell.
86
+ #
87
+ # e.g.
88
+ # assert_alias_command "sh", "alias git=hub"
89
+ #
90
+ # Here we are saying that this:
91
+ # $ hub alias sh
92
+ # Should display this:
93
+ # Run this in your shell to start using `hub` as `git`:
94
+ # alias git=hub
95
+ def assert_alias_command(shell, command)
96
+ expected = "Run this in your shell to start using `hub` as `git`:\n %s\n"
97
+ assert_equal(expected % command, hub("alias #{shell}"))
98
+ end
99
+
100
+ # Asserts that `haystack` includes `needle`.
101
+ def assert_includes(needle, haystack)
102
+ assert haystack.include?(needle),
103
+ "expected #{needle.inspect} in #{haystack.inspect}"
104
+ end
105
+
106
+ # Asserts that `haystack` does not include `needle`.
107
+ def assert_not_includes(needle, haystack)
108
+ assert !haystack.include?(needle),
109
+ "didn't expect #{needle.inspect} in #{haystack.inspect}"
110
+ end
111
+ end
data/test/hub_test.rb ADDED
@@ -0,0 +1,847 @@
1
+ $LOAD_PATH.unshift File.dirname(__FILE__)
2
+ require 'helper'
3
+ require 'webmock/test_unit'
4
+
5
+ WebMock::BodyPattern.class_eval do
6
+ undef normalize_hash
7
+ # override normalizing hash since it otherwise requires JSON
8
+ def normalize_hash(hash) hash end
9
+ end
10
+
11
+ class HubTest < Test::Unit::TestCase
12
+ if defined? WebMock::API
13
+ include WebMock::API
14
+ else
15
+ include WebMock
16
+ end
17
+
18
+ COMMANDS = []
19
+
20
+ Hub::Commands.class_eval do
21
+ remove_method :command?
22
+ define_method :command? do |name|
23
+ COMMANDS.include?(name)
24
+ end
25
+ end
26
+
27
+ def setup
28
+ COMMANDS.replace %w[open groff]
29
+ Hub::Context::DIRNAME.replace 'hub'
30
+ Hub::Context::REMOTES.clear
31
+
32
+ @git = Hub::Context::GIT_CONFIG.replace(Hash.new { |h, k|
33
+ unless k.index('config alias.') == 0
34
+ raise ArgumentError, "`git #{k}` not stubbed"
35
+ end
36
+ }).update(
37
+ 'remote' => "mislav\norigin",
38
+ 'symbolic-ref -q HEAD' => 'refs/heads/master',
39
+ 'config github.user' => 'tpw',
40
+ 'config github.token' => 'abc123',
41
+ 'config --get-all remote.origin.url' => 'git://github.com/defunkt/hub.git',
42
+ 'config --get-all remote.mislav.url' => 'git://github.com/mislav/hub.git',
43
+ 'config branch.master.remote' => 'origin',
44
+ 'config branch.master.merge' => 'refs/heads/master',
45
+ 'config branch.feature.remote' => 'mislav',
46
+ 'config branch.feature.merge' => 'refs/heads/experimental',
47
+ 'config --bool hub.http-clone' => 'false',
48
+ 'config core.repositoryformatversion' => '0'
49
+ )
50
+ super
51
+ end
52
+
53
+ def test_private_clone
54
+ input = "clone -p rtomayko/ronn"
55
+ command = "git clone git@github.com:rtomayko/ronn.git"
56
+ assert_command input, command
57
+ end
58
+
59
+ def test_public_clone
60
+ input = "clone rtomayko/ronn"
61
+ command = "git clone git://github.com/rtomayko/ronn.git"
62
+ assert_command input, command
63
+ end
64
+
65
+ def test_your_private_clone
66
+ input = "clone -p resque"
67
+ command = "git clone git@github.com:tpw/resque.git"
68
+ assert_command input, command
69
+ end
70
+
71
+ def test_your_public_clone
72
+ input = "clone resque"
73
+ command = "git clone git://github.com/tpw/resque.git"
74
+ assert_command input, command
75
+ end
76
+
77
+ def test_clone_with_arguments
78
+ input = "clone --bare -o master resque"
79
+ command = "git clone --bare -o master git://github.com/tpw/resque.git"
80
+ assert_command input, command
81
+ end
82
+
83
+ def test_clone_with_arguments_and_destination
84
+ assert_forwarded "clone --template=one/two git://github.com/tpw/resque.git --origin master resquetastic"
85
+ end
86
+
87
+ def test_your_private_clone_fails_without_config
88
+ out = hub("clone -p mustache") do
89
+ stub_github_user(nil)
90
+ end
91
+
92
+ assert_equal "** No GitHub user set. See http://github.com/guides/local-github-config\n", out
93
+ end
94
+
95
+ def test_your_public_clone_fails_without_config
96
+ out = hub("clone mustache") do
97
+ stub_github_user(nil)
98
+ end
99
+
100
+ assert_equal "** No GitHub user set. See http://github.com/guides/local-github-config\n", out
101
+ end
102
+
103
+ def test_private_clone_left_alone
104
+ assert_forwarded "clone git@github.com:rtomayko/ronn.git"
105
+ end
106
+
107
+ def test_public_clone_left_alone
108
+ assert_forwarded "clone git://github.com/rtomayko/ronn.git"
109
+ end
110
+
111
+ def test_normal_public_clone_with_path
112
+ assert_forwarded "clone git://github.com/rtomayko/ronn.git ronn-dev"
113
+ end
114
+
115
+ def test_normal_clone_from_path
116
+ assert_forwarded "clone ./test"
117
+ end
118
+
119
+ def test_alias_expand
120
+ stub_alias 'c', 'clone --bare'
121
+ input = "c rtomayko/ronn"
122
+ command = "git clone --bare git://github.com/rtomayko/ronn.git"
123
+ assert_command input, command
124
+ end
125
+
126
+ def test_alias_expand_advanced
127
+ stub_alias 'c', 'clone --template="white space"'
128
+ input = "c rtomayko/ronn"
129
+ command = "git clone '--template=white space' git://github.com/rtomayko/ronn.git"
130
+ assert_command input, command
131
+ end
132
+
133
+ def test_alias_doesnt_expand_for_unknown_commands
134
+ stub_alias 'c', 'compute --fast'
135
+ assert_forwarded "c rtomayko/ronn"
136
+ end
137
+
138
+ def test_remote_origin
139
+ input = "remote add origin"
140
+ command = "git remote add origin git://github.com/tpw/hub.git"
141
+ assert_command input, command
142
+ end
143
+
144
+ def test_private_remote_origin
145
+ input = "remote add -p origin"
146
+ command = "git remote add origin git@github.com:tpw/hub.git"
147
+ assert_command input, command
148
+ end
149
+
150
+ def test_public_remote_origin_as_normal
151
+ input = "remote add origin http://github.com/defunkt/resque.git"
152
+ command = "git remote add origin http://github.com/defunkt/resque.git"
153
+ assert_command input, command
154
+ end
155
+
156
+ def test_remote_from_rel_path
157
+ assert_forwarded "remote add origin ./path"
158
+ end
159
+
160
+ def test_remote_from_abs_path
161
+ assert_forwarded "remote add origin /path"
162
+ end
163
+
164
+ def test_private_remote_origin_as_normal
165
+ assert_forwarded "remote add origin git@github.com:defunkt/resque.git"
166
+ end
167
+
168
+ def test_public_submodule
169
+ input = "submodule add wycats/bundler vendor/bundler"
170
+ command = "git submodule add git://github.com/wycats/bundler.git vendor/bundler"
171
+ assert_command input, command
172
+ end
173
+
174
+ def test_private_submodule
175
+ input = "submodule add -p grit vendor/grit"
176
+ command = "git submodule add git@github.com:tpw/grit.git vendor/grit"
177
+ assert_command input, command
178
+ end
179
+
180
+ def test_submodule_branch
181
+ input = "submodule add -b ryppl ryppl/pip vendor/pip"
182
+ command = "git submodule add -b ryppl git://github.com/ryppl/pip.git vendor/pip"
183
+ assert_command input, command
184
+ end
185
+
186
+ def test_submodule_with_args
187
+ input = "submodule -q add --bare -- grit grit"
188
+ command = "git submodule -q add --bare -- git://github.com/tpw/grit.git grit"
189
+ assert_command input, command
190
+ end
191
+
192
+ def test_private_remote
193
+ input = "remote add -p rtomayko"
194
+ command = "git remote add rtomayko git@github.com:rtomayko/hub.git"
195
+ assert_command input, command
196
+ end
197
+
198
+ def test_public_remote
199
+ input = "remote add rtomayko"
200
+ command = "git remote add rtomayko git://github.com/rtomayko/hub.git"
201
+ assert_command input, command
202
+ end
203
+
204
+ def test_public_remote_f
205
+ input = "remote add -f rtomayko"
206
+ command = "git remote add -f rtomayko git://github.com/rtomayko/hub.git"
207
+ assert_command input, command
208
+ end
209
+
210
+ def test_named_public_remote
211
+ input = "remote add origin rtomayko"
212
+ command = "git remote add origin git://github.com/rtomayko/hub.git"
213
+ assert_command input, command
214
+ end
215
+
216
+ def test_named_public_remote_f
217
+ input = "remote add -f origin rtomayko"
218
+ command = "git remote add -f origin git://github.com/rtomayko/hub.git"
219
+ assert_command input, command
220
+ end
221
+
222
+ def test_private_remote_with_repo
223
+ input = "remote add -p jashkenas/coffee-script"
224
+ command = "git remote add jashkenas git@github.com:jashkenas/coffee-script.git"
225
+ assert_command input, command
226
+ end
227
+
228
+ def test_public_remote_with_repo
229
+ input = "remote add jashkenas/coffee-script"
230
+ command = "git remote add jashkenas git://github.com/jashkenas/coffee-script.git"
231
+ assert_command input, command
232
+ end
233
+
234
+ def test_public_remote_f_with_repo
235
+ input = "remote add -f jashkenas/coffee-script"
236
+ command = "git remote add -f jashkenas git://github.com/jashkenas/coffee-script.git"
237
+ assert_command input, command
238
+ end
239
+
240
+ def test_named_private_remote_with_repo
241
+ input = "remote add -p origin jashkenas/coffee-script"
242
+ command = "git remote add origin git@github.com:jashkenas/coffee-script.git"
243
+ assert_command input, command
244
+ end
245
+
246
+ def test_fetch_existing_remote
247
+ assert_forwarded "fetch mislav"
248
+ end
249
+
250
+ def test_fetch_new_remote
251
+ stub_remotes_group('xoebus', nil)
252
+ stub_existing_fork('xoebus')
253
+
254
+ assert_commands "git remote add xoebus git://github.com/xoebus/hub.git",
255
+ "git fetch xoebus",
256
+ "fetch xoebus"
257
+ end
258
+
259
+ def test_fetch_new_remote_with_options
260
+ stub_remotes_group('xoebus', nil)
261
+ stub_existing_fork('xoebus')
262
+
263
+ assert_commands "git remote add xoebus git://github.com/xoebus/hub.git",
264
+ "git fetch --depth=1 --prune xoebus",
265
+ "fetch --depth=1 --prune xoebus"
266
+ end
267
+
268
+ def test_fetch_multiple_new_remotes
269
+ stub_remotes_group('xoebus', nil)
270
+ stub_remotes_group('rtomayko', nil)
271
+ stub_existing_fork('xoebus')
272
+ stub_existing_fork('rtomayko')
273
+
274
+ assert_commands "git remote add xoebus git://github.com/xoebus/hub.git",
275
+ "git remote add rtomayko git://github.com/rtomayko/hub.git",
276
+ "git fetch --multiple xoebus rtomayko",
277
+ "fetch --multiple xoebus rtomayko"
278
+ end
279
+
280
+ def test_fetch_multiple_comma_separated_remotes
281
+ stub_remotes_group('xoebus', nil)
282
+ stub_remotes_group('rtomayko', nil)
283
+ stub_existing_fork('xoebus')
284
+ stub_existing_fork('rtomayko')
285
+
286
+ assert_commands "git remote add xoebus git://github.com/xoebus/hub.git",
287
+ "git remote add rtomayko git://github.com/rtomayko/hub.git",
288
+ "git fetch --multiple xoebus rtomayko",
289
+ "fetch xoebus,rtomayko"
290
+ end
291
+
292
+ def test_fetch_multiple_new_remotes_with_filtering
293
+ stub_remotes_group('xoebus', nil)
294
+ stub_remotes_group('mygrp', 'one two')
295
+ stub_remotes_group('typo', nil)
296
+ stub_existing_fork('xoebus')
297
+ stub_nonexisting_fork('typo')
298
+
299
+ # mislav: existing remote; skipped
300
+ # xoebus: new remote, fork exists; added
301
+ # mygrp: a remotes group; skipped
302
+ # URL: can't be a username; skipped
303
+ # typo: fork doesn't exist; skipped
304
+ assert_commands "git remote add xoebus git://github.com/xoebus/hub.git",
305
+ "git fetch --multiple mislav xoebus mygrp git://example.com typo",
306
+ "fetch --multiple mislav xoebus mygrp git://example.com typo"
307
+ end
308
+
309
+ def test_cherry_pick
310
+ assert_forwarded "cherry-pick a319d88"
311
+ end
312
+
313
+ def test_cherry_pick_url
314
+ url = 'http://github.com/mislav/hub/commit/a319d88'
315
+ assert_commands "git fetch mislav", "git cherry-pick a319d88", "cherry-pick #{url}"
316
+ end
317
+
318
+ def test_cherry_pick_url_with_fragment
319
+ url = 'http://github.com/mislav/hub/commit/abcdef0123456789#comments'
320
+ assert_commands "git fetch mislav", "git cherry-pick abcdef0123456789", "cherry-pick #{url}"
321
+ end
322
+
323
+ def test_cherry_pick_url_with_remote_add
324
+ url = 'https://github.com/xoebus/hub/commit/a319d88'
325
+ assert_commands "git remote add -f xoebus git://github.com/xoebus/hub.git",
326
+ "git cherry-pick a319d88",
327
+ "cherry-pick #{url}"
328
+ end
329
+
330
+ def test_cherry_pick_origin_url
331
+ url = 'https://github.com/defunkt/hub/commit/a319d88'
332
+ assert_commands "git fetch origin", "git cherry-pick a319d88", "cherry-pick #{url}"
333
+ end
334
+
335
+ def test_cherry_pick_github_user_notation
336
+ assert_commands "git fetch mislav", "git cherry-pick a319d88", "cherry-pick mislav@a319d88"
337
+ end
338
+
339
+ def test_cherry_pick_github_user_repo_notation
340
+ # not supported
341
+ assert_forwarded "cherry-pick mislav/hubbub@a319d88"
342
+ end
343
+
344
+ def test_cherry_pick_github_notation_too_short
345
+ assert_forwarded "cherry-pick mislav@a319"
346
+ end
347
+
348
+ def test_cherry_pick_github_notation_with_remote_add
349
+ assert_commands "git remote add -f xoebus git://github.com/xoebus/hub.git",
350
+ "git cherry-pick a319d88",
351
+ "cherry-pick xoebus@a319d88"
352
+ end
353
+
354
+ def test_am_untouched
355
+ assert_forwarded "am some.patch"
356
+ end
357
+
358
+ def test_am_pull_request
359
+ with_tmpdir('/tmp/') do
360
+ assert_commands "curl -#LA 'hub #{Hub::Version}' https://github.com/defunkt/hub/pull/55.patch -o /tmp/55.patch",
361
+ "git am --signoff /tmp/55.patch -p2",
362
+ "am --signoff https://github.com/defunkt/hub/pull/55 -p2"
363
+
364
+ cmd = Hub("am https://github.com/defunkt/hub/pull/55/files").command
365
+ assert_includes '/pull/55.patch', cmd
366
+ end
367
+ end
368
+
369
+ def test_am_commit_url
370
+ with_tmpdir('/tmp/') do
371
+ url = 'https://github.com/davidbalbert/hub/commit/fdb9921'
372
+
373
+ assert_commands "curl -#LA 'hub #{Hub::Version}' #{url}.patch -o /tmp/fdb9921.patch",
374
+ "git am --signoff /tmp/fdb9921.patch -p2",
375
+ "am --signoff #{url} -p2"
376
+ end
377
+ end
378
+
379
+ def test_am_gist
380
+ with_tmpdir('/tmp/') do
381
+ url = 'https://gist.github.com/8da7fb575debd88c54cf'
382
+
383
+ assert_commands "curl -#LA 'hub #{Hub::Version}' #{url}.txt -o /tmp/gist-8da7fb575debd88c54cf.txt",
384
+ "git am --signoff /tmp/gist-8da7fb575debd88c54cf.txt -p2",
385
+ "am --signoff #{url} -p2"
386
+ end
387
+ end
388
+
389
+ def test_init
390
+ assert_commands "git init", "git remote add origin git@github.com:tpw/hub.git", "init -g"
391
+ end
392
+
393
+ def test_init_no_login
394
+ out = hub("init -g") do
395
+ stub_github_user(nil)
396
+ end
397
+
398
+ assert_equal "** No GitHub user set. See http://github.com/guides/local-github-config\n", out
399
+ end
400
+
401
+ def test_push_two
402
+ assert_commands "git push origin cool-feature", "git push staging cool-feature",
403
+ "push origin,staging cool-feature"
404
+ end
405
+
406
+ def test_push_more
407
+ assert_commands "git push origin cool-feature",
408
+ "git push staging cool-feature",
409
+ "git push qa cool-feature",
410
+ "push origin,staging,qa cool-feature"
411
+ end
412
+
413
+ def test_create
414
+ stub_no_remotes
415
+ stub_nonexisting_fork('tpw')
416
+ stub_request(:post, "github.com/api/v2/yaml/repos/create").
417
+ with(:body => { 'login'=>'tpw', 'token'=>'abc123', 'name' => 'hub' })
418
+
419
+ expected = "remote add -f origin git@github.com:tpw/hub.git\n"
420
+ expected << "created repository: tpw/hub\n"
421
+ assert_equal expected, hub("create") { ENV['GIT'] = 'echo' }
422
+ end
423
+
424
+ def test_create_failed
425
+ stub_no_remotes
426
+ stub_nonexisting_fork('tpw')
427
+ stub_request(:post, "github.com/api/v2/yaml/repos/create").
428
+ to_return(:status => [401, "Your token is fail"])
429
+
430
+ expected = "error creating repository: Your token is fail (HTTP 401)\n"
431
+ assert_equal expected, hub("create") { ENV['GIT'] = 'echo' }
432
+ end
433
+
434
+ def test_create_with_env_authentication
435
+ stub_no_remotes
436
+ stub_nonexisting_fork('mojombo')
437
+
438
+ old_user = ENV['GITHUB_USER']
439
+ old_token = ENV['GITHUB_TOKEN']
440
+ ENV['GITHUB_USER'] = 'mojombo'
441
+ ENV['GITHUB_TOKEN'] = '123abc'
442
+
443
+ stub_request(:post, "github.com/api/v2/yaml/repos/create").
444
+ with(:body => { 'login'=>'mojombo', 'token'=>'123abc', 'name' => 'hub' })
445
+
446
+ expected = "remote add -f origin git@github.com:mojombo/hub.git\n"
447
+ expected << "created repository: mojombo/hub\n"
448
+ assert_equal expected, hub("create") { ENV['GIT'] = 'echo' }
449
+
450
+ ensure
451
+ ENV['GITHUB_USER'] = old_user
452
+ ENV['GITHUB_TOKEN'] = old_token
453
+ end
454
+
455
+ def test_create_private_repository
456
+ stub_no_remotes
457
+ stub_nonexisting_fork('tpw')
458
+ stub_request(:post, "github.com/api/v2/yaml/repos/create").
459
+ with(:body => { 'login'=>'tpw', 'token'=>'abc123', 'name' => 'hub', 'public' => '0' })
460
+
461
+ expected = "remote add -f origin git@github.com:tpw/hub.git\n"
462
+ expected << "created repository: tpw/hub\n"
463
+ assert_equal expected, hub("create -p") { ENV['GIT'] = 'echo' }
464
+ end
465
+
466
+ def test_create_with_description_and_homepage
467
+ stub_no_remotes
468
+ stub_nonexisting_fork('tpw')
469
+ stub_request(:post, "github.com/api/v2/yaml/repos/create").with(:body => {
470
+ 'login'=>'tpw', 'token'=>'abc123', 'name' => 'hub',
471
+ 'description' => 'toyproject', 'homepage' => 'http://example.com'
472
+ })
473
+
474
+ expected = "remote add -f origin git@github.com:tpw/hub.git\n"
475
+ expected << "created repository: tpw/hub\n"
476
+ assert_equal expected, hub("create -d toyproject -h http://example.com") { ENV['GIT'] = 'echo' }
477
+ end
478
+
479
+ def test_create_with_existing_repository
480
+ stub_no_remotes
481
+ stub_existing_fork('tpw')
482
+
483
+ expected = "tpw/hub already exists on GitHub\n"
484
+ expected << "remote add -f origin git@github.com:tpw/hub.git\n"
485
+ expected << "set remote origin: tpw/hub\n"
486
+ assert_equal expected, hub("create") { ENV['GIT'] = 'echo' }
487
+ end
488
+
489
+ def test_create_no_user
490
+ stub_no_remotes
491
+ out = hub("create") do
492
+ stub_github_token(nil)
493
+ end
494
+ assert_equal "** No GitHub token set. See http://github.com/guides/local-github-config\n", out
495
+ end
496
+
497
+ def test_create_outside_git_repo
498
+ stub_no_git_repo
499
+ assert_equal "'create' must be run from inside a git repository\n", hub("create")
500
+ end
501
+
502
+ def test_create_origin_already_exists
503
+ stub_nonexisting_fork('tpw')
504
+ stub_request(:post, "github.com/api/v2/yaml/repos/create").
505
+ with(:body => { 'login'=>'tpw', 'token'=>'abc123', 'name' => 'hub' })
506
+
507
+ expected = "remote -v\ncreated repository: tpw/hub\n"
508
+ assert_equal expected, hub("create") { ENV['GIT'] = 'echo' }
509
+ end
510
+
511
+ def test_fork
512
+ stub_nonexisting_fork('tpw')
513
+ stub_request(:post, "github.com/api/v2/yaml/repos/fork/defunkt/hub").
514
+ with(:body => { 'login'=>'tpw', 'token'=>'abc123' })
515
+
516
+ expected = "remote add -f tpw git@github.com:tpw/hub.git\n"
517
+ expected << "new remote: tpw\n"
518
+ assert_equal expected, hub("fork") { ENV['GIT'] = 'echo' }
519
+ end
520
+
521
+ def test_fork_failed
522
+ stub_nonexisting_fork('tpw')
523
+ stub_request(:post, "github.com/api/v2/yaml/repos/fork/defunkt/hub").
524
+ to_return(:status => [500, "Your fork is fail"])
525
+
526
+ expected = "error creating fork: Your fork is fail (HTTP 500)\n"
527
+ assert_equal expected, hub("fork") { ENV['GIT'] = 'echo' }
528
+ end
529
+
530
+ def test_fork_no_remote
531
+ stub_nonexisting_fork('tpw')
532
+ stub_request(:post, "github.com/api/v2/yaml/repos/fork/defunkt/hub")
533
+
534
+ assert_equal "", hub("fork --no-remote") { ENV['GIT'] = 'echo' }
535
+ end
536
+
537
+ def test_fork_already_exists
538
+ stub_existing_fork('tpw')
539
+
540
+ expected = "tpw/hub already exists on GitHub\n"
541
+ expected << "remote add -f tpw git@github.com:tpw/hub.git\n"
542
+ expected << "new remote: tpw\n"
543
+ assert_equal expected, hub("fork") { ENV['GIT'] = 'echo' }
544
+ end
545
+
546
+ def test_version
547
+ out = hub('--version')
548
+ assert_includes "git version 1.7.0.4", out
549
+ assert_includes "hub version #{Hub::Version}", out
550
+ end
551
+
552
+ def test_exec_path
553
+ out = hub('--exec-path')
554
+ assert_equal "/usr/lib/git-core\n", out
555
+ end
556
+
557
+ def test_exec_path_arg
558
+ out = hub('--exec-path=/home/wombat/share/my-l33t-git-core')
559
+ assert_equal Hub::Commands.improved_help_text, hub("")
560
+ end
561
+
562
+ def test_html_path
563
+ out = hub('--html-path')
564
+ assert_equal "/usr/share/doc/git-doc\n", out
565
+ end
566
+
567
+ def test_help
568
+ assert_equal Hub::Commands.improved_help_text, hub("help")
569
+ end
570
+
571
+ def test_help_by_default
572
+ assert_equal Hub::Commands.improved_help_text, hub("")
573
+ end
574
+
575
+ def test_help_with_pager
576
+ assert_equal Hub::Commands.improved_help_text, hub("-p")
577
+ end
578
+
579
+ def test_help_hub
580
+ help_manpage = hub("help hub")
581
+ assert_includes "git + hub = github", help_manpage
582
+ assert_includes <<-config, help_manpage
583
+ Use git-config(1) to display the currently configured GitHub username:
584
+ config
585
+ end
586
+
587
+ def test_help_hub_no_groff
588
+ stub_available_commands()
589
+ assert_equal "** Can't find groff(1)\n", hub("help hub")
590
+ end
591
+
592
+ def test_hub_standalone
593
+ help_standalone = hub("hub standalone")
594
+ assert_equal Hub::Standalone.build, help_standalone
595
+ end
596
+
597
+ def test_hub_compare
598
+ assert_command "compare refactor",
599
+ "open https://github.com/defunkt/hub/compare/refactor"
600
+ end
601
+
602
+ def test_hub_compare_nothing
603
+ expected = "Usage: hub compare [USER] [<START>...]<END>\n"
604
+ assert_equal expected, hub("compare")
605
+ end
606
+
607
+ def test_hub_compare_tracking_nothing
608
+ stub_tracking_nothing
609
+ expected = "Usage: hub compare [USER] [<START>...]<END>\n"
610
+ assert_equal expected, hub("compare")
611
+ end
612
+
613
+ def test_hub_compare_tracking_branch
614
+ stub_branch('refs/heads/feature')
615
+
616
+ assert_command "compare",
617
+ "open https://github.com/mislav/hub/compare/experimental"
618
+ end
619
+
620
+ def test_hub_compare_range
621
+ assert_command "compare 1.0...fix",
622
+ "open https://github.com/defunkt/hub/compare/1.0...fix"
623
+ end
624
+
625
+ def test_hub_compare_on_wiki
626
+ stub_repo_url 'git://github.com/defunkt/hub.wiki.git'
627
+ assert_command "compare 1.0...fix",
628
+ "open https://github.com/defunkt/hub/wiki/_compare/1.0...fix"
629
+ end
630
+
631
+ def test_hub_compare_fork
632
+ assert_command "compare myfork feature",
633
+ "open https://github.com/myfork/hub/compare/feature"
634
+ end
635
+
636
+ def test_hub_compare_url
637
+ assert_command "compare -u 1.0...1.1",
638
+ "echo https://github.com/defunkt/hub/compare/1.0...1.1"
639
+ end
640
+
641
+ def test_hub_browse
642
+ assert_command "browse mojombo/bert", "open https://github.com/mojombo/bert"
643
+ end
644
+
645
+ def test_hub_browse_tracking_nothing
646
+ stub_tracking_nothing
647
+ assert_command "browse mojombo/bert", "open https://github.com/mojombo/bert"
648
+ end
649
+
650
+ def test_hub_browse_url
651
+ assert_command "browse -u mojombo/bert", "echo https://github.com/mojombo/bert"
652
+ end
653
+
654
+ def test_hub_browse_self
655
+ assert_command "browse resque", "open https://github.com/tpw/resque"
656
+ end
657
+
658
+ def test_hub_browse_subpage
659
+ assert_command "browse resque commits",
660
+ "open https://github.com/tpw/resque/commits/master"
661
+ assert_command "browse resque issues",
662
+ "open https://github.com/tpw/resque/issues"
663
+ assert_command "browse resque wiki",
664
+ "open https://github.com/tpw/resque/wiki"
665
+ end
666
+
667
+ def test_hub_browse_on_branch
668
+ stub_branch('refs/heads/feature')
669
+
670
+ assert_command "browse resque", "open https://github.com/tpw/resque"
671
+ assert_command "browse resque commits",
672
+ "open https://github.com/tpw/resque/commits/master"
673
+
674
+ assert_command "browse",
675
+ "open https://github.com/mislav/hub/tree/experimental"
676
+ assert_command "browse -- tree",
677
+ "open https://github.com/mislav/hub/tree/experimental"
678
+ assert_command "browse -- commits",
679
+ "open https://github.com/mislav/hub/commits/experimental"
680
+ end
681
+
682
+ def test_hub_browse_current
683
+ assert_command "browse", "open https://github.com/defunkt/hub"
684
+ assert_command "browse --", "open https://github.com/defunkt/hub"
685
+ end
686
+
687
+ def test_hub_browse_current_wiki
688
+ stub_repo_url 'git://github.com/defunkt/hub.wiki.git'
689
+
690
+ assert_command "browse", "open https://github.com/defunkt/hub/wiki"
691
+ assert_command "browse -- wiki", "open https://github.com/defunkt/hub/wiki"
692
+ assert_command "browse -- commits", "open https://github.com/defunkt/hub/wiki/_history"
693
+ assert_command "browse -- pages", "open https://github.com/defunkt/hub/wiki/_pages"
694
+ end
695
+
696
+ def test_hub_browse_current_subpage
697
+ assert_command "browse -- network",
698
+ "open https://github.com/defunkt/hub/network"
699
+ assert_command "browse -- anything/everything",
700
+ "open https://github.com/defunkt/hub/anything/everything"
701
+ end
702
+
703
+ def test_hub_browse_deprecated_private
704
+ with_browser_env('echo') do
705
+ assert_includes "Warning: the `-p` flag has no effect anymore\n", hub("browse -p defunkt/hub")
706
+ end
707
+ end
708
+
709
+ def test_hub_browse_no_repo
710
+ stub_repo_url(nil)
711
+ assert_equal "Usage: hub browse [<USER>/]<REPOSITORY>\n", hub("browse")
712
+ end
713
+
714
+ def test_custom_browser
715
+ with_browser_env("custom") do
716
+ assert_browser("custom")
717
+ end
718
+ end
719
+
720
+ def test_linux_browser
721
+ stub_available_commands "open", "xdg-open", "cygstart"
722
+ with_browser_env(nil) do
723
+ with_ruby_platform("i686-linux") do
724
+ assert_browser("xdg-open")
725
+ end
726
+ end
727
+ end
728
+
729
+ def test_cygwin_browser
730
+ stub_available_commands "open", "cygstart"
731
+ with_browser_env(nil) do
732
+ with_ruby_platform("i686-linux") do
733
+ assert_browser("cygstart")
734
+ end
735
+ end
736
+ end
737
+
738
+ def test_no_browser
739
+ stub_available_commands()
740
+ expected = "Please set $BROWSER to a web launcher to use this command.\n"
741
+ with_browser_env(nil) do
742
+ with_ruby_platform("i686-linux") do
743
+ assert_equal expected, hub("browse")
744
+ end
745
+ end
746
+ end
747
+
748
+ def test_context_method_doesnt_hijack_git_command
749
+ assert_forwarded 'remotes'
750
+ end
751
+
752
+ def test_not_choking_on_ruby_methods
753
+ assert_forwarded 'id'
754
+ assert_forwarded 'name'
755
+ end
756
+
757
+ def test_multiple_remote_urls
758
+ stub_repo_url("git://example.com/other.git\ngit://github.com/my/repo.git")
759
+ assert_command "browse", "open https://github.com/my/repo"
760
+ end
761
+
762
+ protected
763
+
764
+ def stub_github_user(name)
765
+ @git['config github.user'] = name
766
+ end
767
+
768
+ def stub_github_token(token)
769
+ @git['config github.token'] = token
770
+ end
771
+
772
+ def stub_repo_url(value)
773
+ @git['config --get-all remote.origin.url'] = value
774
+ Hub::Context::REMOTES.clear
775
+ end
776
+
777
+ def stub_branch(value)
778
+ @git['symbolic-ref -q HEAD'] = value
779
+ end
780
+
781
+ def stub_tracking_nothing
782
+ @git['config branch.master.remote'] = nil
783
+ @git['config branch.master.merge'] = nil
784
+ end
785
+
786
+ def stub_remotes_group(name, value)
787
+ @git["config remotes.#{name}"] = value
788
+ end
789
+
790
+ def stub_no_remotes
791
+ @git['remote'] = ''
792
+ end
793
+
794
+ def stub_no_git_repo
795
+ @git.replace({})
796
+ end
797
+
798
+ def stub_alias(name, value)
799
+ @git["config alias.#{name}"] = value
800
+ end
801
+
802
+ def stub_existing_fork(user)
803
+ stub_fork(user, 200)
804
+ end
805
+
806
+ def stub_nonexisting_fork(user)
807
+ stub_fork(user, 404)
808
+ end
809
+
810
+ def stub_fork(user, status)
811
+ stub_request(:get, "github.com/api/v2/yaml/repos/show/#{user}/hub").
812
+ to_return(:status => status)
813
+ end
814
+
815
+ def stub_available_commands(*names)
816
+ COMMANDS.replace names
817
+ end
818
+
819
+ def with_browser_env(value)
820
+ browser, ENV['BROWSER'] = ENV['BROWSER'], value
821
+ yield
822
+ ensure
823
+ ENV['BROWSER'] = browser
824
+ end
825
+
826
+ def with_tmpdir(value)
827
+ dir, ENV['TMPDIR'] = ENV['TMPDIR'], value
828
+ yield
829
+ ensure
830
+ ENV['TMPDIR'] = dir
831
+ end
832
+
833
+ def assert_browser(browser)
834
+ assert_command "browse", "#{browser} https://github.com/defunkt/hub"
835
+ end
836
+
837
+ def with_ruby_platform(value)
838
+ platform = RUBY_PLATFORM
839
+ Object.send(:remove_const, :RUBY_PLATFORM)
840
+ Object.const_set(:RUBY_PLATFORM, value)
841
+ yield
842
+ ensure
843
+ Object.send(:remove_const, :RUBY_PLATFORM)
844
+ Object.const_set(:RUBY_PLATFORM, platform)
845
+ end
846
+
847
+ end