hub 1.6.1 → 1.7.0

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

Potentially problematic release.


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

@@ -1,4 +1,3 @@
1
- $LOAD_PATH.unshift File.dirname(__FILE__)
2
1
  require 'helper'
3
2
 
4
3
  class AliasTest < Test::Unit::TestCase
@@ -1,15 +1,8 @@
1
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
2
  require 'hub'
10
3
  require 'hub/standalone'
11
4
 
12
- # We're looking for `open` in the tests.
5
+ # We're checking for `open` in our tests
13
6
  ENV['BROWSER'] = 'open'
14
7
 
15
8
  # Setup path with fake executables in case a test hits them
@@ -108,4 +101,11 @@ class Test::Unit::TestCase
108
101
  assert !haystack.include?(needle),
109
102
  "didn't expect #{needle.inspect} in #{haystack.inspect}"
110
103
  end
104
+
105
+ # Version of assert_equal tailored for big output
106
+ def assert_output(expected, command)
107
+ output = hub(command) { ENV['GIT'] = 'echo' }
108
+ assert expected == output,
109
+ "expected:\n#{expected}\ngot:\n#{output}"
110
+ end
111
111
  end
@@ -1,7 +1,9 @@
1
- $LOAD_PATH.unshift File.dirname(__FILE__)
2
1
  require 'helper'
3
2
  require 'webmock/test_unit'
4
3
  require 'rbconfig'
4
+ require 'yaml'
5
+ require 'forwardable'
6
+ require 'json'
5
7
 
6
8
  WebMock::BodyPattern.class_eval do
7
9
  undef normalize_hash
@@ -10,6 +12,8 @@ WebMock::BodyPattern.class_eval do
10
12
  end
11
13
 
12
14
  class HubTest < Test::Unit::TestCase
15
+ extend Forwardable
16
+
13
17
  if defined? WebMock::API
14
18
  include WebMock::API
15
19
  else
@@ -25,30 +29,35 @@ class HubTest < Test::Unit::TestCase
25
29
  end
26
30
  end
27
31
 
32
+ attr_reader :git_reader
33
+ include Hub::Context::GitReaderMethods
34
+ def_delegators :git_reader, :stub_config_value, :stub_command_output
35
+
28
36
  def setup
37
+ super
29
38
  COMMANDS.replace %w[open groff]
30
- Hub::Context::DIRNAME.replace 'hub'
31
- Hub::Context::REMOTES.clear
39
+ Hub::Context::PWD.replace '/path/to/hub'
32
40
 
33
- Hub::Context::GIT_CONFIG.executable = 'git'
34
-
35
- @git = Hub::Context::GIT_CONFIG.replace(Hash.new { |h, k|
36
- unless k.index('config alias.') == 0
37
- raise ArgumentError, "`git #{k}` not stubbed"
41
+ @git_reader = Hub::Context::GitReader.new 'git' do |cache, cmd|
42
+ unless cmd.index('config --get alias.') == 0
43
+ raise ArgumentError, "`git #{cmd}` not stubbed"
38
44
  end
39
- }).update(
45
+ end
46
+
47
+ Hub::Commands.instance_variable_set :@git_reader, @git_reader
48
+ Hub::Commands.instance_variable_set :@local_repo, nil
49
+
50
+ @git_reader.stub! \
40
51
  'remote' => "mislav\norigin",
41
52
  'symbolic-ref -q HEAD' => 'refs/heads/master',
42
- 'config github.user' => 'tpw',
43
- 'config github.token' => 'abc123',
53
+ 'config --get github.user' => 'tpw',
54
+ 'config --get github.token' => 'abc123',
44
55
  'config --get-all remote.origin.url' => 'git://github.com/defunkt/hub.git',
45
56
  'config --get-all remote.mislav.url' => 'git://github.com/mislav/hub.git',
46
- 'config branch.master.remote' => 'origin',
47
- 'config branch.master.merge' => 'refs/heads/master',
48
- 'config --bool hub.http-clone' => 'false',
49
- 'config core.repositoryformatversion' => '0'
50
- )
51
- super
57
+ 'rev-parse --symbolic-full-name master@{upstream}' => 'refs/remotes/origin/master',
58
+ 'config --get --bool hub.http-clone' => 'false',
59
+ 'config --get hub.protocol' => nil,
60
+ 'rev-parse -q --git-dir' => '.git'
52
61
  end
53
62
 
54
63
  def test_private_clone
@@ -57,6 +66,19 @@ class HubTest < Test::Unit::TestCase
57
66
  assert_command input, command
58
67
  end
59
68
 
69
+ def test_private_clone_noop
70
+ input = "--noop clone -p rtomayko/ronn"
71
+ command = "git clone git@github.com:rtomayko/ronn.git\n"
72
+ assert_output command, hub(input)
73
+ end
74
+
75
+ def test_https_clone
76
+ stub_https_is_preferred
77
+ input = "clone rtomayko/ronn"
78
+ command = "git clone https://github.com/rtomayko/ronn.git"
79
+ assert_command input, command
80
+ end
81
+
60
82
  def test_public_clone
