hub 1.7.0 → 1.8.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.

data/lib/hub/json.rb ADDED
@@ -0,0 +1,76 @@
1
+ require 'strscan'
2
+ require 'forwardable'
3
+
4
+ class Hub::JSON
5
+ WSP = /\s+/
6
+ OBJ = /[{\[]/
7
+ NUM = /-?\d+(\.\d+)?([eE][+-]?\d+)?/
8
+ BOL = /(?:true|false)\b/
9
+ NUL = /null\b/
10
+
11
+ extend Forwardable
12
+
13
+ attr_reader :scanner
14
+ alias_method :s, :scanner
15
+ private :s
16
+ def_delegators :scanner, :scan, :matched
17
+
18
+ def self.parse(str)
19
+ self.new(str).parse
20
+ end
21
+
22
+ def initialize data
23
+ @scanner = StringScanner.new data.to_s
24
+ end
25
+
26
+ def space
27
+ scan WSP
28
+ end
29
+
30
+ def parse
31
+ space
32
+ object
33
+ end
34
+
35
+ def object
36
+ case scan(OBJ)
37
+ when '{' then hash
38
+ when '[' then array
39
+ end
40
+ end
41
+
42
+ def value
43
+ object or string or
44
+ (scan(NUM) || scan(BOL)) ? eval(matched) :
45
+ scan(NUL) && nil
46
+ end
47
+
48
+ def hash
49
+ current = {}
50
+ space
51
+ until scan(/\}/)
52
+ key = string
53
+ scan(/\s*:\s*/)
54
+ current[key] = value
55
+ scan(/\s*,\s*/) or space
56
+ end
57
+ current
58
+ end
59
+
60
+ def array
61
+ current = []
62
+ space
63
+ until scan(/\]/)
64
+ current << value
65
+ scan(/\s*,\s*/) or space
66
+ end
67
+ current
68
+ end
69
+
70
+ def string
71
+ if str = scan(/"/)
72
+ begin; str << s.scan_until(/"/); end while s.pre_match[-1,1] == '\\'
73
+ eval str
74
+ end
75
+ end
76
+ end
data/lib/hub/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Hub
2
- Version = VERSION = '1.7.0'
2
+ Version = VERSION = '1.8.0'
3
3
  end
data/man/hub.1 CHANGED
@@ -1,7 +1,7 @@
1
1
  .\" generated with Ronn/v0.7.3
2
2
  .\" http://github.com/rtomayko/ronn/tree/0.7.3
3
3
  .
4
- .TH "HUB" "1" "November 2011" "DEFUNKT" "Git Manual"
4
+ .TH "HUB" "1" "January 2012" "DEFUNKT" "Git Manual"
5
5
  .
6
6
  .SH "NAME"
7
7
  \fBhub\fR \- git + hub = github
@@ -138,8 +138,8 @@ Open a GitHub compare view page in the system\'s default web browser\. \fISTART\
138
138
  Forks the original project (referenced by "origin" remote) on GitHub and adds a new remote for it under your username\. Requires \fBgithub\.token\fR to be set (see CONFIGURATION)\.
139
139
  .
140
140
  .TP
141
- \fBgit pull\-request\fR [\fB\-f\fR] [\fITITLE\fR|\fB\-i\fR \fIISSUE\fR] [\fB\-b\fR \fIBASE\fR] [\fB\-h\fR \fIHEAD\fR]
142
- \fBgit pull\-request\fR [\fB\-f\fR] \fIISSUE\-URL\fR [\fB\-h\fR \fIHEAD\fR] Opens a pull request on GitHub for the project that the "origin" remote points to\. The default head of the pull request is the current branch\. Both base and head of the pull request can be explicitly given in one of the following formats: "branch", "owner:branch", "owner/repo:branch"\. This command will abort operation if it detects that the current topic branch has local commits that are not yet pushed to its upstream branch on the remote\. To skip this check, use \fB\-f\fR\.
141
+ \fBgit pull\-request\fR [\fB\-f\fR] [\fITITLE\fR|\fB\-i\fR \fIISSUE\fR|\fIISSUE\-URL\fR] [\fB\-b\fR \fIBASE\fR] [\fB\-h\fR \fIHEAD\fR]
142
+ Opens a pull request on GitHub for the project that the "origin" remote points to\. The default head of the pull request is the current branch\. Both base and head of the pull request can be explicitly given in one of the following formats: "branch", "owner:branch", "owner/repo:branch"\. This command will abort operation if it detects that the current topic branch has local commits that are not yet pushed to its upstream branch on the remote\. To skip this check, use \fB\-f\fR\.
143
143
  .
144
144
  .IP
145
145
  If \fITITLE\fR is omitted, a text editor will open in which title and body of the pull request can be entered in the same manner as git commit message\.
@@ -193,6 +193,46 @@ $ git config \-\-global hub\.protocol https
193
193
  .
194
194
  .IP "" 0
195
195
  .
196
+ .SS "GitHub Enterprise"
197
+ By default, hub will only work with repositories that have remotes which point to github\.com\. GitHub Enterprise hosts need to be whitelisted to configure hub to treat such remotes same as github\.com:
198
+ .
199
+ .IP "" 4
200
+ .
201
+ .nf
202
+
203
+ $ git config \-\-global \-\-add hub\.host my\.git\.org
204
+ .
205
+ .fi
206
+ .
207
+ .IP "" 0
208
+ .
209
+ .P
210
+ API username and token need also be configured for each Enterprise host:
211
+ .
212
+ .IP "" 4
213
+ .
214
+ .nf
215
+
216
+ $ git config \-\-global github\."my\.git\.org"\.user <username>
217
+ $ git config \-\-global github\."my\.git\.org"\.token <token>
218
+ .
219
+ .fi
220
+ .
221
+ .IP "" 0
222
+ .
223
+ .P
224
+ The default host for commands like \fBinit\fR and \fBclone\fR is still github\.com, but this can be affected with the \fIGITHUB_HOST\fR environment variable:
225
+ .
226
+ .IP "" 4
227
+ .
228
+ .nf
229
+
230
+ $ GITHUB_HOST=my\.git\.org git clone myproject
231
+ .
232
+ .fi
233
+ .
234
+ .IP "" 0
235
+ .
196
236
  .SH "EXAMPLES"
197
237
  .
198
238
  .SS "git clone"
data/man/hub.1.html CHANGED
@@ -176,8 +176,7 @@ GitHub will compare against the base branch (the default is "master").</p></dd>
176
176
  <dt><code>git fork</code> [<code>--no-remote</code>]</dt><dd><p>Forks the original project (referenced by "origin" remote) on GitHub and
177
177
  adds a new remote for it under your username. Requires <code>github.token</code> to
178
178
  be set (see CONFIGURATION).</p></dd>
179
- <dt><code>git pull-request</code> [<code>-f</code>] [<var>TITLE</var>|<code>-i</code> <var>ISSUE</var>] [<code>-b</code> <var>BASE</var>] [<code>-h</code> <var>HEAD</var>]</dt><dd><p><code>git pull-request</code> [<code>-f</code>] <var>ISSUE-URL</var> [<code>-h</code> <var>HEAD</var>]
180
- Opens a pull request on GitHub for the project that the "origin" remote
179
+ <dt><code>git pull-request</code> [<code>-f</code>] [<var>TITLE</var>|<code>-i</code> <var>ISSUE</var>|<var>ISSUE-URL</var>] [<code>-b</code> <var>BASE</var>] [<code>-h</code> <var>HEAD</var>]</dt><dd><p>Opens a pull request on GitHub for the project that the "origin" remote
181
180
  points to. The default head of the pull request is the current branch.
182
181
  Both base and head of the pull request can be explicitly given in one of
183
182
  the following formats: "branch", "owner:branch", "owner/repo:branch".
@@ -221,6 +220,28 @@ URLs that otherwise use git and ssh protocols.</p>
221
220
  <pre><code>$ git config --global hub.protocol https
222
221
  </code></pre>
223
222
 
223
+ <h3 id="GitHub-Enterprise">GitHub Enterprise</h3>
224
+
225
+ <p>By default, hub will only work with repositories that have remotes which
226
+ point to github.com. GitHub Enterprise hosts need to be whitelisted to
227
+ configure hub to treat such remotes same as github.com:</p>
228
+
229
+ <pre><code>$ git config --global --add hub.host my.git.org
230
+ </code></pre>
231
+
232
+ <p>API username and token need also be configured for each Enterprise host:</p>
233
+
234
+ <pre><code>$ git config --global github."my.git.org".user &lt;username>
235
+ $ git config --global github."my.git.org".token &lt;token>
236
+ </code></pre>
237
+
238
+ <p>The default host for commands like <code>init</code> and <code>clone</code> is still
239
+ github.com, but this can be affected with the <var>GITHUB_HOST</var> environment
240
+ variable:</p>
241
+
242
+ <pre><code>$ GITHUB_HOST=my.git.org git clone myproject
243
+ </code></pre>
244
+
224
245
  <h2 id="EXAMPLES">EXAMPLES</h2>
225
246
 
226
247
  <h3 id="git-clone">git clone</h3>
@@ -428,7 +449,7 @@ $ git help hub
428
449
 
429
450
  <ol class='man-decor man-foot man foot'>
430
451
  <li class='tl'>DEFUNKT</li>
431
- <li class='tc'>November 2011</li>
452
+ <li class='tc'>January 2012</li>
432
453
  <li class='tr'>hub(1)</li>
433
454
  </ol>
434
455
 
data/man/hub.1.ronn CHANGED
@@ -132,8 +132,7 @@ hub also adds some custom commands that are otherwise not present in git:
132
132
  adds a new remote for it under your username. Requires `github.token` to
133
133
  be set (see CONFIGURATION).
134
134
 
135
- * `git pull-request` [`-f`] [<TITLE>|`-i` <ISSUE>] [`-b` <BASE>] [`-h` <HEAD>]:
136
- `git pull-request` [`-f`] <ISSUE-URL> [`-h` <HEAD>]
135
+ * `git pull-request` [`-f`] [<TITLE>|`-i` <ISSUE>|<ISSUE-URL>] [`-b` <BASE>] [`-h` <HEAD>]:
137
136
  Opens a pull request on GitHub for the project that the "origin" remote
138
137
  points to. The default head of the pull request is the current branch.
139
138
  Both base and head of the pull request can be explicitly given in one of
@@ -173,6 +172,25 @@ URLs that otherwise use git and ssh protocols.
173
172
 
174
173
  $ git config --global hub.protocol https
175
174
 
175
+ ### GitHub Enterprise
176
+
177
+ By default, hub will only work with repositories that have remotes which
178
+ point to github.com. GitHub Enterprise hosts need to be whitelisted to
179
+ configure hub to treat such remotes same as github.com:
180
+
181
+ $ git config --global --add hub.host my.git.org
182
+
183
+ API username and token need also be configured for each Enterprise host:
184
+
185
+ $ git config --global github."my.git.org".user <username>
186
+ $ git config --global github."my.git.org".token <token>
187
+
188
+ The default host for commands like `init` and `clone` is still
189
+ github.com, but this can be affected with the <GITHUB_HOST> environment
190
+ variable:
191
+
192
+ $ GITHUB_HOST=my.git.org git clone myproject
193
+
176
194
  ## EXAMPLES
177
195
 
178
196
  {{README}}
data/test/hub_test.rb CHANGED
@@ -3,7 +3,6 @@ require 'webmock/test_unit'
3
3
  require 'rbconfig'
4
4
  require 'yaml'
5
5
  require 'forwardable'
6
- require 'json'
7
6
 
8
7
  WebMock::BodyPattern.class_eval do
9
8
  undef normalize_hash
@@ -57,22 +56,26 @@ class HubTest < Test::Unit::TestCase
57
56
  'rev-parse --symbolic-full-name master@{upstream}' => 'refs/remotes/origin/master',
58
57
  'config --get --bool hub.http-clone' => 'false',
59
58
  'config --get hub.protocol' => nil,
59
+ 'config --get-all hub.host' => nil,
60
60
  'rev-parse -q --git-dir' => '.git'
61
61
  end
62
62
 
63
63
  def test_private_clone
64
+ stub_no_git_repo
64
65
  input = "clone -p rtomayko/ronn"
65
66
  command = "git clone git@github.com:rtomayko/ronn.git"
66
67
  assert_command input, command
67
68
  end
68
69
 
69
70
  def test_private_clone_noop
71
+ stub_no_git_repo
70
72
  input = "--noop clone -p rtomayko/ronn"
71
73
  command = "git clone git@github.com:rtomayko/ronn.git\n"
72
74
  assert_output command, hub(input)
73
75
  end
74
76
 
75
77
  def test_https_clone
78
+ stub_no_git_repo
76
79
  stub_https_is_preferred
77
80
  input = "clone rtomayko/ronn"
78
81
  command = "git clone https://github.com/rtomayko/ronn.git"
@@ -80,34 +83,47 @@ class HubTest < Test::Unit::TestCase
80
83
  end
81
84
 
82
85
  def test_public_clone
86
+ stub_no_git_repo
83
87
  input = "clone rtomayko/ronn"
84
88
  command = "git clone git://github.com/rtomayko/ronn.git"
85
89
  assert_command input, command
86
90
  end
87
91
 
88
92
  def test_your_private_clone
93
+ stub_no_git_repo
89
94
  input = "clone -p resque"
90
95
  command = "git clone git@github.com:tpw/resque.git"
91
96
  assert_command input, command
92
97
  end
93
98
 
94
99
  def test_your_clone_is_always_private
100
+ stub_no_git_repo
95
101
  input = "clone resque"
96
102
  command = "git clone git@github.com:tpw/resque.git"
97
103
  assert_command input, command
98
104
  end
99
105
 
106
+ def test_clone_repo_with_period
107
+ stub_no_git_repo
108
+ input = "clone hookio/hook.js"
109
+ command = "git clone git://github.com/hookio/hook.js.git"
110
+ assert_command input, command
111
+ end
112
+
100
113
  def test_clone_with_arguments
114
+ stub_no_git_repo
101
115
  input = "clone --bare -o master resque"
102
116
  command = "git clone --bare -o master git@github.com:tpw/resque.git"
103
117
  assert_command input, command
104
118
  end
105
119
 
106
120
  def test_clone_with_arguments_and_destination
121
+ stub_no_git_repo
107
122
  assert_forwarded "clone --template=one/two git://github.com/tpw/resque.git --origin master resquetastic"
108
123
  end
109
124
 
110
125
  def test_your_private_clone_fails_without_config
126
+ stub_no_git_repo
111
127
  out = hub("clone -p mustache") do
112
128
  stub_github_user(nil)
113
129
  end
@@ -116,6 +132,7 @@ class HubTest < Test::Unit::TestCase
116
132
  end
117
133
 
118
134
  def test_your_public_clone_fails_without_config
135
+ stub_no_git_repo
119
136
  out = hub("clone mustache") do
120
137
  stub_github_user(nil)
121
138
  end
@@ -124,25 +141,39 @@ class HubTest < Test::Unit::TestCase
124
141
  end
125
142
 
126
143
  def test_private_clone_left_alone
144
+ stub_no_git_repo
127
145
  assert_forwarded "clone git@github.com:rtomayko/ronn.git"
128
146
  end
129
147
 
130
148
  def test_public_clone_left_alone
149
+ stub_no_git_repo
131
150
  assert_forwarded "clone git://github.com/rtomayko/ronn.git"
132
151
  end
133
152
 
134
153
  def test_normal_public_clone_with_path
154
+ stub_no_git_repo
135
155
  assert_forwarded "clone git://github.com/rtomayko/ronn.git ronn-dev"
136
156
  end
137
157
 
138
158
  def test_normal_clone_from_path
159
+ stub_no_git_repo
139
160
  assert_forwarded "clone ./test"
140
161
  end
141
162
 
142
163
  def test_clone_with_host_alias
164
+ stub_no_git_repo
143
165
  assert_forwarded "clone server:git/repo.git"
144
166
  end
145
167
 
168
+ def test_enterprise_clone
169
+ stub_no_git_repo
170
+ stub_github_user('myfiname', 'git.my.org')
171
+ with_host_env('git.my.org') do
172
+ assert_command "clone myrepo", "git clone git@git.my.org:myfiname/myrepo.git"
173
+ assert_command "clone another/repo", "git clone git@git.my.org:another/repo.git"
174
+ end
175
+ end
176
+
146
177
  def test_alias_expand
147
178
  stub_alias 'c', 'clone --bare'
148
179
  input = "c rtomayko/ronn"
@@ -168,16 +199,24 @@ class HubTest < Test::Unit::TestCase
168
199
  assert_command input, command
169
200
  end
170
201
 
202
+ def test_remote_add_with_name
203
+ input = "remote add another hookio/hub.js"
204
+ command = "git remote add another git://github.com/hookio/hub.js.git"
205
+ assert_command input, command
206
+ end
207
+
171
208
  def test_private_remote_origin
172
209
  input = "remote add -p origin"
173
210
  command = "git remote add origin git@github.com:tpw/hub.git"
174
211
  assert_command input, command
175
212
  end
176
213
 
177
- def test_public_remote_origin_as_normal
178
- input = "remote add origin http://github.com/defunkt/resque.git"
179
- command = "git remote add origin http://github.com/defunkt/resque.git"
180
- assert_command input, command
214
+ def test_public_remote_url_untouched
215
+ assert_forwarded "remote add origin http://github.com/defunkt/resque.git"
216
+ end
217
+
218
+ def test_private_remote_url_untouched
219
+ assert_forwarded "remote add origin git@github.com:defunkt/resque.git"
181
220
  end
182
221
 
183
222
  def test_remote_from_rel_path
@@ -192,8 +231,10 @@ class HubTest < Test::Unit::TestCase
192
231
  assert_forwarded "remote add origin server:/git/repo.git"
193
232
  end
194
233
 
195
- def test_private_remote_origin_as_normal
196
- assert_forwarded "remote add origin git@github.com:defunkt/resque.git"
234
+ def test_remote_add_enterprise
235
+ stub_hub_host('git.my.org')
236
+ stub_repo_url('git@git.my.org:defunkt/hub.git')
237
+ assert_command "remote add another", "git remote add another git@git.my.org:another/hub.git"
197
238
  end
198
239
 
199
240
  def test_public_submodule
@@ -294,6 +335,29 @@ class HubTest < Test::Unit::TestCase
294
335
  "fetch xoebus"
295
336
  end
296
337
 
338
+ def test_fetch_new_remote_https_protocol
339
+ stub_remotes_group('xoebus', nil)
340
+ stub_existing_fork('xoebus')
341
+ stub_https_is_preferred
342
+
343
+ assert_commands "git remote add xoebus https://github.com/xoebus/hub.git",
344
+ "git fetch xoebus",
345
+ "fetch xoebus"
346
+ end
347
+
348
+ def test_fetch_no_auth
349
+ stub_github_user nil
350
+ stub_github_token nil
351
+ stub_remotes_group('xoebus', nil)
352
+ # stub_existing_fork('xoebus')
353
+ stub_request(:get, "https://github.com/api/v2/yaml/repos/show/xoebus/hub").
354
+ to_return(:status => 200)
355
+
356
+ assert_commands "git remote add xoebus git://github.com/xoebus/hub.git",
357
+ "git fetch xoebus",
358
+ "fetch xoebus"
359
+ end
360
+
297
361
  def test_fetch_new_remote_with_options
298
362
  stub_remotes_group('xoebus', nil)
299
363
  stub_existing_fork('xoebus')
@@ -404,6 +468,13 @@ class HubTest < Test::Unit::TestCase
404
468
  end
405
469
  end
406
470
 
471
+ def test_am_no_tmpdir
472
+ with_tmpdir(nil) do
473
+ cmd = Hub("am https://github.com/defunkt/hub/pull/55").command
474
+ assert_includes '/tmp/55.patch', cmd
475
+ end
476
+ end
477
+
407
478
  def test_am_commit_url
408
479
  with_tmpdir('/tmp/') do
409
480
  url = 'https://github.com/davidbalbert/hub/commit/fdb9921'
@@ -460,9 +531,20 @@ class HubTest < Test::Unit::TestCase
460
531
  end
461
532
 
462
533
  def test_init
534
+ stub_no_remotes
535
+ stub_no_git_repo
463
536
  assert_commands "git init", "git remote add origin git@github.com:tpw/hub.git", "init -g"
464
537
  end
465
538
 
539
+ def test_init_enterprise
540
+ stub_no_remotes
541
+ stub_no_git_repo
542
+ stub_github_user('myfiname', 'git.my.org')
543
+ with_host_env('git.my.org') do
544
+ assert_commands "git init", "git remote add origin git@git.my.org:myfiname/hub.git", "init -g"
545
+ end
546
+ end
547
+
466
548
  def test_init_no_login
467
549
  out = hub("init -g") do
468
550
  stub_github_user(nil)
@@ -528,7 +610,10 @@ class HubTest < Test::Unit::TestCase
528
610
 
529
611
  def test_create_no_openssl
530
612
  stub_no_remotes
531
- stub_nonexisting_fork('tpw')
613
+ # stub_nonexisting_fork('tpw')
614
+ stub_request(:get, "http://#{auth}github.com/api/v2/yaml/repos/show/tpw/hub").
615
+ to_return(:status => 404)
616
+
532
617
  stub_request(:post, "http://#{auth}github.com/api/v2/yaml/repos/create").
533
618
  with(:body => { 'name' => 'hub' })
534
619
 
@@ -555,13 +640,15 @@ class HubTest < Test::Unit::TestCase
555
640
 
556
641
  def test_create_with_env_authentication
557
642
  stub_no_remotes
558
- stub_nonexisting_fork('mojombo')
559
-
560
643
  old_user = ENV['GITHUB_USER']
561
644
  old_token = ENV['GITHUB_TOKEN']
562
645
  ENV['GITHUB_USER'] = 'mojombo'
563
646
  ENV['GITHUB_TOKEN'] = '123abc'
564
647
 
648
+ # stub_nonexisting_fork('mojombo')
649
+ stub_request(:get, "https://#{auth('mojombo', '123abc')}github.com/api/v2/yaml/repos/show/mojombo/hub").
650
+ to_return(:status => 404)
651
+
565
652
  stub_request(:post, "https://#{auth('mojombo', '123abc')}github.com/api/v2/yaml/repos/create").
566
653
  with(:body => { 'name' => 'hub' })
567
654
 
@@ -606,7 +693,7 @@ class HubTest < Test::Unit::TestCase
606
693
  stub_no_remotes
607
694
  stub_existing_fork('tpw')
608
695
 
609
- expected = "tpw/hub already exists on GitHub\n"
696
+ expected = "tpw/hub already exists on github.com\n"
610
697
  expected << "remote add -f origin git@github.com:tpw/hub.git\n"
611
698
  expected << "set remote origin: tpw/hub\n"
612
699
  assert_equal expected, hub("create") { ENV['GIT'] = 'echo' }
@@ -617,7 +704,7 @@ class HubTest < Test::Unit::TestCase
617
704
  stub_existing_fork('tpw')
618
705
  stub_https_is_preferred
619
706
 
620
- expected = "tpw/hub already exists on GitHub\n"
707
+ expected = "tpw/hub already exists on github.com\n"
621
708
  expected << "remote add -f origin https://github.com/tpw/hub.git\n"
622
709
  expected << "set remote origin: tpw/hub\n"
623
710
  assert_equal expected, hub("create") { ENV['GIT'] = 'echo' }
@@ -647,11 +734,33 @@ class HubTest < Test::Unit::TestCase
647
734
 
648
735
  def test_fork
649
736
  stub_nonexisting_fork('tpw')
650
- stub_request(:post, "https://#{auth}github.com/api/v2/yaml/repos/fork/defunkt/hub")
737
+ stub_request(:post, "https://#{auth}github.com/api/v2/yaml/repos/fork/defunkt/hub").
738
+ with { |req| req.headers['Content-Length'] == 0 }
651
739
 
652
740
  expected = "remote add -f tpw git@github.com:tpw/hub.git\n"
653
741
  expected << "new remote: tpw\n"
654
- assert_equal expected, hub("fork") { ENV['GIT'] = 'echo' }
742
+ assert_output expected, "fork"
743
+ end
744
+
745
+ def test_fork_not_in_repo
746
+ stub_no_git_repo
747
+ expected = "fatal: Not a git repository\n"
748
+ assert_output expected, "fork"
749
+ end
750
+
751
+ def test_fork_enterprise
752
+ stub_hub_host('git.my.org')
753
+ stub_repo_url('git@git.my.org:defunkt/hub.git')
754
+ stub_github_user('myfiname', 'git.my.org')
755
+ stub_github_token('789xyz', 'git.my.org')
756
+
757
+ stub_request(:get, "https://#{auth('myfiname', '789xyz')}git.my.org/api/v2/yaml/repos/show/myfiname/hub").
758
+ to_return(:status => 404)
759
+ stub_request(:post, "https://#{auth('myfiname', '789xyz')}git.my.org/api/v2/yaml/repos/fork/defunkt/hub")
760
+
761
+ expected = "remote add -f myfiname git@git.my.org:myfiname/hub.git\n"
762
+ expected << "new remote: myfiname\n"
763
+ assert_output expected, "fork"
655
764
  end
656
765
 
657
766
  def test_fork_failed
@@ -673,7 +782,7 @@ class HubTest < Test::Unit::TestCase
673
782
  def test_fork_already_exists
674
783
  stub_existing_fork('tpw')
675
784
 
676
- expected = "tpw/hub already exists on GitHub\n"
785
+ expected = "tpw/hub already exists on github.com\n"
677
786
  expected << "remote add -f tpw git@github.com:tpw/hub.git\n"
678
787
  expected << "new remote: tpw\n"
679
788
  assert_equal expected, hub("fork") { ENV['GIT'] = 'echo' }
@@ -683,7 +792,7 @@ class HubTest < Test::Unit::TestCase
683
792
  stub_existing_fork('tpw')
684
793
  stub_https_is_preferred
685
794
 
686
- expected = "tpw/hub already exists on GitHub\n"
795
+ expected = "tpw/hub already exists on github.com\n"
687
796
  expected << "remote add -f tpw https://github.com/tpw/hub.git\n"
688
797
  expected << "new remote: tpw\n"
689
798
  assert_equal expected, hub("fork") { ENV['GIT'] = 'echo' }
@@ -708,9 +817,10 @@ class HubTest < Test::Unit::TestCase
708
817
  stub_branch('refs/heads/feature')
709
818
  stub_tracking_nothing('feature')
710
819
 
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))
820
+ stub_request(:post, "https://#{auth}github.com/api/v2/json/pulls/defunkt/hub").
821
+ with(:body => { 'pull' => {'base' => "master", 'head' => "tpw:feature", 'title' => "hereyougo"} }) { |req|
822
+ req.headers['Content-Length'] == 76
823
+ }.to_return(:body => mock_pullreq_response(1))
714
824
 
