git_hub 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/History.txt +4 -0
- data/README.txt +61 -0
- data/Rakefile +20 -0
- data/bin/git_hub +7 -0
- data/lib/git_hub/api.rb +39 -0
- data/lib/git_hub/base.rb +50 -0
- data/lib/git_hub/repo.rb +155 -0
- data/lib/git_hub.rb +48 -0
- data/spec/git_hub/api_spec.rb +99 -0
- data/spec/git_hub/base_spec.rb +47 -0
- data/spec/git_hub/repo_spec.rb +247 -0
- data/spec/spec.opts +2 -0
- data/spec/spec_helper.rb +190 -0
- data/spec/stubs/repos/create.res +24 -0
- data/spec/stubs/repos/delete/new_repo.1.res +14 -0
- data/spec/stubs/repos/delete/new_repo.2.res +14 -0
- data/spec/stubs/repos/search/joe+repo.res +54 -0
- data/spec/stubs/repos/show/joe007/err_repo.res +14 -0
- data/spec/stubs/repos/show/joe007/fine_repo.res +24 -0
- data/spec/stubs/repos/show/joe007/new_repo.res +24 -0
- data/spec/stubs/repos/show/joe007.res +44 -0
- metadata +89 -0
data/History.txt
ADDED
data/README.txt
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
= git_hub
|
2
|
+
by:: Arvicco
|
3
|
+
url:: http://github.com/arvicco/git_hub
|
4
|
+
|
5
|
+
== DESCRIPTION:
|
6
|
+
|
7
|
+
git_hub is a library that wraps github API and exposes simple interface for
|
8
|
+
finding, creating and managing github repositories and other resources.
|
9
|
+
|
10
|
+
== FEATURES/PROBLEMS:
|
11
|
+
|
12
|
+
* FIXME (list of features or problems)
|
13
|
+
This project is quite new, so it's probably not ready for prime time just yet...
|
14
|
+
Contributors always welcome!
|
15
|
+
|
16
|
+
== SYNOPSIS:
|
17
|
+
|
18
|
+
require 'git_hub'
|
19
|
+
include GitHub
|
20
|
+
|
21
|
+
# Find existing repos
|
22
|
+
repo = Repo.find(:user=>user_name, :repo=>repo_name)
|
23
|
+
repos = Repo.find(:user=>user_name)
|
24
|
+
search_repos = Repo.find(:query=>['search','terms'])
|
25
|
+
|
26
|
+
# Create new repo (need to authenticate with your github credentials first)
|
27
|
+
Api.auth = {:user=>user_name, :token=>token}
|
28
|
+
new_repo = Repo.create(:name=>repo_name, :desc=>'Description', :homepage=>'http://your_page.org', :private=> false)
|
29
|
+
|
30
|
+
== REQUIREMENTS:
|
31
|
+
|
32
|
+
* FIXME (list of requirements)
|
33
|
+
|
34
|
+
== INSTALL:
|
35
|
+
|
36
|
+
$ sudo gem install git_hub
|
37
|
+
|
38
|
+
== LICENSE:
|
39
|
+
|
40
|
+
(The MIT License)
|
41
|
+
|
42
|
+
Copyright (c) 2009 Arvicco
|
43
|
+
|
44
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
45
|
+
a copy of this software and associated documentation files (the
|
46
|
+
'Software'), to deal in the Software without restriction, including
|
47
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
48
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
49
|
+
permit persons to whom the Software is furnished to do so, subject to
|
50
|
+
the following conditions:
|
51
|
+
|
52
|
+
The above copyright notice and this permission notice shall be
|
53
|
+
included in all copies or substantial portions of the Software.
|
54
|
+
|
55
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
56
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
57
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
58
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
59
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
60
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
61
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
|
2
|
+
require 'bones' rescue abort '### Please install the "bones" gem ###'
|
3
|
+
|
4
|
+
ensure_in_path 'lib'
|
5
|
+
require 'git_hub'
|
6
|
+
|
7
|
+
task :default => 'test:run'
|
8
|
+
task 'gem:release' => 'test:run'
|
9
|
+
|
10
|
+
Bones {
|
11
|
+
ignore_file '.gitignore'
|
12
|
+
name 'git_hub'
|
13
|
+
authors 'Arvicco'
|
14
|
+
email 'arvitallian@gmail.com'
|
15
|
+
url 'http://github.com/arvicco/git_hub'
|
16
|
+
version GitHub::VERSION
|
17
|
+
ignore_file '.gitignore'
|
18
|
+
}
|
19
|
+
|
20
|
+
# EOF
|
data/bin/git_hub
ADDED
data/lib/git_hub/api.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'net/https'
|
2
|
+
require 'singleton'
|
3
|
+
|
4
|
+
module GitHub
|
5
|
+
class Api
|
6
|
+
include Singleton
|
7
|
+
|
8
|
+
attr_writer :auth
|
9
|
+
|
10
|
+
def auth
|
11
|
+
@auth || {}
|
12
|
+
end
|
13
|
+
|
14
|
+
def authenticated?
|
15
|
+
auth != {}
|
16
|
+
end
|
17
|
+
|
18
|
+
# Turns string into appropriate class constant, returns nil if class not found
|
19
|
+
def classify name
|
20
|
+
klass = name.split("::").inject(Kernel) {|klass, const_name| klass.const_get const_name }
|
21
|
+
klass.is_a?(Class) ? klass : nil
|
22
|
+
rescue NameError
|
23
|
+
nil
|
24
|
+
end
|
25
|
+
|
26
|
+
def request verb, url, params = {}
|
27
|
+
method = classify('Net::HTTP::' + verb.to_s.capitalize)
|
28
|
+
uri = URI.parse url
|
29
|
+
server = Net::HTTP.new(uri.host, uri.port)
|
30
|
+
server.use_ssl = (uri.scheme == 'https')
|
31
|
+
server.verify_mode = OpenSSL::SSL::VERIFY_NONE if server.use_ssl?
|
32
|
+
server.start do |http|
|
33
|
+
req = method.new(uri.path)
|
34
|
+
req.form_data = params.merge(auth)
|
35
|
+
http.request(req)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
data/lib/git_hub/base.rb
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
module GitHub
|
4
|
+
class Base
|
5
|
+
@base_uri = ''
|
6
|
+
|
7
|
+
def initialize(attributes={})
|
8
|
+
attributes.each do |key, value|
|
9
|
+
raise "No attr_accessor for #{key} on #{self.class}" unless respond_to?("#{key}=")
|
10
|
+
self.send("#{key}=", value)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.base_uri uri
|
15
|
+
@base_uri = uri
|
16
|
+
end
|
17
|
+
|
18
|
+
class << self
|
19
|
+
def request verb, uri, params = {}
|
20
|
+
res = api.request verb, @base_uri+uri, params
|
21
|
+
YAML::load(res.body) if res.respond_to?(:body) # res.kind_of?(Net::HTTPSuccess)
|
22
|
+
#p "in show: #{res}: #{res.code}: #{res.http_version}: #{res.message}", res.body
|
23
|
+
end
|
24
|
+
|
25
|
+
def get uri, params ={}
|
26
|
+
request :get, uri, params
|
27
|
+
end
|
28
|
+
|
29
|
+
def post uri, params = {}
|
30
|
+
request :post, uri, params
|
31
|
+
end
|
32
|
+
|
33
|
+
def api
|
34
|
+
@@api ||= GitHub::Api.instance
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def get uri, params ={}
|
39
|
+
self.class.get uri, params
|
40
|
+
end
|
41
|
+
|
42
|
+
def post uri, params ={}
|
43
|
+
self.class.post uri, params
|
44
|
+
end
|
45
|
+
|
46
|
+
def api
|
47
|
+
self.class.api
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
data/lib/git_hub/repo.rb
ADDED
@@ -0,0 +1,155 @@
|
|
1
|
+
module GitHub
|
2
|
+
class Repo < Base
|
3
|
+
GITHUB_SERVICES = {
|
4
|
+
#[github]
|
5
|
+
# user = user
|
6
|
+
# token = token
|
7
|
+
# :donate => {:path => '/edit/donate', :inputs => ['paypal']}
|
8
|
+
# homepage = homepage_url
|
9
|
+
# webhooks => {:path => '/edit/postreceive_urls', :fields => []
|
10
|
+
#http://rdoc.info/projects/update, http://runcoderun.com/github, http://api.devver.net/github
|
11
|
+
# basecamp = url, username, password, project, category
|
12
|
+
# cia = true
|
13
|
+
# campfire = subdomain, username, password, room, ssl, play_sound
|
14
|
+
# email = arvitallian@gmail.com
|
15
|
+
# fogbugz = cvssubmit_url, fb_version, fb_repoid
|
16
|
+
# friendfeed = nickname, remotekey
|
17
|
+
# irc = server, port, room, password, nick, ssl
|
18
|
+
# jabber = user
|
19
|
+
# lighthouse = subdomain, project_id, token, private
|
20
|
+
# presently = subdomain, group_name, username, password
|
21
|
+
# rubyforge = username, password, grupid
|
22
|
+
# runcoderun = true
|
23
|
+
# trac = url, token
|
24
|
+
# twitter = username, password, digest
|
25
|
+
}
|
26
|
+
|
27
|
+
base_uri 'http://github.com/api/v2/yaml/repos'
|
28
|
+
|
29
|
+
attr_accessor :name, :owner, :description, :url, :homepage, :open_issues, :watchers, :forks, :fork, :private,
|
30
|
+
# additional attributes from search:
|
31
|
+
:id, :type, :size, :language, :created, :pushed, :score #?
|
32
|
+
|
33
|
+
def initialize options
|
34
|
+
super
|
35
|
+
raise "Unable to initialize #{self.class} without name" unless @name
|
36
|
+
@url ||= "http://github.com/#{@owner}/#{@name}"
|
37
|
+
@type ||= "repo"
|
38
|
+
end
|
39
|
+
|
40
|
+
alias followers= watchers=
|
41
|
+
alias followers watchers
|
42
|
+
alias username= owner=
|
43
|
+
alias username owner
|
44
|
+
|
45
|
+
def fork?;
|
46
|
+
!!self.fork
|
47
|
+
end
|
48
|
+
|
49
|
+
def private?;
|
50
|
+
!!self.private
|
51
|
+
end
|
52
|
+
|
53
|
+
def clone_url
|
54
|
+
url = private? || api.auth['login'] == self.owner ? "git@github.com:" : "git://github.com/"
|
55
|
+
url += "#{self.owner}/#{self.name}.git"
|
56
|
+
end
|
57
|
+
|
58
|
+
class << self # Repo class methods
|
59
|
+
# Find repo(s) of a (valid) github user
|
60
|
+
# Accepts either options Hash (:owner/:user/:username and :repo/:repository/:project/:name)
|
61
|
+
# or several search terms as strings or symbols
|
62
|
+
def find(*params)
|
63
|
+
if params.size == 1 && params.first.is_a?(Hash) # this is /show request
|
64
|
+
opts = params.first
|
65
|
+
owner = opts[:owner] || opts[:user] || opts[:username] || opts[:login] || api.auth['login'] || ''
|
66
|
+
repo = opts[:repo] || opts[:repository] || opts[:name] || opts[:project]
|
67
|
+
path = repo ? "/show/#{owner}/#{repo}" : "/show/#{owner}"
|
68
|
+
else # this is /search request, params are search terms
|
69
|
+
query = params.map(&:to_s).join('+')
|
70
|
+
path = "/search/#{query}"
|
71
|
+
end
|
72
|
+
result = get(path)
|
73
|
+
if result['repository']
|
74
|
+
new result['repository']
|
75
|
+
elsif result['repositories']
|
76
|
+
result['repositories'].map {|r| new r}
|
77
|
+
else
|
78
|
+
result
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
alias show find
|
83
|
+
alias search find
|
84
|
+
|
85
|
+
# Create new github repo, accepts Hash with :repo, :description, :homepage, :public/:private
|
86
|
+
# or repo name as a single parameter
|
87
|
+
def create(*params)
|
88
|
+
if params.size == 1 && params.first.is_a?(Hash)
|
89
|
+
opts = params.first
|
90
|
+
repo = opts[:repo] || opts[:repository] || opts[:name] || opts[:project]
|
91
|
+
description = opts[:description] || opts[:descr] || opts[:desc]
|
92
|
+
homepage = opts[:homepage]
|
93
|
+
public = opts[:public] || !opts[:private] # default to true
|
94
|
+
else # repo name as a single parameter
|
95
|
+
repo = params.first.to_s
|
96
|
+
description = nil
|
97
|
+
homepage = nil
|
98
|
+
public = false
|
99
|
+
end
|
100
|
+
raise("Unable to create #{self.class} without authorization") unless api.authenticated?
|
101
|
+
result = post("/create", 'name' => repo, 'description' => description,
|
102
|
+
'homepage' => homepage, 'public' => (public ? 1 : 0))
|
103
|
+
if result['repository']
|
104
|
+
new result['repository']
|
105
|
+
else
|
106
|
+
result
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
# Delete github repo
|
112
|
+
def delete
|
113
|
+
result = post("/delete/#{@name}")
|
114
|
+
if result['delete_token']
|
115
|
+
post("/delete/#{@name}", 'delete_token' => result['delete_token'])
|
116
|
+
else
|
117
|
+
result
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
def add_service
|
122
|
+
end
|
123
|
+
|
124
|
+
def remove_service
|
125
|
+
end
|
126
|
+
|
127
|
+
def add_collaborator
|
128
|
+
end
|
129
|
+
|
130
|
+
def remove_collaborator
|
131
|
+
end
|
132
|
+
|
133
|
+
# repos/show/:user/:repo/tags
|
134
|
+
# repos/show/:user/:repo/branches
|
135
|
+
# repos/show/:user/:repo/languages
|
136
|
+
# repos/show/:user/:repo/network
|
137
|
+
#
|
138
|
+
# repos/show/:user/:repo/collaborators
|
139
|
+
# POST repos/collaborators/:repo/add/:user
|
140
|
+
# POST repos/collaborators/:repo/remove/:user
|
141
|
+
#
|
142
|
+
# repos/keys/:repo
|
143
|
+
# POST repos/key/:repo/remove
|
144
|
+
# POST repos/key/:repo/add {title => title of the key, key => public key data}
|
145
|
+
|
146
|
+
# POST repos/set/public/:repo
|
147
|
+
# POST repos/set/private/:repo
|
148
|
+
|
149
|
+
# ? repos/fork/:user/:repo
|
150
|
+
# repos/unwatch/:user/:repo
|
151
|
+
# repos/watch/:user/:repo
|
152
|
+
# repos/show/:user/:repo ? new?
|
153
|
+
|
154
|
+
end
|
155
|
+
end
|
data/lib/git_hub.rb
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
|
2
|
+
module GitHub
|
3
|
+
|
4
|
+
# :stopdoc:
|
5
|
+
VERSION = '0.0.1'
|
6
|
+
LIBPATH = ::File.expand_path(::File.dirname(__FILE__)) + ::File::SEPARATOR
|
7
|
+
PATH = ::File.dirname(LIBPATH) + ::File::SEPARATOR
|
8
|
+
# :startdoc:
|
9
|
+
|
10
|
+
# Returns the version string for the library.
|
11
|
+
#
|
12
|
+
def self.version
|
13
|
+
VERSION
|
14
|
+
end
|
15
|
+
|
16
|
+
# Returns the library path for the module. If any arguments are given,
|
17
|
+
# they will be joined to the end of the libray path using
|
18
|
+
# <tt>File.join</tt>.
|
19
|
+
#
|
20
|
+
def self.libpath( *args )
|
21
|
+
args.empty? ? LIBPATH : ::File.join(LIBPATH, args.flatten)
|
22
|
+
end
|
23
|
+
|
24
|
+
# Returns the path for the module. If any arguments are given,
|
25
|
+
# they will be joined to the end of the path using
|
26
|
+
# <tt>File.join</tt>.
|
27
|
+
#
|
28
|
+
def self.path( *args )
|
29
|
+
args.empty? ? PATH : ::File.join(PATH, args.flatten)
|
30
|
+
end
|
31
|
+
|
32
|
+
# Utility method used to require all files ending in .rb that lie in the
|
33
|
+
# directory below this file that has the same name as the filename passed
|
34
|
+
# in. Optionally, a specific _directory_ name can be passed in such that
|
35
|
+
# the _filename_ does not have to be equivalent to the directory.
|
36
|
+
#
|
37
|
+
def self.require_all_libs_relative_to( fname, dir = nil )
|
38
|
+
dir ||= ::File.basename(fname, '.*')
|
39
|
+
search_me = ::File.expand_path(
|
40
|
+
::File.join(::File.dirname(fname), dir, '**', '*.rb'))
|
41
|
+
|
42
|
+
Dir.glob(search_me).sort.each {|rb| require rb}
|
43
|
+
end
|
44
|
+
|
45
|
+
end # module GitHub
|
46
|
+
|
47
|
+
GitHub.require_all_libs_relative_to(__FILE__)
|
48
|
+
|
@@ -0,0 +1,99 @@
|
|
1
|
+
require File.expand_path(
|
2
|
+
File.join(File.dirname(__FILE__), '..', 'spec_helper'))
|
3
|
+
|
4
|
+
module GitHubTest
|
5
|
+
describe GitHub::Api do
|
6
|
+
after(:each) do
|
7
|
+
GitHub::Api.instance.auth.clear
|
8
|
+
end
|
9
|
+
|
10
|
+
context 'authentication' do
|
11
|
+
it 'starts out unauthenticated' do
|
12
|
+
api = described_class.instance
|
13
|
+
api.should_not be_authenticated
|
14
|
+
api.auth.should == {}
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'authenticates with login and token' do
|
18
|
+
api = described_class.instance
|
19
|
+
api.auth = joe_auth
|
20
|
+
api.should be_authenticated
|
21
|
+
api.auth.should == joe_auth
|
22
|
+
api.auth.clear
|
23
|
+
api.should_not be_authenticated
|
24
|
+
api.auth.should == {}
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
context 'requests' do
|
29
|
+
before :each do
|
30
|
+
@api= described_class.instance
|
31
|
+
@api.auth = joe_auth
|
32
|
+
@hash = {'name' => 'name', 'description' => 'descr'}
|
33
|
+
@hash_with_auth = @hash.merge joe_auth
|
34
|
+
end
|
35
|
+
|
36
|
+
context 'post' do
|
37
|
+
it 'connects via http, submits post request' do
|
38
|
+
server, post = stub_server_and_req()
|
39
|
+
Net::HTTP::Post.should_receive(:new).with('/api/v2/yaml/repos/create').and_return(post)
|
40
|
+
Net::HTTP.should_receive(:new).with('github.com', 80).and_return(server)
|
41
|
+
server.should_receive(:request).with(post)
|
42
|
+
|
43
|
+
@api.request(:post, "#{github_yaml}/repos/create", @hash)
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'connects to github via https, submits post request' do
|
47
|
+
server, post = stub_server_and_req( :port => 443)
|
48
|
+
Net::HTTP::Post.should_receive(:new).with('/api/v2/yaml/repos/create').and_return(post)
|
49
|
+
Net::HTTP.should_receive(:new).with('github.com', 443).and_return(server)
|
50
|
+
server.should_receive(:request).with(post)
|
51
|
+
|
52
|
+
@api.request(:post, 'https://github.com/api/v2/yaml/repos/create', @hash)
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'sends form params urlencoded with added authentication' do
|
56
|
+
server = stub_server
|
57
|
+
server.should_receive(:request) do |req|
|
58
|
+
req.content_type.should == 'application/x-www-form-urlencoded'
|
59
|
+
req.body.should == 'name=name&description=descr&login=joe007&token=b937c8e7ea5a5b47f94eafa39b1e0462'
|
60
|
+
end
|
61
|
+
|
62
|
+
@api.request(:post, "#{github_yaml}/repos/create", @hash)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
context 'get' do
|
67
|
+
it 'connects to github via http, submits get request' do
|
68
|
+
server, req = stub_server_and_req(:get => true)
|
69
|
+
Net::HTTP::Get.should_receive(:new).with('/api/v2/yaml/repos/create').and_return(req)
|
70
|
+
Net::HTTP.should_receive(:new).with('github.com', 80).and_return(server)
|
71
|
+
server.should_receive(:request).with(req)
|
72
|
+
|
73
|
+
@api.request(:get, "#{github_yaml}/repos/create")
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'connects to github via https, submits get request' do
|
77
|
+
server, req = stub_server_and_req(:get => true, :port => 443)
|
78
|
+
Net::HTTP::Get.should_receive(:new).with('/api/v2/yaml/repos/create').and_return(req)
|
79
|
+
Net::HTTP.should_receive(:new).with('github.com', 443).and_return(server)
|
80
|
+
server.should_receive(:request).with(req)
|
81
|
+
|
82
|
+
@api.request(:get, "https://github.com/api/v2/yaml/repos/create")
|
83
|
+
end
|
84
|
+
|
85
|
+
it 'sends get request with added authentication' do
|
86
|
+
server = stub_server(:get => true)
|
87
|
+
server.should_receive(:request) do |req|
|
88
|
+
req.content_type.should == 'application/x-www-form-urlencoded'
|
89
|
+
req.body.should == 'login=joe007&token=b937c8e7ea5a5b47f94eafa39b1e0462'
|
90
|
+
end
|
91
|
+
|
92
|
+
@api.request(:get, "#{github_yaml}/repos/create")
|
93
|
+
end
|
94
|
+
end # requests
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end # module GitHubTest
|
98
|
+
|
99
|
+
# EOF
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require File.expand_path(
|
2
|
+
File.join(File.dirname(__FILE__), '..', 'spec_helper'))
|
3
|
+
|
4
|
+
module GitHubTest
|
5
|
+
describe GitHub::Base do
|
6
|
+
after(:each) do
|
7
|
+
api.auth.clear
|
8
|
+
end
|
9
|
+
|
10
|
+
context 'general' do
|
11
|
+
it 'has instance and class method api pointing to the same Api instance' do
|
12
|
+
api1 = described_class.api
|
13
|
+
api2 = described_class.new.api
|
14
|
+
api1.should be_a GitHub::Api
|
15
|
+
api1.should be_equal api2
|
16
|
+
api1.should be_equal api
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
context 'requests' do
|
21
|
+
it 'submits appropriate requests to api as get/post methods (both class and instance)' do
|
22
|
+
base = described_class.new
|
23
|
+
api.should_receive(:request).with(:get, '/blah', anything()).twice
|
24
|
+
base.get ('/blah')
|
25
|
+
described_class.get ('/blah')
|
26
|
+
|
27
|
+
api.should_receive(:request).with(:post, '/blah', anything()).twice
|
28
|
+
base.post ('/blah')
|
29
|
+
described_class.post ('/blah')
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'prepends get/post calls to api by string set by base_uri class macro' do
|
33
|
+
base = described_class.new
|
34
|
+
described_class.class_eval { base_uri 'http://base1.com' }
|
35
|
+
api.should_receive(:request).with(:get, 'http://base1.com/blah', anything()).twice
|
36
|
+
base.get ('/blah')
|
37
|
+
described_class.get ('/blah')
|
38
|
+
|
39
|
+
api.should_receive(:request).with(:post, 'http://base1.com/blah', anything()).twice
|
40
|
+
base.post ('/blah')
|
41
|
+
described_class.post ('/blah')
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end # module GitHubTest
|
46
|
+
|
47
|
+
# EOF
|
@@ -0,0 +1,247 @@
|
|
1
|
+
require File.expand_path(
|
2
|
+
File.join(File.dirname(__FILE__), '..', 'spec_helper'))
|
3
|
+
|
4
|
+
module GitHubTest
|
5
|
+
describe GitHub::Repo do
|
6
|
+
after(:each) do
|
7
|
+
api.auth.clear
|
8
|
+
end
|
9
|
+
|
10
|
+
context '::find as /show/:user)' do
|
11
|
+
it 'returns an array of repos for a valid github user' do
|
12
|
+
expect(:get, "#{github_yaml}/repos/show/joe007") do
|
13
|
+
repos = described_class.find(:user=>'joe007')
|
14
|
+
repos.should_not be_empty
|
15
|
+
repos.should be_an Array
|
16
|
+
repos.should have(3).repos
|
17
|
+
repos.each {|repo| repo.should be_a described_class}
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'returns repos with "show" attributes set' do
|
22
|
+
expect(:get, "#{github_yaml}/repos/show/joe007") do
|
23
|
+
repo = described_class.find(:user=>'joe007').first
|
24
|
+
repo.name.should == 'fine_repo'
|
25
|
+
repo.url.should == 'http://github.com/joe007/fine_repo'
|
26
|
+
repo.clone_url.should == 'git://github.com/joe007/fine_repo.git'
|
27
|
+
repo.description.should == 'Fine repo by joe'
|
28
|
+
repo.homepage.should == ''
|
29
|
+
repo.watchers.should == 3
|
30
|
+
repo.followers.should == 3
|
31
|
+
repo.open_issues.should == 0
|
32
|
+
repo.forks.should == 0
|
33
|
+
repo.should_not be_fork
|
34
|
+
repo.should_not be_private
|
35
|
+
repo.owner.should == 'joe007'
|
36
|
+
repo.username.should == 'joe007'
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'returns repos with "search" attributes unset' do
|
41
|
+
expect(:get, "#{github_yaml}/repos/show/joe007") do
|
42
|
+
repo = described_class.find(:user=>'joe007').first
|
43
|
+
repo.id.should == nil
|
44
|
+
repo.language.should == nil
|
45
|
+
repo.size.should == nil
|
46
|
+
repo.created.should == nil
|
47
|
+
repo.pushed.should == nil
|
48
|
+
repo.score.should == nil
|
49
|
+
repo.type.should == 'repo'
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
context '::find as /search' do
|
55
|
+
it 'searches github repos with specific search terms' do
|
56
|
+
expect(:get, "#{github_yaml}/repos/search/joe+repo") do
|
57
|
+
repos = described_class.find('joe', 'repo')
|
58
|
+
repos.should_not be_empty
|
59
|
+
repos.should be_an Array
|
60
|
+
repos.should have(3).repos
|
61
|
+
repos.each {|repo| repo.should be_a described_class}
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'returns repos with "search" attributes set' do
|
66
|
+
expect(:get, "#{github_yaml}/repos/search/joe+repo") do
|
67
|
+
repo = described_class.find('joe', 'repo').first
|
68
|
+
repo.name.should == 'fine_repo'
|
69
|
+
repo.description.should == 'Fine repo by joe'
|
70
|
+
repo.watchers.should == 3
|
71
|
+
repo.followers.should == 3
|
72
|
+
repo.forks.should == 0
|
73
|
+
repo.should_not be_fork
|
74
|
+
repo.owner.should == 'joe007'
|
75
|
+
repo.username.should == 'joe007'
|
76
|
+
repo.id.should == 'repo-270000'
|
77
|
+
repo.language.should == ''
|
78
|
+
repo.size.should == 1228
|
79
|
+
repo.created.should == '2009-08-06T00:20:39Z'
|
80
|
+
repo.pushed.should == '2009-11-11T22:58:52Z'
|
81
|
+
repo.score.should == 4.918499
|
82
|
+
repo.type.should == 'repo'
|
83
|
+
repo.clone_url.should == 'git://github.com/joe007/fine_repo.git'
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
it 'returns repos with "show" attributes unset' do
|
88
|
+
expect(:get, "#{github_yaml}/repos/search/joe+repo") do
|
89
|
+
repo = described_class.find('joe', 'repo').first
|
90
|
+
repo.url.should == 'http://github.com/joe007/fine_repo'
|
91
|
+
repo.homepage.should == nil
|
92
|
+
repo.open_issues.should == nil
|
93
|
+
repo.should_not be_private
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
context '::find as /show/user/repo' do
|
99
|
+
it 'finds repo of a (valid) github user' do
|
100
|
+
expect(:get, "#{github_yaml}/repos/show/joe007/fine_repo") do
|
101
|
+
repo = described_class.find(:user=>'joe007', :repo=>'fine_repo')
|
102
|
+
repo.should be_a described_class
|
103
|
+
repo.name.should == 'fine_repo'
|
104
|
+
repo.url.should == 'http://github.com/joe007/fine_repo'
|
105
|
+
repo.clone_url.should == 'git://github.com/joe007/fine_repo.git'
|
106
|
+
repo.description.should == 'Fine repo by joe'
|
107
|
+
repo.homepage.should == ''
|
108
|
+
repo.watchers.should == 1
|
109
|
+
repo.followers.should == 1
|
110
|
+
repo.open_issues.should == 0
|
111
|
+
repo.forks.should == 0
|
112
|
+
repo.should_not be_fork
|
113
|
+
repo.should_not be_private
|
114
|
+
repo.owner.should == 'joe007'
|
115
|
+
repo.username.should == 'joe007'
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
it 'returns error object instead of non-existing repo' do
|
120
|
+
expect(:get, "#{github_yaml}/repos/show/joe007/err_repo") do
|
121
|
+
res = described_class.find(:user=>'joe007', :repo=>'err_repo')
|
122
|
+
res.should have_key 'error' # res = {"error"=>[{"error"=>"repository not found"}]}
|
123
|
+
res['error'].should be_kind_of Array
|
124
|
+
res['error'].first.should have_key 'error'
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
context '::create' do
|
130
|
+
it 'creates new repo for authenticated github user' do
|
131
|
+
api.auth = joe_auth
|
132
|
+
keys = {:name => 'new_repo', :description => 'New repo',
|
133
|
+
:homepage => 'http://joe.org/new_repo', :public => 1}.merge joe_auth
|
134
|
+
expects(:post, "#{github_yaml}/repos/create", :expected_keys=>keys, :body=>body_from_file('/repos/create'))
|
135
|
+
repo = described_class.create(:name=>'new_repo', :description => 'New repo',
|
136
|
+
:homepage => 'http://joe.org/new_repo', :private => false)
|
137
|
+
repo.should be_a described_class
|
138
|
+
repo.name.should == 'new_repo'
|
139
|
+
repo.url.should == 'http://github.com/joe007/new_repo'
|
140
|
+
repo.clone_url.should == 'git@github.com:joe007/new_repo.git'
|
141
|
+
repo.description.should == 'New repo'
|
142
|
+
repo.homepage.should == 'http://joe.org/new_repo'
|
143
|
+
repo.watchers.should == 1
|
144
|
+
repo.followers.should == 1
|
145
|
+
repo.open_issues.should == 0
|
146
|
+
repo.forks.should == 0
|
147
|
+
repo.should_not be_fork
|
148
|
+
repo.should_not be_private
|
149
|
+
repo.owner.should == 'joe007'
|
150
|
+
repo.username.should == 'joe007'
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
context '#delete' do
|
155
|
+
it 'deletes new repo for authenticated github user' do
|
156
|
+
api.auth = joe_auth
|
157
|
+
expect(:get, "#{github_yaml}/repos/show/joe007/new_repo")
|
158
|
+
repo = described_class.find(:repo=>'new_repo')
|
159
|
+
post1 = { :expected_keys => joe_auth,
|
160
|
+
:body => body_from_file('/repos/delete/new_repo.1') }
|
161
|
+
post2 = { :expected_keys => {:delete_token => :any}.merge(joe_auth),
|
162
|
+
:body => body_from_file('/repos/delete/new_repo.2') }
|
163
|
+
expects(:post, "#{github_yaml}/repos/delete/new_repo", [post1, post2])
|
164
|
+
res = repo.delete
|
165
|
+
res['status'].should == 'deleted'
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
it 'tests' do
|
170
|
+
pending
|
171
|
+
api.auth = joe_auth
|
172
|
+
expect(:get, "#{github_yaml}/repos/showp/joe007/new_repo")
|
173
|
+
repos = described_class.show('arvicco')
|
174
|
+
p repos
|
175
|
+
p repos.map(&:url)
|
176
|
+
repos.should be_an Array
|
177
|
+
repos.should_not be_empty
|
178
|
+
if repos.last.name == 'new_repo'
|
179
|
+
repos.last.delete
|
180
|
+
end
|
181
|
+
true.should == false
|
182
|
+
end
|
183
|
+
|
184
|
+
# context 'manipulating repos' do
|
185
|
+
# before (:each) do
|
186
|
+
# @gh = described_class.new('joerepo')
|
187
|
+
# @name = "test#{Time.now.to_i}"
|
188
|
+
# end
|
189
|
+
# after (:each) do
|
190
|
+
# @gh.delete_repo @name
|
191
|
+
# end
|
192
|
+
#
|
193
|
+
# it 'creates new repo of a valid github user' do
|
194
|
+
# @gh.create_repo @name
|
195
|
+
# repos = @gh.repos
|
196
|
+
# repos.should_not be_empty
|
197
|
+
# repos.last[:name].should == @name
|
198
|
+
# end
|
199
|
+
#
|
200
|
+
# it 'creates SINGLE new repo' do
|
201
|
+
# # Problem: sticky cache
|
202
|
+
# r = @gh.repos
|
203
|
+
# p r
|
204
|
+
# n = r.size
|
205
|
+
#
|
206
|
+
# @gh.create_repo @name
|
207
|
+
# sleep 2
|
208
|
+
# rr = @gh.repos
|
209
|
+
# p rr
|
210
|
+
# rr.size.should == n+1
|
211
|
+
# end
|
212
|
+
#
|
213
|
+
# it 'creates and deletes repo of a valid github user' do
|
214
|
+
# #creating
|
215
|
+
# @gh.create_repo @name
|
216
|
+
# repos = @gh.repos
|
217
|
+
# repos.should_not be_empty
|
218
|
+
# repos.last[:name].should == @name
|
219
|
+
#
|
220
|
+
# #deleting
|
221
|
+
# @gh.delete_repo @name
|
222
|
+
# sleep 2
|
223
|
+
# repos = @gh.repos
|
224
|
+
# repos.last[:name].should_not == @name
|
225
|
+
# repos.find {|r|r[:name] == @name}.should == nil
|
226
|
+
# #false.should be_true
|
227
|
+
# end
|
228
|
+
#
|
229
|
+
# it 'returns nil if deleting non-existing repo' do
|
230
|
+
# result = @gh.delete_repo @name
|
231
|
+
# result.should == nil
|
232
|
+
# end
|
233
|
+
#
|
234
|
+
# it 'does not change repos size if deleting non-existing repo' do
|
235
|
+
# n = @gh.repos.size
|
236
|
+
#
|
237
|
+
# @gh.delete_repo @name
|
238
|
+
# sleep 1.5
|
239
|
+
# @gh.repos.should have(n).repos
|
240
|
+
# end
|
241
|
+
# end
|
242
|
+
#
|
243
|
+
end # describe GitHub::Repo
|
244
|
+
|
245
|
+
end # module GithubTest
|
246
|
+
|
247
|
+
# EOF
|
data/spec/spec.opts
ADDED
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,190 @@
|
|
1
|
+
require 'spec'
|
2
|
+
require 'cgi'
|
3
|
+
require 'fakeweb'
|
4
|
+
require 'fakeweb_matcher'
|
5
|
+
require File.expand_path(File.join(File.dirname(__FILE__), %w[.. lib git_hub]))
|
6
|
+
|
7
|
+
# Module that extends RSpec with my own extensions/macros
|
8
|
+
module SpecMacros
|
9
|
+
|
10
|
+
# Wrapper for *it* method that extracts description from example source code, such as:
|
11
|
+
# spec{ use{ result = function(arg1 = 4, arg2 = 'string') }}
|
12
|
+
def spec &block
|
13
|
+
it description_from(*block.source_location), &block
|
14
|
+
end
|
15
|
+
|
16
|
+
# reads description line from source file and drops external brackets (like *spec*{}, *use*{})
|
17
|
+
def description_from(file, line)
|
18
|
+
File.open(file) do |f|
|
19
|
+
f.lines.to_a[line-1].gsub( Regexp.new('(spec.*?{)|(use.*?{)|}'), '' ).lstrip.rstrip
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
Spec::Runner.configure do |config|
|
25
|
+
# Add my macros
|
26
|
+
config.extend(SpecMacros)
|
27
|
+
end
|
28
|
+
|
29
|
+
module GitHubTest
|
30
|
+
|
31
|
+
# Test related Constants:
|
32
|
+
TEST_PROJECT = 'GitHub'
|
33
|
+
TEST_STRING = 'This is test string'
|
34
|
+
|
35
|
+
# Checks that given block does not raise any errors
|
36
|
+
def use
|
37
|
+
lambda {yield}.should_not raise_error
|
38
|
+
end
|
39
|
+
|
40
|
+
# Returns empty block (for use in spec descriptions)
|
41
|
+
def any_block
|
42
|
+
lambda {|*args| args}
|
43
|
+
end
|
44
|
+
|
45
|
+
# Extract response from file
|
46
|
+
def response_from_file(path)
|
47
|
+
filename = File.join(File.dirname(__FILE__), 'stubs', path + '.res')
|
48
|
+
unless File.exists?(filename) && !File.directory?(filename)
|
49
|
+
raise "No stub file #{filename}. To obtain it use:\n#{curl_string(path, filename)}"
|
50
|
+
end
|
51
|
+
filename
|
52
|
+
end
|
53
|
+
|
54
|
+
# Extract response body from file
|
55
|
+
def body_from_file(path)
|
56
|
+
File.read(response_from_file(path)).gsub(/.*\n\n/m, '')
|
57
|
+
end
|
58
|
+
|
59
|
+
def curl_string(path, filename)
|
60
|
+
auth_string = api.authenticated? ? "?login=#{api.auth['login']}&token=#{api.auth['token']}" : ""
|
61
|
+
"curl -i #{github_yaml}#{path}#{auth_string} > #{filename}"
|
62
|
+
end
|
63
|
+
|
64
|
+
# Stubs github server, with options:
|
65
|
+
# :host:: Host name - default 'github.com'
|
66
|
+
# :port:: Port - default 80
|
67
|
+
def stub_server(options={})
|
68
|
+
server = Net::HTTP.new(options[:host] ||'github.com', options[:port] || 80)
|
69
|
+
Net::HTTP.stub!(:new).and_return(server)
|
70
|
+
server
|
71
|
+
end
|
72
|
+
|
73
|
+
# Stubs http request, with options:
|
74
|
+
# :path:: Request path - default '/api/v2/yaml/repos/create'
|
75
|
+
# :get:: Indicates that request is get, otherwise post
|
76
|
+
def stub_req(options={})
|
77
|
+
path = options[:path] || '/api/v2/yaml/repos/create'
|
78
|
+
options[:get] ? Net::HTTP::Get.new(path) : Net::HTTP::Post.new(path)
|
79
|
+
end
|
80
|
+
|
81
|
+
def stub_server_and_req(options = {})
|
82
|
+
[stub_server(options), stub_req(options)]
|
83
|
+
end
|
84
|
+
|
85
|
+
# Turns string into appropriate class constant, returns nil if class not found
|
86
|
+
def classify name
|
87
|
+
klass = name.split("::").inject(Kernel) {|klass, const_name| klass.const_get const_name }
|
88
|
+
klass.is_a?(Class) ? klass : nil
|
89
|
+
rescue NameError
|
90
|
+
nil
|
91
|
+
end
|
92
|
+
|
93
|
+
# Builds fake HTTP response from a given options Hash. Accepts options:
|
94
|
+
# :klass:: Response class, default - Net::HTTPOK
|
95
|
+
# :http_version:: HTTP version - default 1.1
|
96
|
+
# :code:: Response return code - default 200
|
97
|
+
# :message:: Response message - default 'OK'
|
98
|
+
# :status:: [code, message] pair as one option
|
99
|
+
# :body:: Response body - default ''
|
100
|
+
# TODO: make it more lifelike using StringIO, instead of just stubbing :body
|
101
|
+
def build_response(options={})
|
102
|
+
code = options[:status] ? options[:status].first : options[:code] || 200
|
103
|
+
message = options[:status] ? options[:status].last : options[:message] || 'OK'
|
104
|
+
version = options[:http_version] || 1.1
|
105
|
+
resp = (options[:klass] || Net::HTTPOK).new(code, version, message)
|
106
|
+
resp.stub!(:body).and_return(options[:body] || '')
|
107
|
+
resp
|
108
|
+
end
|
109
|
+
|
110
|
+
# Expects request of certain method(:get, :post, ... :any) to specific uri (given as a String, URI or Regexp),
|
111
|
+
# (optionally) matches expected query keys with actuals and handles request and response according to options.
|
112
|
+
# In addition to build_response options (:klass, :http_version, :code, :message, :status, :body), it supports:
|
113
|
+
# :expected_keys:: Hash of expected query keys(if value is not important, :key => :any)
|
114
|
+
# :response:: Use this ready-made response object instead of building response
|
115
|
+
# :exception:: Raise this Exception object instead of response
|
116
|
+
# If you expect multiple requests to the same uri, options may also be an Array containing a list of the
|
117
|
+
# above-described Hashes - requests will be expected in the same order they appear in the Array
|
118
|
+
def expects(method, uri, options={})
|
119
|
+
@github ||= stub_server
|
120
|
+
opts = options.is_a?(Array) ? options.shift : options # may be a single options Hash or Array of Hashes
|
121
|
+
@github.should_receive(:request) do |req|
|
122
|
+
case method # match expected request method to actual
|
123
|
+
when :any
|
124
|
+
Net::HTTPRequest
|
125
|
+
when Class
|
126
|
+
method
|
127
|
+
when Symbol, String
|
128
|
+
classify('Net::HTTP::' + method.to_s.capitalize)
|
129
|
+
end.should === req
|
130
|
+
case uri # match expected uri to actual
|
131
|
+
when URI::HTTP, URI::HTTPS
|
132
|
+
uri.path
|
133
|
+
when String
|
134
|
+
URI.parse(uri).path
|
135
|
+
when Regexp
|
136
|
+
uri
|
137
|
+
end.should === req.path
|
138
|
+
if opts[:expected_keys] # match expected request query keys to actual keys
|
139
|
+
actuals = CGI::parse(req.body)
|
140
|
+
opts[:expected_keys].each do |key, val|
|
141
|
+
actuals.should have_key key.to_s
|
142
|
+
actual = actuals[key.to_s]
|
143
|
+
actual = actual.first if actual.size == 1 # if only one array element, extract it
|
144
|
+
case val # match expected key value to actual
|
145
|
+
when :any
|
146
|
+
when Class, Regexp, String
|
147
|
+
val.should === actual
|
148
|
+
else
|
149
|
+
val.to_s.should === actual
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
expects(method, uri, options) if options.is_a?(Array) && !options.empty? # expect next request in Array
|
154
|
+
raise opts[:exception] if opts[:exception] && opts[:exception].kind_of?(Exception)
|
155
|
+
opts[:response] || build_response(opts)
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
# Extends path to uri, registers it with FakeWeb with stub file at stubs/path as a response
|
160
|
+
# If block is given, yields to block and checks that registered uri was hit during block execution
|
161
|
+
def expect(method, path)
|
162
|
+
case path
|
163
|
+
when Regexp.new(github_yaml)
|
164
|
+
uri = path
|
165
|
+
file = path.sub(github_yaml, '')
|
166
|
+
else
|
167
|
+
uri = github_yaml + path
|
168
|
+
file = path
|
169
|
+
end
|
170
|
+
FakeWeb.register_uri(method, uri, :response=>response_from_file(file))
|
171
|
+
if block_given?
|
172
|
+
yield
|
173
|
+
FakeWeb.should have_requested(method, uri)
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
# Auth for joe
|
178
|
+
def joe_auth
|
179
|
+
{'login' => 'joe007', 'token' => 'b937c8e7ea5a5b47f94eafa39b1e0462'}
|
180
|
+
end
|
181
|
+
|
182
|
+
def github_yaml
|
183
|
+
'http://github.com/api/v2/yaml'
|
184
|
+
end
|
185
|
+
|
186
|
+
def api
|
187
|
+
GitHub::Api.instance
|
188
|
+
end
|
189
|
+
|
190
|
+
end # module GithubTest
|
@@ -0,0 +1,24 @@
|
|
1
|
+
HTTP/1.1 200 OK
|
2
|
+
Server: nginx/0.7.61
|
3
|
+
Date: Wed, 30 Dec 2009 14:17:37 GMT
|
4
|
+
Content-Type: application/x-yaml; charset=utf-8
|
5
|
+
Connection: keep-alive
|
6
|
+
Status: 200 OK
|
7
|
+
ETag: "3448dffce35f5b38d4e477cd57aa7249"
|
8
|
+
X-Runtime: 76ms
|
9
|
+
Content-Length: 235
|
10
|
+
Set-Cookie: _github_ses=BAh7BiIKZmxhc2hJQzonQWN0aW9uQ29udHJvbGxlcjo6Rmxhc2g6OkZsYXNoSGFzaHsABjoKQHVzZWR7AA%3D%3D--884981fc5aa85daf318eeff084d98e2cff92578f; path=/; expires=Wed, 01 Jan 2020 08:00:00 GMT; HttpOnly
|
11
|
+
Cache-Control: private, max-age=0, must-revalidate
|
12
|
+
|
13
|
+
---
|
14
|
+
repository:
|
15
|
+
:url: http://github.com/joe007/new_repo
|
16
|
+
:description: New repo
|
17
|
+
:forks: 0
|
18
|
+
:open_issues: 0
|
19
|
+
:homepage: http://joe.org/new_repo
|
20
|
+
:fork: false
|
21
|
+
:private: false
|
22
|
+
:name: new_repo
|
23
|
+
:owner: joe007
|
24
|
+
:watchers: 1
|
@@ -0,0 +1,14 @@
|
|
1
|
+
HTTP/1.1 200 OK
|
2
|
+
Server: nginx/0.7.61
|
3
|
+
Date: Wed, 30 Dec 2009 15:04:15 GMT
|
4
|
+
Content-Type: application/x-yaml; charset=utf-8
|
5
|
+
Connection: keep-alive
|
6
|
+
Status: 200 OK
|
7
|
+
ETag: "71c252d33cdcaab261e3adea39b35dcc"
|
8
|
+
X-Runtime: 7ms
|
9
|
+
Content-Length: 30
|
10
|
+
Set-Cookie: _github_ses=BAh7BiIKZmxhc2hJQzonQWN0aW9uQ29udHJvbGxlcjo6Rmxhc2g6OkZsYXNoSGFzaHsABjoKQHVzZWR7AA%3D%3D--884981fc5aa85daf318eeff084d98e2cff92578f; path=/; expires=Wed, 01 Jan 2020 08:00:00 GMT; HttpOnly
|
11
|
+
Cache-Control: private, max-age=0, must-revalidate
|
12
|
+
|
13
|
+
---
|
14
|
+
delete_token: jtytnzdcdk
|
@@ -0,0 +1,14 @@
|
|
1
|
+
HTTP/1.1 200 OK
|
2
|
+
Server: nginx/0.7.61
|
3
|
+
Date: Wed, 30 Dec 2009 15:05:59 GMT
|
4
|
+
Content-Type: application/x-yaml; charset=utf-8
|
5
|
+
Connection: keep-alive
|
6
|
+
Status: 200 OK
|
7
|
+
ETag: "2805d28a06ffb58479b7a08117a67714"
|
8
|
+
X-Runtime: 23ms
|
9
|
+
Content-Length: 21
|
10
|
+
Set-Cookie: _github_ses=BAh7BiIKZmxhc2hJQzonQWN0aW9uQ29udHJvbGxlcjo6Rmxhc2g6OkZsYXNoSGFzaHsABjoKQHVzZWR7AA%3D%3D--884981fc5aa85daf318eeff084d98e2cff92578f; path=/; expires=Wed, 01 Jan 2020 08:00:00 GMT; HttpOnly
|
11
|
+
Cache-Control: private, max-age=0, must-revalidate
|
12
|
+
|
13
|
+
---
|
14
|
+
status: deleted
|
@@ -0,0 +1,54 @@
|
|
1
|
+
HTTP/1.1 200 OK
|
2
|
+
Server: nginx/0.7.61
|
3
|
+
Date: Wed, 30 Dec 2009 10:59:42 GMT
|
4
|
+
Content-Type: application/x-yaml; charset=utf-8
|
5
|
+
Connection: keep-alive
|
6
|
+
Status: 200 OK
|
7
|
+
ETag: "173a8304817dc5a17d79f49e4b7af5b4"
|
8
|
+
X-Runtime: 48ms
|
9
|
+
Content-Length: 8727
|
10
|
+
Set-Cookie: _github_ses=BAh7BiIKZmxhc2hJQzonQWN0aW9uQ29udHJvbGxlcjo6Rmxhc2g6OkZsYXNoSGFzaHsABjoKQHVzZWR7AA%3D%3D--884981fc5aa85daf318eeff084d98e2cff92578f; path=/; expires=Wed, 01 Jan 2020 08:00:00 GMT; HttpOnly
|
11
|
+
Cache-Control: private, max-age=0, must-revalidate
|
12
|
+
|
13
|
+
---
|
14
|
+
repositories:
|
15
|
+
- name: fine_repo
|
16
|
+
size: 1228
|
17
|
+
followers: 3
|
18
|
+
username: joe007
|
19
|
+
language: ""
|
20
|
+
fork: false
|
21
|
+
id: repo-270000
|
22
|
+
type: repo
|
23
|
+
pushed: "2009-11-11T22:58:52Z"
|
24
|
+
forks: 0
|
25
|
+
description: Fine repo by joe
|
26
|
+
score: 4.918499
|
27
|
+
created: "2009-08-06T00:20:39Z"
|
28
|
+
- name: another_repo
|
29
|
+
size: 224
|
30
|
+
followers: 1
|
31
|
+
username: joe007
|
32
|
+
language: ""
|
33
|
+
fork: false
|
34
|
+
id: repo-270001
|
35
|
+
type: repo
|
36
|
+
pushed: "2009-09-15T22:27:51Z"
|
37
|
+
forks: 1
|
38
|
+
description: Another fine repo by joe
|
39
|
+
score: 0.66973364
|
40
|
+
created: "2009-05-27T03:18:32Z"
|
41
|
+
- name: private_repo
|
42
|
+
size: 656
|
43
|
+
followers: 1
|
44
|
+
username: joe007
|
45
|
+
language: ""
|
46
|
+
fork: false
|
47
|
+
id: repo-26145
|
48
|
+
type: repo
|
49
|
+
pushed: "2009-11-22T18:09:13Z"
|
50
|
+
forks: 0
|
51
|
+
description: Private repo by joe
|
52
|
+
score: 1.9410602
|
53
|
+
created: "2008-06-17T19:51:25Z"
|
54
|
+
|
@@ -0,0 +1,14 @@
|
|
1
|
+
HTTP/1.1 403 Forbidden
|
2
|
+
Server: nginx/0.7.61
|
3
|
+
Date: Wed, 30 Dec 2009 13:12:41 GMT
|
4
|
+
Content-Type: application/x-yaml; charset=utf-8
|
5
|
+
Connection: keep-alive
|
6
|
+
Status: 403 Forbidden
|
7
|
+
X-Runtime: 8ms
|
8
|
+
Content-Length: 43
|
9
|
+
Set-Cookie: _github_ses=BAh7BiIKZmxhc2hJQzonQWN0aW9uQ29udHJvbGxlcjo6Rmxhc2g6OkZsYXNoSGFzaHsABjoKQHVzZWR7AA%3D%3D--884981fc5aa85daf318eeff084d98e2cff92578f; path=/; expires=Wed, 01 Jan 2020 08:00:00 GMT; HttpOnly
|
10
|
+
Cache-Control: no-cache
|
11
|
+
|
12
|
+
---
|
13
|
+
error:
|
14
|
+
- error: repository not found
|
@@ -0,0 +1,24 @@
|
|
1
|
+
HTTP/1.1 200 OK
|
2
|
+
Server: nginx/0.7.61
|
3
|
+
Date: Wed, 30 Dec 2009 13:21:54 GMT
|
4
|
+
Content-Type: application/x-yaml; charset=utf-8
|
5
|
+
Connection: keep-alive
|
6
|
+
Status: 200 OK
|
7
|
+
ETag: "7d6e90fc96569a71927a11994c8125ad"
|
8
|
+
X-Runtime: 14ms
|
9
|
+
Content-Length: 224
|
10
|
+
Set-Cookie: _github_ses=BAh7BiIKZmxhc2hJQzonQWN0aW9uQ29udHJvbGxlcjo6Rmxhc2g6OkZsYXNoSGFzaHsABjoKQHVzZWR7AA%3D%3D--884981fc5aa85daf318eeff084d98e2cff92578f; path=/; expires=Wed, 01 Jan 2020 08:00:00 GMT; HttpOnly
|
11
|
+
Cache-Control: private, max-age=0, must-revalidate
|
12
|
+
|
13
|
+
---
|
14
|
+
repository:
|
15
|
+
:url: http://github.com/joe007/fine_repo
|
16
|
+
:description: Fine repo by joe
|
17
|
+
:open_issues: 0
|
18
|
+
:homepage: ""
|
19
|
+
:forks: 0
|
20
|
+
:fork: false
|
21
|
+
:private: false
|
22
|
+
:name: fine_repo
|
23
|
+
:owner: joe007
|
24
|
+
:watchers: 1
|
@@ -0,0 +1,24 @@
|
|
1
|
+
HTTP/1.1 200 OK
|
2
|
+
Server: nginx/0.7.61
|
3
|
+
Date: Wed, 30 Dec 2009 14:34:15 GMT
|
4
|
+
Content-Type: application/x-yaml; charset=utf-8
|
5
|
+
Connection: keep-alive
|
6
|
+
Status: 200 OK
|
7
|
+
ETag: "62c142268ede730d1035636172c65318"
|
8
|
+
X-Runtime: 8ms
|
9
|
+
Content-Length: 235
|
10
|
+
Set-Cookie: _github_ses=BAh7BiIKZmxhc2hJQzonQWN0aW9uQ29udHJvbGxlcjo6Rmxhc2g6OkZsYXNoSGFzaHsABjoKQHVzZWR7AA%3D%3D--884981fc5aa85daf318eeff084d98e2cff92578f; path=/; expires=Wed, 01 Jan 2020 08:00:00 GMT; HttpOnly
|
11
|
+
Cache-Control: private, max-age=0, must-revalidate
|
12
|
+
|
13
|
+
---
|
14
|
+
repository:
|
15
|
+
:url: http://github.com/joe007/new_repo
|
16
|
+
:description: New repo
|
17
|
+
:open_issues: 0
|
18
|
+
:homepage: http://joe.org/new_repo
|
19
|
+
:fork: false
|
20
|
+
:private: false
|
21
|
+
:name: new_repo
|
22
|
+
:owner: joe007
|
23
|
+
:watchers: 1
|
24
|
+
:forks: 0
|
@@ -0,0 +1,44 @@
|
|
1
|
+
HTTP/1.1 200 OK
|
2
|
+
Server: nginx/0.7.61
|
3
|
+
Date: Tue, 29 Dec 2009 15:54:21 GMT
|
4
|
+
Content-Type: application/x-yaml; charset=utf-8
|
5
|
+
Connection: keep-alive
|
6
|
+
Status: 200 OK
|
7
|
+
ETag: "67456d99562ca82c4e70efcc72b9f5ef"
|
8
|
+
X-Runtime: 13ms
|
9
|
+
Content-Length: 661
|
10
|
+
Set-Cookie: _github_ses=BAh7BiIKZmxhc2hJQzonQWN0aW9uQ29udHJvbGxlcjo6Rmxhc2g6OkZsYXNoSGFzaHsABjoKQHVzZWR7AA%3D%3D--884981fc5aa85daf318eeff084d98e2cff92578f; path=/; expires=Wed, 01 Jan 2020 08:00:00 GMT; HttpOnly
|
11
|
+
Cache-Control: private, max-age=0, must-revalidate
|
12
|
+
|
13
|
+
---
|
14
|
+
repositories:
|
15
|
+
- :url: http://github.com/joe007/fine_repo
|
16
|
+
:description: Fine repo by joe
|
17
|
+
:forks: 0
|
18
|
+
:open_issues: 0
|
19
|
+
:homepage: ""
|
20
|
+
:fork: false
|
21
|
+
:private: false
|
22
|
+
:name: fine_repo
|
23
|
+
:owner: joe007
|
24
|
+
:watchers: 3
|
25
|
+
- :url: http://github.com/joe007/another_repo
|
26
|
+
:description: Another fine repo by joe
|
27
|
+
:forks: 0
|
28
|
+
:open_issues: 0
|
29
|
+
:homepage: ""
|
30
|
+
:fork: false
|
31
|
+
:private: false
|
32
|
+
:name: another_repo
|
33
|
+
:owner: joe007
|
34
|
+
:watchers: 1
|
35
|
+
- :url: http://github.com/joe007/private_repo
|
36
|
+
:description: Private repo by joe
|
37
|
+
:forks: 0
|
38
|
+
:open_issues: 0
|
39
|
+
:homepage: ""
|
40
|
+
:fork: false
|
41
|
+
:private: false
|
42
|
+
:name: private_repo
|
43
|
+
:owner: joe007
|
44
|
+
:watchers: 1
|
metadata
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: git_hub
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Arvicco
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2010-01-05 00:00:00 +03:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: bones
|
17
|
+
type: :development
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 3.2.0
|
24
|
+
version:
|
25
|
+
description: |-
|
26
|
+
git_hub is a library that wraps github API and exposes simple interface for
|
27
|
+
finding, creating and managing github repositories and other resources.
|
28
|
+
email: arvitallian@gmail.com
|
29
|
+
executables:
|
30
|
+
- git_hub
|
31
|
+
extensions: []
|
32
|
+
|
33
|
+
extra_rdoc_files:
|
34
|
+
- History.txt
|
35
|
+
- README.txt
|
36
|
+
- bin/git_hub
|
37
|
+
files:
|
38
|
+
- History.txt
|
39
|
+
- README.txt
|
40
|
+
- Rakefile
|
41
|
+
- bin/git_hub
|
42
|
+
- lib/git_hub.rb
|
43
|
+
- lib/git_hub/api.rb
|
44
|
+
- lib/git_hub/base.rb
|
45
|
+
- lib/git_hub/repo.rb
|
46
|
+
- spec/git_hub/api_spec.rb
|
47
|
+
- spec/git_hub/base_spec.rb
|
48
|
+
- spec/git_hub/repo_spec.rb
|
49
|
+
- spec/spec.opts
|
50
|
+
- spec/spec_helper.rb
|
51
|
+
- spec/stubs/repos/create.res
|
52
|
+
- spec/stubs/repos/delete/new_repo.1.res
|
53
|
+
- spec/stubs/repos/delete/new_repo.2.res
|
54
|
+
- spec/stubs/repos/search/joe+repo.res
|
55
|
+
- spec/stubs/repos/show/joe007.res
|
56
|
+
- spec/stubs/repos/show/joe007/err_repo.res
|
57
|
+
- spec/stubs/repos/show/joe007/fine_repo.res
|
58
|
+
- spec/stubs/repos/show/joe007/new_repo.res
|
59
|
+
has_rdoc: true
|
60
|
+
homepage: http://github.com/arvicco/git_hub
|
61
|
+
licenses: []
|
62
|
+
|
63
|
+
post_install_message:
|
64
|
+
rdoc_options:
|
65
|
+
- --main
|
66
|
+
- README.txt
|
67
|
+
require_paths:
|
68
|
+
- lib
|
69
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
70
|
+
requirements:
|
71
|
+
- - ">="
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
version: "0"
|
74
|
+
version:
|
75
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
76
|
+
requirements:
|
77
|
+
- - ">="
|
78
|
+
- !ruby/object:Gem::Version
|
79
|
+
version: "0"
|
80
|
+
version:
|
81
|
+
requirements: []
|
82
|
+
|
83
|
+
rubyforge_project: git_hub
|
84
|
+
rubygems_version: 1.3.5
|
85
|
+
signing_key:
|
86
|
+
specification_version: 3
|
87
|
+
summary: git_hub is a library that wraps github API and exposes simple interface for finding, creating and managing github repositories and other resources
|
88
|
+
test_files: []
|
89
|
+
|