61
83
  input = "clone rtomayko/ronn"
62
84
  command = "git clone git://github.com/rtomayko/ronn.git"
@@ -69,15 +91,15 @@ class HubTest < Test::Unit::TestCase
69
91
  assert_command input, command
70
92
  end
71
93
 
72
- def test_your_public_clone
94
+ def test_your_clone_is_always_private
73
95
  input = "clone resque"
74
- command = "git clone git://github.com/tpw/resque.git"
96
+ command = "git clone git@github.com:tpw/resque.git"
75
97
  assert_command input, command
76
98
  end
77
99
 
78
100
  def test_clone_with_arguments
79
101
  input = "clone --bare -o master resque"
80
- command = "git clone --bare -o master git://github.com/tpw/resque.git"
102
+ command = "git clone --bare -o master git@github.com:tpw/resque.git"
81
103
  assert_command input, command
82
104
  end
83
105
 
@@ -90,7 +112,7 @@ class HubTest < Test::Unit::TestCase
90
112
  stub_github_user(nil)
91
113
  end
92
114
 
93
- assert_equal "** No GitHub user set. See http://help.github.com/git-email-settings/\n", out
115
+ assert_equal "** No GitHub user set. See http://help.github.com/set-your-user-name-email-and-github-token/\n", out
94
116
  end
95
117
 
96
118
  def test_your_public_clone_fails_without_config
@@ -98,7 +120,7 @@ class HubTest < Test::Unit::TestCase
98
120
  stub_github_user(nil)
99
121
  end
100
122
 
101
- assert_equal "** No GitHub user set. See http://help.github.com/git-email-settings/\n", out
123
+ assert_equal "** No GitHub user set. See http://help.github.com/set-your-user-name-email-and-github-token/\n", out
102
124
  end
103
125
 
104
126
  def test_private_clone_left_alone
@@ -117,6 +139,10 @@ class HubTest < Test::Unit::TestCase
117
139
  assert_forwarded "clone ./test"
118
140
  end
119
141
 
142
+ def test_clone_with_host_alias
143
+ assert_forwarded "clone server:git/repo.git"
144
+ end
145
+
120
146
  def test_alias_expand
121
147
  stub_alias 'c', 'clone --bare'
122
148
  input = "c rtomayko/ronn"
@@ -162,6 +188,10 @@ class HubTest < Test::Unit::TestCase
162
188
  assert_forwarded "remote add origin /path"
163
189
  end
164
190
 
191
+ def test_remote_with_host_alias
192
+ assert_forwarded "remote add origin server:/git/repo.git"
193
+ end
194
+
165
195
  def test_private_remote_origin_as_normal
166
196
  assert_forwarded "remote add origin git@github.com:defunkt/resque.git"
167
197
  end
@@ -196,6 +226,13 @@ class HubTest < Test::Unit::TestCase
196
226
  assert_command input, command
197
227
  end
198
228
 
229
+ def test_https_protocol_remote
230
+ stub_https_is_preferred
231
+ input = "remote add rtomayko"
232
+ command = "git remote add rtomayko https://github.com/rtomayko/hub.git"
233
+ assert_command input, command
234
+ end
235
+
199
236
  def test_public_remote
200
237
  input = "remote add rtomayko"
201
238
  command = "git remote add rtomayko git://github.com/rtomayko/hub.git"
@@ -334,7 +371,7 @@ class HubTest < Test::Unit::TestCase
334
371
  end
335
372
 
336
373
  def test_cherry_pick_github_user_notation
337
- assert_commands "git fetch mislav", "git cherry-pick a319d88", "cherry-pick mislav@a319d88"
374
+ assert_commands "git fetch mislav", "git cherry-pick 368af20", "cherry-pick mislav@368af20"
338
375
  end
339
376
 
340
377
  def test_cherry_pick_github_user_repo_notation
@@ -387,6 +424,41 @@ class HubTest < Test::Unit::TestCase
387
424
  end
388
425
  end
389
426
 
427
+ def test_apply_untouched
428
+ assert_forwarded "apply some.patch"
429
+ end
430
+
431
+ def test_apply_pull_request
432
+ with_tmpdir('/tmp/') do
433
+ assert_commands "curl -#LA 'hub #{Hub::Version}' https://github.com/defunkt/hub/pull/55.patch -o /tmp/55.patch",
434
+ "git apply /tmp/55.patch -p2",
435
+ "apply https://github.com/defunkt/hub/pull/55 -p2"
436
+
437
+ cmd = Hub("apply https://github.com/defunkt/hub/pull/55/files").command
438
+ assert_includes '/pull/55.patch', cmd
439
+ end
440
+ end
441
+
442
+ def test_apply_commit_url
443
+ with_tmpdir('/tmp/') do
444
+ url = 'https://github.com/davidbalbert/hub/commit/fdb9921'
445
+
446
+ assert_commands "curl -#LA 'hub #{Hub::Version}' #{url}.patch -o /tmp/fdb9921.patch",
447
+ "git apply /tmp/fdb9921.patch -p2",
448
+ "apply #{url} -p2"
449
+ end
450
+ end
451
+
452
+ def test_apply_gist
453
+ with_tmpdir('/tmp/') do
454
+ url = 'https://gist.github.com/8da7fb575debd88c54cf'
455
+
456
+ assert_commands "curl -#LA 'hub #{Hub::Version}' #{url}.txt -o /tmp/gist-8da7fb575debd88c54cf.txt",
457
+ "git apply /tmp/gist-8da7fb575debd88c54cf.txt -p2",
458
+ "apply #{url} -p2"
459
+ end
460
+ end
461
+
390
462
  def test_init