715
825
  expected = "https://github.com/defunkt/hub/pull/1\n"
716
826
  assert_output expected, "pull-request hereyougo -f"
@@ -721,7 +831,7 @@ class HubTest < Test::Unit::TestCase
721
831
  stub_tracking('feature', 'mislav', 'yay-feature')
722
832
  stub_command_output "rev-list --cherry mislav/master...", nil
723
833
 
724
- stub_request(:post, "https://#{auth}github.com/api/v2/yaml/pulls/defunkt/hub").
834
+ stub_request(:post, "https://#{auth}github.com/api/v2/json/pulls/defunkt/hub").
725
835
  with(:body => { 'pull' => {'base' => "master", 'head' => "mislav:yay-feature", 'title' => "hereyougo"} }).
726
836
  to_return(:body => mock_pullreq_response(1))
727
837
 
@@ -729,8 +839,25 @@ class HubTest < Test::Unit::TestCase
729
839
  assert_output expected, "pull-request hereyougo -f"
730
840
  end
731
841
 
842
+ def test_pullrequest_enterprise_no_tracking
843
+ stub_hub_host('git.my.org')
844
+ stub_repo_url('git@git.my.org:defunkt/hub.git')
845
+ stub_github_user('myfiname', 'git.my.org')
846
+ stub_github_token('789xyz', 'git.my.org')
847
+ stub_branch('refs/heads/feature')
848
+ stub_tracking_nothing('feature')
849
+ stub_command_output "rev-list --cherry origin/feature...", nil
850
+
851
+ stub_request(:post, "https://#{auth('myfiname', '789xyz')}git.my.org/api/v2/json/pulls/defunkt/hub").
852
+ with(:body => { 'pull' => {'base' => "master", 'head' => "myfiname:feature", 'title' => "hereyougo"} }).
853
+ to_return(:body => mock_pullreq_response(1, 'defunkt/hub', 'git.my.org'))
854
+
855
+ expected = "https://git.my.org/defunkt/hub/pull/1\n"
856
+ assert_output expected, "pull-request hereyougo -f"
857
+ end
858
+
732
859
  def test_pullrequest_explicit_head
