git_go 0.0.1 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.travis.yml +2 -2
- data/Gemfile +1 -0
- data/Gemfile.lock +5 -3
- data/README.md +9 -2
- data/bin/gg +2 -2
- data/lib/git_go/{cli/gg.rb → cli.rb} +22 -19
- data/lib/git_go/connection/base.rb +102 -0
- data/lib/git_go/connection/local.rb +37 -0
- data/lib/git_go/connection/remote.rb +51 -0
- data/lib/git_go/connection.rb +1 -133
- data/lib/git_go/version.rb +1 -1
- data/lib/git_go.rb +11 -1
- data/spec/lib/git_go/cli_spec.rb +220 -0
- data/spec/lib/git_go/{connection_spec.rb → connection/base_spec.rb} +3 -25
- data/spec/lib/git_go/connection/local_spec.rb +20 -0
- data/spec/lib/git_go/connection/remote_spec.rb +29 -0
- data/spec/lib/git_go_spec.rb +20 -0
- data/spec/spec_helper.rb +13 -3
- metadata +16 -7
data/.travis.yml
CHANGED
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
git_go (0.0
|
4
|
+
git_go (0.1.0)
|
5
5
|
net-ssh (~> 2.6.2)
|
6
6
|
thor (~> 0.16.0)
|
7
7
|
|
@@ -27,12 +27,13 @@ GEM
|
|
27
27
|
mocha (0.13.1)
|
28
28
|
metaclass (~> 0.0.1)
|
29
29
|
net-ssh (2.6.2)
|
30
|
+
open4 (1.3.0)
|
30
31
|
pry (0.9.10)
|
31
32
|
coderay (~> 1.0.5)
|
32
33
|
method_source (~> 0.8)
|
33
34
|
slop (~> 3.3.1)
|
34
35
|
rake (10.0.2)
|
35
|
-
rb-fchange (0.0.
|
36
|
+
rb-fchange (0.0.6)
|
36
37
|
ffi
|
37
38
|
rb-fsevent (0.9.2)
|
38
39
|
rb-inotify (0.8.8)
|
@@ -47,7 +48,7 @@ GEM
|
|
47
48
|
rspec-mocks (2.12.0)
|
48
49
|
slop (3.3.3)
|
49
50
|
thor (0.16.0)
|
50
|
-
yard (0.8.
|
51
|
+
yard (0.8.3)
|
51
52
|
|
52
53
|
PLATFORMS
|
53
54
|
ruby
|
@@ -57,6 +58,7 @@ DEPENDENCIES
|
|
57
58
|
growl
|
58
59
|
guard-rspec
|
59
60
|
mocha
|
61
|
+
open4
|
60
62
|
rake
|
61
63
|
rb-fchange
|
62
64
|
rb-fsevent
|
data/README.md
CHANGED
@@ -1,11 +1,18 @@
|
|
1
1
|
# Git Go
|
2
2
|
|
3
|
-
[![Build Status](https://travis-ci.org/meskyanichi/git_go.png)](https://travis-ci.org/meskyanichi/git_go)
|
4
|
-
|
5
3
|
Git Go is a small command-line utility distributed as a RubyGem that allows you to easily create/destroy/rename/list all your private-hosted git repositories on your own server. All you need is a small VPS (256MB RAM / 10GB HDD / 1vCPUCore should be sufficient).
|
6
4
|
|
7
5
|
Git Go also provides you with detailed instructions on how to set up your server in order to be able to create remote repositories from your local machine using the provided command-line utility. The instructions also show you how to set up automatic/daily compressed/archived backups of all your git repositories, store them on Amazon S3, cycle them and send you success/error notifications by email, all using the [Backup](http://github.com/meskyanichi/backup) RubyGem. It's easy, and only takes a few minutes to set up.
|
8
6
|
|
7
|
+
Git Go is tested against:
|
8
|
+
|
9
|
+
* **Ruby** 1.9.3, 1.9.2, 1.8.7
|
10
|
+
* **Rubinius** 1.8 mode, 1.9 mode
|
11
|
+
|
12
|
+
It *should* work with **JRuby**, but it's currently untestable due to issues with `Process.waitpid`. But, `Process.waitpid` is only used in the test environment, not in the distributed gem you'll be using.
|
13
|
+
|
14
|
+
[![Build Status](https://travis-ci.org/meskyanichi/git_go.png)](https://travis-ci.org/meskyanichi/git_go)
|
15
|
+
|
9
16
|
## Get Git Go
|
10
17
|
|
11
18
|
Install Git Go with the following command:
|
data/bin/gg
CHANGED
@@ -1,16 +1,17 @@
|
|
1
1
|
# -*- encoding : utf-8 -*-
|
2
2
|
|
3
3
|
module GitGo
|
4
|
-
class
|
4
|
+
class CLI < Thor
|
5
5
|
include Thor::Actions
|
6
6
|
|
7
7
|
desc "create NAME", "Create a new remote repository named NAME"
|
8
8
|
def create(name)
|
9
9
|
core = GitGo::Core.new
|
10
10
|
conn = core.connection
|
11
|
+
|
11
12
|
if conn.directory?("#{name}.git")
|
12
|
-
puts "
|
13
|
-
conn.close_and_exit(1)
|
13
|
+
puts %Q("#{name}" already exists.)
|
14
|
+
return conn.close_and_exit(1)
|
14
15
|
else
|
15
16
|
conn.mkdir("#{name}.git")
|
16
17
|
conn.cd("#{name}.git")
|
@@ -29,23 +30,24 @@ module GitGo
|
|
29
30
|
|
30
31
|
desc "destroy NAME", "Destroy the remote repository named NAME"
|
31
32
|
def destroy(name)
|
32
|
-
core
|
33
|
-
conn
|
33
|
+
core = GitGo::Core.new
|
34
|
+
conn = core.connection
|
34
35
|
repository = "#{name}.git"
|
36
|
+
|
35
37
|
if conn.directory?(repository)
|
36
|
-
if yes?(
|
38
|
+
if yes?(%Q(Are you sure you want to destroy "#{name}"?))
|
37
39
|
response = conn.rm(repository)
|
38
40
|
if response[:exit_code] == 0
|
39
|
-
puts
|
41
|
+
puts %Q(Repository "#{name}" was destroyed.)
|
40
42
|
else
|
41
|
-
puts
|
43
|
+
puts %Q(Repository "#{name}" could not be destroyed.)
|
42
44
|
puts response[:stdout] + response[:stderr]
|
43
|
-
conn.close_and_exit(1)
|
45
|
+
return conn.close_and_exit(1)
|
44
46
|
end
|
45
47
|
end
|
46
48
|
else
|
47
|
-
puts
|
48
|
-
conn.close_and_exit(1)
|
49
|
+
puts %Q(Repository "#{name}" does not exist.)
|
50
|
+
return conn.close_and_exit(1)
|
49
51
|
end
|
50
52
|
|
51
53
|
conn.close
|
@@ -59,22 +61,22 @@ module GitGo
|
|
59
61
|
new_repository = "#{new_name}.git"
|
60
62
|
|
61
63
|
if not conn.directory?(repository)
|
62
|
-
puts
|
63
|
-
conn.close_and_exit(1)
|
64
|
+
puts %Q(Repository "#{name}" does not exist.)
|
65
|
+
return conn.close_and_exit(1)
|
64
66
|
end
|
65
67
|
|
66
68
|
if conn.directory?(new_repository)
|
67
|
-
puts
|
68
|
-
conn.close_and_exit(1)
|
69
|
+
puts %Q(Repository "#{new_name}" already exists.)
|
70
|
+
return conn.close_and_exit(1)
|
69
71
|
end
|
70
72
|
|
71
73
|
response = conn.mv(repository, new_repository)
|
72
74
|
if response[:exit_code] == 0
|
73
|
-
puts
|
75
|
+
puts %Q(Repository "#{name}" renamed to "#{new_name}".)
|
74
76
|
else
|
75
|
-
puts
|
77
|
+
puts %Q(Could not rename "#{name}" to "#{new_name}".)
|
76
78
|
puts response[:stderr] + response[:stdout]
|
77
|
-
conn.close_and_exit(1)
|
79
|
+
return conn.close_and_exit(1)
|
78
80
|
end
|
79
81
|
|
80
82
|
conn.close
|
@@ -101,7 +103,8 @@ module GitGo
|
|
101
103
|
amount = list.count - 1
|
102
104
|
out = Formatter.columns(list, :spacing => 4, :header => true)
|
103
105
|
|
104
|
-
puts "\n"
|
106
|
+
puts "\n"
|
107
|
+
puts out
|
105
108
|
puts "\nThere #{amount == 1 ? "is" : "are"} #{amount} git " +
|
106
109
|
"#{amount == 1 ? "repository" : "repositories"}.\n"
|
107
110
|
else
|
@@ -0,0 +1,102 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
|
3
|
+
class GitGo::Connection::Base
|
4
|
+
|
5
|
+
# @return [GitGo::Core] instance.
|
6
|
+
attr_reader :core
|
7
|
+
|
8
|
+
# @return [String] the current path on the host.
|
9
|
+
attr_reader :current_path
|
10
|
+
|
11
|
+
def initialize(core)
|
12
|
+
@core = core
|
13
|
+
@current_path = ""
|
14
|
+
end
|
15
|
+
|
16
|
+
# Moves the instance to the provided path and remembers it for the next
|
17
|
+
# action performed through the #bash method. It keeps the current path
|
18
|
+
# in #current_path
|
19
|
+
#
|
20
|
+
# @see #bash
|
21
|
+
# @see #current_path
|
22
|
+
# @param [String] path the path to navigate to.
|
23
|
+
# @return [String] the new path.
|
24
|
+
def cd(path)
|
25
|
+
@current_path = bash("cd '#{current_path}'; cd '#{path}'; pwd")[:stdout].chomp
|
26
|
+
end
|
27
|
+
|
28
|
+
# Tests to see whether the provided path is a directory.
|
29
|
+
# It will take the path relative from #current_path if no absolute
|
30
|
+
# path was provided.
|
31
|
+
#
|
32
|
+
# @param [String] path the path to test.
|
33
|
+
# @return [true, false]
|
34
|
+
def directory?(path)
|
35
|
+
bash("[ -d '#{path}' ]")[:exit_code] == 0
|
36
|
+
end
|
37
|
+
|
38
|
+
# Tests to see whether the provided path is a file.
|
39
|
+
# It will take the path relative from #current_path if no absolute
|
40
|
+
# path was provided.
|
41
|
+
#
|
42
|
+
# @param [String] path the path to test.
|
43
|
+
# @return [true, false]
|
44
|
+
def file?(path)
|
45
|
+
bash("[ -f '#{path}' ]")[:exit_code] == 0
|
46
|
+
end
|
47
|
+
|
48
|
+
# Creates a directory at the provided path.
|
49
|
+
# It will take the path relative from #current_path if no absolute
|
50
|
+
# path was provided.
|
51
|
+
#
|
52
|
+
# @param [String] path the path to create one or more directories for.
|
53
|
+
# @return [Hash] containing #bash response data.
|
54
|
+
def mkdir(path)
|
55
|
+
bash("mkdir -p '#{path}'")
|
56
|
+
end
|
57
|
+
|
58
|
+
# Removes a file or directory at the provided path.
|
59
|
+
# It will take the path relative from #current_path if no absolute
|
60
|
+
# path was provided.
|
61
|
+
#
|
62
|
+
# @param [String] path the path to the file or directory to remove.
|
63
|
+
# @return [Hash] containing #bash response data.
|
64
|
+
def rm(path)
|
65
|
+
bash("rm -rf '#{path}'")
|
66
|
+
end
|
67
|
+
|
68
|
+
# Moves a file or directory from the PATH to the NEW_PATH.
|
69
|
+
# It will take the path relative from #current_path if no absolute
|
70
|
+
# path was provided.
|
71
|
+
#
|
72
|
+
# @param [String] path the path to the file or directory to move.
|
73
|
+
# @param [String] new_path the path to where the new file or directory should be placed.
|
74
|
+
# @return [Hash] containing #bash response data.
|
75
|
+
def mv(path, new_path)
|
76
|
+
bash("mv '#{path}' '#{new_path}'")
|
77
|
+
end
|
78
|
+
|
79
|
+
# Closes the connection and exits the program with CODE.
|
80
|
+
#
|
81
|
+
# @see #close
|
82
|
+
# @param [Integer] code the code to exit the program with.
|
83
|
+
def close_and_exit(code = 0)
|
84
|
+
close
|
85
|
+
exit(code)
|
86
|
+
end
|
87
|
+
|
88
|
+
private
|
89
|
+
|
90
|
+
# Sources the ~/.bashrc or ~/.zshrc files.
|
91
|
+
# This ensures that the correct $PATH is always set and the propper binaries
|
92
|
+
# can be accessed by the remote shell. Will only source files if present.
|
93
|
+
#
|
94
|
+
# @return [String] code to source the .bashrc/.zshrc files.
|
95
|
+
def source
|
96
|
+
[
|
97
|
+
"if [ -f ~/.bashrc ]; then source ~/.bashrc; fi;",
|
98
|
+
"if [ -f ~/.zshrc ]; then source ~/.zshrc; fi;",
|
99
|
+
].join(" ")
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
|
3
|
+
require "open4"
|
4
|
+
|
5
|
+
class GitGo::Connection::Local < GitGo::Connection::Base
|
6
|
+
|
7
|
+
# Creates a new instance of GitGo::Connection::Local.
|
8
|
+
#
|
9
|
+
# @param [GitGo::Core] core takes and assigns a reference to parent class in #core.
|
10
|
+
# @return [GitGo::Connection::Local] an instance of GitGo::Connection.
|
11
|
+
def initialize(core)
|
12
|
+
super(core)
|
13
|
+
end
|
14
|
+
|
15
|
+
# Clears the `@connection` instance variable of this objects parent `Core`
|
16
|
+
# instance so new connections can be established.
|
17
|
+
def close
|
18
|
+
core.clear_connection
|
19
|
+
end
|
20
|
+
|
21
|
+
# Executes the provided COMMAND on the local machine.
|
22
|
+
# This is a blocking (non-asynchronous) operation.
|
23
|
+
#
|
24
|
+
# @param [String] command the command to perform on the host.
|
25
|
+
# @return [Hash] containing response data (:stdout, :stderr, :exit_code).
|
26
|
+
def bash(command)
|
27
|
+
pid, _, stdout, stderr = Open4::popen4(%Q(#{source} cd "#{current_path}"; #{command}))
|
28
|
+
_, status = Process::waitpid2(pid)
|
29
|
+
|
30
|
+
{
|
31
|
+
:stdout => stdout.read.strip,
|
32
|
+
:stderr => stderr.read.strip,
|
33
|
+
:exit_code => status.exitstatus
|
34
|
+
}
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
|
3
|
+
class GitGo::Connection::Remote < GitGo::Connection::Base
|
4
|
+
|
5
|
+
# @return [Net::SSH::Connection::Session] instance.
|
6
|
+
attr_reader :ssh
|
7
|
+
|
8
|
+
# Creates a new instance of GitGo::Connection::Remote. Establishes
|
9
|
+
# a session with the host and stores that session in #ssh.
|
10
|
+
#
|
11
|
+
# @param [GitGo::Core] core takes and assigns a reference to parent class in #core.
|
12
|
+
# @return [GitGo::Connection::Remote] an instance of GitGo::Connection.
|
13
|
+
def initialize(core)
|
14
|
+
super(core)
|
15
|
+
@ssh = Net::SSH.start(core.host, core.user)
|
16
|
+
end
|
17
|
+
|
18
|
+
# Closes the #ssh connection and clears the `@connection` instance
|
19
|
+
# variable of this objects parent `Core` instance so new connections
|
20
|
+
# can be established.
|
21
|
+
def close
|
22
|
+
ssh.close
|
23
|
+
core.clear_connection
|
24
|
+
end
|
25
|
+
|
26
|
+
# Executes the provided COMMAND over the #ssh connection.
|
27
|
+
# This is a blocking (non-asynchronous) operation.
|
28
|
+
#
|
29
|
+
# @param [String] command the command to perform on the host.
|
30
|
+
# @return [Hash] containing response data (:stdout, :stderr, :exit_code).
|
31
|
+
def bash(command)
|
32
|
+
response = {
|
33
|
+
:stdout => "",
|
34
|
+
:stderr => ""
|
35
|
+
}
|
36
|
+
|
37
|
+
ssh.open_channel do |channel|
|
38
|
+
channel.exec(%Q(#{source} cd "#{current_path}"; #{command})) do |ch, success|
|
39
|
+
abort "Failed: Couldn't execute command (ssh.channel.exec)." unless success
|
40
|
+
|
41
|
+
channel.on_data { |_, data| response[:stdout] += data }
|
42
|
+
channel.on_extended_data { |_, __, data| response[:stderr] += data }
|
43
|
+
channel.on_request("exit-status") { |_, data| response[:exit_code] = data.read_long }
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
ssh.loop
|
48
|
+
response
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
data/lib/git_go/connection.rb
CHANGED
@@ -1,139 +1,7 @@
|
|
1
1
|
# -*- encoding : utf-8 -*-
|
2
2
|
|
3
3
|
module GitGo
|
4
|
-
|
5
|
-
|
6
|
-
# @return [GitGo::Core] instance.
|
7
|
-
attr_reader :core
|
8
|
-
|
9
|
-
# @return [Net::SSH::Connection::Session] instance.
|
10
|
-
attr_reader :ssh
|
11
|
-
|
12
|
-
# @return [String] the current path on the host.
|
13
|
-
attr_reader :current_path
|
14
|
-
|
15
|
-
# Creates a new instane of GitGo::Connection. Establishes
|
16
|
-
# a session with the host and stores that session in #ssh.
|
17
|
-
#
|
18
|
-
# @param [GitGo::Core] core takes and assigns a reference to parent class in #core.
|
19
|
-
# @return [GitGo::Connection] an instance of GitGo::Connection.
|
20
|
-
def initialize(core)
|
21
|
-
@core = core
|
22
|
-
@ssh = Net::SSH.start(core.host, core.user)
|
23
|
-
@current_path = ""
|
24
|
-
end
|
25
|
-
|
26
|
-
# Moves the session to the provided path and remembers it for the next
|
27
|
-
# action performed through the #bash method. It keeps the current path
|
28
|
-
# in #current_path
|
29
|
-
#
|
30
|
-
# @see #bash
|
31
|
-
# @see #current_path
|
32
|
-
# @param [String] path the path to navigate to.
|
33
|
-
# @return [String] the new path.
|
34
|
-
def cd(path)
|
35
|
-
@current_path = bash("cd '#{current_path}'; cd '#{path}'; pwd")[:stdout].chomp
|
36
|
-
end
|
37
|
-
|
38
|
-
# Tests to see whether the provided path is a directory.
|
39
|
-
# It will take the path relative from #current_path if no absolute
|
40
|
-
# path was provided.
|
41
|
-
#
|
42
|
-
# @param [String] path the path to test.
|
43
|
-
# @return [true, false]
|
44
|
-
def directory?(path)
|
45
|
-
bash("[ -d '#{path}' ]")[:exit_code] == 0
|
46
|
-
end
|
47
|
-
|
48
|
-
# Tests to see whether the provided path is a file.
|
49
|
-
# It will take the path relative from #current_path if no absolute
|
50
|
-
# path was provided.
|
51
|
-
#
|
52
|
-
# @param [String] path the path to test.
|
53
|
-
# @return [true, false]
|
54
|
-
def file?(path)
|
55
|
-
bash("[ -f '#{path}' ]")[:exit_code] == 0
|
56
|
-
end
|
57
|
-
|
58
|
-
# Creates a directory at the provided path.
|
59
|
-
# It will take the path relative from #current_path if no absolute
|
60
|
-
# path was provided.
|
61
|
-
#
|
62
|
-
# @param [String] path the path to create one or more directories for.
|
63
|
-
# @return [Hash] containing #bash response data.
|
64
|
-
def mkdir(path)
|
65
|
-
bash("mkdir -p '#{path}'")
|
66
|
-
end
|
67
|
-
|
68
|
-
# Removes a file or directory at the provided path.
|
69
|
-
# It will take the path relative from #current_path if no absolute
|
70
|
-
# path was provided.
|
71
|
-
#
|
72
|
-
# @param [String] path the path to the file or directory to remove.
|
73
|
-
# @return [Hash] containing #bash response data.
|
74
|
-
def rm(path)
|
75
|
-
bash("rm -rf '#{path}'")
|
76
|
-
end
|
77
|
-
|
78
|
-
# Moves a file or directory from the provided path to the newly specified path.
|
79
|
-
# It will take the path relative from #current_path if no absolute
|
80
|
-
# path was provided.
|
81
|
-
#
|
82
|
-
# @param [String] path the path to the file or directory to move.
|
83
|
-
# @param [String] new_path the path to where the new file or directory should be placed.
|
84
|
-
# @return [Hash] containing #bash response data.
|
85
|
-
def mv(path, new_path)
|
86
|
-
bash("mv '#{path}' '#{new_path}'")
|
87
|
-
end
|
88
|
-
|
89
|
-
# Closes the #ssh connection and clears the `@connection` instance
|
90
|
-
# variable of this objects parent `Core` instance so new connections
|
91
|
-
# can be established.
|
92
|
-
def close
|
93
|
-
ssh.close
|
94
|
-
core.clear_connection
|
95
|
-
end
|
96
|
-
|
97
|
-
# Closes the #ssh connection and exits the program with CODE.
|
98
|
-
#
|
99
|
-
# @see #close
|
100
|
-
# @param [Integer] code the code to exit the program with.
|
101
|
-
def close_and_exit(code = 0)
|
102
|
-
close
|
103
|
-
exit(code)
|
104
|
-
end
|
105
|
-
|
106
|
-
# Opens a channel for the #ssh connection and executes the provided COMMAND.
|
107
|
-
# This is a blocking (non-asynchronous) operation.
|
108
|
-
#
|
109
|
-
# @param [String] command the command to perform on the host.
|
110
|
-
# @return [Hash] containing response data (:stdout, :stderr, :exit_code, :exit_signal).
|
111
|
-
def bash(command)
|
112
|
-
stdout_data = ""
|
113
|
-
stderr_data = ""
|
114
|
-
exit_code = nil
|
115
|
-
exit_signal = nil
|
116
|
-
|
117
|
-
ssh.open_channel do |channel|
|
118
|
-
channel.exec("cd '#{current_path}'; #{command}") do |ch, success|
|
119
|
-
abort "FAILED: couldn't execute command (ssh.channel.exec)" unless success
|
120
|
-
|
121
|
-
channel.on_data { |ch,data| stdout_data += data }
|
122
|
-
channel.on_extended_data { |ch,type,data| stderr_data += data }
|
123
|
-
channel.on_request("exit-status") { |ch,data| exit_code = data.read_long }
|
124
|
-
channel.on_request("exit-signal") { |ch, data|exit_signal = data.read_long }
|
125
|
-
end
|
126
|
-
end
|
127
|
-
|
128
|
-
ssh.loop
|
129
|
-
|
130
|
-
{
|
131
|
-
:stdout => stdout_data,
|
132
|
-
:stderr => stderr_data,
|
133
|
-
:exit_code => exit_code,
|
134
|
-
:exit_signal => exit_signal
|
135
|
-
}
|
136
|
-
end
|
4
|
+
module Connection
|
137
5
|
end
|
138
6
|
end
|
139
7
|
|
data/lib/git_go/version.rb
CHANGED
data/lib/git_go.rb
CHANGED
@@ -5,6 +5,8 @@ require "thor"
|
|
5
5
|
require "net/ssh"
|
6
6
|
|
7
7
|
require "git_go/connection"
|
8
|
+
require "git_go/connection/base"
|
9
|
+
require "git_go/connection/remote"
|
8
10
|
require "git_go/formatter"
|
9
11
|
require "git_go/version"
|
10
12
|
|
@@ -37,9 +39,17 @@ module GitGo
|
|
37
39
|
# Subsequent calls to this method will returned the same cached
|
38
40
|
# reference to the previously created instance.
|
39
41
|
#
|
42
|
+
# @note
|
43
|
+
# GitGo::Connection::Local is intended for the test-suite.
|
44
|
+
# End-users should only use remote IP addresses.
|
45
|
+
#
|
40
46
|
# @return [GitGo::Connection] an instance of GitGo::Connection
|
41
47
|
def connection
|
42
|
-
|
48
|
+
if host == "127.0.0.1"
|
49
|
+
@connection ||= Connection::Local.new(self)
|
50
|
+
else
|
51
|
+
@connection ||= Connection::Remote.new(self)
|
52
|
+
end
|
43
53
|
end
|
44
54
|
|
45
55
|
# Clears a previously established connection reference. After
|
@@ -0,0 +1,220 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
|
3
|
+
require "spec_helper"
|
4
|
+
|
5
|
+
describe GitGo::CLI do
|
6
|
+
|
7
|
+
let(:cli) { GitGo::CLI.new }
|
8
|
+
let(:core) { GitGo::Core.new }
|
9
|
+
let(:conn) { core.connection }
|
10
|
+
|
11
|
+
before do
|
12
|
+
conn.rm(TMP)
|
13
|
+
conn.mkdir(TMP)
|
14
|
+
conn.cd(TMP)
|
15
|
+
end
|
16
|
+
|
17
|
+
def after
|
18
|
+
conn.close
|
19
|
+
end
|
20
|
+
|
21
|
+
def init
|
22
|
+
cli = GitGo::CLI.new
|
23
|
+
core = GitGo::Core.new
|
24
|
+
conn = core.connection
|
25
|
+
conn.cd(TMP)
|
26
|
+
GitGo::Core.stubs(:new).returns(core)
|
27
|
+
|
28
|
+
[cli, core, conn]
|
29
|
+
end
|
30
|
+
|
31
|
+
def create_silent(name)
|
32
|
+
cli, core, conn = init
|
33
|
+
cli.expects(:puts)
|
34
|
+
cli.create(name)
|
35
|
+
|
36
|
+
[cli, core, conn]
|
37
|
+
end
|
38
|
+
|
39
|
+
describe "#create" do
|
40
|
+
it "should create a repository" do
|
41
|
+
cli, core, conn = init
|
42
|
+
|
43
|
+
cli.expects(:puts).with("Repository created at: git@127.0.0.1:rspec.git")
|
44
|
+
cli.create("rspec")
|
45
|
+
conn.directory?("#{TMP}/rspec.git").should be_true
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should not create a repository if it already exists" do
|
49
|
+
cli, core, conn = create_silent("rspec")
|
50
|
+
|
51
|
+
cli, core, conn = init
|
52
|
+
cli.expects(:puts).with(%Q("rspec" already exists.))
|
53
|
+
conn.expects(:close_and_exit).with(1)
|
54
|
+
cli.create("rspec")
|
55
|
+
end
|
56
|
+
|
57
|
+
it "should report an error on failure" do
|
58
|
+
cli, core, conn = init
|
59
|
+
|
60
|
+
cli.expects(:puts).with("Failed to create repository.")
|
61
|
+
cli.expects(:puts).with("failed")
|
62
|
+
|
63
|
+
conn.expects(:directory?).returns(false)
|
64
|
+
conn.expects(:mkdir)
|
65
|
+
conn.expects(:cd)
|
66
|
+
conn.expects(:bash).with("git init --bare").returns({
|
67
|
+
:exit_code => 1, :stdout => "", :stderr => "failed"
|
68
|
+
})
|
69
|
+
|
70
|
+
cli.create("rspec")
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
describe "#destroy" do
|
75
|
+
it "should destroy an existing repository" do
|
76
|
+
cli, core, conn = create_silent("rspec")
|
77
|
+
|
78
|
+
cli, core, conn = init
|
79
|
+
cli.expects(:yes?).returns(true)
|
80
|
+
cli.expects(:puts).with(%Q(Repository "rspec" was destroyed.))
|
81
|
+
cli.destroy("rspec")
|
82
|
+
conn.directory?("#{TMP}/rspec.git").should be_false
|
83
|
+
end
|
84
|
+
|
85
|
+
it "should not destroy a non-existing repository" do
|
86
|
+
cli, core, conn = init
|
87
|
+
cli.expects(:puts).with(%Q(Repository "rspec" does not exist.))
|
88
|
+
conn.expects(:close_and_exit).with(1)
|
89
|
+
cli.destroy("rspec")
|
90
|
+
conn.directory?("#{TMP}/rspec.git").should be_false
|
91
|
+
end
|
92
|
+
|
93
|
+
it "should report an error on failure" do
|
94
|
+
cli, core, conn = init
|
95
|
+
|
96
|
+
cli.expects(:puts).with(%Q(Repository "rspec" could not be destroyed.))
|
97
|
+
cli.expects(:puts).with("failed")
|
98
|
+
|
99
|
+
conn.expects(:directory?).returns(true)
|
100
|
+
conn.expects(:close_and_exit).with(1)
|
101
|
+
cli.expects(:yes?).returns(true)
|
102
|
+
conn.expects(:rm).returns(
|
103
|
+
:exit_code => 1, :stdout => "", :stderr => "failed"
|
104
|
+
)
|
105
|
+
|
106
|
+
cli.destroy("rspec")
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
describe "#rename" do
|
111
|
+
it "should rename the repository" do
|
112
|
+
cli, core, conn = create_silent("rspec")
|
113
|
+
|
114
|
+
cli, core, conn = init
|
115
|
+
cli.expects(:puts).with(%Q(Repository "rspec" renamed to "minitest".))
|
116
|
+
cli.rename("rspec", "minitest")
|
117
|
+
conn.directory?("#{TMP}/rspec.git").should be_false
|
118
|
+
conn.directory?("#{TMP}/minitest.git").should be_true
|
119
|
+
end
|
120
|
+
|
121
|
+
it "should not rename a non-existent repository" do
|
122
|
+
cli, core, conn = init
|
123
|
+
|
124
|
+
cli.expects(:puts).with(%Q(Repository "rspec" does not exist.))
|
125
|
+
conn.expects(:close_and_exit).with(1)
|
126
|
+
cli.rename("rspec", "minitest")
|
127
|
+
end
|
128
|
+
|
129
|
+
it "should not rename to an already existing repository" do
|
130
|
+
create_silent("rspec")
|
131
|
+
create_silent("minitest")
|
132
|
+
|
133
|
+
cli, core, conn = init
|
134
|
+
cli.expects(:puts).with(%Q(Repository "minitest" already exists.))
|
135
|
+
conn.expects(:close_and_exit).with(1)
|
136
|
+
cli.rename("rspec", "minitest")
|
137
|
+
end
|
138
|
+
|
139
|
+
it "should report an error on failure" do
|
140
|
+
create_silent("rspec")
|
141
|
+
create_silent("minitest")
|
142
|
+
|
143
|
+
cli, core, conn = init
|
144
|
+
cli.expects(:puts).with(%Q(Could not rename "rspec" to "minitest".))
|
145
|
+
cli.expects(:puts).with("failed")
|
146
|
+
conn.expects(:mv).with("rspec.git", "minitest.git").returns({
|
147
|
+
:exit_code => 1, :stdout => "", :stderr => "failed"
|
148
|
+
})
|
149
|
+
|
150
|
+
conn.expects(:directory?).with("rspec.git").returns(true)
|
151
|
+
conn.expects(:directory?).with("minitest.git").returns(false)
|
152
|
+
conn.expects(:close_and_exit).with(1)
|
153
|
+
|
154
|
+
cli.rename("rspec", "minitest")
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
describe "#list" do
|
159
|
+
it "should not list any repositories" do
|
160
|
+
cli.expects(:puts).with(%Q(There are no repositories at git@127.0.0.1.))
|
161
|
+
cli.list
|
162
|
+
end
|
163
|
+
|
164
|
+
it "should list one repository" do
|
165
|
+
create_silent("rspec")
|
166
|
+
|
167
|
+
cli, core, conn = init
|
168
|
+
cli.expects(:puts).with("\n")
|
169
|
+
cli.expects(:puts).with((<<-EOS
|
170
|
+
Repository Git Fetch/Push URL#{" " * 5}
|
171
|
+
---------- -----------------------
|
172
|
+
rspec git@127.0.0.1:rspec.git
|
173
|
+
EOS
|
174
|
+
).gsub(/^\s+/, ""))
|
175
|
+
cli.expects(:puts).with("\nThere is 1 git repository.\n")
|
176
|
+
cli.list
|
177
|
+
end
|
178
|
+
|
179
|
+
it "should list two repositories" do
|
180
|
+
create_silent("rspec")
|
181
|
+
create_silent("minitest")
|
182
|
+
|
183
|
+
cli, core, conn = init
|
184
|
+
cli.expects(:puts).with("\n")
|
185
|
+
cli.expects(:puts).with((<<-EOS
|
186
|
+
Repository Git Fetch/Push URL#{" " * 8}
|
187
|
+
---------- --------------------------
|
188
|
+
minitest git@127.0.0.1:minitest.git
|
189
|
+
rspec git@127.0.0.1:rspec.git#{" " * 3}
|
190
|
+
EOS
|
191
|
+
).gsub(/^\s+/, ""))
|
192
|
+
cli.expects(:puts).with("\nThere are 2 git repositories.\n")
|
193
|
+
cli.list
|
194
|
+
end
|
195
|
+
|
196
|
+
it "should list 5 repositories" do
|
197
|
+
create_silent("rspec")
|
198
|
+
create_silent("minitest")
|
199
|
+
create_silent("testunit")
|
200
|
+
create_silent("mocha")
|
201
|
+
create_silent("fabrication")
|
202
|
+
|
203
|
+
cli, core, conn = init
|
204
|
+
cli.expects(:puts).with("\n")
|
205
|
+
cli.expects(:puts).with((<<-EOS
|
206
|
+
Repository Git Fetch/Push URL#{" " * 11}
|
207
|
+
----------- -----------------------------
|
208
|
+
fabrication git@127.0.0.1:fabrication.git
|
209
|
+
minitest git@127.0.0.1:minitest.git#{" " * 3}
|
210
|
+
mocha git@127.0.0.1:mocha.git#{" " * 6}
|
211
|
+
rspec git@127.0.0.1:rspec.git#{" " * 6}
|
212
|
+
testunit git@127.0.0.1:testunit.git#{" " * 3}
|
213
|
+
EOS
|
214
|
+
).gsub(/^\s+/, ""))
|
215
|
+
cli.expects(:puts).with("\nThere are 5 git repositories.\n")
|
216
|
+
cli.list
|
217
|
+
end
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
@@ -2,19 +2,10 @@
|
|
2
2
|
|
3
3
|
require "spec_helper"
|
4
4
|
|
5
|
-
describe GitGo::Connection do
|
5
|
+
describe GitGo::Connection::Base do
|
6
6
|
|
7
|
-
let(:core) { GitGo::Core.new
|
8
|
-
let(:conn) { GitGo::Connection.new(core) }
|
9
|
-
let(:ssh) { mock("Net::SSH") }
|
10
|
-
|
11
|
-
before do
|
12
|
-
ENV["GIT_GO_USER"] = "git"
|
13
|
-
ENV["GIT_GO_HOST"] = "127.0.0.1"
|
14
|
-
Net::SSH.stubs(:start).returns(ssh)
|
15
|
-
end
|
16
|
-
|
17
|
-
it("test if propperly mocked") { core; conn; ssh }
|
7
|
+
let(:core) { GitGo::Core.new }
|
8
|
+
let(:conn) { GitGo::Connection::Base.new(core) }
|
18
9
|
|
19
10
|
describe "#cd" do
|
20
11
|
it "should update the #current_path" do
|
@@ -79,18 +70,6 @@ describe GitGo::Connection do
|
|
79
70
|
end
|
80
71
|
end
|
81
72
|
|
82
|
-
describe "#close" do
|
83
|
-
it "should close the ssh connection and unset the instance variable on `core`" do
|
84
|
-
ssh.expects(:close)
|
85
|
-
|
86
|
-
core.connection
|
87
|
-
core.instance_variable_get("@connection").should_not be_nil
|
88
|
-
|
89
|
-
conn.close
|
90
|
-
core.instance_variable_get("@connection").should be_nil
|
91
|
-
end
|
92
|
-
end
|
93
|
-
|
94
73
|
describe "#close_and_exit" do
|
95
74
|
it "should #close the connection, and #exit the program" do
|
96
75
|
conn.expects(:close)
|
@@ -105,4 +84,3 @@ describe GitGo::Connection do
|
|
105
84
|
end
|
106
85
|
end
|
107
86
|
end
|
108
|
-
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
|
3
|
+
require "spec_helper"
|
4
|
+
|
5
|
+
describe GitGo::Connection::Local do
|
6
|
+
|
7
|
+
let(:core) { GitGo::Core.new }
|
8
|
+
let(:conn) { GitGo::Connection::Local.new(core) }
|
9
|
+
|
10
|
+
describe "#close" do
|
11
|
+
it "should close the ssh connection and unset the instance variable on `core`" do
|
12
|
+
core.connection
|
13
|
+
core.instance_variable_get("@connection").should_not be_nil
|
14
|
+
|
15
|
+
conn.close
|
16
|
+
core.instance_variable_get("@connection").should be_nil
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
|
3
|
+
require "spec_helper"
|
4
|
+
|
5
|
+
describe GitGo::Connection::Remote do
|
6
|
+
|
7
|
+
let(:core) { GitGo::Core.new }
|
8
|
+
let(:conn) { GitGo::Connection::Remote.new(core) }
|
9
|
+
let(:ssh) { mock("Net::SSH") }
|
10
|
+
|
11
|
+
before do
|
12
|
+
ENV["GIT_GO_USER"] = "git"
|
13
|
+
ENV["GIT_GO_HOST"] = "192.168.1.1" # Remote IP
|
14
|
+
Net::SSH.stubs(:start).returns(ssh)
|
15
|
+
end
|
16
|
+
|
17
|
+
describe "#close" do
|
18
|
+
it "should close the ssh connection and unset the instance variable on `core`" do
|
19
|
+
ssh.expects(:close)
|
20
|
+
|
21
|
+
core.connection
|
22
|
+
core.instance_variable_get("@connection").should_not be_nil
|
23
|
+
|
24
|
+
conn.close
|
25
|
+
core.instance_variable_get("@connection").should be_nil
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
data/spec/lib/git_go_spec.rb
CHANGED
@@ -19,5 +19,25 @@ describe GitGo do
|
|
19
19
|
GitGo::Core.any_instance.expects(:exit).never
|
20
20
|
GitGo::Core.new
|
21
21
|
end
|
22
|
+
|
23
|
+
it "should initialize a GitGo::Connection::Remote connection" do
|
24
|
+
ENV["GIT_GO_USER"] = "git"
|
25
|
+
ENV["GIT_GO_HOST"] = "192.168.1.1"
|
26
|
+
|
27
|
+
core = GitGo::Core.new
|
28
|
+
GitGo::Connection::Remote.expects(:new).with(core)
|
29
|
+
|
30
|
+
core.connection
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should initialize a GitGo::Connection::Local connection" do
|
34
|
+
ENV["GIT_GO_USER"] = "git"
|
35
|
+
ENV["GIT_GO_HOST"] = "127.0.0.1"
|
36
|
+
|
37
|
+
core = GitGo::Core.new
|
38
|
+
GitGo::Connection::Local.expects(:new).with(core)
|
39
|
+
|
40
|
+
core.connection
|
41
|
+
end
|
22
42
|
end
|
23
43
|
|
data/spec/spec_helper.rb
CHANGED
@@ -1,12 +1,22 @@
|
|
1
1
|
# -*- encoding : utf-8 -*-
|
2
2
|
|
3
3
|
require "git_go"
|
4
|
+
require "git_go/connection/local"
|
5
|
+
require "git_go/cli"
|
6
|
+
require "etc"
|
4
7
|
|
5
8
|
RSpec.configure do |config|
|
6
9
|
config.treat_symbols_as_metadata_keys_with_true_values = true
|
7
|
-
config.run_all_when_everything_filtered
|
10
|
+
config.run_all_when_everything_filtered = true
|
11
|
+
config.mock_framework = :mocha
|
12
|
+
config.order = "random"
|
8
13
|
config.filter_run :focus
|
9
|
-
|
10
|
-
config.
|
14
|
+
|
15
|
+
config.before do
|
16
|
+
ENV["GIT_GO_USER"] = "git"
|
17
|
+
ENV["GIT_GO_HOST"] = "127.0.0.1" # localhost
|
18
|
+
end
|
11
19
|
end
|
12
20
|
|
21
|
+
TMP = "/tmp/git_go"
|
22
|
+
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: git_go
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-12-
|
12
|
+
date: 2012-12-13 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: thor
|
@@ -66,11 +66,17 @@ files:
|
|
66
66
|
- bin/gg
|
67
67
|
- gitgo.gemspec
|
68
68
|
- lib/git_go.rb
|
69
|
-
- lib/git_go/cli
|
69
|
+
- lib/git_go/cli.rb
|
70
70
|
- lib/git_go/connection.rb
|
71
|
+
- lib/git_go/connection/base.rb
|
72
|
+
- lib/git_go/connection/local.rb
|
73
|
+
- lib/git_go/connection/remote.rb
|
71
74
|
- lib/git_go/formatter.rb
|
72
75
|
- lib/git_go/version.rb
|
73
|
-
- spec/lib/git_go/
|
76
|
+
- spec/lib/git_go/cli_spec.rb
|
77
|
+
- spec/lib/git_go/connection/base_spec.rb
|
78
|
+
- spec/lib/git_go/connection/local_spec.rb
|
79
|
+
- spec/lib/git_go/connection/remote_spec.rb
|
74
80
|
- spec/lib/git_go/formatter_spec.rb
|
75
81
|
- spec/lib/git_go/version_spec.rb
|
76
82
|
- spec/lib/git_go_spec.rb
|
@@ -89,7 +95,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
89
95
|
version: '0'
|
90
96
|
segments:
|
91
97
|
- 0
|
92
|
-
hash: -
|
98
|
+
hash: -3461265323293730929
|
93
99
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
94
100
|
none: false
|
95
101
|
requirements:
|
@@ -98,7 +104,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
98
104
|
version: '0'
|
99
105
|
segments:
|
100
106
|
- 0
|
101
|
-
hash: -
|
107
|
+
hash: -3461265323293730929
|
102
108
|
requirements: []
|
103
109
|
rubyforge_project:
|
104
110
|
rubygems_version: 1.8.23
|
@@ -108,7 +114,10 @@ summary: Git Go is a small command-line utility distributed as a RubyGem that al
|
|
108
114
|
you to easily create/destroy/rename/list all your private-hosted git repositories
|
109
115
|
on your own server.
|
110
116
|
test_files:
|
111
|
-
- spec/lib/git_go/
|
117
|
+
- spec/lib/git_go/cli_spec.rb
|
118
|
+
- spec/lib/git_go/connection/base_spec.rb
|
119
|
+
- spec/lib/git_go/connection/local_spec.rb
|
120
|
+
- spec/lib/git_go/connection/remote_spec.rb
|
112
121
|
- spec/lib/git_go/formatter_spec.rb
|
113
122
|
- spec/lib/git_go/version_spec.rb
|
114
123
|
- spec/lib/git_go_spec.rb
|