391
463
  assert_commands "git init", "git remote add origin git@github.com:tpw/hub.git", "init -g"
392
464
  end
@@ -396,7 +468,7 @@ class HubTest < Test::Unit::TestCase
396
468
  stub_github_user(nil)
397
469
  end
398
470
 
399
- assert_equal "** No GitHub user set. See http://help.github.com/git-email-settings/\n", out
471
+ assert_equal "** No GitHub user set. See http://help.github.com/set-your-user-name-email-and-github-token/\n", out
400
472
  end
401
473
 
402
474
  def test_push_untouched
@@ -424,21 +496,60 @@ class HubTest < Test::Unit::TestCase
424
496
  def test_create
425
497
  stub_no_remotes
426
498
  stub_nonexisting_fork('tpw')
427
- stub_request(:post, "github.com/api/v2/yaml/repos/create").
428
- with(:body => { 'login'=>'tpw', 'token'=>'abc123', 'name' => 'hub' })
499
+ stub_request(:post, "https://#{auth}github.com/api/v2/yaml/repos/create").
500
+ with(:body => { 'name' => 'hub' })
429
501
 
430
502
  expected = "remote add -f origin git@github.com:tpw/hub.git\n"
431
503
  expected << "created repository: tpw/hub\n"
432
504
  assert_equal expected, hub("create") { ENV['GIT'] = 'echo' }
433
505
  end
434
506
 
507
+ def test_create_custom_name
508
+ stub_no_remotes
509
+ stub_nonexisting_fork('tpw', 'hubbub')
510
+ stub_request(:post, "https://#{auth}github.com/api/v2/yaml/repos/create").
511
+ with(:body => { 'name' => 'hubbub' })
512
+
513
+ expected = "remote add -f origin git@github.com:tpw/hubbub.git\n"
514
+ expected << "created repository: tpw/hubbub\n"
515
+ assert_equal expected, hub("create hubbub") { ENV['GIT'] = 'echo' }
516
+ end
517
+
518
+ def test_create_in_organization
519
+ stub_no_remotes
520
+ stub_nonexisting_fork('acme', 'hubbub')
521
+ stub_request(:post, "https://#{auth}github.com/api/v2/yaml/repos/create").
522
+ with(:body => { 'name' => 'acme/hubbub' })
523
+
524
+ expected = "remote add -f origin git@github.com:acme/hubbub.git\n"
525
+ expected << "created repository: acme/hubbub\n"
526
+ assert_equal expected, hub("create acme/hubbub") { ENV['GIT'] = 'echo' }
527
+ end
528
+
529
+ def test_create_no_openssl
530
+ stub_no_remotes
531
+ stub_nonexisting_fork('tpw')
532
+ stub_request(:post, "http://#{auth}github.com/api/v2/yaml/repos/create").
533
+ with(:body => { 'name' => 'hub' })
534
+
535
+ expected = "remote add -f origin git@github.com:tpw/hub.git\n"
536
+ expected << "created repository: tpw/hub\n"
537
+
538
+ assert_equal expected, hub("create") {
539
+ ENV['GIT'] = 'echo'
540
+ require 'net/https'
541
+ Object.send :remove_const, :OpenSSL
542
+ }
543
+ end
544
+
435
545
  def test_create_failed
436
546
  stub_no_remotes
437
547
  stub_nonexisting_fork('tpw')
438
- stub_request(:post, "github.com/api/v2/yaml/repos/create").
548
+ stub_request(:post, "https://#{auth}github.com/api/v2/yaml/repos/create").
439
549
  to_return(:status => [401, "Your token is fail"])
440
550
 
441
- expected = "error creating repository: Your token is fail (HTTP 401)\n"
551
+ expected = "Error creating repository: Your token is fail (HTTP 401)\n"
552
+ expected << "Check your token configuration (`git config github.token`)\n"
442
553
  assert_equal expected, hub("create") { ENV['GIT'] = 'echo' }
443
554
  end
444
555
 
@@ -451,8 +562,8 @@ class HubTest < Test::Unit::TestCase
451
562
  ENV['GITHUB_USER'] = 'mojombo'
452
563
  ENV['GITHUB_TOKEN'] = '123abc'
453
564
 