733
- stub_request(:post, "https://#{auth}github.com/api/v2/yaml/pulls/defunkt/hub").
860
+ stub_request(:post, "https://#{auth}github.com/api/v2/json/pulls/defunkt/hub").
734
861
  with(:body => { 'pull' => {'base' => "master", 'head' => "tpw:yay-feature", 'title' => "hereyougo"} }).
735
862
  to_return(:body => mock_pullreq_response(1))
736
863
 
@@ -739,7 +866,7 @@ class HubTest < Test::Unit::TestCase
739
866
  end
740
867
 
741
868
  def test_pullrequest_explicit_head_with_owner
742
- stub_request(:post, "https://#{auth}github.com/api/v2/yaml/pulls/defunkt/hub").
869
+ stub_request(:post, "https://#{auth}github.com/api/v2/json/pulls/defunkt/hub").
743
870
  with(:body => { 'pull' => {'base' => "master", 'head' => "mojombo:feature", 'title' => "hereyougo"} }).
744
871
  to_return(:body => mock_pullreq_response(1))
745
872
 
@@ -748,7 +875,7 @@ class HubTest < Test::Unit::TestCase
748
875
  end
749
876
 
750
877
  def test_pullrequest_explicit_base
751
- stub_request(:post, "https://#{auth}github.com/api/v2/yaml/pulls/defunkt/hub").
878
+ stub_request(:post, "https://#{auth}github.com/api/v2/json/pulls/defunkt/hub").
752
879
  with(:body => { 'pull' => {'base' => "feature", 'head' => "defunkt:master", 'title' => "hereyougo"} }).
