hubflow 1.7.0
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +20 -0
- data/README.md +385 -0
- data/Rakefile +140 -0
- data/bin/hubflow +7 -0
- data/lib/hub.rb +5 -0
- data/lib/hub/args.rb +117 -0
- data/lib/hub/commands.rb +977 -0
- data/lib/hub/context.rb +367 -0
- data/lib/hub/runner.rb +73 -0
- data/lib/hub/standalone.rb +58 -0
- data/lib/hub/version.rb +3 -0
- data/man/hub.1 +438 -0
- data/man/hub.1.html +437 -0
- data/man/hub.1.ronn +192 -0
- data/test/alias_test.rb +40 -0
- data/test/deps.rip +1 -0
- data/test/fakebin/git +11 -0
- data/test/fakebin/open +3 -0
- data/test/helper.rb +111 -0
- data/test/hub_test.rb +1224 -0
- data/test/standalone_test.rb +48 -0
- metadata +106 -0
data/man/hub.1.ronn
ADDED
@@ -0,0 +1,192 @@
|
|
1
|
+
hub(1) -- git + hub = github
|
2
|
+
============================
|
3
|
+
|
4
|
+
## SYNOPSIS
|
5
|
+
|
6
|
+
`hub` [`--noop`] <COMMAND> <OPTIONS>
|
7
|
+
`hub alias` [`-s`] <SHELL>
|
8
|
+
|
9
|
+
### Expanded git commands:
|
10
|
+
|
11
|
+
`git init -g` <OPTIONS>
|
12
|
+
`git clone` [`-p`] <OPTIONS> [<USER>/]<REPOSITORY> <DIRECTORY>
|
13
|
+
`git remote add` [`-p`] <OPTIONS> <USER>[/<REPOSITORY>]
|
14
|
+
`git remote set-url` [`-p`] <OPTIONS> <REMOTE-NAME> <USER>[/<REPOSITORY>]
|
15
|
+
`git fetch` <USER-1>,[<USER-2>,...]
|
16
|
+
`git checkout` <PULLREQ-URL> [<BRANCH>]
|
17
|
+
`git cherry-pick` <GITHUB-REF>
|
18
|
+
`git am` <GITHUB-URL>
|
19
|
+
`git apply` <GITHUB-URL>
|
20
|
+
`git push` <REMOTE-1>,<REMOTE-2>,...,<REMOTE-N> [<REF>]
|
21
|
+
`git submodule add` [`-p`] <OPTIONS> [<USER>/]<REPOSITORY> <DIRECTORY>
|
22
|
+
|
23
|
+
### Custom git commands:
|
24
|
+
|
25
|
+
`git create` [<NAME>] [`-p`] [`-d` <DESCRIPTION>] [`-h` <HOMEPAGE>]
|
26
|
+
`git browse` [`-u`] [[<USER>`/`]<REPOSITORY>] [SUBPAGE]
|
27
|
+
`git compare` [`-u`] [<USER>] [<START>...]<END>
|
28
|
+
`git fork` [`--no-remote`]
|
29
|
+
`git pull-request` [`-f`] [<TITLE>|`-i` <ISSUE>] [`-b` <BASE>] [`-h` <HEAD>]:
|
30
|
+
|
31
|
+
## DESCRIPTION
|
32
|
+
|
33
|
+
hub enhances various git commands to ease most common workflows with GitHub.
|
34
|
+
|
35
|
+
* `hub --noop` <COMMAND>:
|
36
|
+
Shows which command(s) would be run as a result of the current command.
|
37
|
+
Doesn't perform anything.
|
38
|
+
|
39
|
+
* `hub alias` [`-s`] <SHELL>:
|
40
|
+
Writes shell aliasing code for <SHELL> (`bash`, `sh`, `zsh`,
|
41
|
+
`csh`) to standard output. With the `-s` option, the output of
|
42
|
+
this command can be evaluated directly within the shell:
|
43
|
+
`eval $(hub alias -s bash)`
|
44
|
+
|
45
|
+
* `git init` `-g` <OPTIONS>:
|
46
|
+
Create a git repository as with git-init(1) and add remote `origin` at
|
47
|
+
"git@github.com:<USER>/<REPOSITORY>.git"; <USER> is your GitHub username and
|
48
|
+
<REPOSITORY> is the current working directory's basename.
|
49
|
+
|
50
|
+
* `git clone` [`-p`] <OPTIONS> [<USER>`/`]<REPOSITORY> <DIRECTORY>:
|
51
|
+
Clone repository "git://github.com/<USER>/<REPOSITORY>.git" into
|
52
|
+
<DIRECTORY> as with git-clone(1). When <USER>/ is omitted, assumes
|
53
|
+
your GitHub login. With `-p`, clone private repositories over SSH.
|
54
|
+
For repositories under your GitHub login, `-p` is implicit.
|
55
|
+
|
56
|
+
* `git remote add` [`-p`] <OPTIONS> <USER>[`/`<REPOSITORY>]:
|
57
|
+
Add remote "git://github.com/<USER>/<REPOSITORY>.git" as with
|
58
|
+
git-remote(1). When /<REPOSITORY> is omitted, the basename of the
|
59
|
+
current working directory is used. With `-p`, use private remote
|
60
|
+
"git@github.com:<USER>/<REPOSITORY>.git". If <USER> is "origin"
|
61
|
+
then uses your GitHub login.
|
62
|
+
|
63
|
+
* `git remote set-url` [`-p`] <OPTIONS> <REMOTE-NAME> <USER>[/<REPOSITORY>]:
|
64
|
+
Sets the url of remote <REMOTE-NAME> using the same rules as
|
65
|
+
`git remote add`.
|
66
|
+
|
67
|
+
* `git fetch` <USER-1>,[<USER-2>,...]:
|
68
|
+
Adds missing remote(s) with `git remote add` prior to fetching. New
|
69
|
+
remotes are only added if they correspond to valid forks on GitHub.
|
70
|
+
|
71
|
+
* `git checkout` <PULLREQ-URL> [<BRANCH>]:
|
72
|
+
Checks out the head of the pull request as a local branch, to allow for
|
73
|
+
reviewing, rebasing and otherwise cleaning up the commits in the pull
|
74
|
+
request before merging. The name of the local branch can explicitly be
|
75
|
+
set with <BRANCH>.
|
76
|
+
|
77
|
+
* `git cherry-pick` <GITHUB-REF>:
|
78
|
+
Cherry-pick a commit from a fork using either full URL to the commit
|
79
|
+
or GitHub-flavored Markdown notation, which is `user@sha`. If the remote
|
80
|
+
doesn't yet exist, it will be added. A `git fetch <user>` is issued
|
81
|
+
prior to the cherry-pick attempt.
|
82
|
+
|
83
|
+
* `git [am|apply]` <GITHUB-URL>:
|
84
|
+
Downloads the patch file for the pull request or commit at the URL and
|
85
|
+
applies that patch from disk with `git am` or `git apply`. Similar to
|
86
|
+
`cherry-pick`, but doesn't add new remotes. `git am` creates commits while
|
87
|
+
preserving authorship info while `apply` only applies the patch to the
|
88
|
+
working copy.
|
89
|
+
|
90
|
+
* `git push` <REMOTE-1>,<REMOTE-2>,...,<REMOTE-N> [<REF>]:
|
91
|
+
Push <REF> to each of <REMOTE-1> through <REMOTE-N> by executing
|
92
|
+
multiple `git push` commands.
|
93
|
+
|
94
|
+
* `git submodule add` [`-p`] <OPTIONS> [<USER>/]<REPOSITORY> <DIRECTORY>:
|
95
|
+
Submodule repository "git://github.com/<USER>/<REPOSITORY>.git" into
|
96
|
+
<DIRECTORY> as with git-submodule(1). When <USER>/ is omitted, assumes
|
97
|
+
your GitHub login. With `-p`, use private remote
|
98
|
+
"git@github.com:<USER>/<REPOSITORY>.git".
|
99
|
+
|
100
|
+
* `git help`:
|
101
|
+
Display enhanced git-help(1).
|
102
|
+
|
103
|
+
hub also adds some custom commands that are otherwise not present in git:
|
104
|
+
|
105
|
+
* `git create` [<NAME>] [`-p`] [`-d` <DESCRIPTION>] [`-h` <HOMEPAGE>]:
|
106
|
+
Create a new public GitHub repository from the current git
|
107
|
+
repository and add remote `origin` at
|
108
|
+
"git@github.com:<USER>/<REPOSITORY>.git"; <USER> is your GitHub
|
109
|
+
username and <REPOSITORY> is the current working directory name.
|
110
|
+
To explicitly name the new repository, pass in <NAME>, optionally in
|
111
|
+
<ORGANIZATION>/<NAME> form to create under an organization you're a
|
112
|
+
member of. With `-p`, create a private repository, and with `-d` and `-h`
|
113
|
+
set the repository's description and homepage URL, respectively.
|
114
|
+
|
115
|
+
* `git browse` [`-u`] [[<USER>`/`]<REPOSITORY>] [SUBPAGE]:
|
116
|
+
Open repository's GitHub page in the system's default web browser using
|
117
|
+
`open(1)` or the `BROWSER` env variable. If the repository isn't
|
118
|
+
specified, `browse` opens the page of the repository found in the current
|
119
|
+
directory. If SUBPAGE is specified, the browser will open on the specified
|
120
|
+
subpage: one of "wiki", "commits", "issues" or other (the default is
|
121
|
+
"tree").
|
122
|
+
|
123
|
+
* `git compare` [`-u`] [<USER>] [<START>...]<END>:
|
124
|
+
Open a GitHub compare view page in the system's default web browser.
|
125
|
+
<START> to <END> are branch names, tag names, or commit SHA1s specifying
|
126
|
+
the range of history to compare. If a range with two dots (`a..b`) is given,
|
127
|
+
it will be transformed into one with three dots. If <START> is omitted,
|
128
|
+
GitHub will compare against the base branch (the default is "master").
|
129
|
+
|
130
|
+
* `git fork` [`--no-remote`]:
|
131
|
+
Forks the original project (referenced by "origin" remote) on GitHub and
|
132
|
+
adds a new remote for it under your username. Requires `github.token` to
|
133
|
+
be set (see CONFIGURATION).
|
134
|
+
|
135
|
+
* `git pull-request` [`-f`] [<TITLE>|`-i` <ISSUE>] [`-b` <BASE>] [`-h` <HEAD>]:
|
136
|
+
`git pull-request` [`-f`] <ISSUE-URL> [`-h` <HEAD>]
|
137
|
+
Opens a pull request on GitHub for the project that the "origin" remote
|
138
|
+
points to. The default head of the pull request is the current branch.
|
139
|
+
Both base and head of the pull request can be explicitly given in one of
|
140
|
+
the following formats: "branch", "owner:branch", "owner/repo:branch".
|
141
|
+
This command will abort operation if it detects that the current topic
|
142
|
+
branch has local commits that are not yet pushed to its upstream branch
|
143
|
+
on the remote. To skip this check, use `-f`.
|
144
|
+
|
145
|
+
If <TITLE> is omitted, a text editor will open in which title and body of
|
146
|
+
the pull request can be entered in the same manner as git commit message.
|
147
|
+
|
148
|
+
If instead of normal <TITLE> an issue number is given with `-i`, the pull
|
149
|
+
request will be attached to an existing GitHub issue. Alternatively, instead
|
150
|
+
of title you can paste a full URL to an issue on GitHub.
|
151
|
+
|
152
|
+
## CONFIGURATION
|
153
|
+
|
154
|
+
Use git-config(1) to display the currently configured GitHub username:
|
155
|
+
|
156
|
+
$ git config --global github.user
|
157
|
+
|
158
|
+
Or, set the GitHub username and token with:
|
159
|
+
|
160
|
+
$ git config --global github.user <username>
|
161
|
+
$ git config --global github.token <token>
|
162
|
+
|
163
|
+
You can override these values with <GITHUB_USER> and <GITHUB_TOKEN>
|
164
|
+
environment variables.
|
165
|
+
|
166
|
+
See <http://help.github.com/set-your-user-name-email-and-github-token/> for more
|
167
|
+
information.
|
168
|
+
|
169
|
+
If you prefer the HTTPS protocol for GitHub repositories, you can set
|
170
|
+
"hub.protocol" to "https". This will affect `clone`, `fork`, `remote add`
|
171
|
+
and other operations that expand references to GitHub repositories as full
|
172
|
+
URLs that otherwise use git and ssh protocols.
|
173
|
+
|
174
|
+
$ git config --global hub.protocol https
|
175
|
+
|
176
|
+
## EXAMPLES
|
177
|
+
|
178
|
+
{{README}}
|
179
|
+
|
180
|
+
## BUGS
|
181
|
+
|
182
|
+
<https://github.com/defunkt/hub/issues>
|
183
|
+
|
184
|
+
## AUTHORS
|
185
|
+
|
186
|
+
<https://github.com/defunkt/hub/contributors>
|
187
|
+
|
188
|
+
## SEE ALSO
|
189
|
+
|
190
|
+
git(1), git-clone(1), git-remote(1), git-init(1),
|
191
|
+
<http://github.com>,
|
192
|
+
<https://github.com/defunkt/hub>
|
data/test/alias_test.rb
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class AliasTest < Test::Unit::TestCase
|
4
|
+
def test_alias
|
5
|
+
instructions = hub("alias")
|
6
|
+
assert_includes "bash", instructions
|
7
|
+
assert_includes "sh", instructions
|
8
|
+
assert_includes "csh", instructions
|
9
|
+
assert_includes "zsh", instructions
|
10
|
+
assert_includes "fish", instructions
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_alias_silent
|
14
|
+
assert_equal "alias git=hub\n", hub("alias -s bash")
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_alias_bash
|
18
|
+
assert_alias_command "bash", "alias git=hub"
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_alias_sh
|
22
|
+
assert_alias_command "sh", "alias git=hub"
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_alias_zsh
|
26
|
+
assert_alias_command "zsh", 'function git(){hub "$@"}'
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_alias_csh
|
30
|
+
assert_alias_command "csh", "alias git hub"
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_alias_fish
|
34
|
+
assert_alias_command "fish", "alias git hub"
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_alias_blah
|
38
|
+
assert_alias_command "blah", "fatal: never heard of `blah'"
|
39
|
+
end
|
40
|
+
end
|
data/test/deps.rip
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
webmock 1.3.0
|
data/test/fakebin/git
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
#!/bin/sh
|
2
|
+
if [ "$1" = "--version" ] || [ "$1" = "version" ]; then
|
3
|
+
echo "git version 1.7.0.4"
|
4
|
+
elif [ "$1" = "--exec-path" ]; then
|
5
|
+
echo "/usr/lib/git-core"
|
6
|
+
elif [ "$1" = "--html-path" ]; then
|
7
|
+
echo "/usr/share/doc/git-doc"
|
8
|
+
else
|
9
|
+
echo "ERROR: git was called, but wasn't supposed to:" git $*
|
10
|
+
exit 1
|
11
|
+
fi
|
data/test/fakebin/open
ADDED
data/test/helper.rb
ADDED
@@ -0,0 +1,111 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'hub'
|
3
|
+
require 'hub/standalone'
|
4
|
+
|
5
|
+
# We're checking for `open` in our tests
|
6
|
+
ENV['BROWSER'] = 'open'
|
7
|
+
|
8
|
+
# Setup path with fake executables in case a test hits them
|
9
|
+
fakebin_dir = File.expand_path('../fakebin', __FILE__)
|
10
|
+
ENV['PATH'] = "#{fakebin_dir}:#{ENV['PATH']}"
|
11
|
+
|
12
|
+
class Test::Unit::TestCase
|
13
|
+
# Shortcut for creating a `Hub` instance. Pass it what you would
|
14
|
+
# normally pass `hub` on the command line, e.g.
|
15
|
+
#
|
16
|
+
# shell: hub clone rtomayko/tilt
|
17
|
+
# test: Hub("clone rtomayko/tilt")
|
18
|
+
def Hub(args)
|
19
|
+
Hub::Runner.new(*args.split(' '))
|
20
|
+
end
|
21
|
+
|
22
|
+
# Shortcut for running the `hub` command in a subprocess. Returns
|
23
|
+
# STDOUT as a string. Pass it what you would normally pass `hub` on
|
24
|
+
# the command line, e.g.
|
25
|
+
#
|
26
|
+
# shell: hub clone rtomayko/tilt
|
27
|
+
# test: hub("clone rtomayko/tilt")
|
28
|
+
#
|
29
|
+
# If a block is given it will be run in the child process before
|
30
|
+
# execution begins. You can use this to monkeypatch or fudge the
|
31
|
+
# environment before running hub.
|
32
|
+
def hub(args, input = nil)
|
33
|
+
parent_read, child_write = IO.pipe
|
34
|
+
child_read, parent_write = IO.pipe if input
|
35
|
+
|
36
|
+
fork do
|
37
|
+
yield if block_given?
|
38
|
+
$stdin.reopen(child_read) if input
|
39
|
+
$stdout.reopen(child_write)
|
40
|
+
$stderr.reopen(child_write)
|
41
|
+
Hub(args).execute
|
42
|
+
end
|
43
|
+
|
44
|
+
if input
|
45
|
+
parent_write.write input
|
46
|
+
parent_write.close
|
47
|
+
end
|
48
|
+
child_write.close
|
49
|
+
parent_read.read
|
50
|
+
end
|
51
|
+
|
52
|
+
# Asserts that `hub` will run a specific git command based on
|
53
|
+
# certain input.
|
54
|
+
#
|
55
|
+
# e.g.
|
56
|
+
# assert_command "clone git/hub", "git clone git://github.com/git/hub.git"
|
57
|
+
#
|
58
|
+
# Here we are saying that this:
|
59
|
+
# $ hub clone git/hub
|
60
|
+
# Should in turn execute this:
|
61
|
+
# $ git clone git://github.com/git/hub.git
|
62
|
+
def assert_command(input, expected)
|
63
|
+
assert_equal expected, Hub(input).command, "$ git #{input}"
|
64
|
+
end
|
65
|
+
|
66
|
+
def assert_commands(*expected)
|
67
|
+
input = expected.pop
|
68
|
+
assert_equal expected, Hub(input).commands
|
69
|
+
end
|
70
|
+
|
71
|
+
# Asserts that the command will be forwarded to git without changes
|
72
|
+
def assert_forwarded(input)
|
73
|
+
cmd = Hub(input)
|
74
|
+
assert !cmd.args.changed?, "arguments were not supposed to change: #{cmd.args.inspect}"
|
75
|
+
end
|
76
|
+
|
77
|
+
# Asserts that `hub` will show a specific alias command for a
|
78
|
+
# specific shell.
|
79
|
+
#
|
80
|
+
# e.g.
|
81
|
+
# assert_alias_command "sh", "alias git=hub"
|
82
|
+
#
|
83
|
+
# Here we are saying that this:
|
84
|
+
# $ hub alias sh
|
85
|
+
# Should display this:
|
86
|
+
# Run this in your shell to start using `hub` as `git`:
|
87
|
+
# alias git=hub
|
88
|
+
def assert_alias_command(shell, command)
|
89
|
+
expected = "Run this in your shell to start using `hub` as `git`:\n %s\n"
|
90
|
+
assert_equal(expected % command, hub("alias #{shell}"))
|
91
|
+
end
|
92
|
+
|
93
|
+
# Asserts that `haystack` includes `needle`.
|
94
|
+
def assert_includes(needle, haystack)
|
95
|
+
assert haystack.include?(needle),
|
96
|
+
"expected #{needle.inspect} in #{haystack.inspect}"
|
97
|
+
end
|
98
|
+
|
99
|
+
# Asserts that `haystack` does not include `needle`.
|
100
|
+
def assert_not_includes(needle, haystack)
|
101
|
+
assert !haystack.include?(needle),
|
102
|
+
"didn't expect #{needle.inspect} in #{haystack.inspect}"
|
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
|
+
end
|
data/test/hub_test.rb
ADDED
@@ -0,0 +1,1224 @@
|
|
1
|
+
require 'helper'
|
2
|
+
require 'webmock/test_unit'
|
3
|
+
require 'rbconfig'
|
4
|
+
require 'yaml'
|
5
|
+
require 'forwardable'
|
6
|
+
require 'json'
|
7
|
+
|
8
|
+
WebMock::BodyPattern.class_eval do
|
9
|
+
undef normalize_hash
|
10
|
+
# override normalizing hash since it otherwise requires JSON
|
11
|
+
def normalize_hash(hash) hash end
|
12
|
+
end
|
13
|
+
|
14
|
+
class HubTest < Test::Unit::TestCase
|
15
|
+
extend Forwardable
|
16
|
+
|
17
|
+
if defined? WebMock::API
|
18
|
+
include WebMock::API
|
19
|
+
else
|
20
|
+
include WebMock
|
21
|
+
end
|
22
|
+
|
23
|
+
COMMANDS = []
|
24
|
+
|
25
|
+
Hub::Context.class_eval do
|
26
|
+
remove_method :which
|
27
|
+
define_method :which do |name|
|
28
|
+
COMMANDS.include?(name) ? "/usr/bin/#{name}" : nil
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
attr_reader :git_reader
|
33
|
+
include Hub::Context::GitReaderMethods
|
34
|
+
def_delegators :git_reader, :stub_config_value, :stub_command_output
|
35
|
+
|
36
|
+
def setup
|
37
|
+
super
|
38
|
+
COMMANDS.replace %w[open groff]
|
39
|
+
Hub::Context::PWD.replace '/path/to/hub'
|
40
|
+
|
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"
|
44
|
+
end
|
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! \
|
51
|
+
'remote' => "mislav\norigin",
|
52
|
+
'symbolic-ref -q HEAD' => 'refs/heads/master',
|
53
|
+
'config --get github.user' => 'tpw',
|
54
|
+
'config --get github.token' => 'abc123',
|
55
|
+
'config --get-all remote.origin.url' => 'git://github.com/defunkt/hub.git',
|
56
|
+
'config --get-all remote.mislav.url' => 'git://github.com/mislav/hub.git',
|
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'
|
61
|
+
end
|
62
|
+
|
63
|
+
def test_private_clone
|
64
|
+
input = "clone -p rtomayko/ronn"
|
65
|
+
command = "git clone git@github.com:rtomayko/ronn.git"
|
66
|
+
assert_command input, command
|
67
|
+
end
|
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
|
+
|
82
|
+
def test_public_clone
|
83
|
+
input = "clone rtomayko/ronn"
|
84
|
+
command = "git clone git://github.com/rtomayko/ronn.git"
|
85
|
+
assert_command input, command
|
86
|
+
end
|
87
|
+
|
88
|
+
def test_your_private_clone
|
89
|
+
input = "clone -p resque"
|
90
|
+
command = "git clone git@github.com:tpw/resque.git"
|
91
|
+
assert_command input, command
|
92
|
+
end
|
93
|
+
|
94
|
+
def test_your_clone_is_always_private
|
95
|
+
input = "clone resque"
|
96
|
+
command = "git clone git@github.com:tpw/resque.git"
|
97
|
+
assert_command input, command
|
98
|
+
end
|
99
|
+
|
100
|
+
def test_clone_repo_with_period
|
101
|
+
input = "clone hookio/hook.js"
|
102
|
+
command = "git clone git://github.com/hookio/hook.js.git"
|
103
|
+
assert_command input, command
|
104
|
+
end
|
105
|
+
|
106
|
+
def test_clone_with_arguments
|
107
|
+
input = "clone --bare -o master resque"
|
108
|
+
command = "git clone --bare -o master git@github.com:tpw/resque.git"
|
109
|
+
assert_command input, command
|
110
|
+
end
|
111
|
+
|
112
|
+
def test_clone_with_arguments_and_destination
|
113
|
+
assert_forwarded "clone --template=one/two git://github.com/tpw/resque.git --origin master resquetastic"
|
114
|
+
end
|
115
|
+
|
116
|
+
def test_your_private_clone_fails_without_config
|
117
|
+
out = hub("clone -p mustache") do
|
118
|
+
stub_github_user(nil)
|
119
|
+
end
|
120
|
+
|
121
|
+
assert_equal "** No GitHub user set. See http://help.github.com/set-your-user-name-email-and-github-token/\n", out
|
122
|
+
end
|
123
|
+
|
124
|
+
def test_your_public_clone_fails_without_config
|
125
|
+
out = hub("clone mustache") do
|
126
|
+
stub_github_user(nil)
|
127
|
+
end
|
128
|
+
|
129
|
+
assert_equal "** No GitHub user set. See http://help.github.com/set-your-user-name-email-and-github-token/\n", out
|
130
|
+
end
|
131
|
+
|
132
|
+
def test_private_clone_left_alone
|
133
|
+
assert_forwarded "clone git@github.com:rtomayko/ronn.git"
|
134
|
+
end
|
135
|
+
|
136
|
+
def test_public_clone_left_alone
|
137
|
+
assert_forwarded "clone git://github.com/rtomayko/ronn.git"
|
138
|
+
end
|
139
|
+
|
140
|
+
def test_normal_public_clone_with_path
|
141
|
+
assert_forwarded "clone git://github.com/rtomayko/ronn.git ronn-dev"
|
142
|
+
end
|
143
|
+
|
144
|
+
def test_normal_clone_from_path
|
145
|
+
assert_forwarded "clone ./test"
|
146
|
+
end
|
147
|
+
|
148
|
+
def test_clone_with_host_alias
|
149
|
+
assert_forwarded "clone server:git/repo.git"
|
150
|
+
end
|
151
|
+
|
152
|
+
def test_alias_expand
|
153
|
+
stub_alias 'c', 'clone --bare'
|
154
|
+
input = "c rtomayko/ronn"
|
155
|
+
command = "git clone --bare git://github.com/rtomayko/ronn.git"
|
156
|
+
assert_command input, command
|
157
|
+
end
|
158
|
+
|
159
|
+
def test_alias_expand_advanced
|
160
|
+
stub_alias 'c', 'clone --template="white space"'
|
161
|
+
input = "c rtomayko/ronn"
|
162
|
+
command = "git clone '--template=white space' git://github.com/rtomayko/ronn.git"
|
163
|
+
assert_command input, command
|
164
|
+
end
|
165
|
+
|
166
|
+
def test_alias_doesnt_expand_for_unknown_commands
|
167
|
+
stub_alias 'c', 'compute --fast'
|
168
|
+
assert_forwarded "c rtomayko/ronn"
|
169
|
+
end
|
170
|
+
|
171
|
+
def test_remote_origin
|
172
|
+
input = "remote add origin"
|
173
|
+
command = "git remote add origin git://github.com/tpw/hub.git"
|
174
|
+
assert_command input, command
|
175
|
+
end
|
176
|
+
|
177
|
+
def test_remote_add_with_name
|
178
|
+
input = "remote add another hookio/hub.js"
|
179
|
+
command = "git remote add another git://github.com/hookio/hub.js.git"
|
180
|
+
assert_command input, command
|
181
|
+
end
|
182
|
+
|
183
|
+
def test_private_remote_origin
|
184
|
+
input = "remote add -p origin"
|
185
|
+
command = "git remote add origin git@github.com:tpw/hub.git"
|
186
|
+
assert_command input, command
|
187
|
+
end
|
188
|
+
|
189
|
+
def test_public_remote_origin_as_normal
|
190
|
+
input = "remote add origin http://github.com/defunkt/resque.git"
|
191
|
+
command = "git remote add origin http://github.com/defunkt/resque.git"
|
192
|
+
assert_command input, command
|
193
|
+
end
|
194
|
+
|
195
|
+
def test_remote_from_rel_path
|
196
|
+
assert_forwarded "remote add origin ./path"
|
197
|
+
end
|
198
|
+
|
199
|
+
def test_remote_from_abs_path
|
200
|
+
assert_forwarded "remote add origin /path"
|
201
|
+
end
|
202
|
+
|
203
|
+
def test_remote_with_host_alias
|
204
|
+
assert_forwarded "remote add origin server:/git/repo.git"
|
205
|
+
end
|
206
|
+
|
207
|
+
def test_private_remote_origin_as_normal
|
208
|
+
assert_forwarded "remote add origin git@github.com:defunkt/resque.git"
|
209
|
+
end
|
210
|
+
|
211
|
+
def test_public_submodule
|
212
|
+
input = "submodule add wycats/bundler vendor/bundler"
|
213
|
+
command = "git submodule add git://github.com/wycats/bundler.git vendor/bundler"
|
214
|
+
assert_command input, command
|
215
|
+
end
|
216
|
+
|
217
|
+
def test_private_submodule
|
218
|
+
input = "submodule add -p grit vendor/grit"
|
219
|
+
command = "git submodule add git@github.com:tpw/grit.git vendor/grit"
|
220
|
+
assert_command input, command
|
221
|
+
end
|
222
|
+
|
223
|
+
def test_submodule_branch
|
224
|
+
input = "submodule add -b ryppl ryppl/pip vendor/pip"
|
225
|
+
command = "git submodule add -b ryppl git://github.com/ryppl/pip.git vendor/pip"
|
226
|
+
assert_command input, command
|
227
|
+
end
|
228
|
+
|
229
|
+
def test_submodule_with_args
|
230
|
+
input = "submodule -q add --bare -- grit grit"
|
231
|
+
command = "git submodule -q add --bare -- git://github.com/tpw/grit.git grit"
|
232
|
+
assert_command input, command
|
233
|
+
end
|
234
|
+
|
235
|
+
def test_private_remote
|
236
|
+
input = "remote add -p rtomayko"
|
237
|
+
command = "git remote add rtomayko git@github.com:rtomayko/hub.git"
|
238
|
+
assert_command input, command
|
239
|
+
end
|
240
|
+
|
241
|
+
def test_https_protocol_remote
|
242
|
+
stub_https_is_preferred
|
243
|
+
input = "remote add rtomayko"
|
244
|
+
command = "git remote add rtomayko https://github.com/rtomayko/hub.git"
|
245
|
+
assert_command input, command
|
246
|
+
end
|
247
|
+
|
248
|
+
def test_public_remote
|
249
|
+
input = "remote add rtomayko"
|
250
|
+
command = "git remote add rtomayko git://github.com/rtomayko/hub.git"
|
251
|
+
assert_command input, command
|
252
|
+
end
|
253
|
+
|
254
|
+
def test_public_remote_f
|
255
|
+
input = "remote add -f rtomayko"
|
256
|
+
command = "git remote add -f rtomayko git://github.com/rtomayko/hub.git"
|
257
|
+
assert_command input, command
|
258
|
+
end
|
259
|
+
|
260
|
+
def test_named_public_remote
|
261
|
+
input = "remote add origin rtomayko"
|
262
|
+
command = "git remote add origin git://github.com/rtomayko/hub.git"
|
263
|
+
assert_command input, command
|
264
|
+
end
|
265
|
+
|
266
|
+
def test_named_public_remote_f
|
267
|
+
input = "remote add -f origin rtomayko"
|
268
|
+
command = "git remote add -f origin git://github.com/rtomayko/hub.git"
|
269
|
+
assert_command input, command
|
270
|
+
end
|
271
|
+
|
272
|
+
def test_private_remote_with_repo
|
273
|
+
input = "remote add -p jashkenas/coffee-script"
|
274
|
+
command = "git remote add jashkenas git@github.com:jashkenas/coffee-script.git"
|
275
|
+
assert_command input, command
|
276
|
+
end
|
277
|
+
|
278
|
+
def test_public_remote_with_repo
|
279
|
+
input = "remote add jashkenas/coffee-script"
|
280
|
+
command = "git remote add jashkenas git://github.com/jashkenas/coffee-script.git"
|
281
|
+
assert_command input, command
|
282
|
+
end
|
283
|
+
|
284
|
+
def test_public_remote_f_with_repo
|
285
|
+
input = "remote add -f jashkenas/coffee-script"
|
286
|
+
command = "git remote add -f jashkenas git://github.com/jashkenas/coffee-script.git"
|
287
|
+
assert_command input, command
|
288
|
+
end
|
289
|
+
|
290
|
+
def test_named_private_remote_with_repo
|
291
|
+
input = "remote add -p origin jashkenas/coffee-script"
|
292
|
+
command = "git remote add origin git@github.com:jashkenas/coffee-script.git"
|
293
|
+
assert_command input, command
|
294
|
+
end
|
295
|
+
|
296
|
+
def test_fetch_existing_remote
|
297
|
+
assert_forwarded "fetch mislav"
|
298
|
+
end
|
299
|
+
|
300
|
+
def test_fetch_new_remote
|
301
|
+
stub_remotes_group('xoebus', nil)
|
302
|
+
stub_existing_fork('xoebus')
|
303
|
+
|
304
|
+
assert_commands "git remote add xoebus git://github.com/xoebus/hub.git",
|
305
|
+
"git fetch xoebus",
|
306
|
+
"fetch xoebus"
|
307
|
+
end
|
308
|
+
|
309
|
+
def test_fetch_new_remote_with_options
|
310
|
+
stub_remotes_group('xoebus', nil)
|
311
|
+
stub_existing_fork('xoebus')
|
312
|
+
|
313
|
+
assert_commands "git remote add xoebus git://github.com/xoebus/hub.git",
|
314
|
+
"git fetch --depth=1 --prune xoebus",
|
315
|
+
"fetch --depth=1 --prune xoebus"
|
316
|
+
end
|
317
|
+
|
318
|
+
def test_fetch_multiple_new_remotes
|
319
|
+
stub_remotes_group('xoebus', nil)
|
320
|
+
stub_remotes_group('rtomayko', nil)
|
321
|
+
stub_existing_fork('xoebus')
|
322
|
+
stub_existing_fork('rtomayko')
|
323
|
+
|
324
|
+
assert_commands "git remote add xoebus git://github.com/xoebus/hub.git",
|
325
|
+
"git remote add rtomayko git://github.com/rtomayko/hub.git",
|
326
|
+
"git fetch --multiple xoebus rtomayko",
|
327
|
+
"fetch --multiple xoebus rtomayko"
|
328
|
+
end
|
329
|
+
|
330
|
+
def test_fetch_multiple_comma_separated_remotes
|
331
|
+
stub_remotes_group('xoebus', nil)
|
332
|
+
stub_remotes_group('rtomayko', nil)
|
333
|
+
stub_existing_fork('xoebus')
|
334
|
+
stub_existing_fork('rtomayko')
|
335
|
+
|
336
|
+
assert_commands "git remote add xoebus git://github.com/xoebus/hub.git",
|
337
|
+
"git remote add rtomayko git://github.com/rtomayko/hub.git",
|
338
|
+
"git fetch --multiple xoebus rtomayko",
|
339
|
+
"fetch xoebus,rtomayko"
|
340
|
+
end
|
341
|
+
|
342
|
+
def test_fetch_multiple_new_remotes_with_filtering
|
343
|
+
stub_remotes_group('xoebus', nil)
|
344
|
+
stub_remotes_group('mygrp', 'one two')
|
345
|
+
stub_remotes_group('typo', nil)
|
346
|
+
stub_existing_fork('xoebus')
|
347
|
+
stub_nonexisting_fork('typo')
|
348
|
+
|
349
|
+
# mislav: existing remote; skipped
|
350
|
+
# xoebus: new remote, fork exists; added
|
351
|
+
# mygrp: a remotes group; skipped
|
352
|
+
# URL: can't be a username; skipped
|
353
|
+
# typo: fork doesn't exist; skipped
|
354
|
+
assert_commands "git remote add xoebus git://github.com/xoebus/hub.git",
|
355
|
+
"git fetch --multiple mislav xoebus mygrp git://example.com typo",
|
356
|
+
"fetch --multiple mislav xoebus mygrp git://example.com typo"
|
357
|
+
end
|
358
|
+
|
359
|
+
def test_cherry_pick
|
360
|
+
assert_forwarded "cherry-pick a319d88"
|
361
|
+
end
|
362
|
+
|
363
|
+
def test_cherry_pick_url
|
364
|
+
url = 'http://github.com/mislav/hub/commit/a319d88'
|
365
|
+
assert_commands "git fetch mislav", "git cherry-pick a319d88", "cherry-pick #{url}"
|
366
|
+
end
|
367
|
+
|
368
|
+
def test_cherry_pick_url_with_fragment
|
369
|
+
url = 'http://github.com/mislav/hub/commit/abcdef0123456789#comments'
|
370
|
+
assert_commands "git fetch mislav", "git cherry-pick abcdef0123456789", "cherry-pick #{url}"
|
371
|
+
end
|
372
|
+
|
373
|
+
def test_cherry_pick_url_with_remote_add
|
374
|
+
url = 'https://github.com/xoebus/hub/commit/a319d88'
|
375
|
+
assert_commands "git remote add -f xoebus git://github.com/xoebus/hub.git",
|
376
|
+
"git cherry-pick a319d88",
|
377
|
+
"cherry-pick #{url}"
|
378
|
+
end
|
379
|
+
|
380
|
+
def test_cherry_pick_origin_url
|
381
|
+
url = 'https://github.com/defunkt/hub/commit/a319d88'
|
382
|
+
assert_commands "git fetch origin", "git cherry-pick a319d88", "cherry-pick #{url}"
|
383
|
+
end
|
384
|
+
|
385
|
+
def test_cherry_pick_github_user_notation
|
386
|
+
assert_commands "git fetch mislav", "git cherry-pick 368af20", "cherry-pick mislav@368af20"
|
387
|
+
end
|
388
|
+
|
389
|
+
def test_cherry_pick_github_user_repo_notation
|
390
|
+
# not supported
|
391
|
+
assert_forwarded "cherry-pick mislav/hubbub@a319d88"
|
392
|
+
end
|
393
|
+
|
394
|
+
def test_cherry_pick_github_notation_too_short
|
395
|
+
assert_forwarded "cherry-pick mislav@a319"
|
396
|
+
end
|
397
|
+
|
398
|
+
def test_cherry_pick_github_notation_with_remote_add
|
399
|
+
assert_commands "git remote add -f xoebus git://github.com/xoebus/hub.git",
|
400
|
+
"git cherry-pick a319d88",
|
401
|
+
"cherry-pick xoebus@a319d88"
|
402
|
+
end
|
403
|
+
|
404
|
+
def test_am_untouched
|
405
|
+
assert_forwarded "am some.patch"
|
406
|
+
end
|
407
|
+
|
408
|
+
def test_am_pull_request
|
409
|
+
with_tmpdir('/tmp/') do
|
410
|
+
assert_commands "curl -#LA 'hub #{Hub::Version}' https://github.com/defunkt/hub/pull/55.patch -o /tmp/55.patch",
|
411
|
+
"git am --signoff /tmp/55.patch -p2",
|
412
|
+
"am --signoff https://github.com/defunkt/hub/pull/55 -p2"
|
413
|
+
|
414
|
+
cmd = Hub("am https://github.com/defunkt/hub/pull/55/files").command
|
415
|
+
assert_includes '/pull/55.patch', cmd
|
416
|
+
end
|
417
|
+
end
|
418
|
+
|
419
|
+
def test_am_no_tmpdir
|
420
|
+
with_tmpdir(nil) do
|
421
|
+
cmd = Hub("am https://github.com/defunkt/hub/pull/55").command
|
422
|
+
assert_includes '/tmp/55.patch', cmd
|
423
|
+
end
|
424
|
+
end
|
425
|
+
|
426
|
+
def test_am_commit_url
|
427
|
+
with_tmpdir('/tmp/') do
|
428
|
+
url = 'https://github.com/davidbalbert/hub/commit/fdb9921'
|
429
|
+
|
430
|
+
assert_commands "curl -#LA 'hub #{Hub::Version}' #{url}.patch -o /tmp/fdb9921.patch",
|
431
|
+
"git am --signoff /tmp/fdb9921.patch -p2",
|
432
|
+
"am --signoff #{url} -p2"
|
433
|
+
end
|
434
|
+
end
|
435
|
+
|
436
|
+
def test_am_gist
|
437
|
+
with_tmpdir('/tmp/') do
|
438
|
+
url = 'https://gist.github.com/8da7fb575debd88c54cf'
|
439
|
+
|
440
|
+
assert_commands "curl -#LA 'hub #{Hub::Version}' #{url}.txt -o /tmp/gist-8da7fb575debd88c54cf.txt",
|
441
|
+
"git am --signoff /tmp/gist-8da7fb575debd88c54cf.txt -p2",
|
442
|
+
"am --signoff #{url} -p2"
|
443
|
+
end
|
444
|
+
end
|
445
|
+
|
446
|
+
def test_apply_untouched
|
447
|
+
assert_forwarded "apply some.patch"
|
448
|
+
end
|
449
|
+
|
450
|
+
def test_apply_pull_request
|
451
|
+
with_tmpdir('/tmp/') do
|
452
|
+
assert_commands "curl -#LA 'hub #{Hub::Version}' https://github.com/defunkt/hub/pull/55.patch -o /tmp/55.patch",
|
453
|
+
"git apply /tmp/55.patch -p2",
|
454
|
+
"apply https://github.com/defunkt/hub/pull/55 -p2"
|
455
|
+
|
456
|
+
cmd = Hub("apply https://github.com/defunkt/hub/pull/55/files").command
|
457
|
+
assert_includes '/pull/55.patch', cmd
|
458
|
+
end
|
459
|
+
end
|
460
|
+
|
461
|
+
def test_apply_commit_url
|
462
|
+
with_tmpdir('/tmp/') do
|
463
|
+
url = 'https://github.com/davidbalbert/hub/commit/fdb9921'
|
464
|
+
|
465
|
+
assert_commands "curl -#LA 'hub #{Hub::Version}' #{url}.patch -o /tmp/fdb9921.patch",
|
466
|
+
"git apply /tmp/fdb9921.patch -p2",
|
467
|
+
"apply #{url} -p2"
|
468
|
+
end
|
469
|
+
end
|
470
|
+
|
471
|
+
def test_apply_gist
|
472
|
+
with_tmpdir('/tmp/') do
|
473
|
+
url = 'https://gist.github.com/8da7fb575debd88c54cf'
|
474
|
+
|
475
|
+
assert_commands "curl -#LA 'hub #{Hub::Version}' #{url}.txt -o /tmp/gist-8da7fb575debd88c54cf.txt",
|
476
|
+
"git apply /tmp/gist-8da7fb575debd88c54cf.txt -p2",
|
477
|
+
"apply #{url} -p2"
|
478
|
+
end
|
479
|
+
end
|
480
|
+
|
481
|
+
def test_init
|
482
|
+
assert_commands "git init", "git remote add origin git@github.com:tpw/hub.git", "init -g"
|
483
|
+
end
|
484
|
+
|
485
|
+
def test_init_no_login
|
486
|
+
out = hub("init -g") do
|
487
|
+
stub_github_user(nil)
|
488
|
+
end
|
489
|
+
|
490
|
+
assert_equal "** No GitHub user set. See http://help.github.com/set-your-user-name-email-and-github-token/\n", out
|
491
|
+
end
|
492
|
+
|
493
|
+
def test_push_untouched
|
494
|
+
assert_forwarded "push"
|
495
|
+
end
|
496
|
+
|
497
|
+
def test_push_two
|
498
|
+
assert_commands "git push origin cool-feature", "git push staging cool-feature",
|
499
|
+
"push origin,staging cool-feature"
|
500
|
+
end
|
501
|
+
|
502
|
+
def test_push_current_branch
|
503
|
+
stub_branch('refs/heads/cool-feature')
|
504
|
+
assert_commands "git push origin cool-feature", "git push staging cool-feature",
|
505
|
+
"push origin,staging"
|
506
|
+
end
|
507
|
+
|
508
|
+
def test_push_more
|
509
|
+
assert_commands "git push origin cool-feature",
|
510
|
+
"git push staging cool-feature",
|
511
|
+
"git push qa cool-feature",
|
512
|
+
"push origin,staging,qa cool-feature"
|
513
|
+
end
|
514
|
+
|
515
|
+
def test_create
|
516
|
+
stub_no_remotes
|
517
|
+
stub_nonexisting_fork('tpw')
|
518
|
+
stub_request(:post, "https://#{auth}github.com/api/v2/yaml/repos/create").
|
519
|
+
with(:body => { 'name' => 'hub' })
|
520
|
+
|
521
|
+
expected = "remote add -f origin git@github.com:tpw/hub.git\n"
|
522
|
+
expected << "created repository: tpw/hub\n"
|
523
|
+
assert_equal expected, hub("create") { ENV['GIT'] = 'echo' }
|
524
|
+
end
|
525
|
+
|
526
|
+
def test_create_custom_name
|
527
|
+
stub_no_remotes
|
528
|
+
stub_nonexisting_fork('tpw', 'hubbub')
|
529
|
+
stub_request(:post, "https://#{auth}github.com/api/v2/yaml/repos/create").
|
530
|
+
with(:body => { 'name' => 'hubbub' })
|
531
|
+
|
532
|
+
expected = "remote add -f origin git@github.com:tpw/hubbub.git\n"
|
533
|
+
expected << "created repository: tpw/hubbub\n"
|
534
|
+
assert_equal expected, hub("create hubbub") { ENV['GIT'] = 'echo' }
|
535
|
+
end
|
536
|
+
|
537
|
+
def test_create_in_organization
|
538
|
+
stub_no_remotes
|
539
|
+
stub_nonexisting_fork('acme', 'hubbub')
|
540
|
+
stub_request(:post, "https://#{auth}github.com/api/v2/yaml/repos/create").
|
541
|
+
with(:body => { 'name' => 'acme/hubbub' })
|
542
|
+
|
543
|
+
expected = "remote add -f origin git@github.com:acme/hubbub.git\n"
|
544
|
+
expected << "created repository: acme/hubbub\n"
|
545
|
+
assert_equal expected, hub("create acme/hubbub") { ENV['GIT'] = 'echo' }
|
546
|
+
end
|
547
|
+
|
548
|
+
def test_create_no_openssl
|
549
|
+
stub_no_remotes
|
550
|
+
stub_nonexisting_fork('tpw')
|
551
|
+
stub_request(:post, "http://#{auth}github.com/api/v2/yaml/repos/create").
|
552
|
+
with(:body => { 'name' => 'hub' })
|
553
|
+
|
554
|
+
expected = "remote add -f origin git@github.com:tpw/hub.git\n"
|
555
|
+
expected << "created repository: tpw/hub\n"
|
556
|
+
|
557
|
+
assert_equal expected, hub("create") {
|
558
|
+
ENV['GIT'] = 'echo'
|
559
|
+
require 'net/https'
|
560
|
+
Object.send :remove_const, :OpenSSL
|
561
|
+
}
|
562
|
+
end
|
563
|
+
|
564
|
+
def test_create_failed
|
565
|
+
stub_no_remotes
|
566
|
+
stub_nonexisting_fork('tpw')
|
567
|
+
stub_request(:post, "https://#{auth}github.com/api/v2/yaml/repos/create").
|
568
|
+
to_return(:status => [401, "Your token is fail"])
|
569
|
+
|
570
|
+
expected = "Error creating repository: Your token is fail (HTTP 401)\n"
|
571
|
+
expected << "Check your token configuration (`git config github.token`)\n"
|
572
|
+
assert_equal expected, hub("create") { ENV['GIT'] = 'echo' }
|
573
|
+
end
|
574
|
+
|
575
|
+
def test_create_with_env_authentication
|
576
|
+
stub_no_remotes
|
577
|
+
stub_nonexisting_fork('mojombo')
|
578
|
+
|
579
|
+
old_user = ENV['GITHUB_USER']
|
580
|
+
old_token = ENV['GITHUB_TOKEN']
|
581
|
+
ENV['GITHUB_USER'] = 'mojombo'
|
582
|
+
ENV['GITHUB_TOKEN'] = '123abc'
|
583
|
+
|
584
|
+
stub_request(:post, "https://#{auth('mojombo', '123abc')}github.com/api/v2/yaml/repos/create").
|
585
|
+
with(:body => { 'name' => 'hub' })
|
586
|
+
|
587
|
+
expected = "remote add -f origin git@github.com:mojombo/hub.git\n"
|
588
|
+
expected << "created repository: mojombo/hub\n"
|
589
|
+
assert_equal expected, hub("create") { ENV['GIT'] = 'echo' }
|
590
|
+
|
591
|
+
ensure
|
592
|
+
ENV['GITHUB_USER'] = old_user
|
593
|
+
ENV['GITHUB_TOKEN'] = old_token
|
594
|
+
end
|
595
|
+
|
596
|
+
def test_create_private_repository
|
597
|
+
stub_no_remotes
|
598
|
+
stub_nonexisting_fork('tpw')
|
599
|
+
stub_request(:post, "https://#{auth}github.com/api/v2/yaml/repos/create").
|
600
|
+
with(:body => { 'name' => 'hub', 'public' => '0' })
|
601
|
+
|
602
|
+
expected = "remote add -f origin git@github.com:tpw/hub.git\n"
|
603
|
+
expected << "created repository: tpw/hub\n"
|
604
|
+
assert_equal expected, hub("create -p") { ENV['GIT'] = 'echo' }
|
605
|
+
end
|
606
|
+
|
607
|
+
def test_create_with_description_and_homepage
|
608
|
+
stub_no_remotes
|
609
|
+
stub_nonexisting_fork('tpw')
|
610
|
+
stub_request(:post, "https://#{auth}github.com/api/v2/yaml/repos/create").with(:body => {
|
611
|
+
'name' => 'hub', 'description' => 'toyproject', 'homepage' => 'http://example.com'
|
612
|
+
})
|
613
|
+
|
614
|
+
expected = "remote add -f origin git@github.com:tpw/hub.git\n"
|
615
|
+
expected << "created repository: tpw/hub\n"
|
616
|
+
assert_equal expected, hub("create -d toyproject -h http://example.com") { ENV['GIT'] = 'echo' }
|
617
|
+
end
|
618
|
+
|
619
|
+
def test_create_with_invalid_arguments
|
620
|
+
assert_equal "invalid argument: -a\n", hub("create -a blah") { ENV['GIT'] = 'echo' }
|
621
|
+
assert_equal "invalid argument: bleh\n", hub("create blah bleh") { ENV['GIT'] = 'echo' }
|
622
|
+
end
|
623
|
+
|
624
|
+
def test_create_with_existing_repository
|
625
|
+
stub_no_remotes
|
626
|
+
stub_existing_fork('tpw')
|
627
|
+
|
628
|
+
expected = "tpw/hub already exists on GitHub\n"
|
629
|
+
expected << "remote add -f origin git@github.com:tpw/hub.git\n"
|
630
|
+
expected << "set remote origin: tpw/hub\n"
|
631
|
+
assert_equal expected, hub("create") { ENV['GIT'] = 'echo' }
|
632
|
+
end
|
633
|
+
|
634
|
+
def test_create_https_protocol
|
635
|
+
stub_no_remotes
|
636
|
+
stub_existing_fork('tpw')
|
637
|
+
stub_https_is_preferred
|
638
|
+
|
639
|
+
expected = "tpw/hub already exists on GitHub\n"
|
640
|
+
expected << "remote add -f origin https://github.com/tpw/hub.git\n"
|
641
|
+
expected << "set remote origin: tpw/hub\n"
|
642
|
+
assert_equal expected, hub("create") { ENV['GIT'] = 'echo' }
|
643
|
+
end
|
644
|
+
|
645
|
+
def test_create_no_user
|
646
|
+
stub_no_remotes
|
647
|
+
out = hub("create") do
|
648
|
+
stub_github_token(nil)
|
649
|
+
end
|
650
|
+
assert_equal "** No GitHub token set. See http://help.github.com/set-your-user-name-email-and-github-token/\n", out
|
651
|
+
end
|
652
|
+
|
653
|
+
def test_create_outside_git_repo
|
654
|
+
stub_no_git_repo
|
655
|
+
assert_equal "'create' must be run from inside a git repository\n", hub("create")
|
656
|
+
end
|
657
|
+
|
658
|
+
def test_create_origin_already_exists
|
659
|
+
stub_nonexisting_fork('tpw')
|
660
|
+
stub_request(:post, "https://#{auth}github.com/api/v2/yaml/repos/create").
|
661
|
+
with(:body => { 'name' => 'hub' })
|
662
|
+
|
663
|
+
expected = "remote -v\ncreated repository: tpw/hub\n"
|
664
|
+
assert_equal expected, hub("create") { ENV['GIT'] = 'echo' }
|
665
|
+
end
|
666
|
+
|
667
|
+
def test_fork
|
668
|
+
stub_nonexisting_fork('tpw')
|
669
|
+
stub_request(:post, "https://#{auth}github.com/api/v2/yaml/repos/fork/defunkt/hub")
|
670
|
+
|
671
|
+
expected = "remote add -f tpw git@github.com:tpw/hub.git\n"
|
672
|
+
expected << "new remote: tpw\n"
|
673
|
+
assert_equal expected, hub("fork") { ENV['GIT'] = 'echo' }
|
674
|
+
end
|
675
|
+
|
676
|
+
def test_fork_failed
|
677
|
+
stub_nonexisting_fork('tpw')
|
678
|
+
stub_request(:post, "https://#{auth}github.com/api/v2/yaml/repos/fork/defunkt/hub").
|
679
|
+
to_return(:status => [500, "Your fork is fail"])
|
680
|
+
|
681
|
+
expected = "Error creating fork: Your fork is fail (HTTP 500)\n"
|
682
|
+
assert_equal expected, hub("fork") { ENV['GIT'] = 'echo' }
|
683
|
+
end
|
684
|
+
|
685
|
+
def test_fork_no_remote
|
686
|
+
stub_nonexisting_fork('tpw')
|
687
|
+
stub_request(:post, "https://#{auth}github.com/api/v2/yaml/repos/fork/defunkt/hub")
|
688
|
+
|
689
|
+
assert_equal "", hub("fork --no-remote") { ENV['GIT'] = 'echo' }
|
690
|
+
end
|
691
|
+
|
692
|
+
def test_fork_already_exists
|
693
|
+
stub_existing_fork('tpw')
|
694
|
+
|
695
|
+
expected = "tpw/hub already exists on GitHub\n"
|
696
|
+
expected << "remote add -f tpw git@github.com:tpw/hub.git\n"
|
697
|
+
expected << "new remote: tpw\n"
|
698
|
+
assert_equal expected, hub("fork") { ENV['GIT'] = 'echo' }
|
699
|
+
end
|
700
|
+
|
701
|
+
def test_fork_https_protocol
|
702
|
+
stub_existing_fork('tpw')
|
703
|
+
stub_https_is_preferred
|
704
|
+
|
705
|
+
expected = "tpw/hub already exists on GitHub\n"
|
706
|
+
expected << "remote add -f tpw https://github.com/tpw/hub.git\n"
|
707
|
+
expected << "new remote: tpw\n"
|
708
|
+
assert_equal expected, hub("fork") { ENV['GIT'] = 'echo' }
|
709
|
+
end
|
710
|
+
|
711
|
+
def test_pullrequest
|
712
|
+
expected = "Aborted: head branch is the same as base (\"master\")\n" <<
|
713
|
+
"(use `-h <branch>` to specify an explicit pull request head)\n"
|
714
|
+
assert_output expected, "pull-request hereyougo"
|
715
|
+
end
|
716
|
+
|
717
|
+
def test_pullrequest_with_unpushed_commits
|
718
|
+
stub_tracking('master', 'mislav', 'master')
|
719
|
+
stub_command_output "rev-list --cherry mislav/master...", "+abcd1234\n+bcde2345"
|
720
|
+
|
721
|
+
expected = "Aborted: 2 commits are not yet pushed to mislav/master\n" <<
|
722
|
+
"(use `-f` to force submit a pull request anyway)\n"
|
723
|
+
assert_output expected, "pull-request hereyougo"
|
724
|
+
end
|
725
|
+
|
726
|
+
def test_pullrequest_from_branch
|
727
|
+
stub_branch('refs/heads/feature')
|
728
|
+
stub_tracking_nothing('feature')
|
729
|
+
|
730
|
+
stub_request(:post, "https://#{auth}github.com/api/v2/yaml/pulls/defunkt/hub").
|
731
|
+
with(:body => { 'pull' => {'base' => "master", 'head' => "tpw:feature", 'title' => "hereyougo"} }).
|
732
|
+
to_return(:body => mock_pullreq_response(1))
|
733
|
+
|
734
|
+
expected = "https://github.com/defunkt/hub/pull/1\n"
|
735
|
+
assert_output expected, "pull-request hereyougo -f"
|
736
|
+
end
|
737
|
+
|
738
|
+
def test_pullrequest_from_tracking_branch
|
739
|
+
stub_branch('refs/heads/feature')
|
740
|
+
stub_tracking('feature', 'mislav', 'yay-feature')
|
741
|
+
stub_command_output "rev-list --cherry mislav/master...", nil
|
742
|
+
|
743
|
+
stub_request(:post, "https://#{auth}github.com/api/v2/yaml/pulls/defunkt/hub").
|
744
|
+
with(:body => { 'pull' => {'base' => "master", 'head' => "mislav:yay-feature", 'title' => "hereyougo"} }).
|
745
|
+
to_return(:body => mock_pullreq_response(1))
|
746
|
+
|
747
|
+
expected = "https://github.com/defunkt/hub/pull/1\n"
|
748
|
+
assert_output expected, "pull-request hereyougo -f"
|
749
|
+
end
|
750
|
+
|
751
|
+
def test_pullrequest_explicit_head
|
752
|
+
stub_request(:post, "https://#{auth}github.com/api/v2/yaml/pulls/defunkt/hub").
|
753
|
+
with(:body => { 'pull' => {'base' => "master", 'head' => "tpw:yay-feature", 'title' => "hereyougo"} }).
|
754
|
+
to_return(:body => mock_pullreq_response(1))
|
755
|
+
|
756
|
+
expected = "https://github.com/defunkt/hub/pull/1\n"
|
757
|
+
assert_output expected, "pull-request hereyougo -h yay-feature -f"
|
758
|
+
end
|
759
|
+
|
760
|
+
def test_pullrequest_explicit_head_with_owner
|
761
|
+
stub_request(:post, "https://#{auth}github.com/api/v2/yaml/pulls/defunkt/hub").
|
762
|
+
with(:body => { 'pull' => {'base' => "master", 'head' => "mojombo:feature", 'title' => "hereyougo"} }).
|
763
|
+
to_return(:body => mock_pullreq_response(1))
|
764
|
+
|
765
|
+
expected = "https://github.com/defunkt/hub/pull/1\n"
|
766
|
+
assert_output expected, "pull-request hereyougo -h mojombo:feature -f"
|
767
|
+
end
|
768
|
+
|
769
|
+
def test_pullrequest_explicit_base
|
770
|
+
stub_request(:post, "https://#{auth}github.com/api/v2/yaml/pulls/defunkt/hub").
|
771
|
+
with(:body => { 'pull' => {'base' => "feature", 'head' => "defunkt:master", 'title' => "hereyougo"} }).
|
772
|
+
to_return(:body => mock_pullreq_response(1))
|
773
|
+
|
774
|
+
expected = "https://github.com/defunkt/hub/pull/1\n"
|
775
|
+
assert_output expected, "pull-request hereyougo -b feature -f"
|
776
|
+
end
|
777
|
+
|
778
|
+
def test_pullrequest_explicit_base_with_owner
|
779
|
+
stub_request(:post, "https://#{auth}github.com/api/v2/yaml/pulls/mojombo/hub").
|
780
|
+
with(:body => { 'pull' => {'base' => "feature", 'head' => "defunkt:master", 'title' => "hereyougo"} }).
|
781
|
+
to_return(:body => mock_pullreq_response(1))
|
782
|
+
|
783
|
+
expected = "https://github.com/defunkt/hub/pull/1\n"
|
784
|
+
assert_output expected, "pull-request hereyougo -b mojombo:feature -f"
|
785
|
+
end
|
786
|
+
|
787
|
+
def test_pullrequest_explicit_base_with_repo
|
788
|
+
stub_request(:post, "https://#{auth}github.com/api/v2/yaml/pulls/mojombo/hubbub").
|
789
|
+
with(:body => { 'pull' => {'base' => "feature", 'head' => "defunkt:master", 'title' => "hereyougo"} }).
|
790
|
+
to_return(:body => mock_pullreq_response(1))
|
791
|
+
|
792
|
+
expected = "https://github.com/defunkt/hub/pull/1\n"
|
793
|
+
assert_output expected, "pull-request hereyougo -b mojombo/hubbub:feature -f"
|
794
|
+
end
|
795
|
+
|
796
|
+
def test_pullrequest_existing_issue
|
797
|
+
stub_branch('refs/heads/myfix')
|
798
|
+
stub_tracking('myfix', 'mislav', 'awesomefix')
|
799
|
+
stub_command_output "rev-list --cherry mislav/awesomefix...", nil
|
800
|
+
|
801
|
+
stub_request(:post, "https://#{auth}github.com/api/v2/yaml/pulls/defunkt/hub").
|
802
|
+
with(:body => { 'pull' => {'base' => "master", 'head' => "mislav:awesomefix", 'issue' => '92'} }).
|
803
|
+
to_return(:body => mock_pullreq_response(92))
|
804
|
+
|
805
|
+
expected = "https://github.com/defunkt/hub/pull/92\n"
|
806
|
+
assert_output expected, "pull-request -i 92"
|
807
|
+
end
|
808
|
+
|
809
|
+
def test_pullrequest_existing_issue_url
|
810
|
+
stub_branch('refs/heads/myfix')
|
811
|
+
stub_tracking('myfix', 'mislav', 'awesomefix')
|
812
|
+
stub_command_output "rev-list --cherry mislav/awesomefix...", nil
|
813
|
+
|
814
|
+
stub_request(:post, "https://#{auth}github.com/api/v2/yaml/pulls/mojombo/hub").
|
815
|
+
with(:body => { 'pull' => {'base' => "master", 'head' => "mislav:awesomefix", 'issue' => '92'} }).
|
816
|
+
to_return(:body => mock_pullreq_response(92, 'mojombo/hub'))
|
817
|
+
|
818
|
+
expected = "https://github.com/mojombo/hub/pull/92\n"
|
819
|
+
assert_output expected, "pull-request https://github.com/mojombo/hub/issues/92#comment_4"
|
820
|
+
end
|
821
|
+
|
822
|
+
def test_checkout_no_changes
|
823
|
+
assert_forwarded "checkout master"
|
824
|
+
end
|
825
|
+
|
826
|
+
def test_checkout_pullrequest
|
827
|
+
stub_request(:get, "http://github.com/api/v2/json/pulls/defunkt/hub/73").
|
828
|
+
to_return(:body => mock_pull_response('blueyed:feature'))
|
829
|
+
|
830
|
+
assert_commands 'git remote add -f -t feature blueyed git://github.com/blueyed/hub.git',
|
831
|
+
'git checkout -b blueyed-feature blueyed/feature',
|
832
|
+
"checkout https://github.com/defunkt/hub/pull/73/files"
|
833
|
+
end
|
834
|
+
|
835
|
+
def test_checkout_pullrequest_custom_branch
|
836
|
+
stub_request(:get, "http://github.com/api/v2/json/pulls/defunkt/hub/73").
|
837
|
+
to_return(:body => mock_pull_response('blueyed:feature'))
|
838
|
+
|
839
|
+
assert_commands 'git remote add -f -t feature blueyed git://github.com/blueyed/hub.git',
|
840
|
+
'git checkout -b review blueyed/feature',
|
841
|
+
"checkout https://github.com/defunkt/hub/pull/73/files review"
|
842
|
+
end
|
843
|
+
|
844
|
+
def test_checkout_pullrequest_existing_remote
|
845
|
+
stub_command_output 'remote', "origin\nblueyed"
|
846
|
+
|
847
|
+
stub_request(:get, "http://github.com/api/v2/json/pulls/defunkt/hub/73").
|
848
|
+
to_return(:body => mock_pull_response('blueyed:feature'))
|
849
|
+
|
850
|
+
assert_commands 'git remote set-branches --add blueyed feature',
|
851
|
+
'git fetch blueyed +refs/heads/feature:refs/remotes/blueyed/feature',
|
852
|
+
'git checkout -b blueyed-feature blueyed/feature',
|
853
|
+
"checkout https://github.com/defunkt/hub/pull/73/files"
|
854
|
+
end
|
855
|
+
|
856
|
+
def test_version
|
857
|
+
out = hub('--version')
|
858
|
+
assert_includes "git version 1.7.0.4", out
|
859
|
+
assert_includes "hub version #{Hub::Version}", out
|
860
|
+
end
|
861
|
+
|
862
|
+
def test_exec_path
|
863
|
+
out = hub('--exec-path')
|
864
|
+
assert_equal "/usr/lib/git-core\n", out
|
865
|
+
end
|
866
|
+
|
867
|
+
def test_exec_path_arg
|
868
|
+
out = hub('--exec-path=/home/wombat/share/my-l33t-git-core')
|
869
|
+
assert_equal improved_help_text, out
|
870
|
+
end
|
871
|
+
|
872
|
+
def test_html_path
|
873
|
+
out = hub('--html-path')
|
874
|
+
assert_equal "/usr/share/doc/git-doc\n", out
|
875
|
+
end
|
876
|
+
|
877
|
+
def test_help
|
878
|
+
assert_equal improved_help_text, hub("help")
|
879
|
+
end
|
880
|
+
|
881
|
+
def test_help_by_default
|
882
|
+
assert_equal improved_help_text, hub("")
|
883
|
+
end
|
884
|
+
|
885
|
+
def test_help_with_pager
|
886
|
+
assert_equal improved_help_text, hub("-p")
|
887
|
+
end
|
888
|
+
|
889
|
+
def test_help_hub
|
890
|
+
help_manpage = hub("help hub")
|
891
|
+
assert_includes "git + hub = github", help_manpage
|
892
|
+
assert_includes <<-config, help_manpage
|
893
|
+
Use git-config(1) to display the currently configured GitHub username:
|
894
|
+
config
|
895
|
+
end
|
896
|
+
|
897
|
+
def test_help_hub_no_groff
|
898
|
+
stub_available_commands()
|
899
|
+
assert_equal "** Can't find groff(1)\n", hub("help hub")
|
900
|
+
end
|
901
|
+
|
902
|
+
def test_hub_standalone
|
903
|
+
help_standalone = hub("hub standalone")
|
904
|
+
assert_equal Hub::Standalone.build, help_standalone
|
905
|
+
end
|
906
|
+
|
907
|
+
def test_hub_compare
|
908
|
+
assert_command "compare refactor",
|
909
|
+
"open https://github.com/defunkt/hub/compare/refactor"
|
910
|
+
end
|
911
|
+
|
912
|
+
def test_hub_compare_nothing
|
913
|
+
expected = "Usage: hub compare [USER] [<START>...]<END>\n"
|
914
|
+
assert_equal expected, hub("compare")
|
915
|
+
end
|
916
|
+
|
917
|
+
def test_hub_compare_tracking_nothing
|
918
|
+
stub_tracking_nothing
|
919
|
+
expected = "Usage: hub compare [USER] [<START>...]<END>\n"
|
920
|
+
assert_equal expected, hub("compare")
|
921
|
+
end
|
922
|
+
|
923
|
+
def test_hub_compare_tracking_branch
|
924
|
+
stub_branch('refs/heads/feature')
|
925
|
+
stub_tracking('feature', 'mislav', 'experimental')
|
926
|
+
|
927
|
+
assert_command "compare",
|
928
|
+
"open https://github.com/mislav/hub/compare/experimental"
|
929
|
+
end
|
930
|
+
|
931
|
+
def test_hub_compare_range
|
932
|
+
assert_command "compare 1.0...fix",
|
933
|
+
"open https://github.com/defunkt/hub/compare/1.0...fix"
|
934
|
+
end
|
935
|
+
|
936
|
+
def test_hub_compare_range_fixes_two_dots_for_tags
|
937
|
+
assert_command "compare 1.0..fix",
|
938
|
+
"open https://github.com/defunkt/hub/compare/1.0...fix"
|
939
|
+
end
|
940
|
+
|
941
|
+
def test_hub_compare_range_fixes_two_dots_for_shas
|
942
|
+
assert_command "compare 1234abc..3456cde",
|
943
|
+
"open https://github.com/defunkt/hub/compare/1234abc...3456cde"
|
944
|
+
end
|
945
|
+
|
946
|
+
def test_hub_compare_range_ignores_two_dots_for_complex_ranges
|
947
|
+
assert_command "compare @{a..b}..@{c..d}",
|
948
|
+
"open https://github.com/defunkt/hub/compare/@{a..b}..@{c..d}"
|
949
|
+
end
|
950
|
+
|
951
|
+
def test_hub_compare_on_wiki
|
952
|
+
stub_repo_url 'git://github.com/defunkt/hub.wiki.git'
|
953
|
+
assert_command "compare 1.0...fix",
|
954
|
+
"open https://github.com/defunkt/hub/wiki/_compare/1.0...fix"
|
955
|
+
end
|
956
|
+
|
957
|
+
def test_hub_compare_fork
|
958
|
+
assert_command "compare myfork feature",
|
959
|
+
"open https://github.com/myfork/hub/compare/feature"
|
960
|
+
end
|
961
|
+
|
962
|
+
def test_hub_compare_url
|
963
|
+
assert_command "compare -u 1.0...1.1",
|
964
|
+
"echo https://github.com/defunkt/hub/compare/1.0...1.1"
|
965
|
+
end
|
966
|
+
|
967
|
+
def test_hub_browse
|
968
|
+
assert_command "browse mojombo/bert", "open https://github.com/mojombo/bert"
|
969
|
+
end
|
970
|
+
|
971
|
+
def test_hub_browse_commit
|
972
|
+
assert_command "browse mojombo/bert commit/5d5582", "open https://github.com/mojombo/bert/commit/5d5582"
|
973
|
+
end
|
974
|
+
|
975
|
+
def test_hub_browse_tracking_nothing
|
976
|
+
stub_tracking_nothing
|
977
|
+
assert_command "browse mojombo/bert", "open https://github.com/mojombo/bert"
|
978
|
+
end
|
979
|
+
|
980
|
+
def test_hub_browse_url
|
981
|
+
assert_command "browse -u mojombo/bert", "echo https://github.com/mojombo/bert"
|
982
|
+
end
|
983
|
+
|
984
|
+
def test_hub_browse_self
|
985
|
+
assert_command "browse resque", "open https://github.com/tpw/resque"
|
986
|
+
end
|
987
|
+
|
988
|
+
def test_hub_browse_subpage
|
989
|
+
assert_command "browse resque commits",
|
990
|
+
"open https://github.com/tpw/resque/commits/master"
|
991
|
+
assert_command "browse resque issues",
|
992
|
+
"open https://github.com/tpw/resque/issues"
|
993
|
+
assert_command "browse resque wiki",
|
994
|
+
"open https://github.com/tpw/resque/wiki"
|
995
|
+
end
|
996
|
+
|
997
|
+
def test_hub_browse_on_branch
|
998
|
+
stub_branch('refs/heads/feature')
|
999
|
+
stub_tracking('feature', 'mislav', 'experimental')
|
1000
|
+
|
1001
|
+
assert_command "browse resque", "open https://github.com/tpw/resque"
|
1002
|
+
assert_command "browse resque commits",
|
1003
|
+
"open https://github.com/tpw/resque/commits/master"
|
1004
|
+
|
1005
|
+
assert_command "browse",
|
1006
|
+
"open https://github.com/mislav/hub/tree/experimental"
|
1007
|
+
assert_command "browse -- tree",
|
1008
|
+
"open https://github.com/mislav/hub/tree/experimental"
|
1009
|
+
assert_command "browse -- commits",
|
1010
|
+
"open https://github.com/mislav/hub/commits/experimental"
|
1011
|
+
end
|
1012
|
+
|
1013
|
+
def test_hub_browse_current
|
1014
|
+
assert_command "browse", "open https://github.com/defunkt/hub"
|
1015
|
+
assert_command "browse --", "open https://github.com/defunkt/hub"
|
1016
|
+
end
|
1017
|
+
|
1018
|
+
def test_hub_browse_commit_from_current
|
1019
|
+
assert_command "browse -- commit/6616e4", "open https://github.com/defunkt/hub/commit/6616e4"
|
1020
|
+
end
|
1021
|
+
|
1022
|
+
def test_hub_browse_no_tracking
|
1023
|
+
stub_tracking_nothing
|
1024
|
+
assert_command "browse", "open https://github.com/defunkt/hub"
|
1025
|
+
end
|
1026
|
+
|
1027
|
+
def test_hub_browse_no_tracking_on_branch
|
1028
|
+
stub_branch('refs/heads/feature')
|
1029
|
+
stub_tracking_nothing('feature')
|
1030
|
+
assert_command "browse", "open https://github.com/defunkt/hub"
|
1031
|
+
end
|
1032
|
+
|
1033
|
+
def test_hub_browse_current_wiki
|
1034
|
+
stub_repo_url 'git://github.com/defunkt/hub.wiki.git'
|
1035
|
+
|
1036
|
+
assert_command "browse", "open https://github.com/defunkt/hub/wiki"
|
1037
|
+
assert_command "browse -- wiki", "open https://github.com/defunkt/hub/wiki"
|
1038
|
+
assert_command "browse -- commits", "open https://github.com/defunkt/hub/wiki/_history"
|
1039
|
+
assert_command "browse -- pages", "open https://github.com/defunkt/hub/wiki/_pages"
|
1040
|
+
end
|
1041
|
+
|
1042
|
+
def test_hub_browse_current_subpage
|
1043
|
+
assert_command "browse -- network",
|
1044
|
+
"open https://github.com/defunkt/hub/network"
|
1045
|
+
assert_command "browse -- anything/everything",
|
1046
|
+
"open https://github.com/defunkt/hub/anything/everything"
|
1047
|
+
end
|
1048
|
+
|
1049
|
+
def test_hub_browse_deprecated_private
|
1050
|
+
with_browser_env('echo') do
|
1051
|
+
assert_includes "Warning: the `-p` flag has no effect anymore\n", hub("browse -p defunkt/hub")
|
1052
|
+
end
|
1053
|
+
end
|
1054
|
+
|
1055
|
+
def test_hub_browse_no_repo
|
1056
|
+
stub_repo_url(nil)
|
1057
|
+
assert_equal "Usage: hub browse [<USER>/]<REPOSITORY>\n", hub("browse")
|
1058
|
+
end
|
1059
|
+
|
1060
|
+
def test_custom_browser
|
1061
|
+
with_browser_env("custom") do
|
1062
|
+
assert_browser("custom")
|
1063
|
+
end
|
1064
|
+
end
|
1065
|
+
|
1066
|
+
def test_linux_browser
|
1067
|
+
stub_available_commands "open", "xdg-open", "cygstart"
|
1068
|
+
with_browser_env(nil) do
|
1069
|
+
with_host_os("i686-linux") do
|
1070
|
+
assert_browser("xdg-open")
|
1071
|
+
end
|
1072
|
+
end
|
1073
|
+
end
|
1074
|
+
|
1075
|
+
def test_cygwin_browser
|
1076
|
+
stub_available_commands "open", "cygstart"
|
1077
|
+
with_browser_env(nil) do
|
1078
|
+
with_host_os("i686-linux") do
|
1079
|
+
assert_browser("cygstart")
|
1080
|
+
end
|
1081
|
+
end
|
1082
|
+
end
|
1083
|
+
|
1084
|
+
def test_no_browser
|
1085
|
+
stub_available_commands()
|
1086
|
+
expected = "Please set $BROWSER to a web launcher to use this command.\n"
|
1087
|
+
with_browser_env(nil) do
|
1088
|
+
with_host_os("i686-linux") do
|
1089
|
+
assert_equal expected, hub("browse")
|
1090
|
+
end
|
1091
|
+
end
|
1092
|
+
end
|
1093
|
+
|
1094
|
+
def test_context_method_doesnt_hijack_git_command
|
1095
|
+
assert_forwarded 'remotes'
|
1096
|
+
end
|
1097
|
+
|
1098
|
+
def test_not_choking_on_ruby_methods
|
1099
|
+
assert_forwarded 'id'
|
1100
|
+
assert_forwarded 'name'
|
1101
|
+
end
|
1102
|
+
|
1103
|
+
def test_multiple_remote_urls
|
1104
|
+
stub_repo_url("git://example.com/other.git\ngit://github.com/my/repo.git")
|
1105
|
+
assert_command "browse", "open https://github.com/my/repo"
|
1106
|
+
end
|
1107
|
+
|
1108
|
+
def test_global_flags_preserved
|
1109
|
+
cmd = '--no-pager --bare -c core.awesome=true -c name=value --git-dir=/srv/www perform'
|
1110
|
+
assert_command cmd, 'git --bare -c core.awesome=true -c name=value --git-dir=/srv/www --no-pager perform'
|
1111
|
+
assert_equal %w[git --bare -c core.awesome=true -c name=value --git-dir=/srv/www], git_reader.executable
|
1112
|
+
end
|
1113
|
+
|
1114
|
+
protected
|
1115
|
+
|
1116
|
+
def stub_github_user(name)
|
1117
|
+
stub_config_value 'github.user', name
|
1118
|
+
end
|
1119
|
+
|
1120
|
+
def stub_github_token(token)
|
1121
|
+
stub_config_value 'github.token', token
|
1122
|
+
end
|
1123
|
+
|
1124
|
+
def stub_repo_url(value, remote_name = 'origin')
|
1125
|
+
stub_config_value "remote.#{remote_name}.url", value, '--get-all'
|
1126
|
+
end
|
1127
|
+
|
1128
|
+
def stub_branch(value)
|
1129
|
+
stub_command_output 'symbolic-ref -q HEAD', value
|
1130
|
+
end
|
1131
|
+
|
1132
|
+
def stub_tracking(from, remote_name, remote_branch)
|
1133
|
+
stub_command_output "rev-parse --symbolic-full-name #{from}@{upstream}",
|
1134
|
+
remote_branch ? "refs/remotes/#{remote_name}/#{remote_branch}" : nil
|
1135
|
+
end
|
1136
|
+
|
1137
|
+
def stub_tracking_nothing(from = 'master')
|
1138
|
+
stub_tracking(from, nil, nil)
|
1139
|
+
end
|
1140
|
+
|
1141
|
+
def stub_remotes_group(name, value)
|
1142
|
+
stub_config_value "remotes.#{name}", value
|
1143
|
+
end
|
1144
|
+
|
1145
|
+
def stub_no_remotes
|
1146
|
+
stub_command_output 'remote', nil
|
1147
|
+
end
|
1148
|
+
|
1149
|
+
def stub_no_git_repo
|
1150
|
+
stub_command_output 'rev-parse -q --git-dir', nil
|
1151
|
+
end
|
1152
|
+
|
1153
|
+
def stub_alias(name, value)
|
1154
|
+
stub_config_value "alias.#{name}", value
|
1155
|
+
end
|
1156
|
+
|
1157
|
+
def stub_existing_fork(user, repo = 'hub')
|
1158
|
+
stub_fork(user, repo, 200)
|
1159
|
+
end
|
1160
|
+
|
1161
|
+
def stub_nonexisting_fork(user, repo = 'hub')
|
1162
|
+
stub_fork(user, repo, 404)
|
1163
|
+
end
|
1164
|
+
|
1165
|
+
def stub_fork(user, repo, status)
|
1166
|
+
stub_request(:get, "github.com/api/v2/yaml/repos/show/#{user}/#{repo}").
|
1167
|
+
to_return(:status => status)
|
1168
|
+
end
|
1169
|
+
|
1170
|
+
def stub_available_commands(*names)
|
1171
|
+
COMMANDS.replace names
|
1172
|
+
end
|
1173
|
+
|
1174
|
+
def stub_https_is_preferred
|
1175
|
+
stub_config_value 'hub.protocol', 'https'
|
1176
|
+
end
|
1177
|
+
|
1178
|
+
def with_browser_env(value)
|
1179
|
+
browser, ENV['BROWSER'] = ENV['BROWSER'], value
|
1180
|
+
yield
|
1181
|
+
ensure
|
1182
|
+
ENV['BROWSER'] = browser
|
1183
|
+
end
|
1184
|
+
|
1185
|
+
def with_tmpdir(value)
|
1186
|
+
dir, ENV['TMPDIR'] = ENV['TMPDIR'], value
|
1187
|
+
yield
|
1188
|
+
ensure
|
1189
|
+
ENV['TMPDIR'] = dir
|
1190
|
+
end
|
1191
|
+
|
1192
|
+
def assert_browser(browser)
|
1193
|
+
assert_command "browse", "#{browser} https://github.com/defunkt/hub"
|
1194
|
+
end
|
1195
|
+
|
1196
|
+
def with_host_os(value)
|
1197
|
+
host_os = RbConfig::CONFIG['host_os']
|
1198
|
+
RbConfig::CONFIG['host_os'] = value
|
1199
|
+
begin
|
1200
|
+
yield
|
1201
|
+
ensure
|
1202
|
+
RbConfig::CONFIG['host_os'] = host_os
|
1203
|
+
end
|
1204
|
+
end
|
1205
|
+
|
1206
|
+
def auth(user = git_config('github.user'), password = git_config('github.token'))
|
1207
|
+
"#{user}%2Ftoken:#{password}@"
|
1208
|
+
end
|
1209
|
+
|
1210
|
+
def mock_pullreq_response(id, name_with_owner = 'defunkt/hub')
|
1211
|
+
YAML.dump('pull' => {
|
1212
|
+
'html_url' => "https://github.com/#{name_with_owner}/pull/#{id}"
|
1213
|
+
})
|
1214
|
+
end
|
1215
|
+
|
1216
|
+
def mock_pull_response(label)
|
1217
|
+
JSON.generate('pull' => { 'head' => {'label' => label} })
|
1218
|
+
end
|
1219
|
+
|
1220
|
+
def improved_help_text
|
1221
|
+
Hub::Commands.send :improved_help_text
|
1222
|
+
end
|
1223
|
+
|
1224
|
+
end
|