454
- stub_request(:post, "github.com/api/v2/yaml/repos/create").
455
- with(:body => { 'login'=>'mojombo', 'token'=>'123abc', 'name' => 'hub' })
565
+ stub_request(:post, "https://#{auth('mojombo', '123abc')}github.com/api/v2/yaml/repos/create").
566
+ with(:body => { 'name' => 'hub' })
456
567
 
457
568
  expected = "remote add -f origin git@github.com:mojombo/hub.git\n"
458
569
  expected << "created repository: mojombo/hub\n"
@@ -466,8 +577,8 @@ class HubTest < Test::Unit::TestCase
466
577
  def test_create_private_repository
467
578
  stub_no_remotes
468
579
  stub_nonexisting_fork('tpw')
469
- stub_request(:post, "github.com/api/v2/yaml/repos/create").
470
- with(:body => { 'login'=>'tpw', 'token'=>'abc123', 'name' => 'hub', 'public' => '0' })
580
+ stub_request(:post, "https://#{auth}github.com/api/v2/yaml/repos/create").
581
+ with(:body => { 'name' => 'hub', 'public' => '0' })
471
582
 
472
583
  expected = "remote add -f origin git@github.com:tpw/hub.git\n"
473
584
  expected << "created repository: tpw/hub\n"
@@ -477,9 +588,8 @@ class HubTest < Test::Unit::TestCase
477
588
  def test_create_with_description_and_homepage
478
589
  stub_no_remotes
479
590
  stub_nonexisting_fork('tpw')