753
880
  to_return(:body => mock_pullreq_response(1))
754
881
 
@@ -757,7 +884,7 @@ class HubTest < Test::Unit::TestCase
757
884
  end
758
885
 
759
886
  def test_pullrequest_explicit_base_with_owner
760
- stub_request(:post, "https://#{auth}github.com/api/v2/yaml/pulls/mojombo/hub").
887
+ stub_request(:post, "https://#{auth}github.com/api/v2/json/pulls/mojombo/hub").
761
888
  with(:body => { 'pull' => {'base' => "feature", 'head' => "defunkt:master", 'title' => "hereyougo"} }).
762
889
  to_return(:body => mock_pullreq_response(1))
763
890
 
@@ -766,7 +893,7 @@ class HubTest < Test::Unit::TestCase
766
893
  end
767
894
 
768
895
  def test_pullrequest_explicit_base_with_repo
769
- stub_request(:post, "https://#{auth}github.com/api/v2/yaml/pulls/mojombo/hubbub").
896
+ stub_request(:post, "https://#{auth}github.com/api/v2/json/pulls/mojombo/hubbub").
770
897
  with(:body => { 'pull' => {'base' => "feature", 'head' => "defunkt:master", 'title' => "hereyougo"} }).
771
898
  to_return(:body => mock_pullreq_response(1))
