git_goggles 0.0.1
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/.gitignore +18 -0
- data/.rvmrc +1 -0
- data/.travis.yml +3 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +61 -0
- data/README.md +4 -0
- data/Rakefile +9 -0
- data/bin/git-goggles +6 -0
- data/clients/python/.gitignore +2 -0
- data/clients/python/gitgoggles.py +78 -0
- data/config.ru +4 -0
- data/git_goggles.gemspec +26 -0
- data/lib/git_goggles.rb +19 -0
- data/lib/git_goggles/app.rb +62 -0
- data/lib/git_goggles/cli.rb +51 -0
- data/lib/git_goggles/repository.rb +81 -0
- data/lib/git_goggles/version.rb +3 -0
- data/spec/git_goggles/app_spec.rb +284 -0
- data/spec/git_goggles/repository_spec.rb +119 -0
- data/spec/spec_helper.rb +46 -0
- metadata +183 -0
data/.gitignore
ADDED
data/.rvmrc
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
rvm use 1.9.3-p194@giggoggles --create
|
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
git_goggles (0.0.1)
|
5
|
+
grit (~> 2.5.0)
|
6
|
+
sinatra (~> 1.3)
|
7
|
+
sinatra-contrib (= 1.3.1)
|
8
|
+
thin (~> 1.3.1)
|
9
|
+
|
10
|
+
GEM
|
11
|
+
remote: https://rubygems.org/
|
12
|
+
specs:
|
13
|
+
backports (2.5.3)
|
14
|
+
daemons (1.1.8)
|
15
|
+
diff-lcs (1.1.3)
|
16
|
+
eventmachine (0.12.10)
|
17
|
+
grit (2.5.0)
|
18
|
+
diff-lcs (~> 1.1)
|
19
|
+
mime-types (~> 1.15)
|
20
|
+
posix-spawn (~> 0.3.6)
|
21
|
+
mime-types (1.18)
|
22
|
+
posix-spawn (0.3.6)
|
23
|
+
rack (1.4.1)
|
24
|
+
rack-protection (1.2.0)
|
25
|
+
rack
|
26
|
+
rack-test (0.6.1)
|
27
|
+
rack (>= 1.0)
|
28
|
+
rake (0.9.2.2)
|
29
|
+
rspec (2.8.0)
|
30
|
+
rspec-core (~> 2.8.0)
|
31
|
+
rspec-expectations (~> 2.8.0)
|
32
|
+
rspec-mocks (~> 2.8.0)
|
33
|
+
rspec-core (2.8.0)
|
34
|
+
rspec-expectations (2.8.0)
|
35
|
+
diff-lcs (~> 1.1.2)
|
36
|
+
rspec-mocks (2.8.0)
|
37
|
+
sinatra (1.3.2)
|
38
|
+
rack (~> 1.3, >= 1.3.6)
|
39
|
+
rack-protection (~> 1.2)
|
40
|
+
tilt (~> 1.3, >= 1.3.3)
|
41
|
+
sinatra-contrib (1.3.1)
|
42
|
+
backports (>= 2.0)
|
43
|
+
eventmachine
|
44
|
+
rack-protection
|
45
|
+
rack-test
|
46
|
+
sinatra (~> 1.3.0)
|
47
|
+
tilt (~> 1.3)
|
48
|
+
thin (1.3.1)
|
49
|
+
daemons (>= 1.0.9)
|
50
|
+
eventmachine (>= 0.12.6)
|
51
|
+
rack (>= 1.0.0)
|
52
|
+
tilt (1.3.3)
|
53
|
+
|
54
|
+
PLATFORMS
|
55
|
+
ruby
|
56
|
+
|
57
|
+
DEPENDENCIES
|
58
|
+
git_goggles!
|
59
|
+
rack-test (~> 0.6.1)
|
60
|
+
rake
|
61
|
+
rspec (~> 2.8.0)
|
data/README.md
ADDED
data/Rakefile
ADDED
data/bin/git-goggles
ADDED
@@ -0,0 +1,78 @@
|
|
1
|
+
'''
|
2
|
+
Created on Jun 3, 2012
|
3
|
+
@author: yelkalay
|
4
|
+
@summary: A Pythonic class based interface to the GitGoggles REST service.
|
5
|
+
'''
|
6
|
+
import string
|
7
|
+
import requests
|
8
|
+
|
9
|
+
class GitGoggles(object):
|
10
|
+
'''
|
11
|
+
Pythonic interface to GitGoggles REST service via urllib2. GitGoggles returns responses in JSON.
|
12
|
+
Since we're interested in using Python data structures all JSON responses are converted to Python dictionaries.
|
13
|
+
Each of the helper methods below uses an existing requests handle/thread to do an HTTP GET on a GitGoggles
|
14
|
+
resource. The requests module detects response headers with a application/json content type and converts
|
15
|
+
the JSON into a Python dictionary.
|
16
|
+
'''
|
17
|
+
|
18
|
+
def __init__(self,service_url):
|
19
|
+
|
20
|
+
self.service_url = service_url
|
21
|
+
self.repositories_uri = '/repositories'
|
22
|
+
self.repository_uri = '/repository'
|
23
|
+
self.commits_uri = '/commits'
|
24
|
+
self.commit_uri = '/commit'
|
25
|
+
self.tags_uri = '/tags'
|
26
|
+
self.tag_uri = '/tag'
|
27
|
+
self.branch_uri = '/branch'
|
28
|
+
self.branches_uri = '/branches'
|
29
|
+
self.request = None
|
30
|
+
|
31
|
+
self.get_service_root()
|
32
|
+
|
33
|
+
def get_service_root(self):
|
34
|
+
'''Open a connection to the root of the service to verify it's a valid URL. '''
|
35
|
+
try:
|
36
|
+
requests.get(self.service_url)
|
37
|
+
|
38
|
+
except requests.exceptions.ConnectionError, error:
|
39
|
+
error = "Invalid URL (%s) or connection timeout. Check Service URL" %(self.service_url)
|
40
|
+
raise RuntimeError(error)
|
41
|
+
|
42
|
+
|
43
|
+
def get_all_repositories(self):
|
44
|
+
url = string.join([self.service_url,self.repositories_uri],'/')
|
45
|
+
return requests.get(url).json
|
46
|
+
|
47
|
+
def get_repository_tree(self,repository):
|
48
|
+
url = string.join([self.service_url,self.repository_uri],repository,'/')
|
49
|
+
return requests.get(url)
|
50
|
+
|
51
|
+
|
52
|
+
def get_repository_commits(self,repository):
|
53
|
+
url = string.join([self.service_url,self.repository_uri,repository,self.commits_uri],'/')
|
54
|
+
return requests.get(url)
|
55
|
+
|
56
|
+
def get_repository_revisions(self,repository,revision):
|
57
|
+
url = string.join(self.service_url,self.repository_uri,repository,self.commit_uri,revision,'/')
|
58
|
+
return requests.get(url)
|
59
|
+
|
60
|
+
def get_repository_tags(self, repository):
|
61
|
+
url = string.join(self.service_url,self.repository_uri,repository,self.tags_uri,'/')
|
62
|
+
return requests.get(url)
|
63
|
+
|
64
|
+
def get_tag_base(self,repository,tag):
|
65
|
+
url = string.join(self.service_url,self.repository_uri,repository,self.tag_uri,tag,'/')
|
66
|
+
return requests.get(url)
|
67
|
+
|
68
|
+
def get_repository_branches(self,repository):
|
69
|
+
url = string.join(self.service_url,self.repository_uri,repository,self.branches_uri,'/')
|
70
|
+
return requests.get(url)
|
71
|
+
|
72
|
+
def get_branch_commits(self,repository,branch):
|
73
|
+
url = string.join(self.service_url,self.repository_uri,repository,self.branch_uri,branch,'/')
|
74
|
+
return requests.get(url)
|
75
|
+
|
76
|
+
if __name__ == '__main__':
|
77
|
+
pass
|
78
|
+
|
data/config.ru
ADDED
data/git_goggles.gemspec
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/git_goggles/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.authors = ["Ben Mills", "Youssuf ElKalay", "Zac Friedman"]
|
6
|
+
gem.email = ["ben@bmdev.org"]
|
7
|
+
gem.description = %q{A simple API for a git server}
|
8
|
+
gem.summary = %q{Expose information about your git repositories}
|
9
|
+
gem.homepage = "https://github.com/DePaulCS438/gitgoggles"
|
10
|
+
|
11
|
+
gem.files = `git ls-files`.split($\)
|
12
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
13
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
14
|
+
gem.name = "git_goggles"
|
15
|
+
gem.require_paths = ["lib"]
|
16
|
+
gem.version = GitGoggles::VERSION
|
17
|
+
|
18
|
+
gem.add_dependency "thin", "~> 1.3.1"
|
19
|
+
gem.add_dependency "sinatra", "~> 1.3"
|
20
|
+
gem.add_dependency "sinatra-contrib", "1.3.1"
|
21
|
+
gem.add_dependency "grit", "~> 2.5.0"
|
22
|
+
|
23
|
+
gem.add_development_dependency "rspec", "~> 2.8.0"
|
24
|
+
gem.add_development_dependency "rack-test", "~> 0.6.1"
|
25
|
+
gem.add_development_dependency "rake"
|
26
|
+
end
|
data/lib/git_goggles.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'sinatra/base'
|
3
|
+
require 'sinatra/namespace'
|
4
|
+
require 'grit'
|
5
|
+
|
6
|
+
require 'git_goggles/app'
|
7
|
+
require 'git_goggles/repository'
|
8
|
+
|
9
|
+
module GitGoggles
|
10
|
+
class << self
|
11
|
+
attr_accessor :root_dir
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.repositories
|
15
|
+
Dir.glob(root_dir + "/*/").map do |full_path|
|
16
|
+
File.basename(full_path)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module GitGoggles
|
2
|
+
class App < Sinatra::Base
|
3
|
+
register Sinatra::Namespace
|
4
|
+
|
5
|
+
get '/' do
|
6
|
+
'Hello world'
|
7
|
+
end
|
8
|
+
|
9
|
+
get '/repositories/?' do
|
10
|
+
json(:repositories, {:repositories => GitGoggles.repositories})
|
11
|
+
end
|
12
|
+
|
13
|
+
namespace '/repository/:name/?' do
|
14
|
+
before do
|
15
|
+
@repository = GitGoggles::Repository.new(params[:name])
|
16
|
+
halt 404, "Repository #{params[:name]} not found" unless @repository.exists?
|
17
|
+
end
|
18
|
+
|
19
|
+
get do
|
20
|
+
json(:repository, @repository)
|
21
|
+
end
|
22
|
+
|
23
|
+
get '/commits/?' do
|
24
|
+
json(:commits, @repository.commits)
|
25
|
+
end
|
26
|
+
|
27
|
+
get '/commit/:sha/?' do
|
28
|
+
json(:commit, @repository.commit(params[:sha]))
|
29
|
+
end
|
30
|
+
|
31
|
+
get '/tags/?' do
|
32
|
+
json(:tags, @repository.tags)
|
33
|
+
end
|
34
|
+
|
35
|
+
get '/tag/:tag/?' do
|
36
|
+
json(:tag, @repository.tag(params[:tag]))
|
37
|
+
end
|
38
|
+
|
39
|
+
get '/branches/?' do
|
40
|
+
json(:branches, @repository.branches)
|
41
|
+
end
|
42
|
+
|
43
|
+
get '/branch/:branch/?' do
|
44
|
+
json(:branch, @repository.branch(params[:branch]))
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def json(type, object)
|
49
|
+
halt 404, "#{type.to_s.capitalize} not found" if object.nil?
|
50
|
+
|
51
|
+
json = object.to_json
|
52
|
+
|
53
|
+
if params[:callback]
|
54
|
+
content_type 'text/javascript'
|
55
|
+
"#{params[:callback]}(#{json});"
|
56
|
+
else
|
57
|
+
content_type :json
|
58
|
+
json
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module GitGoggles
|
2
|
+
class CLI < Rack::Server
|
3
|
+
class Options
|
4
|
+
def parse!(args)
|
5
|
+
args, options = args.dup, {}
|
6
|
+
|
7
|
+
opt_parser = OptionParser.new do |opts|
|
8
|
+
opts.banner = "Usage: git-goggles [options]"
|
9
|
+
opts.on("-R", "--root-dir=path", String,
|
10
|
+
"GitGoggles root directory") { |v| options[:root_dir] = v }
|
11
|
+
|
12
|
+
opts.separator ""
|
13
|
+
|
14
|
+
opts.on("-p", "--port=port", Integer,
|
15
|
+
"Runs GitGoggles on the specified port.", "Default: 9292") { |v| options[:Port] = v }
|
16
|
+
opts.on("-b", "--binding=ip", String,
|
17
|
+
"Binds GitGoggles to the specified ip.", "Default: 0.0.0.0") { |v| options[:Host] = v }
|
18
|
+
opts.on("-d", "--daemon", "Make server run as a Daemon.") { options[:daemonize] = true }
|
19
|
+
opts.on("-P","--pid=pid",String,
|
20
|
+
"Specifies the PID file.",
|
21
|
+
"Default: rack.pid") { |v| options[:pid] = v }
|
22
|
+
|
23
|
+
opts.separator ""
|
24
|
+
|
25
|
+
opts.on("-h", "--help", "Show this help message.") { puts opts; exit }
|
26
|
+
end
|
27
|
+
|
28
|
+
opt_parser.parse! args
|
29
|
+
|
30
|
+
options[:config] = File.expand_path("../../config.ru", File.dirname(__FILE__))
|
31
|
+
options
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def initialize(options = nil)
|
36
|
+
super
|
37
|
+
end
|
38
|
+
|
39
|
+
def opt_parser
|
40
|
+
Options.new
|
41
|
+
end
|
42
|
+
|
43
|
+
def start
|
44
|
+
throw 'Must specifify a root_dir' unless options[:root_dir]
|
45
|
+
GitGoggles.root_dir = options[:root_dir]
|
46
|
+
puts ">> Using root directory #{GitGoggles.root_dir}"
|
47
|
+
|
48
|
+
super
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
module GitGoggles
|
2
|
+
class Repository
|
3
|
+
def initialize(name)
|
4
|
+
@name = name
|
5
|
+
end
|
6
|
+
|
7
|
+
def branches
|
8
|
+
_repo.branches.map(&:name)
|
9
|
+
end
|
10
|
+
|
11
|
+
def branch(branch_name)
|
12
|
+
if branch = _repo.branches.find { |branch| branch.name == branch_name }
|
13
|
+
{
|
14
|
+
:name => branch.name,
|
15
|
+
:latest_commit => branch.commit.sha
|
16
|
+
}
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def commits
|
21
|
+
output = []
|
22
|
+
|
23
|
+
_repo.commits.each do |commit|
|
24
|
+
output << {
|
25
|
+
:author => "#{commit.author.name} <#{commit.author.email}>",
|
26
|
+
:message => commit.message,
|
27
|
+
:sha => commit.id
|
28
|
+
}
|
29
|
+
end
|
30
|
+
|
31
|
+
output
|
32
|
+
end
|
33
|
+
|
34
|
+
def commit(sha)
|
35
|
+
if commit = _repo.commit(sha)
|
36
|
+
{
|
37
|
+
:author => "#{commit.author.name} <#{commit.author.email}>",
|
38
|
+
:message => commit.message,
|
39
|
+
:date => commit.date.to_s,
|
40
|
+
:diffs => commit.diffs.map(&:diff)
|
41
|
+
}
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def exists?
|
46
|
+
File.exists?(_path)
|
47
|
+
end
|
48
|
+
|
49
|
+
def tags
|
50
|
+
_repo.tags.map(&:name)
|
51
|
+
end
|
52
|
+
|
53
|
+
def tag(tag_name)
|
54
|
+
if tag = _repo.tags.find { |tag| tag.name == tag_name }
|
55
|
+
{
|
56
|
+
:name => tag.name,
|
57
|
+
:commit => tag.commit.sha
|
58
|
+
}
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def to_json
|
63
|
+
{
|
64
|
+
:name => @name,
|
65
|
+
:branches => _repo.branches.map(&:name)
|
66
|
+
}.to_json
|
67
|
+
end
|
68
|
+
|
69
|
+
def _path
|
70
|
+
File.join(GitGoggles.root_dir, @name)
|
71
|
+
end
|
72
|
+
|
73
|
+
def _repo
|
74
|
+
if exists?
|
75
|
+
@repo ||= Grit::Repo.new(_path, :is_bare => true)
|
76
|
+
else
|
77
|
+
nil
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,284 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe GitGoggles::App do
|
4
|
+
def app
|
5
|
+
GitGoggles::App
|
6
|
+
end
|
7
|
+
|
8
|
+
describe 'GET /repositories' do
|
9
|
+
it 'returns an empty JSON list if no repositories are found' do
|
10
|
+
get '/repositories'
|
11
|
+
|
12
|
+
last_response.status.should == 200
|
13
|
+
last_response.content_type.should match('application/json')
|
14
|
+
last_response.body.should == "{\"repositories\":[]}"
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'returns a JSON list of repositories' do
|
18
|
+
create_repo('riak')
|
19
|
+
create_repo('web2py')
|
20
|
+
create_repo('rails')
|
21
|
+
|
22
|
+
get '/repositories'
|
23
|
+
|
24
|
+
last_response.status.should == 200
|
25
|
+
last_response.content_type.should match('application/json')
|
26
|
+
|
27
|
+
repositories = JSON.parse(last_response.body)
|
28
|
+
|
29
|
+
repositories['repositories'].should include('riak')
|
30
|
+
repositories['repositories'].should include('web2py')
|
31
|
+
repositories['repositories'].should include('rails')
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'matches with or without a trailing slash' do
|
35
|
+
get '/repositories/'
|
36
|
+
|
37
|
+
last_response.status.should == 200
|
38
|
+
last_response.content_type.should match('application/json')
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'returns a JSON list of repositories' do
|
42
|
+
create_repo('foo')
|
43
|
+
|
44
|
+
get '/repositories?callback=bar'
|
45
|
+
|
46
|
+
last_response.status.should == 200
|
47
|
+
last_response.content_type.should match('text/javascript')
|
48
|
+
last_response.body.should == 'bar({"repositories":["foo"]});'
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
|
53
|
+
describe 'GET /repository/:name' do
|
54
|
+
it 'returns a 404 if a repository is not found' do
|
55
|
+
get '/repository/bad_repo'
|
56
|
+
|
57
|
+
last_response.status.should == 404
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'returns details of the repository as JSON' do
|
61
|
+
create_repo('foo')
|
62
|
+
|
63
|
+
get '/repository/foo'
|
64
|
+
|
65
|
+
last_response.status.should == 200
|
66
|
+
last_response.content_type.should match('application/json')
|
67
|
+
|
68
|
+
repository = JSON.parse(last_response.body)
|
69
|
+
|
70
|
+
repository['name'].should == 'foo'
|
71
|
+
repository['branches'].should include('master')
|
72
|
+
end
|
73
|
+
|
74
|
+
it 'matches with or without a trailing slash' do
|
75
|
+
create_repo('foo')
|
76
|
+
|
77
|
+
get '/repository/foo/'
|
78
|
+
|
79
|
+
last_response.status.should == 200
|
80
|
+
last_response.content_type.should match('application/json')
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
describe 'GET /repository/:name/commits' do
|
85
|
+
it 'returns a list of commits as JSON' do
|
86
|
+
create_repo('foo', :commit_msg => 'my fake commit')
|
87
|
+
|
88
|
+
get '/repository/foo/commits'
|
89
|
+
|
90
|
+
last_response.status.should == 200
|
91
|
+
last_response.content_type.should match('application/json')
|
92
|
+
|
93
|
+
commits = JSON.parse(last_response.body)
|
94
|
+
|
95
|
+
commits.length.should == 1
|
96
|
+
commits.first['message'].should == 'my fake commit'
|
97
|
+
end
|
98
|
+
|
99
|
+
it 'returns a list of commits as JSON' do
|
100
|
+
get '/repository/bad_repo/commits'
|
101
|
+
|
102
|
+
last_response.status.should == 404
|
103
|
+
end
|
104
|
+
|
105
|
+
it 'matches with or without a trailing slash' do
|
106
|
+
create_repo('foo')
|
107
|
+
|
108
|
+
get '/repository/foo/commits/'
|
109
|
+
|
110
|
+
last_response.status.should == 200
|
111
|
+
last_response.content_type.should match('application/json')
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
describe 'GET /repository/:name/commit/:sha' do
|
116
|
+
it 'returns commit detail as JSON' do
|
117
|
+
repo = create_repo('foo', :commit_msg => 'my fake commit')
|
118
|
+
|
119
|
+
get "/repository/foo/commit/#{repo.commits.first.id}"
|
120
|
+
|
121
|
+
last_response.status.should == 200
|
122
|
+
last_response.content_type.should match('application/json')
|
123
|
+
|
124
|
+
commit = JSON.parse(last_response.body)
|
125
|
+
|
126
|
+
commit['message'].should == 'my fake commit'
|
127
|
+
end
|
128
|
+
|
129
|
+
it 'returns 404 if the commit does not exist' do
|
130
|
+
get '/repository/foo/commit/badsha'
|
131
|
+
|
132
|
+
last_response.status.should == 404
|
133
|
+
end
|
134
|
+
|
135
|
+
it 'matches with or without a trailing slash' do
|
136
|
+
repo = create_repo('foo', :commit_msg => 'my fake commit')
|
137
|
+
|
138
|
+
get "/repository/foo/commit/#{repo.commits.first.id}/"
|
139
|
+
|
140
|
+
last_response.status.should == 200
|
141
|
+
last_response.content_type.should match('application/json')
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
describe 'GET /repository/:name/tags' do
|
146
|
+
it 'returns a JSON array of tags' do
|
147
|
+
create_repo('foo', :tags => ['0.0.1', '1.0.0-rc1'])
|
148
|
+
|
149
|
+
get '/repository/foo/tags'
|
150
|
+
|
151
|
+
last_response.status.should == 200
|
152
|
+
last_response.content_type.should match('application/json')
|
153
|
+
|
154
|
+
tags = JSON.parse(last_response.body)
|
155
|
+
|
156
|
+
tags.should include('0.0.1')
|
157
|
+
tags.should include('1.0.0-rc1')
|
158
|
+
end
|
159
|
+
|
160
|
+
it 'returns an empty JSON array for no tags' do
|
161
|
+
create_repo('foo')
|
162
|
+
|
163
|
+
get '/repository/foo/tags'
|
164
|
+
|
165
|
+
last_response.status.should == 200
|
166
|
+
last_response.content_type.should match('application/json')
|
167
|
+
|
168
|
+
tags = JSON.parse(last_response.body)
|
169
|
+
|
170
|
+
tags.should be_empty
|
171
|
+
end
|
172
|
+
|
173
|
+
it 'matches with or without a trailing slash' do
|
174
|
+
create_repo('foo')
|
175
|
+
|
176
|
+
get '/repository/foo/tags/'
|
177
|
+
|
178
|
+
last_response.status.should == 200
|
179
|
+
last_response.content_type.should match('application/json')
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
describe 'GET /repository/:name/tag/:tag' do
|
184
|
+
it 'returns a JSON object for a tag' do
|
185
|
+
create_repo('foo', :tags => ['0.0.1'])
|
186
|
+
|
187
|
+
get '/repository/foo/tag/0.0.1'
|
188
|
+
|
189
|
+
last_response.status.should == 200
|
190
|
+
last_response.content_type.should match('application/json')
|
191
|
+
|
192
|
+
tag = JSON.parse(last_response.body)
|
193
|
+
|
194
|
+
tag['name'].should == '0.0.1'
|
195
|
+
end
|
196
|
+
|
197
|
+
it 'returns a 404 for a tag not found' do
|
198
|
+
create_repo('foo')
|
199
|
+
|
200
|
+
get '/repository/foo/tag/badtag'
|
201
|
+
|
202
|
+
last_response.status.should == 404
|
203
|
+
end
|
204
|
+
|
205
|
+
it 'matches with or without a trailing slash' do
|
206
|
+
create_repo('foo', :tags => ['0.0.1'])
|
207
|
+
|
208
|
+
get '/repository/foo/tag/0.0.1/'
|
209
|
+
|
210
|
+
last_response.status.should == 200
|
211
|
+
last_response.content_type.should match('application/json')
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
describe 'GET /repository/:name/branches' do
|
216
|
+
it 'returns a JSON array of branches' do
|
217
|
+
create_repo('foo', :branches => ['master', 'release'])
|
218
|
+
|
219
|
+
get '/repository/foo/branches'
|
220
|
+
|
221
|
+
last_response.status.should == 200
|
222
|
+
last_response.content_type.should match('application/json')
|
223
|
+
|
224
|
+
branches = JSON.parse(last_response.body)
|
225
|
+
|
226
|
+
branches.should include('master')
|
227
|
+
branches.should include('release')
|
228
|
+
end
|
229
|
+
|
230
|
+
it 'returns an empty JSON array for no branches' do
|
231
|
+
create_repo('foo', :commit => false)
|
232
|
+
|
233
|
+
get '/repository/foo/branches'
|
234
|
+
|
235
|
+
last_response.status.should == 200
|
236
|
+
last_response.content_type.should match('application/json')
|
237
|
+
|
238
|
+
branches = JSON.parse(last_response.body)
|
239
|
+
|
240
|
+
branches.should be_empty
|
241
|
+
end
|
242
|
+
|
243
|
+
it 'matches with or without a trailing slash' do
|
244
|
+
create_repo('foo')
|
245
|
+
|
246
|
+
get '/repository/foo/branches/'
|
247
|
+
|
248
|
+
last_response.status.should == 200
|
249
|
+
last_response.content_type.should match('application/json')
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
253
|
+
describe 'GET /repository/:name/branch/:branch_name' do
|
254
|
+
it 'returns a 404 if a branch is not found' do
|
255
|
+
create_repo('foo')
|
256
|
+
|
257
|
+
get '/repository/foo/branch/badbranch'
|
258
|
+
|
259
|
+
last_response.status.should == 404
|
260
|
+
end
|
261
|
+
|
262
|
+
it 'returns the branch as JSON' do
|
263
|
+
create_repo('foo', :branches => ['master'])
|
264
|
+
|
265
|
+
get '/repository/foo/branch/master'
|
266
|
+
|
267
|
+
last_response.status.should == 200
|
268
|
+
last_response.content_type.should match('application/json')
|
269
|
+
|
270
|
+
branch = JSON.parse(last_response.body)
|
271
|
+
|
272
|
+
branch['name'].should == 'master'
|
273
|
+
end
|
274
|
+
|
275
|
+
it 'matches with or without a trailing slash' do
|
276
|
+
create_repo('foo', :branches => ['master'])
|
277
|
+
|
278
|
+
get '/repository/foo/branch/master/'
|
279
|
+
|
280
|
+
last_response.status.should == 200
|
281
|
+
last_response.content_type.should match('application/json')
|
282
|
+
end
|
283
|
+
end
|
284
|
+
end
|
@@ -0,0 +1,119 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe GitGoggles::Repository do
|
4
|
+
|
5
|
+
describe '#branches' do
|
6
|
+
it 'returns an array of branches' do
|
7
|
+
create_repo('foo', :branches => ['master', 'release'])
|
8
|
+
|
9
|
+
repository = GitGoggles::Repository.new('foo')
|
10
|
+
|
11
|
+
repository.branches.should include('master')
|
12
|
+
repository.branches.should include('release')
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe '#branch' do
|
17
|
+
it 'returns a hash of a branch' do
|
18
|
+
repo = create_repo('foo', :branches => ['master'])
|
19
|
+
|
20
|
+
branch = GitGoggles::Repository.new('foo').branch('master')
|
21
|
+
|
22
|
+
branch[:name].should == 'master'
|
23
|
+
branch[:latest_commit].should == repo.commits.last.sha
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'returns nil for an unknown branch' do
|
27
|
+
repo = create_repo('foo')
|
28
|
+
|
29
|
+
GitGoggles::Repository.new('foo').branch('badbranch').should be_nil
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
describe "#commits" do
|
34
|
+
it 'returns an array of commit objects' do
|
35
|
+
create_repo('foo',
|
36
|
+
:commit_msg => 'my commit',
|
37
|
+
:user_name => 'Bob',
|
38
|
+
:user_email => 'bob@foo.com'
|
39
|
+
)
|
40
|
+
|
41
|
+
repository = GitGoggles::Repository.new('foo')
|
42
|
+
|
43
|
+
repository.commits.first[:author].should == 'Bob <bob@foo.com>'
|
44
|
+
repository.commits.first[:message].should == 'my commit'
|
45
|
+
repository.commits.first[:sha].should be_kind_of(String)
|
46
|
+
repository.commits.first[:sha].length.should > 0
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe "#commit" do
|
51
|
+
it 'returns nil when the commit is not found' do
|
52
|
+
repo = create_repo('foo')
|
53
|
+
|
54
|
+
GitGoggles::Repository.new('foo').commit('bad_sha').should be_nil
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'returns a commit object' do
|
58
|
+
repo = create_repo('foo',
|
59
|
+
:commit_msg => 'my commit',
|
60
|
+
:user_name => 'Bob',
|
61
|
+
:user_email => 'bob@foo.com'
|
62
|
+
)
|
63
|
+
|
64
|
+
repository = GitGoggles::Repository.new('foo')
|
65
|
+
commit = repository.commit(repo.commits.first.sha)
|
66
|
+
|
67
|
+
commit[:author].should == 'Bob <bob@foo.com>'
|
68
|
+
commit[:diffs].should be_kind_of(Array)
|
69
|
+
commit[:date].should be_kind_of(String)
|
70
|
+
commit[:date].length.should > 0
|
71
|
+
commit[:message].should == 'my commit'
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
describe '#exists?' do
|
76
|
+
it 'is true if the repo exists inside the root_dir' do
|
77
|
+
create_repo('foo')
|
78
|
+
repository = GitGoggles::Repository.new('foo')
|
79
|
+
|
80
|
+
repository.exists?.should be_true
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
describe '#to_json' do
|
85
|
+
it 'returns itself as json' do
|
86
|
+
create_repo('foo')
|
87
|
+
repository = GitGoggles::Repository.new('foo')
|
88
|
+
|
89
|
+
repository.to_json.should == '{"name":"foo","branches":["master"]}'
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
describe '#tags' do
|
94
|
+
it 'returns an array of tags' do
|
95
|
+
create_repo('foo', :tags => ['0.0.1'])
|
96
|
+
repository = GitGoggles::Repository.new('foo')
|
97
|
+
|
98
|
+
repository.tags.should include('0.0.1')
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
describe '#tag' do
|
103
|
+
it 'returns an array of tags' do
|
104
|
+
repo = create_repo('foo', :tags => ['0.0.1'])
|
105
|
+
repository = GitGoggles::Repository.new('foo')
|
106
|
+
tag = repository.tag('0.0.1')
|
107
|
+
|
108
|
+
tag[:name].should == '0.0.1'
|
109
|
+
tag[:commit].should == repo.commits.first.sha
|
110
|
+
end
|
111
|
+
|
112
|
+
it 'returns nil for a tag not found' do
|
113
|
+
repo = create_repo('foo')
|
114
|
+
repository = GitGoggles::Repository.new('foo')
|
115
|
+
|
116
|
+
repository.tag('badtag').should be_nil
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
ENV['RACK_ENV'] = 'test'
|
2
|
+
|
3
|
+
require 'rspec'
|
4
|
+
require 'rack/test'
|
5
|
+
require 'git_goggles'
|
6
|
+
|
7
|
+
RSpec.configure do |config|
|
8
|
+
config.expect_with :rspec
|
9
|
+
config.include Rack::Test::Methods
|
10
|
+
|
11
|
+
config.before(:each) do
|
12
|
+
FileUtils.rm_rf(GitGoggles.root_dir)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
GitGoggles.root_dir = '/tmp/git_goggles'
|
17
|
+
|
18
|
+
def create_repo(name, options = {})
|
19
|
+
should_commit = options.fetch(:commit, true)
|
20
|
+
commit_msg = options.fetch(:commit_msg, 'test commit')
|
21
|
+
user_name = options.fetch(:user_name, 'Bob')
|
22
|
+
user_email = options.fetch(:user_email, 'bob@foo.com')
|
23
|
+
tags = options.fetch(:tags, [])
|
24
|
+
branches = options.fetch(:branches, []) - ['master']
|
25
|
+
|
26
|
+
path = File.join(GitGoggles.root_dir, name)
|
27
|
+
FileUtils.mkdir_p(path)
|
28
|
+
FileUtils.touch(path+'/testfile')
|
29
|
+
|
30
|
+
Dir.chdir(path) do
|
31
|
+
repo = Grit::Repo.init(path)
|
32
|
+
|
33
|
+
if should_commit
|
34
|
+
repo.config['user.name'] = user_name
|
35
|
+
repo.config['user.email'] = user_email
|
36
|
+
|
37
|
+
repo.add('testfile')
|
38
|
+
repo.commit_index(commit_msg)
|
39
|
+
tags.each { |tag| `git tag #{tag}` }
|
40
|
+
branches.each { |branch| `git checkout -q -b #{branch}` }
|
41
|
+
end
|
42
|
+
|
43
|
+
`rm testfile && mv .git/* . && rm -rf .git/`
|
44
|
+
end
|
45
|
+
Grit::Repo.new(path, {:is_bare => true})
|
46
|
+
end
|
metadata
ADDED
@@ -0,0 +1,183 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: git_goggles
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Ben Mills
|
9
|
+
- Youssuf ElKalay
|
10
|
+
- Zac Friedman
|
11
|
+
autorequire:
|
12
|
+
bindir: bin
|
13
|
+
cert_chain: []
|
14
|
+
date: 2012-06-05 00:00:00.000000000 Z
|
15
|
+
dependencies:
|
16
|
+
- !ruby/object:Gem::Dependency
|
17
|
+
name: thin
|
18
|
+
requirement: !ruby/object:Gem::Requirement
|
19
|
+
none: false
|
20
|
+
requirements:
|
21
|
+
- - ~>
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 1.3.1
|
24
|
+
type: :runtime
|
25
|
+
prerelease: false
|
26
|
+
version_requirements: !ruby/object:Gem::Requirement
|
27
|
+
none: false
|
28
|
+
requirements:
|
29
|
+
- - ~>
|
30
|
+
- !ruby/object:Gem::Version
|
31
|
+
version: 1.3.1
|
32
|
+
- !ruby/object:Gem::Dependency
|
33
|
+
name: sinatra
|
34
|
+
requirement: !ruby/object:Gem::Requirement
|
35
|
+
none: false
|
36
|
+
requirements:
|
37
|
+
- - ~>
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '1.3'
|
40
|
+
type: :runtime
|
41
|
+
prerelease: false
|
42
|
+
version_requirements: !ruby/object:Gem::Requirement
|
43
|
+
none: false
|
44
|
+
requirements:
|
45
|
+
- - ~>
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '1.3'
|
48
|
+
- !ruby/object:Gem::Dependency
|
49
|
+
name: sinatra-contrib
|
50
|
+
requirement: !ruby/object:Gem::Requirement
|
51
|
+
none: false
|
52
|
+
requirements:
|
53
|
+
- - '='
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: 1.3.1
|
56
|
+
type: :runtime
|
57
|
+
prerelease: false
|
58
|
+
version_requirements: !ruby/object:Gem::Requirement
|
59
|
+
none: false
|
60
|
+
requirements:
|
61
|
+
- - '='
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: 1.3.1
|
64
|
+
- !ruby/object:Gem::Dependency
|
65
|
+
name: grit
|
66
|
+
requirement: !ruby/object:Gem::Requirement
|
67
|
+
none: false
|
68
|
+
requirements:
|
69
|
+
- - ~>
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
version: 2.5.0
|
72
|
+
type: :runtime
|
73
|
+
prerelease: false
|
74
|
+
version_requirements: !ruby/object:Gem::Requirement
|
75
|
+
none: false
|
76
|
+
requirements:
|
77
|
+
- - ~>
|
78
|
+
- !ruby/object:Gem::Version
|
79
|
+
version: 2.5.0
|
80
|
+
- !ruby/object:Gem::Dependency
|
81
|
+
name: rspec
|
82
|
+
requirement: !ruby/object:Gem::Requirement
|
83
|
+
none: false
|
84
|
+
requirements:
|
85
|
+
- - ~>
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: 2.8.0
|
88
|
+
type: :development
|
89
|
+
prerelease: false
|
90
|
+
version_requirements: !ruby/object:Gem::Requirement
|
91
|
+
none: false
|
92
|
+
requirements:
|
93
|
+
- - ~>
|
94
|
+
- !ruby/object:Gem::Version
|
95
|
+
version: 2.8.0
|
96
|
+
- !ruby/object:Gem::Dependency
|
97
|
+
name: rack-test
|
98
|
+
requirement: !ruby/object:Gem::Requirement
|
99
|
+
none: false
|
100
|
+
requirements:
|
101
|
+
- - ~>
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: 0.6.1
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
none: false
|
108
|
+
requirements:
|
109
|
+
- - ~>
|
110
|
+
- !ruby/object:Gem::Version
|
111
|
+
version: 0.6.1
|
112
|
+
- !ruby/object:Gem::Dependency
|
113
|
+
name: rake
|
114
|
+
requirement: !ruby/object:Gem::Requirement
|
115
|
+
none: false
|
116
|
+
requirements:
|
117
|
+
- - ! '>='
|
118
|
+
- !ruby/object:Gem::Version
|
119
|
+
version: '0'
|
120
|
+
type: :development
|
121
|
+
prerelease: false
|
122
|
+
version_requirements: !ruby/object:Gem::Requirement
|
123
|
+
none: false
|
124
|
+
requirements:
|
125
|
+
- - ! '>='
|
126
|
+
- !ruby/object:Gem::Version
|
127
|
+
version: '0'
|
128
|
+
description: A simple API for a git server
|
129
|
+
email:
|
130
|
+
- ben@bmdev.org
|
131
|
+
executables:
|
132
|
+
- git-goggles
|
133
|
+
extensions: []
|
134
|
+
extra_rdoc_files: []
|
135
|
+
files:
|
136
|
+
- .gitignore
|
137
|
+
- .rvmrc
|
138
|
+
- .travis.yml
|
139
|
+
- Gemfile
|
140
|
+
- Gemfile.lock
|
141
|
+
- README.md
|
142
|
+
- Rakefile
|
143
|
+
- bin/git-goggles
|
144
|
+
- clients/python/.gitignore
|
145
|
+
- clients/python/gitgoggles.py
|
146
|
+
- config.ru
|
147
|
+
- git_goggles.gemspec
|
148
|
+
- lib/git_goggles.rb
|
149
|
+
- lib/git_goggles/app.rb
|
150
|
+
- lib/git_goggles/cli.rb
|
151
|
+
- lib/git_goggles/repository.rb
|
152
|
+
- lib/git_goggles/version.rb
|
153
|
+
- spec/git_goggles/app_spec.rb
|
154
|
+
- spec/git_goggles/repository_spec.rb
|
155
|
+
- spec/spec_helper.rb
|
156
|
+
homepage: https://github.com/DePaulCS438/gitgoggles
|
157
|
+
licenses: []
|
158
|
+
post_install_message:
|
159
|
+
rdoc_options: []
|
160
|
+
require_paths:
|
161
|
+
- lib
|
162
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
163
|
+
none: false
|
164
|
+
requirements:
|
165
|
+
- - ! '>='
|
166
|
+
- !ruby/object:Gem::Version
|
167
|
+
version: '0'
|
168
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
169
|
+
none: false
|
170
|
+
requirements:
|
171
|
+
- - ! '>='
|
172
|
+
- !ruby/object:Gem::Version
|
173
|
+
version: '0'
|
174
|
+
requirements: []
|
175
|
+
rubyforge_project:
|
176
|
+
rubygems_version: 1.8.23
|
177
|
+
signing_key:
|
178
|
+
specification_version: 3
|
179
|
+
summary: Expose information about your git repositories
|
180
|
+
test_files:
|
181
|
+
- spec/git_goggles/app_spec.rb
|
182
|
+
- spec/git_goggles/repository_spec.rb
|
183
|
+
- spec/spec_helper.rb
|