480
- stub_request(:post, "github.com/api/v2/yaml/repos/create").with(:body => {
481
- 'login'=>'tpw', 'token'=>'abc123', 'name' => 'hub',
482
- 'description' => 'toyproject', 'homepage' => 'http://example.com'
591
+ stub_request(:post, "https://#{auth}github.com/api/v2/yaml/repos/create").with(:body => {
592
+ 'name' => 'hub', 'description' => 'toyproject', 'homepage' => 'http://example.com'
483
593
  })
484
594
 
485
595
  expected = "remote add -f origin git@github.com:tpw/hub.git\n"
@@ -487,6 +597,11 @@ class HubTest < Test::Unit::TestCase
487
597
  assert_equal expected, hub("create -d toyproject -h http://example.com") { ENV['GIT'] = 'echo' }
488
598
  end
489
599
 
600
+ def test_create_with_invalid_arguments
601
+ assert_equal "invalid argument: -a\n", hub("create -a blah") { ENV['GIT'] = 'echo' }
602
+ assert_equal "invalid argument: bleh\n", hub("create blah bleh") { ENV['GIT'] = 'echo' }
603
+ end
604
+
490
605
  def test_create_with_existing_repository
491
606
  stub_no_remotes
492
607
  stub_existing_fork('tpw')
@@ -497,12 +612,23 @@ class HubTest < Test::Unit::TestCase
497
612
  assert_equal expected, hub("create") { ENV['GIT'] = 'echo' }
498
613
  end
499
614
 
615
+ def test_create_https_protocol
616
+ stub_no_remotes
617
+ stub_existing_fork('tpw')
618
+ stub_https_is_preferred
619
+
620
+ expected = "tpw/hub already exists on GitHub\n"
621
+ expected << "remote add -f origin https://github.com/tpw/hub.git\n"
622
+ expected << "set remote origin: tpw/hub\n"
623
+ assert_equal expected, hub("create") { ENV['GIT'] = 'echo' }
624
+ end
625
+
500
626
  def test_create_no_user
501
627
  stub_no_remotes
502
628
  out = hub("create") do
503
629
  stub_github_token(nil)
504
630
  end
505
- assert_equal "** No GitHub token set. See http://help.github.com/git-email-settings/\n", out
631
+ assert_equal "** No GitHub token set. See http://help.github.com/set-your-user-name-email-and-github-token/\n", out
506
632
  end
507
633
 
508
634
  def test_create_outside_git_repo
@@ -512,8 +638,8 @@ class HubTest < Test::Unit::TestCase
512
638
 
513
639
  def test_create_origin_already_exists
514
640
  stub_nonexisting_fork('tpw')
515
- stub_request(:post, "github.com/api/v2/yaml/repos/create").
516
- with(:body => { 'login'=>'tpw', 'token'=>'abc123', 'name' => 'hub' })
641
+ stub_request(:post, "https://#{auth}github.com/api/v2/yaml/repos/create").
642
+ with(:body => { 'name' => 'hub' })
517
643
 
518
644
  expected = "remote -v\ncreated repository: tpw/hub\n"
519
645
  assert_equal expected, hub("create") { ENV['GIT'] = 'echo' }
@@ -521,8 +647,7 @@ class HubTest < Test::Unit::TestCase
521
647
 
522
648
  def test_fork
523
649
  stub_nonexisting_fork('tpw')
524
- stub_request(:post, "github.com/api/v2/yaml/repos/fork/defunkt/hub").
525
- with(:body => { 'login'=>'tpw', 'token'=>'abc123' })
650
+ stub_request(:post, "https://#{auth}github.com/api/v2/yaml/repos/fork/defunkt/hub")
526
651
 
527
652
  expected = "remote add -f tpw git@github.com:tpw/hub.git\n"
528
653
  expected << "new remote: tpw\n"
@@ -531,16 +656,16 @@ class HubTest < Test::Unit::TestCase
531
656
 
532
657
  def test_fork_failed
533
658
  stub_nonexisting_fork('tpw')
534
- stub_request(:post, "github.com/api/v2/yaml/repos/fork/defunkt/hub").
659
+ stub_request(:post, "https://#{auth}github.com/api/v2/yaml/repos/fork/defunkt/hub").
535
660
  to_return(:status => [500, "Your fork is fail"])
536
661
 
537
- expected = "error creating fork: Your fork is fail (HTTP 500)\n"
662
+ expected = "Error creating fork: Your fork is fail (HTTP 500)\n"
538
663
  assert_equal expected, hub("fork") { ENV['GIT'] = 'echo' }
539
664
  end
540
665
 
541
666
  def test_fork_no_remote
542
667
  stub_nonexisting_fork('tpw')
543
- stub_request(:post, "github.com/api/v2/yaml/repos/fork/defunkt/hub")
668
+ stub_request(:post, "https://#{auth}github.com/api/v2/yaml/repos/fork/defunkt/hub")
544
669
 
545
670
  assert_equal "", hub("fork --no-remote") { ENV['GIT'] = 'echo' }
546
671
  end
@@ -554,6 +679,161 @@ class HubTest < Test::Unit::TestCase
554
679
  assert_equal expected, hub("fork") { ENV['GIT'] = 'echo' }
555
680
  end
556
681
 
682
+ def test_fork_https_protocol
683
+ stub_existing_fork('tpw')
684
+ stub_https_is_preferred
685
+
686
+ expected = "tpw/hub already exists on GitHub\n"
687
+ expected << "remote add -f tpw https://github.com/tpw/hub.git\n"
688
+ expected << "new remote: tpw\n"
689
+ assert_equal expected, hub("fork") { ENV['GIT'] = 'echo' }
690
+ end
691
+
692
+ def test_pullrequest
693
+ expected = "Aborted: head branch is the same as base (\"master\")\n" <<
694
+ "(use `-h <branch>` to specify an explicit pull request head)\n"
695
+ assert_output expected, "pull-request hereyougo"
696
+ end
697
+
698
+ def test_pullrequest_with_unpushed_commits
699
+ stub_tracking('master', 'mislav', 'master')
700
+ stub_command_output "rev-list --cherry mislav/master...", "+abcd1234\n+bcde2345"
701
+
702
+ expected = "Aborted: 2 commits are not yet pushed to mislav/master\n" <<
703
+ "(use `-f` to force submit a pull request anyway)\n"
704
+ assert_output expected, "pull-request hereyougo"
705
+ end
706
+
707
+ def test_pullrequest_from_branch
708
+ stub_branch('refs/heads/feature')
709
+ stub_tracking_nothing('feature')
710
+
711
+ stub_request(:post, "https://#{auth}github.com/api/v2/yaml/pulls/defunkt/hub").
712
+ with(:body => { 'pull' => {'base' => "master", 'head' => "tpw:feature", 'title' => "hereyougo"} }).
713
+ to_return(:body => mock_pullreq_response(1))
714
+
715
+ expected = "https://github.com/defunkt/hub/pull/1\n"
716
+ assert_output expected, "pull-request hereyougo -f"
717
+ end
718
+
719
+ def test_pullrequest_from_tracking_branch
720
+ stub_branch('refs/heads/feature')
721
+ stub_tracking('feature', 'mislav', 'yay-feature')
722
+ stub_command_output "rev-list --cherry mislav/master...", nil
723
+
724
+ stub_request(:post, "https://#{auth}github.com/api/v2/yaml/pulls/defunkt/hub").
725
+ with(:body => { 'pull' => {'base' => "master", 'head' => "mislav:yay-feature", 'title' => "hereyougo"} }).
726
+ to_return(:body => mock_pullreq_response(1))
727
+
728
+ expected = "https://github.com/defunkt/hub/pull/1\n"
729
+ assert_output expected, "pull-request hereyougo -f"
730
+ end
731
+
732
+ def test_pullrequest_explicit_head
733
+ stub_request(:post, "https://#{auth}github.com/api/v2/yaml/pulls/defunkt/hub").
734
+ with(:body => { 'pull' => {'base' => "master", 'head' => "tpw:yay-feature", 'title' => "hereyougo"} }).
735
+ to_return(:body => mock_pullreq_response(1))
736
+
737
+ expected = "https://github.com/defunkt/hub/pull/1\n"
738
+ assert_output expected, "pull-request hereyougo -h yay-feature -f"
739
+ end
740
+
741
+ def test_pullrequest_explicit_head_with_owner
742
+ stub_request(:post, "https://#{auth}github.com/api/v2/yaml/pulls/defunkt/hub").
743
+ with(:body => { 'pull' => {'base' => "master", 'head' => "mojombo:feature", 'title' => "hereyougo"} }).
744
+ to_return(:body => mock_pullreq_response(1))
745
+
746
+ expected = "https://github.com/defunkt/hub/pull/1\n"
747
+ assert_output expected, "pull-request hereyougo -h mojombo:feature -f"
748
+ end
749
+
750
+ def test_pullrequest_explicit_base
751
+ stub_request(:post, "https://#{auth}github.com/api/v2/yaml/pulls/defunkt/hub").
752
+ with(:body => { 'pull' => {'base' => "feature", 'head' => "defunkt:master", 'title' => "hereyougo"} }).
753
+ to_return(:body => mock_pullreq_response(1))
754
+
755
+ expected = "https://github.com/defunkt/hub/pull/1\n"
756
+ assert_output expected, "pull-request hereyougo -b feature -f"
757
+ end
758
+
759
+ def test_pullrequest_explicit_base_with_owner
760
+ stub_request(:post, "https://#{auth}github.com/api/v2/yaml/pulls/mojombo/hub").
761
+ with(:body => { 'pull' => {'base' => "feature", 'head' => "defunkt:master", 'title' => "hereyougo"} }).
762
+ to_return(:body => mock_pullreq_response(1))
763
+
764
+ expected = "https://github.com/defunkt/hub/pull/1\n"
765
+ assert_output expected, "pull-request hereyougo -b mojombo:feature -f"
766
+ end
767
+
768
+ def test_pullrequest_explicit_base_with_repo
769
+ stub_request(:post, "https://#{auth}github.com/api/v2/yaml/pulls/mojombo/hubbub").
770
+ with(:body => { 'pull' => {'base' => "feature", 'head' => "defunkt:master", 'title' => "hereyougo"} }).
771
+ to_return(:body => mock_pullreq_response(1))
772
+
773
+ expected = "https://github.com/defunkt/hub/pull/1\n"
774
+ assert_output expected, "pull-request hereyougo -b mojombo/hubbub:feature -f"
775
+ end
776
+
777
+ def test_pullrequest_existing_issue
778
+ stub_branch('refs/heads/myfix')
779
+ stub_tracking('myfix', 'mislav', 'awesomefix')
780
+ stub_command_output "rev-list --cherry mislav/awesomefix...", nil
781
+
782
+ stub_request(:post, "https://#{auth}github.com/api/v2/yaml/pulls/defunkt/hub").
783
+ with(:body => { 'pull' => {'base' => "master", 'head' => "mislav:awesomefix", 'issue' => '92'} }).
784
+ to_return(:body => mock_pullreq_response(92))
785
+
786
+ expected = "https://github.com/defunkt/hub/pull/92\n"
787
+ assert_output expected, "pull-request -i 92"
788
+ end
789
+
790
+ def test_pullrequest_existing_issue_url
791
+ stub_branch('refs/heads/myfix')
792
+ stub_tracking('myfix', 'mislav', 'awesomefix')
793
+ stub_command_output "rev-list --cherry mislav/awesomefix...", nil
794
+
795
+ stub_request(:post, "https://#{auth}github.com/api/v2/yaml/pulls/mojombo/hub").
796
+ with(:body => { 'pull' => {'base' => "master", 'head' => "mislav:awesomefix", 'issue' => '92'} }).
797
+ to_return(:body => mock_pullreq_response(92, 'mojombo/hub'))
798
+
799
+ expected = "https://github.com/mojombo/hub/pull/92\n"
800
+ assert_output expected, "pull-request https://github.com/mojombo/hub/issues/92#comment_4"
801
+ end
802
+
803
+ def test_checkout_no_changes
804
+ assert_forwarded "checkout master"
805
+ end
806
+
807
+ def test_checkout_pullrequest
808
+ stub_request(:get, "http://github.com/api/v2/json/pulls/defunkt/hub/73").
809
+ to_return(:body => mock_pull_response('blueyed:feature'))
810
+
811
+ assert_commands 'git remote add -f -t feature blueyed git://github.com/blueyed/hub.git',
812
+ 'git checkout -b blueyed-feature blueyed/feature',
813
+ "checkout https://github.com/defunkt/hub/pull/73/files"
814
+ end
815
+
816
+ def test_checkout_pullrequest_custom_branch
817
+ stub_request(:get, "http://github.com/api/v2/json/pulls/defunkt/hub/73").
818
+ to_return(:body => mock_pull_response('blueyed:feature'))
819
+
820
+ assert_commands 'git remote add -f -t feature blueyed git://github.com/blueyed/hub.git',
821
+ 'git checkout -b review blueyed/feature',
822
+ "checkout https://github.com/defunkt/hub/pull/73/files review"
823
+ end
824
+
825
+ def test_checkout_pullrequest_existing_remote
826
+ stub_command_output 'remote', "origin\nblueyed"
827
+
828
+ stub_request(:get, "http://github.com/api/v2/json/pulls/defunkt/hub/73").
829
+ to_return(:body => mock_pull_response('blueyed:feature'))
830
+
831
+ assert_commands 'git remote set-branches --add blueyed feature',
832
+ 'git fetch blueyed +refs/heads/feature:refs/remotes/blueyed/feature',
833
+ 'git checkout -b blueyed-feature blueyed/feature',
834
+ "checkout https://github.com/defunkt/hub/pull/73/files"
835
+ end
836
+
557
837
  def test_version
558
838
  out = hub('--version')
559
839
  assert_includes "git version 1.7.0.4", out
@@ -567,7 +847,7 @@ class HubTest < Test::Unit::TestCase
567
847
 
568
848
  def test_exec_path_arg
569
849
  out = hub('--exec-path=/home/wombat/share/my-l33t-git-core')
570
- assert_equal Hub::Commands.improved_help_text, out
850
+ assert_equal improved_help_text, out
571
851
  end
572
852
 
573
853
  def test_html_path
@@ -576,15 +856,15 @@ class HubTest < Test::Unit::TestCase
576
856
  end
577
857
 
578
858
  def test_help
579
- assert_equal Hub::Commands.improved_help_text, hub("help")
859
+ assert_equal improved_help_text, hub("help")
580
860
  end
581
861
 
582
862
  def test_help_by_default
583
- assert_equal Hub::Commands.improved_help_text, hub("")
863
+ assert_equal improved_help_text, hub("")
584
864
  end
585
865
 
586
866
  def test_help_with_pager
587
- assert_equal Hub::Commands.improved_help_text, hub("-p")
867
+ assert_equal improved_help_text, hub("-p")
588
868
  end
589
869
 
590
870
  def test_help_hub
@@ -623,7 +903,7 @@ config
623
903
 
624
904
  def test_hub_compare_tracking_branch
625
905
  stub_branch('refs/heads/feature')
626
- stub_tracking('feature', 'mislav', 'refs/heads/experimental')
906
+ stub_tracking('feature', 'mislav', 'experimental')
627
907
 
628
908
  assert_command "compare",
629
909
  "open https://github.com/mislav/hub/compare/experimental"
@@ -634,6 +914,21 @@ config
634
914
  "open https://github.com/defunkt/hub/compare/1.0...fix"
635
915
  end
636
916
 
917
+ def test_hub_compare_range_fixes_two_dots_for_tags
918
+ assert_command "compare 1.0..fix",
919
+ "open https://github.com/defunkt/hub/compare/1.0...fix"
920
+ end
921
+
922
+ def test_hub_compare_range_fixes_two_dots_for_shas
923
+ assert_command "compare 1234abc..3456cde",
924
+ "open https://github.com/defunkt/hub/compare/1234abc...3456cde"
925
+ end
926
+
927
+ def test_hub_compare_range_ignores_two_dots_for_complex_ranges
928
+ assert_command "compare @{a..b}..@{c..d}",
929
+ "open https://github.com/defunkt/hub/compare/@{a..b}..@{c..d}"
930
+ end
931
+
637
932
  def test_hub_compare_on_wiki
638
933
  stub_repo_url 'git://github.com/defunkt/hub.wiki.git'
639
934
  assert_command "compare 1.0...fix",
@@ -654,6 +949,10 @@ config
654
949
  assert_command "browse mojombo/bert", "open https://github.com/mojombo/bert"
655
950
  end
656
951
 
952
+ def test_hub_browse_commit
953
+ assert_command "browse mojombo/bert commit/5d5582", "open https://github.com/mojombo/bert/commit/5d5582"
954
+ end
955
+
657
956
  def test_hub_browse_tracking_nothing
658
957
  stub_tracking_nothing
659
958
  assert_command "browse mojombo/bert", "open https://github.com/mojombo/bert"
@@ -678,7 +977,7 @@ config
678
977
 
679
978
  def test_hub_browse_on_branch
680
979
  stub_branch('refs/heads/feature')
681
- stub_tracking('feature', 'mislav', 'refs/heads/experimental')
980
+ stub_tracking('feature', 'mislav', 'experimental')
682
981
 
683
982
  assert_command "browse resque", "open https://github.com/tpw/resque"
684
983
  assert_command "browse resque commits",
@@ -697,6 +996,10 @@ config
697
996
  assert_command "browse --", "open https://github.com/defunkt/hub"
698
997
  end
699
998
 
999
+ def test_hub_browse_commit_from_current
1000
+ assert_command "browse -- commit/6616e4", "open https://github.com/defunkt/hub/commit/6616e4"
1001
+ end
1002
+
700
1003
  def test_hub_browse_no_tracking
701
1004
  stub_tracking_nothing
702
1005
  assert_command "browse", "open https://github.com/defunkt/hub"
@@ -704,7 +1007,7 @@ config
704
1007
 
705
1008
  def test_hub_browse_no_tracking_on_branch
706
1009
  stub_branch('refs/heads/feature')
707
- stub_tracking('feature', nil, nil)
1010
+ stub_tracking_nothing('feature')
708
1011
  assert_command "browse", "open https://github.com/defunkt/hub"
709
1012
  end
710
1013
 
@@ -786,63 +1089,62 @@ config
786
1089
  def test_global_flags_preserved
787
1090
  cmd = '--no-pager --bare -c core.awesome=true -c name=value --git-dir=/srv/www perform'
788
1091
  assert_command cmd, 'git --bare -c core.awesome=true -c name=value --git-dir=/srv/www --no-pager perform'
789
- assert_equal %w[git --bare -c core.awesome=true -c name=value --git-dir=/srv/www], @git.executable
1092
+ assert_equal %w[git --bare -c core.awesome=true -c name=value --git-dir=/srv/www], git_reader.executable
790
1093
  end
791
1094
 
792
1095
  protected
793
1096
 
794
1097
  def stub_github_user(name)
795
- @git['config github.user'] = name
1098
+ stub_config_value 'github.user', name
796
1099
  end
797
1100
 
798
1101
  def stub_github_token(token)
799
- @git['config github.token'] = token
1102
+ stub_config_value 'github.token', token
800
1103
  end
801
1104
 
802
- def stub_repo_url(value)
803
- @git['config --get-all remote.origin.url'] = value
804
- Hub::Context::REMOTES.clear
1105
+ def stub_repo_url(value, remote_name = 'origin')
1106
+ stub_config_value "remote.#{remote_name}.url", value, '--get-all'
805
1107
  end
806
1108
 
807
1109
  def stub_branch(value)
808
- @git['symbolic-ref -q HEAD'] = value
1110
+ stub_command_output 'symbolic-ref -q HEAD', value
809
1111
  end
810
1112
 
811
1113
  def stub_tracking(from, remote_name, remote_branch)
812
- @git["config branch.#{from}.remote"] = remote_name
813
- @git["config branch.#{from}.merge"] = remote_branch
1114
+ stub_command_output "rev-parse --symbolic-full-name #{from}@{upstream}",
1115
+ remote_branch ? "refs/remotes/#{remote_name}/#{remote_branch}" : nil
814
1116
  end
815
1117
 
816
- def stub_tracking_nothing
817
- stub_tracking('master', nil, nil)
1118
+ def stub_tracking_nothing(from = 'master')
1119
+ stub_tracking(from, nil, nil)
818
1120
  end
819
1121
 
820
1122
  def stub_remotes_group(name, value)
821
- @git["config remotes.#{name}"] = value
1123
+ stub_config_value "remotes.#{name}", value
822
1124
  end
823
1125
 
824
1126
  def stub_no_remotes
825
- @git['remote'] = ''
1127
+ stub_command_output 'remote', nil
826
1128
  end
827
1129
 
828
1130
  def stub_no_git_repo
829
- @git.replace({})
1131
+ stub_command_output 'rev-parse -q --git-dir', nil
830
1132
  end
831
1133
 
832
1134
  def stub_alias(name, value)
833
- @git["config alias.#{name}"] = value
1135
+ stub_config_value "alias.#{name}", value
834
1136
  end
835
1137
 
836
- def stub_existing_fork(user)
837
- stub_fork(user, 200)
1138
+ def stub_existing_fork(user, repo = 'hub')
1139
+ stub_fork(user, repo, 200)
838
1140
  end
839
1141
 
840
- def stub_nonexisting_fork(user)
841
- stub_fork(user, 404)
1142
+ def stub_nonexisting_fork(user, repo = 'hub')
1143
+ stub_fork(user, repo, 404)
842
1144
  end
843
1145
 
844
- def stub_fork(user, status)
845
- stub_request(:get, "github.com/api/v2/yaml/repos/show/#{user}/hub").
1146
+ def stub_fork(user, repo, status)
1147
+ stub_request(:get, "github.com/api/v2/yaml/repos/show/#{user}/#{repo}").
846
1148
  to_return(:status => status)
847
1149
  end
848
1150
 
@@ -850,6 +1152,10 @@ config
850
1152
  COMMANDS.replace names
851
1153
  end
852
1154
 
1155
+ def stub_https_is_preferred
1156
+ stub_config_value 'hub.protocol', 'https'
1157
+ end
1158
+
853
1159
  def with_browser_env(value)
854
1160
  browser, ENV['BROWSER'] = ENV['BROWSER'], value
855
1161
  yield
@@ -878,4 +1184,22 @@ config
878
1184
  end
879
1185
  end
880
1186
 
1187
+ def auth(user = git_config('github.user'), password = git_config('github.token'))
1188
+ "#{user}%2Ftoken:#{password}@"
1189
+ end
1190
+
1191
+ def mock_pullreq_response(id, name_with_owner = 'defunkt/hub')
1192
+ YAML.dump('pull' => {
1193
+ 'html_url' => "https://github.com/#{name_with_owner}/pull/#{id}"
1194
+ })
1195
+ end
1196
+
1197
+ def mock_pull_response(label)
1198
+ JSON.generate('pull' => { 'head' => {'label' => label} })
1199
+ end
1200
+
1201
+ def improved_help_text
1202
+ Hub::Commands.send :improved_help_text
1203
+ end
1204
+
881
1205
  end