772
899
 
@@ -779,7 +906,7 @@ class HubTest < Test::Unit::TestCase
779
906
  stub_tracking('myfix', 'mislav', 'awesomefix')
780
907
  stub_command_output "rev-list --cherry mislav/awesomefix...", nil
781
908
 
782
- stub_request(:post, "https://#{auth}github.com/api/v2/yaml/pulls/defunkt/hub").
909
+ stub_request(:post, "https://#{auth}github.com/api/v2/json/pulls/defunkt/hub").
783
910
  with(:body => { 'pull' => {'base' => "master", 'head' => "mislav:awesomefix", 'issue' => '92'} }).
784
911
  to_return(:body => mock_pullreq_response(92))
785
912
 
@@ -792,7 +919,7 @@ class HubTest < Test::Unit::TestCase
792
919
  stub_tracking('myfix', 'mislav', 'awesomefix')
793
920
  stub_command_output "rev-list --cherry mislav/awesomefix...", nil
794
921
 
795
- stub_request(:post, "https://#{auth}github.com/api/v2/yaml/pulls/mojombo/hub").
922
+ stub_request(:post, "https://#{auth}github.com/api/v2/json/pulls/mojombo/hub").
796
923
  with(:body => { 'pull' => {'base' => "master", 'head' => "mislav:awesomefix", 'issue' => '92'} }).
