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