hub 1.9.0 → 1.10.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/HISTORY.md +12 -0
- data/README.md +11 -5
- data/lib/hub/commands.rb +48 -17
- data/lib/hub/context.rb +11 -5
- data/lib/hub/github_api.rb +33 -10
- data/lib/hub/version.rb +1 -1
- data/man/hub.1 +22 -5
- data/man/hub.1.html +15 -5
- data/man/hub.1.ronn +5 -0
- data/test/hub_test.rb +1 -260
- metadata +6 -7
- data/test/alias_test.rb +0 -59
data/HISTORY.md
CHANGED
@@ -1,3 +1,15 @@
|
|
1
|
+
## master
|
2
|
+
|
3
|
+
* fix GitHub username prompt in `create` command
|
4
|
+
* make `fetch` command work with private repos too
|
5
|
+
* add `merge` command to merge pull requests
|
6
|
+
|
7
|
+
## 1.9.0 (2012-05-04)
|
8
|
+
|
9
|
+
* internal refactoring and code reorganization
|
10
|
+
* switch to GitHub API v3 and authenticate via OAuth
|
11
|
+
* auth info is now stored in ~/.config/hub instead of ~/.gitconfig
|
12
|
+
|
1
13
|
## 1.8.4 (2012-03-20)
|
2
14
|
|
3
15
|
* add bash, zsh completion
|
data/README.md
CHANGED
@@ -206,11 +206,17 @@ superpowers:
|
|
206
206
|
|
207
207
|
### git checkout
|
208
208
|
|
209
|
-
|
210
|
-
|
211
|
-
|
209
|
+
$ git checkout https://github.com/defunkt/hub/pull/73
|
210
|
+
> git remote add -f -t feature git://github:com/mislav/hub.git
|
211
|
+
> git checkout --track -B mislav-feature mislav/feature
|
212
212
|
|
213
|
-
|
213
|
+
$ git checkout https://github.com/defunkt/hub/pull/73 custom-branch-name
|
214
|
+
|
215
|
+
### git merge
|
216
|
+
|
217
|
+
$ git merge https://github.com/defunkt/hub/pull/73
|
218
|
+
> git fetch git://github.com/mislav/hub.git +refs/heads/feature:refs/remotes/mislav/feature
|
219
|
+
> git merge mislav/feature --no-ff -m 'Merge pull request #73 from mislav/feature...'
|
214
220
|
|
215
221
|
### git create
|
216
222
|
|
@@ -307,7 +313,7 @@ Configuration
|
|
307
313
|
Hub will prompt for GitHub username & password the first time it needs to access
|
308
314
|
the API and exchange it for an OAuth token, which it saves in "~/.config/hub".
|
309
315
|
|
310
|
-
### HTTPS
|
316
|
+
### HTTPS instead of git protocol
|
311
317
|
|
312
318
|
If you prefer using the HTTPS protocol for GitHub repositories instead of the git
|
313
319
|
protocol for read and ssh for write, you can set "hub.protocol" to "https".
|
data/lib/hub/commands.rb
CHANGED
@@ -55,7 +55,7 @@ module Hub
|
|
55
55
|
respect_help_flags(expanded_args || args) if custom_command? cmd
|
56
56
|
|
57
57
|
# git commands can have dashes
|
58
|
-
cmd = cmd.
|
58
|
+
cmd = cmd.gsub(/(\w)-/, '\1_')
|
59
59
|
if method_defined?(cmd) and cmd != 'run'
|
60
60
|
args.replace expanded_args if expanded_args
|
61
61
|
send(cmd, args)
|
@@ -213,12 +213,10 @@ module Hub
|
|
213
213
|
# $ hub clone rtomayko/tilt
|
214
214
|
# $ hub clone tilt
|
215
215
|
if arg =~ NAME_WITH_OWNER_RE and !File.directory?(arg)
|
216
|
-
# FIXME: this logic shouldn't be duplicated here!
|
217
216
|
name, owner = arg, nil
|
218
217
|
owner, name = name.split('/', 2) if name.index('/')
|
219
|
-
|
220
|
-
|
221
|
-
ssh ||= args[0] != 'submodule' && project.owner == github_user(host) || host != 'github.com'
|
218
|
+
project = github_project(name, owner || github_user)
|
219
|
+
ssh ||= args[0] != 'submodule' && project.owner == github_user(project.host) { }
|
222
220
|
args[idx] = project.git_url(:private => ssh, :https => https_protocol?)
|
223
221
|
end
|
224
222
|
break
|
@@ -321,7 +319,11 @@ module Hub
|
|
321
319
|
projects = names.map { |name|
|
322
320
|
unless name =~ /\W/ or remotes.include?(name) or remotes_group(name)
|
323
321
|
project = github_project(nil, name)
|
324
|
-
|
322
|
+
repo_info = api_client.repo_info(project)
|
323
|
+
if repo_info.success?
|
324
|
+
project.repo_data = repo_info.data
|
325
|
+
project
|
326
|
+
end
|
325
327
|
end
|
326
328
|
}.compact
|
327
329
|
|
@@ -360,6 +362,31 @@ module Hub
|
|
360
362
|
end
|
361
363
|
end
|
362
364
|
|
365
|
+
# $ git merge https://github.com/defunkt/hub/pull/73
|
366
|
+
# > git fetch git://github.com/mislav/hub.git +refs/heads/feature:refs/remotes/mislav/feature
|
367
|
+
# > git merge mislav/feature --no-ff -m 'Merge pull request #73 from mislav/feature...'
|
368
|
+
def merge(args)
|
369
|
+
_, url_arg = args.words
|
370
|
+
if url = resolve_github_url(url_arg) and url.project_path =~ /^pull\/(\d+)/
|
371
|
+
pull_id = $1
|
372
|
+
pull_data = api_client.pullrequest_info(url.project, pull_id)
|
373
|
+
|
374
|
+
user, branch = pull_data['head']['label'].split(':', 2)
|
375
|
+
abort "Error: #{user}'s fork is not available anymore" unless pull_data['head']['repo']
|
376
|
+
|
377
|
+
url = github_project(url.project_name, user).git_url(:private => pull_data['head']['repo']['private'],
|
378
|
+
:https => https_protocol?)
|
379
|
+
|
380
|
+
merge_head = "#{user}/#{branch}"
|
381
|
+
args.before ['fetch', url, "+refs/heads/#{branch}:refs/remotes/#{merge_head}"]
|
382
|
+
|
383
|
+
idx = args.index url_arg
|
384
|
+
args.delete_at idx
|
385
|
+
args.insert idx, merge_head, '--no-ff', '-m',
|
386
|
+
"Merge pull request ##{pull_id} from #{merge_head}\n\n#{pull_data['title']}"
|
387
|
+
end
|
388
|
+
end
|
389
|
+
|
363
390
|
# $ git cherry-pick http://github.com/mislav/hub/commit/a319d88#comments
|
364
391
|
# > git remote add -f mislav git://github.com/mislav/hub.git
|
365
392
|
# > git cherry-pick a319d88
|
@@ -423,10 +450,7 @@ module Hub
|
|
423
450
|
# > git remote add origin git@github.com:USER/REPO.git
|
424
451
|
def init(args)
|
425
452
|
if args.delete('-g')
|
426
|
-
|
427
|
-
# FIXME: this shouldn't be here!
|
428
|
-
host = ENV['GITHUB_HOST'] || 'github.com'
|
429
|
-
project = Context::GithubProject.new(nil, github_user(host), File.basename(current_dir), host)
|
453
|
+
project = github_project(File.basename(current_dir))
|
430
454
|
url = project.git_url(:private => true, :https => https_protocol?)
|
431
455
|
args.after ['remote', 'add', 'origin', url]
|
432
456
|
end
|
@@ -466,7 +490,8 @@ module Hub
|
|
466
490
|
def create(args)
|
467
491
|
if !is_repo?
|
468
492
|
abort "'create' must be run from inside a git repository"
|
469
|
-
|
493
|
+
else
|
494
|
+
owner = github_user
|
470
495
|
args.shift
|
471
496
|
options = {}
|
472
497
|
options[:private] = true if args.delete('-p')
|
@@ -702,10 +727,9 @@ module Hub
|
|
702
727
|
end
|
703
728
|
end
|
704
729
|
|
705
|
-
def github_user host = nil
|
706
|
-
host ||= local_repo(false)
|
707
|
-
|
708
|
-
api_client.config.username(host) { }
|
730
|
+
def github_user host = nil, &block
|
731
|
+
host ||= (local_repo(false) || Context::LocalRepo).default_host
|
732
|
+
api_client.config.username(host, &block)
|
709
733
|
end
|
710
734
|
|
711
735
|
def custom_command? cmd
|
@@ -768,12 +792,19 @@ Remote Commands:
|
|
768
792
|
push Upload data, tags and branches to a remote repository
|
769
793
|
remote View and manage a set of remote repositories
|
770
794
|
|
771
|
-
Advanced
|
795
|
+
Advanced Commands:
|
772
796
|
reset Reset your staging area or working directory to another point
|
773
797
|
rebase Re-apply a series of patches in one branch onto another
|
774
798
|
bisect Find by binary search the change that introduced a bug
|
775
799
|
grep Print files with lines matching a pattern in your codebase
|
776
800
|
|
801
|
+
GitHub Commands:
|
802
|
+
pull-request Open a pull request on GitHub
|
803
|
+
fork Make a fork of a remote repository on GitHub and add as remote
|
804
|
+
create Create this repository on GitHub and add GitHub as origin
|
805
|
+
browse Open a GitHub page in the default browser
|
806
|
+
compare Open a compare page on GitHub
|
807
|
+
|
777
808
|
See 'git help <command>' for more information on a specific command.
|
778
809
|
help
|
779
810
|
end
|
@@ -944,7 +975,7 @@ help
|
|
944
975
|
title.tr!("\n", ' ')
|
945
976
|
title.strip!
|
946
977
|
body.strip!
|
947
|
-
|
978
|
+
|
948
979
|
[title =~ /\S/ ? title : nil, body =~ /\S/ ? body : nil]
|
949
980
|
end
|
950
981
|
|
data/lib/hub/context.rb
CHANGED
@@ -179,14 +179,17 @@ module Hub
|
|
179
179
|
git_config('hub.host', :all).to_s.split("\n") + [default_host]
|
180
180
|
end
|
181
181
|
|
182
|
-
def default_host
|
182
|
+
def self.default_host
|
183
183
|
ENV['GITHUB_HOST'] || main_host
|
184
184
|
end
|
185
185
|
|
186
|
-
def main_host
|
186
|
+
def self.main_host
|
187
187
|
'github.com'
|
188
188
|
end
|
189
189
|
|
190
|
+
extend Forwardable
|
191
|
+
def_delegators :'self.class', :default_host, :main_host
|
192
|
+
|
190
193
|
def ssh_config
|
191
194
|
@ssh_config ||= SshConfig.new
|
192
195
|
end
|
@@ -200,13 +203,16 @@ module Hub
|
|
200
203
|
end
|
201
204
|
end
|
202
205
|
|
206
|
+
attr_accessor :repo_data
|
207
|
+
|
203
208
|
def initialize(*args)
|
204
209
|
super
|
205
|
-
self.host ||= local_repo.default_host
|
210
|
+
self.host ||= (local_repo || LocalRepo).default_host
|
206
211
|
end
|
207
212
|
|
208
213
|
def private?
|
209
|
-
|
214
|
+
repo_data ? repo_data.fetch('private') :
|
215
|
+
host != (local_repo || LocalRepo).main_host
|
210
216
|
end
|
211
217
|
|
212
218
|
def owned_by(new_owner)
|
@@ -357,7 +363,7 @@ module Hub
|
|
357
363
|
project.name = name
|
358
364
|
project
|
359
365
|
else
|
360
|
-
GithubProject.new(local_repo, owner, name)
|
366
|
+
GithubProject.new(local_repo(false), owner, name)
|
361
367
|
end
|
362
368
|
end
|
363
369
|
|
data/lib/hub/github_api.rb
CHANGED
@@ -46,11 +46,15 @@ module Hub
|
|
46
46
|
'github.com' == host ? 'api.github.com' : host
|
47
47
|
end
|
48
48
|
|
49
|
-
# Public:
|
50
|
-
def
|
51
|
-
|
49
|
+
# Public: Fetch data for a specific repo.
|
50
|
+
def repo_info project
|
51
|
+
get "https://%s/repos/%s/%s" %
|
52
52
|
[api_host(project.host), project.owner, project.name]
|
53
|
-
|
53
|
+
end
|
54
|
+
|
55
|
+
# Public: Determine whether a specific repo exists.
|
56
|
+
def repo_exists? project
|
57
|
+
repo_info(project).success?
|
54
58
|
end
|
55
59
|
|
56
60
|
# Public: Fork the specified repo.
|
@@ -147,11 +151,14 @@ module Hub
|
|
147
151
|
end
|
148
152
|
|
149
153
|
def perform_request url, type
|
150
|
-
url = URI.parse url unless url.respond_to? :
|
154
|
+
url = URI.parse url unless url.respond_to? :host
|
151
155
|
|
152
156
|
require 'net/https'
|
153
157
|
req = Net::HTTP.const_get(type).new(url.request_uri)
|
154
|
-
|
158
|
+
# TODO: better naming?
|
159
|
+
http = configure_connection(req, url) do |host_url|
|
160
|
+
create_connection host_url
|
161
|
+
end
|
155
162
|
|
156
163
|
apply_authentication(req, url)
|
157
164
|
yield req if block_given?
|
@@ -162,6 +169,17 @@ module Hub
|
|
162
169
|
raise Context::FatalError, "error with #{type.to_s.upcase} #{url} (#{err.message})"
|
163
170
|
end
|
164
171
|
|
172
|
+
def configure_connection req, url
|
173
|
+
if ENV['HUB_TEST_HOST']
|
174
|
+
req['Host'] = url.host
|
175
|
+
url = url.dup
|
176
|
+
url.scheme = 'http'
|
177
|
+
url.host, test_port = ENV['HUB_TEST_HOST'].split(':')
|
178
|
+
url.port = test_port.to_i if test_port
|
179
|
+
end
|
180
|
+
yield url
|
181
|
+
end
|
182
|
+
|
165
183
|
def apply_authentication req, url
|
166
184
|
user = url.user || config.username(url.host)
|
167
185
|
pass = config.password(url.host, user)
|
@@ -325,9 +343,14 @@ module Hub
|
|
325
343
|
# special prompt that has hidden input
|
326
344
|
def prompt_password host, user
|
327
345
|
print "#{host} password for #{user} (never stored): "
|
328
|
-
|
329
|
-
|
330
|
-
|
346
|
+
if $stdin.tty?
|
347
|
+
password = askpass
|
348
|
+
puts ''
|
349
|
+
password
|
350
|
+
else
|
351
|
+
# in testing
|
352
|
+
$stdin.gets.chomp
|
353
|
+
end
|
331
354
|
end
|
332
355
|
|
333
356
|
# FIXME: probably not cross-platform
|
@@ -349,7 +372,7 @@ module Hub
|
|
349
372
|
|
350
373
|
def proxy_uri(with_ssl)
|
351
374
|
env_name = "HTTP#{with_ssl ? 'S' : ''}_PROXY"
|
352
|
-
if proxy = ENV[env_name] || ENV[env_name.downcase]
|
375
|
+
if proxy = ENV[env_name] || ENV[env_name.downcase] and !proxy.empty?
|
353
376
|
proxy = "http://#{proxy}" unless proxy.include? '://'
|
354
377
|
URI.parse proxy
|
355
378
|
end
|
data/lib/hub/version.rb
CHANGED
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" "
|
4
|
+
.TH "HUB" "1" "May 2012" "DEFUNKT" "Git Manual"
|
5
5
|
.
|
6
6
|
.SH "NAME"
|
7
7
|
\fBhub\fR \- git + hub = github
|
@@ -31,6 +31,9 @@
|
|
31
31
|
\fBgit checkout\fR \fIPULLREQ\-URL\fR [\fIBRANCH\fR]
|
32
32
|
.
|
33
33
|
.br
|
34
|
+
\fBgit merge\fR \fIPULLREQ\-URL\fR
|
35
|
+
.
|
36
|
+
.br
|
34
37
|
\fBgit cherry\-pick\fR \fIGITHUB\-REF\fR
|
35
38
|
.
|
36
39
|
.br
|
@@ -96,6 +99,10 @@ Adds missing remote(s) with \fBgit remote add\fR prior to fetching\. New remotes
|
|
96
99
|
Checks out the head of the pull request as a local branch, to allow for reviewing, rebasing and otherwise cleaning up the commits in the pull request before merging\. The name of the local branch can explicitly be set with \fIBRANCH\fR\.
|
97
100
|
.
|
98
101
|
.TP
|
102
|
+
\fBgit merge\fR \fIPULLREQ\-URL\fR
|
103
|
+
Merge the pull request with a commit message that includes the pull request ID and title, similar to the GitHub Merge Button\.
|
104
|
+
.
|
105
|
+
.TP
|
99
106
|
\fBgit cherry\-pick\fR \fIGITHUB\-REF\fR
|
100
107
|
Cherry\-pick a commit from a fork using either full URL to the commit or GitHub\-flavored Markdown notation, which is \fBuser@sha\fR\. If the remote doesn\'t yet exist, it will be added\. A \fBgit fetch <user>\fR is issued prior to the cherry\-pick attempt\.
|
101
108
|
.
|
@@ -300,11 +307,21 @@ $ git pull\-request \-i 123
|
|
300
307
|
.
|
301
308
|
.nf
|
302
309
|
|
303
|
-
|
304
|
-
|
305
|
-
|
310
|
+
$ git checkout https://github\.com/defunkt/hub/pull/73
|
311
|
+
> git remote add \-f \-t feature git://github:com/mislav/hub\.git
|
312
|
+
> git checkout \-\-track \-B mislav\-feature mislav/feature
|
313
|
+
|
314
|
+
$ git checkout https://github\.com/defunkt/hub/pull/73 custom\-branch\-name
|
315
|
+
.
|
316
|
+
.fi
|
317
|
+
.
|
318
|
+
.SS "git merge"
|
319
|
+
.
|
320
|
+
.nf
|
306
321
|
|
307
|
-
|
322
|
+
$ git merge https://github\.com/defunkt/hub/pull/73
|
323
|
+
> git fetch git://github\.com/mislav/hub\.git +refs/heads/feature:refs/remotes/mislav/feature
|
324
|
+
> git merge mislav/feature \-\-no\-ff \-m \'Merge pull request #73 from mislav/feature\.\.\.\'
|
308
325
|
.
|
309
326
|
.fi
|
310
327
|
.
|
data/man/hub.1.html
CHANGED
@@ -87,6 +87,7 @@
|
|
87
87
|
<code>git remote set-url</code> [<code>-p</code>] <var>OPTIONS</var> <var>REMOTE-NAME</var> <var>USER</var>[/<var>REPOSITORY</var>]<br />
|
88
88
|
<code>git fetch</code> <var>USER-1</var>,[<var>USER-2</var>,...]<br />
|
89
89
|
<code>git checkout</code> <var>PULLREQ-URL</var> [<var>BRANCH</var>]<br />
|
90
|
+
<code>git merge</code> <var>PULLREQ-URL</var><br />
|
90
91
|
<code>git cherry-pick</code> <var>GITHUB-REF</var><br />
|
91
92
|
<code>git am</code> <var>GITHUB-URL</var><br />
|
92
93
|
<code>git apply</code> <var>GITHUB-URL</var><br />
|
@@ -131,6 +132,8 @@ remotes are only added if they correspond to valid forks on GitHub.</p></dd>
|
|
131
132
|
reviewing, rebasing and otherwise cleaning up the commits in the pull
|
132
133
|
request before merging. The name of the local branch can explicitly be
|
133
134
|
set with <var>BRANCH</var>.</p></dd>
|
135
|
+
<dt><code>git merge</code> <var>PULLREQ-URL</var></dt><dd><p>Merge the pull request with a commit message that includes the pull request
|
136
|
+
ID and title, similar to the GitHub Merge Button.</p></dd>
|
134
137
|
<dt><code>git cherry-pick</code> <var>GITHUB-REF</var></dt><dd><p>Cherry-pick a commit from a fork using either full URL to the commit
|
135
138
|
or GitHub-flavored Markdown notation, which is <code>user@sha</code>. If the remote
|
136
139
|
doesn't yet exist, it will be added. A <code>git fetch <user></code> is issued
|
@@ -311,11 +314,18 @@ $ git pull-request -i 123
|
|
311
314
|
|
312
315
|
<h3 id="git-checkout">git checkout</h3>
|
313
316
|
|
314
|
-
<pre><code
|
315
|
-
|
316
|
-
|
317
|
+
<pre><code>$ git checkout https://github.com/defunkt/hub/pull/73
|
318
|
+
> git remote add -f -t feature git://github:com/mislav/hub.git
|
319
|
+
> git checkout --track -B mislav-feature mislav/feature
|
317
320
|
|
318
|
-
|
321
|
+
$ git checkout https://github.com/defunkt/hub/pull/73 custom-branch-name
|
322
|
+
</code></pre>
|
323
|
+
|
324
|
+
<h3 id="git-merge">git merge</h3>
|
325
|
+
|
326
|
+
<pre><code>$ git merge https://github.com/defunkt/hub/pull/73
|
327
|
+
> git fetch git://github.com/mislav/hub.git +refs/heads/feature:refs/remotes/mislav/feature
|
328
|
+
> git merge mislav/feature --no-ff -m 'Merge pull request #73 from mislav/feature...'
|
319
329
|
</code></pre>
|
320
330
|
|
321
331
|
<h3 id="git-create">git create</h3>
|
@@ -427,7 +437,7 @@ $ git help hub
|
|
427
437
|
|
428
438
|
<ol class='man-decor man-foot man foot'>
|
429
439
|
<li class='tl'>DEFUNKT</li>
|
430
|
-
<li class='tc'>
|
440
|
+
<li class='tc'>May 2012</li>
|
431
441
|
<li class='tr'>hub(1)</li>
|
432
442
|
</ol>
|
433
443
|
|
data/man/hub.1.ronn
CHANGED
@@ -14,6 +14,7 @@ hub(1) -- git + hub = github
|
|
14
14
|
`git remote set-url` [`-p`] <OPTIONS> <REMOTE-NAME> <USER>[/<REPOSITORY>]
|
15
15
|
`git fetch` <USER-1>,[<USER-2>,...]
|
16
16
|
`git checkout` <PULLREQ-URL> [<BRANCH>]
|
17
|
+
`git merge` <PULLREQ-URL>
|
17
18
|
`git cherry-pick` <GITHUB-REF>
|
18
19
|
`git am` <GITHUB-URL>
|
19
20
|
`git apply` <GITHUB-URL>
|
@@ -73,6 +74,10 @@ hub enhances various git commands to ease most common workflows with GitHub.
|
|
73
74
|
request before merging. The name of the local branch can explicitly be
|
74
75
|
set with <BRANCH>.
|
75
76
|
|
77
|
+
* `git merge` <PULLREQ-URL>:
|
78
|
+
Merge the pull request with a commit message that includes the pull request
|
79
|
+
ID and title, similar to the GitHub Merge Button.
|
80
|
+
|
76
81
|
* `git cherry-pick` <GITHUB-REF>:
|
77
82
|
Cherry-pick a commit from a fork using either full URL to the commit
|
78
83
|
or GitHub-flavored Markdown notation, which is `user@sha`. If the remote
|
data/test/hub_test.rb
CHANGED
@@ -82,79 +82,6 @@ class HubTest < Test::Unit::TestCase
|
|
82
82
|
'rev-parse -q --git-dir' => '.git'
|
83
83
|
end
|
84
84
|
|
85
|
-
def test_fetch_existing_remote
|
86
|
-
assert_forwarded "fetch mislav"
|
87
|
-
end
|
88
|
-
|
89
|
-
def test_fetch_new_remote
|
90
|
-
stub_remotes_group('xoebus', nil)
|
91
|
-
stub_existing_fork('xoebus')
|
92
|
-
|
93
|
-
assert_commands "git remote add xoebus git://github.com/xoebus/hub.git",
|
94
|
-
"git fetch xoebus",
|
95
|
-
"fetch xoebus"
|
96
|
-
end
|
97
|
-
|
98
|
-
def test_fetch_new_remote_https_protocol
|
99
|
-
stub_remotes_group('xoebus', nil)
|
100
|
-
stub_existing_fork('xoebus')
|
101
|
-
stub_https_is_preferred
|
102
|
-
|
103
|
-
assert_commands "git remote add xoebus https://github.com/xoebus/hub.git",
|
104
|
-
"git fetch xoebus",
|
105
|
-
"fetch xoebus"
|
106
|
-
end
|
107
|
-
|
108
|
-
def test_fetch_new_remote_with_options
|
109
|
-
stub_remotes_group('xoebus', nil)
|
110
|
-
stub_existing_fork('xoebus')
|
111
|
-
|
112
|
-
assert_commands "git remote add xoebus git://github.com/xoebus/hub.git",
|
113
|
-
"git fetch --depth=1 --prune xoebus",
|
114
|
-
"fetch --depth=1 --prune xoebus"
|
115
|
-
end
|
116
|
-
|
117
|
-
def test_fetch_multiple_new_remotes
|
118
|
-
stub_remotes_group('xoebus', nil)
|
119
|
-
stub_remotes_group('rtomayko', nil)
|
120
|
-
stub_existing_fork('xoebus')
|
121
|
-
stub_existing_fork('rtomayko')
|
122
|
-
|
123
|
-
assert_commands "git remote add xoebus git://github.com/xoebus/hub.git",
|
124
|
-
"git remote add rtomayko git://github.com/rtomayko/hub.git",
|
125
|
-
"git fetch --multiple xoebus rtomayko",
|
126
|
-
"fetch --multiple xoebus rtomayko"
|
127
|
-
end
|
128
|
-
|
129
|
-
def test_fetch_multiple_comma_separated_remotes
|
130
|
-
stub_remotes_group('xoebus', nil)
|
131
|
-
stub_remotes_group('rtomayko', nil)
|
132
|
-
stub_existing_fork('xoebus')
|
133
|
-
stub_existing_fork('rtomayko')
|
134
|
-
|
135
|
-
assert_commands "git remote add xoebus git://github.com/xoebus/hub.git",
|
136
|
-
"git remote add rtomayko git://github.com/rtomayko/hub.git",
|
137
|
-
"git fetch --multiple xoebus rtomayko",
|
138
|
-
"fetch xoebus,rtomayko"
|
139
|
-
end
|
140
|
-
|
141
|
-
def test_fetch_multiple_new_remotes_with_filtering
|
142
|
-
stub_remotes_group('xoebus', nil)
|
143
|
-
stub_remotes_group('mygrp', 'one two')
|
144
|
-
stub_remotes_group('typo', nil)
|
145
|
-
stub_existing_fork('xoebus')
|
146
|
-
stub_nonexisting_fork('typo')
|
147
|
-
|
148
|
-
# mislav: existing remote; skipped
|
149
|
-
# xoebus: new remote, fork exists; added
|
150
|
-
# mygrp: a remotes group; skipped
|
151
|
-
# URL: can't be a username; skipped
|
152
|
-
# typo: fork doesn't exist; skipped
|
153
|
-
assert_commands "git remote add xoebus git://github.com/xoebus/hub.git",
|
154
|
-
"git fetch --multiple mislav xoebus mygrp git://example.com typo",
|
155
|
-
"fetch --multiple mislav xoebus mygrp git://example.com typo"
|
156
|
-
end
|
157
|
-
|
158
85
|
def test_cherry_pick
|
159
86
|
assert_forwarded "cherry-pick a319d88"
|
160
87
|
end
|
@@ -317,192 +244,6 @@ class HubTest < Test::Unit::TestCase
|
|
317
244
|
"push origin,staging,qa cool-feature"
|
318
245
|
end
|
319
246
|
|
320
|
-
def test_create
|
321
|
-
stub_no_remotes
|
322
|
-
stub_nonexisting_fork('tpw')
|
323
|
-
stub_request(:post, "https://api.github.com/user/repos").
|
324
|
-
with(:body => { 'name' => 'hub', 'private' => false })
|
325
|
-
|
326
|
-
expected = "remote add -f origin git@github.com:tpw/hub.git\n"
|
327
|
-
expected << "created repository: tpw/hub\n"
|
328
|
-
assert_equal expected, hub("create") { ENV['GIT'] = 'echo' }
|
329
|
-
end
|
330
|
-
|
331
|
-
def test_create_custom_name
|
332
|
-
stub_no_remotes
|
333
|
-
stub_nonexisting_fork('tpw', 'hubbub')
|
334
|
-
stub_request(:post, "https://api.github.com/user/repos").
|
335
|
-
with(:body => { 'name' => 'hubbub', 'private' => false })
|
336
|
-
|
337
|
-
expected = "remote add -f origin git@github.com:tpw/hubbub.git\n"
|
338
|
-
expected << "created repository: tpw/hubbub\n"
|
339
|
-
assert_equal expected, hub("create hubbub") { ENV['GIT'] = 'echo' }
|
340
|
-
end
|
341
|
-
|
342
|
-
def test_create_in_organization
|
343
|
-
stub_no_remotes
|
344
|
-
stub_nonexisting_fork('acme', 'hubbub')
|
345
|
-
stub_request(:post, "https://api.github.com/orgs/acme/repos").
|
346
|
-
with(:body => { 'name' => 'hubbub', 'private' => false })
|
347
|
-
|
348
|
-
expected = "remote add -f origin git@github.com:acme/hubbub.git\n"
|
349
|
-
expected << "created repository: acme/hubbub\n"
|
350
|
-
assert_equal expected, hub("create acme/hubbub") { ENV['GIT'] = 'echo' }
|
351
|
-
end
|
352
|
-
|
353
|
-
def test_create_failed
|
354
|
-
stub_no_remotes
|
355
|
-
stub_nonexisting_fork('tpw')
|
356
|
-
stub_request(:post, "https://api.github.com/user/repos").
|
357
|
-
to_return(:status => [401, "Your token is fail"])
|
358
|
-
|
359
|
-
expected = "Error creating repository: Your token is fail (HTTP 401)\n"
|
360
|
-
assert_equal expected, hub("create") { ENV['GIT'] = 'echo' }
|
361
|
-
end
|
362
|
-
|
363
|
-
def test_create_private_repository
|
364
|
-
stub_no_remotes
|
365
|
-
stub_nonexisting_fork('tpw')
|
366
|
-
stub_request(:post, "https://api.github.com/user/repos").
|
367
|
-
with(:body => { 'name' => 'hub', 'private' => true })
|
368
|
-
|
369
|
-
expected = "remote add -f origin git@github.com:tpw/hub.git\n"
|
370
|
-
expected << "created repository: tpw/hub\n"
|
371
|
-
assert_equal expected, hub("create -p") { ENV['GIT'] = 'echo' }
|
372
|
-
end
|
373
|
-
|
374
|
-
def test_create_private_repository_fails
|
375
|
-
stub_no_remotes
|
376
|
-
stub_nonexisting_fork('tpw')
|
377
|
-
stub_request(:post, "https://api.github.com/user/repos").
|
378
|
-
to_return(:status => [422, "Unprocessable Entity"],
|
379
|
-
:headers => {"Content-type" => "application/json"},
|
380
|
-
:body => %({"message":"repository creation failed: You are over your quota."}))
|
381
|
-
|
382
|
-
expected = "Error creating repository: Unprocessable Entity (HTTP 422)\n"
|
383
|
-
expected << "repository creation failed: You are over your quota.\n"
|
384
|
-
assert_equal expected, hub("create -p") { ENV['GIT'] = 'echo' }
|
385
|
-
end
|
386
|
-
|
387
|
-
def test_create_with_description_and_homepage
|
388
|
-
stub_no_remotes
|
389
|
-
stub_nonexisting_fork('tpw')
|
390
|
-
stub_request(:post, "https://api.github.com/user/repos").with(:body => {
|
391
|
-
'name' => 'hub', 'private' => false,
|
392
|
-
'description' => 'toyproject', 'homepage' => 'http://example.com'
|
393
|
-
})
|
394
|
-
|
395
|
-
expected = "remote add -f origin git@github.com:tpw/hub.git\n"
|
396
|
-
expected << "created repository: tpw/hub\n"
|
397
|
-
assert_equal expected, hub("create -d toyproject -h http://example.com") { ENV['GIT'] = 'echo' }
|
398
|
-
end
|
399
|
-
|
400
|
-
def test_create_with_invalid_arguments
|
401
|
-
assert_equal "invalid argument: -a\n", hub("create -a blah") { ENV['GIT'] = 'echo' }
|
402
|
-
assert_equal "invalid argument: bleh\n", hub("create blah bleh") { ENV['GIT'] = 'echo' }
|
403
|
-
end
|
404
|
-
|
405
|
-
def test_create_with_existing_repository
|
406
|
-
stub_no_remotes
|
407
|
-
stub_existing_fork('tpw')
|
408
|
-
|
409
|
-
expected = "tpw/hub already exists on github.com\n"
|
410
|
-
expected << "remote add -f origin git@github.com:tpw/hub.git\n"
|
411
|
-
expected << "set remote origin: tpw/hub\n"
|
412
|
-
assert_equal expected, hub("create") { ENV['GIT'] = 'echo' }
|
413
|
-
end
|
414
|
-
|
415
|
-
def test_create_https_protocol
|
416
|
-
stub_no_remotes
|
417
|
-
stub_existing_fork('tpw')
|
418
|
-
stub_https_is_preferred
|
419
|
-
|
420
|
-
expected = "tpw/hub already exists on github.com\n"
|
421
|
-
expected << "remote add -f origin https://github.com/tpw/hub.git\n"
|
422
|
-
expected << "set remote origin: tpw/hub\n"
|
423
|
-
assert_equal expected, hub("create") { ENV['GIT'] = 'echo' }
|
424
|
-
end
|
425
|
-
|
426
|
-
def test_create_outside_git_repo
|
427
|
-
stub_no_git_repo
|
428
|
-
assert_equal "'create' must be run from inside a git repository\n", hub("create")
|
429
|
-
end
|
430
|
-
|
431
|
-
def test_create_origin_already_exists
|
432
|
-
stub_nonexisting_fork('tpw')
|
433
|
-
stub_request(:post, "https://api.github.com/user/repos").
|
434
|
-
with(:body => { 'name' => 'hub', 'private' => false })
|
435
|
-
|
436
|
-
expected = "remote -v\ncreated repository: tpw/hub\n"
|
437
|
-
assert_equal expected, hub("create") { ENV['GIT'] = 'echo' }
|
438
|
-
end
|
439
|
-
|
440
|
-
def test_fork
|
441
|
-
stub_nonexisting_fork('tpw')
|
442
|
-
stub_request(:post, "https://api.github.com/repos/defunkt/hub/forks").
|
443
|
-
with { |req| req.headers['Content-Length'] == 0 }
|
444
|
-
|
445
|
-
expected = "remote add -f tpw git@github.com:tpw/hub.git\n"
|
446
|
-
expected << "new remote: tpw\n"
|
447
|
-
assert_output expected, "fork"
|
448
|
-
end
|
449
|
-
|
450
|
-
def test_fork_https_protocol
|
451
|
-
stub_https_is_preferred
|
452
|
-
stub_nonexisting_fork('tpw')
|
453
|
-
stub_request(:post, "https://api.github.com/repos/defunkt/hub/forks")
|
454
|
-
|
455
|
-
expected = "remote add -f tpw https://github.com/tpw/hub.git\n"
|
456
|
-
expected << "new remote: tpw\n"
|
457
|
-
assert_equal expected, hub("fork") { ENV['GIT'] = 'echo' }
|
458
|
-
end
|
459
|
-
|
460
|
-
def test_fork_not_in_repo
|
461
|
-
stub_no_git_repo
|
462
|
-
expected = "fatal: Not a git repository\n"
|
463
|
-
assert_output expected, "fork"
|
464
|
-
end
|
465
|
-
|
466
|
-
def test_fork_enterprise
|
467
|
-
stub_hub_host('git.my.org')
|
468
|
-
stub_repo_url('git@git.my.org:defunkt/hub.git')
|
469
|
-
edit_hub_config do |data|
|
470
|
-
data['git.my.org'] = [{'user'=>'myfiname', 'oauth_token' => 'FITOKEN'}]
|
471
|
-
end
|
472
|
-
|
473
|
-
stub_request(:get, "https://git.my.org/repos/myfiname/hub").
|
474
|
-
to_return(:status => 404)
|
475
|
-
stub_request(:post, "https://git.my.org/repos/defunkt/hub/forks").
|
476
|
-
with(:headers => {"Authorization" => "token FITOKEN"})
|
477
|
-
|
478
|
-
expected = "remote add -f myfiname git@git.my.org:myfiname/hub.git\n"
|
479
|
-
expected << "new remote: myfiname\n"
|
480
|
-
assert_output expected, "fork"
|
481
|
-
end
|
482
|
-
|
483
|
-
def test_fork_failed
|
484
|
-
stub_nonexisting_fork('tpw')
|
485
|
-
stub_request(:post, "https://api.github.com/repos/defunkt/hub/forks").
|
486
|
-
to_return(:status => [500, "Your fork is fail"])
|
487
|
-
|
488
|
-
expected = "Error creating fork: Your fork is fail (HTTP 500)\n"
|
489
|
-
assert_equal expected, hub("fork") { ENV['GIT'] = 'echo' }
|
490
|
-
end
|
491
|
-
|
492
|
-
def test_fork_no_remote
|
493
|
-
stub_nonexisting_fork('tpw')
|
494
|
-
stub_request(:post, "https://api.github.com/repos/defunkt/hub/forks")
|
495
|
-
|
496
|
-
assert_equal "", hub("fork --no-remote") { ENV['GIT'] = 'echo' }
|
497
|
-
end
|
498
|
-
|
499
|
-
def test_fork_already_exists
|
500
|
-
stub_existing_fork('tpw')
|
501
|
-
|
502
|
-
expected = "Error creating fork: tpw/hub already exists on github.com\n"
|
503
|
-
assert_equal expected, hub("fork") { ENV['GIT'] = 'echo' }
|
504
|
-
end
|
505
|
-
|
506
247
|
def test_pullrequest
|
507
248
|
expected = "Aborted: head branch is the same as base (\"master\")\n" <<
|
508
249
|
"(use `-h <branch>` to specify an explicit pull request head)\n"
|
@@ -743,7 +484,7 @@ class HubTest < Test::Unit::TestCase
|
|
743
484
|
def test_help_hub
|
744
485
|
help_manpage = hub("help hub")
|
745
486
|
assert_includes "git + hub = github", help_manpage
|
746
|
-
assert_includes "Hub will prompt for GitHub username & password", help_manpage
|
487
|
+
assert_includes "Hub will prompt for GitHub username & password", help_manpage.gsub(/ {2,}/, ' ')
|
747
488
|
end
|
748
489
|
|
749
490
|
def test_help_flag_on_command
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hub
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.10.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -10,11 +10,11 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2012-05-
|
13
|
+
date: 2012-05-08 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: rake
|
17
|
-
requirement: &
|
17
|
+
requirement: &70214831337220 !ruby/object:Gem::Requirement
|
18
18
|
none: false
|
19
19
|
requirements:
|
20
20
|
- - ! '>='
|
@@ -22,10 +22,10 @@ dependencies:
|
|
22
22
|
version: '0'
|
23
23
|
type: :development
|
24
24
|
prerelease: false
|
25
|
-
version_requirements: *
|
25
|
+
version_requirements: *70214831337220
|
26
26
|
- !ruby/object:Gem::Dependency
|
27
27
|
name: webmock
|
28
|
-
requirement: &
|
28
|
+
requirement: &70214831336720 !ruby/object:Gem::Requirement
|
29
29
|
none: false
|
30
30
|
requirements:
|
31
31
|
- - ! '>='
|
@@ -33,7 +33,7 @@ dependencies:
|
|
33
33
|
version: '0'
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
|
-
version_requirements: *
|
36
|
+
version_requirements: *70214831336720
|
37
37
|
description: ! " `hub` is a command line utility which adds GitHub knowledge to `git`.\n\n
|
38
38
|
\ It can used on its own or as a `git` wrapper.\n\n Normal:\n\n $ hub clone
|
39
39
|
rtomayko/tilt\n\n Expands to:\n $ git clone git://github.com/rtomayko/tilt.git\n\n
|
@@ -63,7 +63,6 @@ files:
|
|
63
63
|
- man/hub.1
|
64
64
|
- man/hub.1.html
|
65
65
|
- man/hub.1.ronn
|
66
|
-
- test/alias_test.rb
|
67
66
|
- test/deps.rip
|
68
67
|
- test/fakebin/git
|
69
68
|
- test/fakebin/open
|
data/test/alias_test.rb
DELETED
@@ -1,59 +0,0 @@
|
|
1
|
-
require 'helper'
|
2
|
-
|
3
|
-
class AliasTest < Test::Unit::TestCase
|
4
|
-
def test_alias_instructions
|
5
|
-
expected = "# Wrap git automatically by adding the following to your profile:\n"
|
6
|
-
expected << "\n"
|
7
|
-
expected << 'eval "$(hub alias -s)"' << "\n"
|
8
|
-
assert_equal expected, hub("alias sh")
|
9
|
-
end
|
10
|
-
|
11
|
-
def test_alias_instructions_bash
|
12
|
-
with_shell('bash') do
|
13
|
-
assert_includes '~/.bash_profile', hub("alias")
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
def test_alias_instructions_zsh
|
18
|
-
with_shell('zsh') do
|
19
|
-
assert_includes '~/.zshrc', hub("alias")
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
def test_alias_script_bash
|
24
|
-
with_shell('bash') do
|
25
|
-
assert_equal "alias git=hub\n", hub("alias -s")
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
def test_alias_script_zsh
|
30
|
-
with_shell('zsh') do
|
31
|
-
script = hub("alias -s")
|
32
|
-
assert_includes "alias git=hub\n", script
|
33
|
-
assert_includes "compdef hub=git\n", script
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
def test_unknown_shell
|
38
|
-
with_shell(nil) do
|
39
|
-
assert_equal "hub alias: unknown shell\n", hub("alias -s")
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
def test_unsupported_shell
|
44
|
-
with_shell('foosh') do
|
45
|
-
expected = "hub alias: unsupported shell\n"
|
46
|
-
expected << "supported shells: bash zsh sh ksh csh fish\n"
|
47
|
-
assert_equal expected, hub("alias -s")
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
private
|
52
|
-
|
53
|
-
def with_shell(shell)
|
54
|
-
old_shell, ENV['SHELL'] = ENV['SHELL'], shell
|
55
|
-
yield
|
56
|
-
ensure
|
57
|
-
ENV['SHELL'] = old_shell
|
58
|
-
end
|
59
|
-
end
|