797
924
  to_return(:body => mock_pullreq_response(92, 'mojombo/hub'))
798
925
 
@@ -800,12 +927,23 @@ class HubTest < Test::Unit::TestCase
800
927
  assert_output expected, "pull-request https://github.com/mojombo/hub/issues/92#comment_4"
801
928
  end
802
929
 
930
+ def test_pullrequest_fails
931
+ stub_request(:post, "https://#{auth}github.com/api/v2/json/pulls/defunkt/hub").
932
+ to_return(:status => [422, "Unprocessable Entity"],
933
+ :headers => {"Content-type" => "application/json"},
934
+ :body => %({"error":["oh no!", "it failed."]}))
935
+
936
+ expected = "Error creating pull request: Unprocessable Entity (HTTP 422)\n"
937
+ expected << "oh no!\nit failed.\n"
938
+ assert_output expected, "pull-request hereyougo -b feature -f"
939
+ end
940
+
803
941
  def test_checkout_no_changes
804
942
  assert_forwarded "checkout master"
805
943
  end
806
944
 
807
945
  def test_checkout_pullrequest
808
- stub_request(:get, "http://github.com/api/v2/json/pulls/defunkt/hub/73").
946
+ stub_request(:get, "https://#{auth}github.com/api/v2/json/pulls/defunkt/hub/73").
809
947
  to_return(:body => mock_pull_response('blueyed:feature'))
810
948
 
811
949
  assert_commands 'git remote add -f -t feature blueyed git://github.com/blueyed/hub.git',
@@ -813,8 +951,17 @@ class HubTest < Test::Unit::TestCase
813
951
  "checkout https://github.com/defunkt/hub/pull/73/files"
814
952
  end
815
953
 
954
+ def test_checkout_private_pullrequest
955
+ stub_request(:get, "https://#{auth}github.com/api/v2/json/pulls/defunkt/hub/73").
956
+ to_return(:body => mock_pull_response('blueyed:feature', :private))
957
+
958
+ assert_commands 'git remote add -f -t feature blueyed git@github.com:blueyed/hub.git',
959
+ 'git checkout -b blueyed-feature blueyed/feature',
960
+ "checkout https://github.com/defunkt/hub/pull/73/files"
961
+ end
962
+
816
963
  def test_checkout_pullrequest_custom_branch
817
- stub_request(:get, "http://github.com/api/v2/json/pulls/defunkt/hub/73").
964
+ stub_request(:get, "https://#{auth}github.com/api/v2/json/pulls/defunkt/hub/73").
818
965
  to_return(:body => mock_pull_response('blueyed:feature'))
819
966
 
820
967
  assert_commands 'git remote add -f -t feature blueyed git://github.com/blueyed/hub.git',
@@ -825,7 +972,7 @@ class HubTest < Test::Unit::TestCase
825
972
  def test_checkout_pullrequest_existing_remote
826
973
  stub_command_output 'remote', "origin\nblueyed"
827
974
 
828
- stub_request(:get, "http://github.com/api/v2/json/pulls/defunkt/hub/73").
975
+ stub_request(:get, "https://#{auth}github.com/api/v2/json/pulls/defunkt/hub/73").
829
976
  to_return(:body => mock_pull_response('blueyed:feature'))
830
977
 
831
978
  assert_commands 'git remote set-branches --add blueyed feature',
@@ -991,11 +1138,24 @@ config
991
1138
  "open https://github.com/mislav/hub/commits/experimental"
992
1139
  end
993
1140
 
1141
+ def test_hub_browse_on_complex_branch
1142
+ stub_branch('refs/heads/feature/foo')
1143
+ stub_tracking('feature/foo', 'mislav', 'feature/bar')
1144
+
1145
+ assert_command 'browse',
1146
+ 'open https://github.com/mislav/hub/tree/feature/bar'
1147
+ end
1148
+
994
1149
  def test_hub_browse_current
995
1150
  assert_command "browse", "open https://github.com/defunkt/hub"
996
1151
  assert_command "browse --", "open https://github.com/defunkt/hub"
997
1152
  end
998
1153
 
1154
+ def test_hub_browse_current_https_uri
1155
+ stub_repo_url "https://github.com/defunkt/hub"
1156
+ assert_command "browse", "open https://github.com/defunkt/hub"
1157
+ end
1158
+
999
1159
  def test_hub_browse_commit_from_current
1000
1160
  assert_command "browse -- commit/6616e4", "open https://github.com/defunkt/hub/commit/6616e4"
1001
1161
  end
@@ -1092,14 +1252,16 @@ config
1092
1252
  assert_equal %w[git --bare -c core.awesome=true -c name=value --git-dir=/srv/www], git_reader.executable
1093
1253
  end
1094
1254
 
1095
- protected
1255
+ private
1096
1256
 
1097
- def stub_github_user(name)
1098
- stub_config_value 'github.user', name
1257
+ def stub_github_user(name, host = '')
1258
+ host = %(."#{host}") unless host.empty?
1259
+ stub_config_value "github#{host}.user", name
1099
1260
  end
1100
1261
 
1101
- def stub_github_token(token)
1102
- stub_config_value 'github.token', token
1262
+ def stub_github_token(token, host = '')
1263
+ host = %(."#{host}") unless host.empty?
1264
+ stub_config_value "github#{host}.token", token
1103
1265
  end
1104
1266
 
1105
1267
  def stub_repo_url(value, remote_name = 'origin')
@@ -1144,7 +1306,7 @@ config
1144
1306
  end
1145
1307
 
1146
1308
  def stub_fork(user, repo, status)
1147
- stub_request(:get, "github.com/api/v2/yaml/repos/show/#{user}/#{repo}").
1309
+ stub_request(:get, "https://#{auth}github.com/api/v2/yaml/repos/show/#{user}/#{repo}").
1148
1310
  to_return(:status => status)
1149
1311
  end
1150
1312
 
@@ -1156,6 +1318,10 @@ config
1156
1318
  stub_config_value 'hub.protocol', 'https'
1157
1319
  end
1158
1320
 
1321
+ def stub_hub_host(names)
1322
+ stub_config_value "hub.host", Array(names).join("\n"), '--get-all'
1323
+ end
1324
+
1159
1325
  def with_browser_env(value)
1160
1326
  browser, ENV['BROWSER'] = ENV['BROWSER'], value
1161
1327
  yield
@@ -1170,6 +1336,13 @@ config
1170
1336
  ENV['TMPDIR'] = dir
1171
1337
  end
1172
1338
 
1339
+ def with_host_env(value)
1340
+ host, ENV['GITHUB_HOST'] = ENV['GITHUB_HOST'], value
1341
+ yield
1342
+ ensure
1343
+ ENV['GITHUB_HOST'] = host
1344
+ end
1345
+
1173
1346
  def assert_browser(browser)
1174
1347
  assert_command "browse", "#{browser} https://github.com/defunkt/hub"
1175
1348
  end
@@ -1188,14 +1361,12 @@ config
1188
1361
  "#{user}%2Ftoken:#{password}@"
1189
1362
  end
1190
1363
 
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
- })
1364
+ def mock_pullreq_response(id, name_with_owner = 'defunkt/hub', host = 'github.com')
1365
+ %({"pull": { "html_url": "https://#{host}/#{name_with_owner}/pull/#{id}" }})
1195
1366
  end
1196
1367
 
1197
- def mock_pull_response(label)
1198
- JSON.generate('pull' => { 'head' => {'label' => label} })
1368
+ def mock_pull_response(label, priv = false)
1369
+ %({"pull": { "head": { "label": "#{label}", "repository": {"private":#{!!priv}} }}})
1199
1370
  end
1200
1371
 
1201
1372
  def improved_help_text