fcoury-octopi 0.0.6 → 0.0.7
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +61 -15
- data/VERSION.yml +2 -2
- data/lib/octopi/base.rb +10 -3
- data/lib/octopi/issue.rb +4 -5
- data/lib/octopi/repository.rb +18 -6
- data/lib/octopi/resource.rb +11 -11
- data/lib/octopi.rb +47 -11
- metadata +3 -3
data/README.rdoc
CHANGED
@@ -4,9 +4,20 @@ Octopi is a Ruby interface to GitHub API v2 (http://develop.github.com). It's un
|
|
4
4
|
|
5
5
|
== Authenticated Usage
|
6
6
|
|
7
|
-
|
7
|
+
=== Seamless authentication using .gitconfig defaults
|
8
8
|
|
9
|
-
|
9
|
+
If you have your <tt>~/.gitconfig</tt> file in place, and you have a [github] section (if you don't, take a look at this GitHub Guides entry: http://github.com/guides/tell-git-your-user-name-and-email-address), you can use seamless authentication using this method:
|
10
|
+
|
11
|
+
authenticated do |g|
|
12
|
+
repo = g.repository("api-labrat")
|
13
|
+
(...)
|
14
|
+
end
|
15
|
+
|
16
|
+
=== Explicit authentication
|
17
|
+
|
18
|
+
Sometimes, you may not want to get authentication data from <tt>~/.gitconfig</tt>. You want to use GitHub API authenticated as a third party. For this use case, you have a couple of options too.
|
19
|
+
|
20
|
+
<b>1. Providing login and token inline:</b>
|
10
21
|
|
11
22
|
authenticated_with "mylogin", "mytoken" do |g|
|
12
23
|
repo = g.repository("api-labrat")
|
@@ -15,7 +26,9 @@ Once you found your login and token you can run authenticated commands using:
|
|
15
26
|
puts issue.number
|
16
27
|
end
|
17
28
|
|
18
|
-
|
29
|
+
<b>2. Providing a YAML file with authentication information:</b>
|
30
|
+
|
31
|
+
Use the following format:
|
19
32
|
|
20
33
|
#
|
21
34
|
# Octopi GitHub API configuration file
|
@@ -32,20 +45,12 @@ You can also create a YAML file with your information, with the following format
|
|
32
45
|
# curl - same as true, but in addition will output the curl equivalent of each command (for debugging)
|
33
46
|
trace: curl
|
34
47
|
|
35
|
-
|
48
|
+
This changes the way you connect to:
|
36
49
|
|
37
50
|
authenticated_with :config => "github.yml" do |g|
|
38
51
|
(...)
|
39
52
|
end
|
40
|
-
|
41
|
-
This way you can benefit from better debugging when something goes wrong. If you choose curl tracing, the curl command equivalent to each command sent to GitHub will be output to the stdout, like this example:
|
42
|
-
|
43
|
-
=> Trace on: curl
|
44
|
-
POST: /issues/open/webbynode/api-labrat params: body=This issue was opened using GitHub API and Octopi, title=Sample issue
|
45
|
-
===== curl version
|
46
|
-
curl -F 'body=This issue was opened using GitHub API and Octopi' -F 'login=mylogin' -F 'token=mytoken' -F 'title=Sample issue' http://github.com/api/v2/issues/open/webbynode/api-labrat
|
47
|
-
==================
|
48
|
-
|
53
|
+
|
49
54
|
== Anonymous Usage
|
50
55
|
|
51
56
|
This reflects the usage of the API to retrieve information, on a read-only mode where the user doesn't have to be authenticated.
|
@@ -104,13 +109,54 @@ Single commit information:
|
|
104
109
|
puts "Diff:"
|
105
110
|
first_commit.details.modified.each {|m| puts "#{m['filename']} DIFF: #{m['diff']}" }
|
106
111
|
|
112
|
+
== Tracing
|
113
|
+
|
114
|
+
=== Levels
|
115
|
+
|
116
|
+
You can can use tracing to enable better debugging output when something goes wrong. There are 3 tracing levels:
|
117
|
+
|
118
|
+
* false (default) - no tracing
|
119
|
+
* true - will output each GET and POST calls, along with URL and params
|
120
|
+
* curl - same as true, but additionally outputs the curl command to replicate the issue
|
121
|
+
|
122
|
+
If you choose curl tracing, the curl command equivalent to each command sent to GitHub will be output to the stdout, like this example:
|
123
|
+
|
124
|
+
=> Trace on: curl
|
125
|
+
POST: /issues/open/webbynode/api-labrat params: body=This issue was opened using GitHub API and Octopi, title=Sample issue
|
126
|
+
===== curl version
|
127
|
+
curl -F 'body=This issue was opened using GitHub API and Octopi' -F 'login=mylogin' -F 'token=mytoken' -F 'title=Sample issue' http://github.com/api/v2/issues/open/webbynode/api-labrat
|
128
|
+
==================
|
129
|
+
|
130
|
+
=== Enabling
|
131
|
+
|
132
|
+
Tracing can be enabled in different ways, depending on the API feature you're using:
|
133
|
+
|
134
|
+
<b>Anonymous (this will be improved later):</b>
|
135
|
+
|
136
|
+
ANONYMOUS_API.trace_level = "trace-level"
|
137
|
+
|
138
|
+
<b>Seamless authenticated</b>
|
139
|
+
|
140
|
+
authenticated :trace => "trace-level" do |g|; ...; end
|
141
|
+
|
142
|
+
<b>Explicitly authenticated</b>
|
143
|
+
|
144
|
+
Current version of explicit authentication requires a :config param to a YAML file to allow tracing. For enabling tracing on a YAML file refer to the config.yml example presented on the Explicit authentication section.
|
145
|
+
|
107
146
|
== Author
|
108
147
|
|
109
148
|
* Felipe Coury - http://felipecoury.com
|
110
149
|
* HasMany.info blog - http://hasmany.info
|
111
150
|
|
112
|
-
==
|
151
|
+
== Contributors
|
152
|
+
|
153
|
+
In alphabetical order:
|
154
|
+
|
155
|
+
* Brandon Calloway - http://github.com/bcalloway
|
156
|
+
* runpaint - http://github.com/runpaint
|
113
157
|
|
114
|
-
|
158
|
+
Thanks guys!
|
159
|
+
|
160
|
+
== Copyright
|
115
161
|
|
116
162
|
Copyright (c) 2009 Felipe Coury. See LICENSE for details.
|
data/VERSION.yml
CHANGED
data/lib/octopi/base.rb
CHANGED
@@ -19,7 +19,12 @@ module Octopi
|
|
19
19
|
:msg => "%s is an invalid filename"},
|
20
20
|
:sha => {
|
21
21
|
:pat => /^[a-f0-9]{40}$/,
|
22
|
-
:msg => "%s is an invalid SHA hash"}
|
22
|
+
:msg => "%s is an invalid SHA hash"},
|
23
|
+
:state => {
|
24
|
+
# FIXME: Any way to access Issue::STATES from here?
|
25
|
+
:pat => /^(open|closed)$/,
|
26
|
+
:msg => "%s is an invalid state; should be 'open' or 'closed'."
|
27
|
+
}
|
23
28
|
}
|
24
29
|
|
25
30
|
attr_accessor :api
|
@@ -35,11 +40,13 @@ module Octopi
|
|
35
40
|
next if k =~ /\./
|
36
41
|
instance_variable_set("@#{k}", v)
|
37
42
|
|
38
|
-
|
43
|
+
method = (TrueClass === v || FalseClass === v) ? "#{k}?" : k
|
44
|
+
|
45
|
+
self.class.send :define_method, "#{method}=" do |v|
|
39
46
|
instance_variable_set("@#{k}", v)
|
40
47
|
end
|
41
48
|
|
42
|
-
self.class.send :define_method,
|
49
|
+
self.class.send :define_method, method do
|
43
50
|
instance_variable_get("@#{k}")
|
44
51
|
end
|
45
52
|
end
|
data/lib/octopi/issue.rb
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
module Octopi
|
2
2
|
class Issue < Base
|
3
3
|
include Resource
|
4
|
-
|
4
|
+
STATES = %w{open closed}
|
5
|
+
|
5
6
|
find_path "/issues/list/:query"
|
6
7
|
resource_path "/issues/show/:id"
|
7
8
|
|
@@ -24,12 +25,10 @@ module Octopi
|
|
24
25
|
def self.find_all(*args)
|
25
26
|
repo = args.first
|
26
27
|
user, repo_name, opts = extract_user_repository(*args)
|
27
|
-
validate_args(user => :user, repo_name => :repo)
|
28
28
|
state = opts[:state] || "open"
|
29
29
|
state.downcase! if state
|
30
|
-
|
31
|
-
|
32
|
-
|
30
|
+
validate_args(user => :user, repo_name => :repo, state => :state)
|
31
|
+
|
33
32
|
issues = super user, repo_name, state
|
34
33
|
issues.each { |i| i.repository = repo } if repo.is_a? Repository
|
35
34
|
issues
|
data/lib/octopi/repository.rb
CHANGED
@@ -22,11 +22,19 @@ module Octopi
|
|
22
22
|
find_plural(user, :resource)
|
23
23
|
end
|
24
24
|
|
25
|
-
def self.find(
|
25
|
+
def self.find(*args)
|
26
|
+
api = args.last.is_a?(Api) ? args.pop : ANONYMOUS_API
|
27
|
+
repo = args.pop
|
28
|
+
user = args.pop
|
29
|
+
|
26
30
|
user = user.login if user.is_a? User
|
27
|
-
|
28
|
-
|
29
|
-
|
31
|
+
if repo.is_a? Repository
|
32
|
+
repo = repo.name
|
33
|
+
user ||= repo.owner
|
34
|
+
end
|
35
|
+
|
36
|
+
self.validate_args(user => :user, repo => :repo)
|
37
|
+
super user, repo, api
|
30
38
|
end
|
31
39
|
|
32
40
|
def self.find_all(*args)
|
@@ -50,9 +58,13 @@ module Octopi
|
|
50
58
|
def issues(state = "open")
|
51
59
|
Issue.find_all(self, :state => state)
|
52
60
|
end
|
53
|
-
|
61
|
+
|
62
|
+
def all_issues
|
63
|
+
Issue::STATES.map{|state| self.issues(state)}.flatten
|
64
|
+
end
|
65
|
+
|
54
66
|
def issue(number)
|
55
67
|
Issue.find(self, number)
|
56
68
|
end
|
57
69
|
end
|
58
|
-
end
|
70
|
+
end
|
data/lib/octopi/resource.rb
CHANGED
@@ -27,17 +27,17 @@ module Octopi
|
|
27
27
|
def resource_path(path)
|
28
28
|
(@path_spec||={})[:resource] = path
|
29
29
|
end
|
30
|
-
|
31
|
-
def find(*
|
32
|
-
|
33
|
-
|
30
|
+
|
31
|
+
def find(*args)
|
32
|
+
api = args.last.is_a?(Api) ? args.pop : ANONYMOUS_API
|
33
|
+
args = args.join('/') if args.is_a? Array
|
34
|
+
result = api.find(path_for(:resource), @resource_name[:singular], args)
|
34
35
|
key = result.keys.first
|
36
|
+
|
35
37
|
if result[key].is_a? Array
|
36
|
-
result[key].map
|
37
|
-
new(ANONYMOUS_API, r)
|
38
|
-
end
|
38
|
+
result[key].map { |r| new(api, r) }
|
39
39
|
else
|
40
|
-
Resource.for(key).new(
|
40
|
+
Resource.for(key).new(api, result[key])
|
41
41
|
end
|
42
42
|
end
|
43
43
|
|
@@ -45,12 +45,12 @@ module Octopi
|
|
45
45
|
find_plural(s, :find)
|
46
46
|
end
|
47
47
|
|
48
|
-
def find_plural(s, path)
|
48
|
+
def find_plural(s, path, api = ANONYMOUS_API)
|
49
49
|
s = s.join('/') if s.is_a? Array
|
50
|
-
|
50
|
+
api.find_all(path_for(path), @resource_name[:plural], s).
|
51
51
|
map do |item|
|
52
52
|
payload = block_given? ? yield(item) : item
|
53
|
-
new(
|
53
|
+
new(api, payload)
|
54
54
|
end
|
55
55
|
end
|
56
56
|
|
data/lib/octopi.rb
CHANGED
@@ -7,6 +7,20 @@ module Octopi
|
|
7
7
|
class Api; end
|
8
8
|
ANONYMOUS_API = Api.new
|
9
9
|
|
10
|
+
def authenticated(*args, &block)
|
11
|
+
opts = args.last.is_a?(Hash) ? args.last : {}
|
12
|
+
config = read_gitconfig
|
13
|
+
login = config["github"]["user"]
|
14
|
+
token = config["github"]["token"]
|
15
|
+
|
16
|
+
api = Api.new(login, token)
|
17
|
+
api.trace_level = opts[:trace]
|
18
|
+
|
19
|
+
puts "=> Trace on: #{api.trace_level}" if api.trace_level
|
20
|
+
|
21
|
+
yield api
|
22
|
+
end
|
23
|
+
|
10
24
|
def authenticated_with(*args, &block)
|
11
25
|
opts = args.last.is_a?(Hash) ? args.last : {}
|
12
26
|
if opts[:config]
|
@@ -23,10 +37,27 @@ module Octopi
|
|
23
37
|
puts "=> Trace on: #{trace}" if trace
|
24
38
|
|
25
39
|
api = Api.new(login, token)
|
26
|
-
api.
|
40
|
+
api.trace_level = trace if trace
|
27
41
|
yield api
|
28
42
|
end
|
29
43
|
|
44
|
+
def read_gitconfig
|
45
|
+
config = {}
|
46
|
+
group = nil
|
47
|
+
File.foreach("#{ENV['HOME']}/.gitconfig") do |line|
|
48
|
+
line.strip!
|
49
|
+
if line[0] != ?# and line =~ /\S/
|
50
|
+
if line =~ /^\[(.*)\]$/
|
51
|
+
group = $1
|
52
|
+
else
|
53
|
+
key, value = line.split("=")
|
54
|
+
(config[group]||={})[key.strip] = value.strip
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
config
|
59
|
+
end
|
60
|
+
|
30
61
|
class Api
|
31
62
|
include HTTParty
|
32
63
|
CONTENT_TYPE = {
|
@@ -36,7 +67,7 @@ module Octopi
|
|
36
67
|
}
|
37
68
|
base_uri "http://github.com/api/v2"
|
38
69
|
|
39
|
-
attr_accessor :format, :login, :token, :
|
70
|
+
attr_accessor :format, :login, :token, :trace_level, :read_only
|
40
71
|
|
41
72
|
def initialize(login = nil, token = nil, format = "yaml")
|
42
73
|
@format = format
|
@@ -66,7 +97,7 @@ module Octopi
|
|
66
97
|
end
|
67
98
|
|
68
99
|
def repository(name)
|
69
|
-
repo = Repository.find(
|
100
|
+
repo = Repository.find(user, name, self)
|
70
101
|
repo.api = self
|
71
102
|
repo
|
72
103
|
end
|
@@ -91,7 +122,7 @@ module Octopi
|
|
91
122
|
end
|
92
123
|
|
93
124
|
def post(path, params = {}, format = "yaml")
|
94
|
-
trace "POST", path, params
|
125
|
+
trace "POST", "/#{format}#{path}", params
|
95
126
|
submit(path, params, format) do |path, params, format|
|
96
127
|
resp = self.class.post "/#{format}#{path}", :query => params
|
97
128
|
resp
|
@@ -100,18 +131,23 @@ module Octopi
|
|
100
131
|
|
101
132
|
private
|
102
133
|
def submit(path, params = {}, format = "yaml", &block)
|
103
|
-
params.each_pair
|
134
|
+
params.each_pair do |k,v|
|
135
|
+
if path =~ /:#{k.to_s}/
|
136
|
+
params.delete(k)
|
137
|
+
path = path.gsub(":#{k.to_s}", v)
|
138
|
+
end
|
139
|
+
end
|
104
140
|
query = login ? { :login => login, :token => token } : {}
|
105
141
|
query.merge!(params)
|
106
142
|
|
107
|
-
if @
|
108
|
-
case @
|
143
|
+
if @trace_level
|
144
|
+
case @trace_level
|
109
145
|
when "curl"
|
110
146
|
query_trace = []
|
111
147
|
query.each_pair { |k,v| query_trace << "-F '#{k}=#{v}'" }
|
112
148
|
puts "===== [curl version]"
|
113
|
-
puts "curl #{query_trace.join(" ")} #{self.class.base_uri}#{path}"
|
114
|
-
puts "
|
149
|
+
puts "curl #{query_trace.join(" ")} #{self.class.base_uri}/#{format}#{path}"
|
150
|
+
puts "===================="
|
115
151
|
end
|
116
152
|
end
|
117
153
|
|
@@ -130,14 +166,14 @@ module Octopi
|
|
130
166
|
end
|
131
167
|
|
132
168
|
def get(path, params = {}, format = "yaml")
|
133
|
-
trace "GET", path, params
|
169
|
+
trace "GET [#{format}]", "/#{format}#{path}", params
|
134
170
|
submit(path, params, format) do |path, params, format|
|
135
171
|
self.class.get "/#{format}#{path}"
|
136
172
|
end
|
137
173
|
end
|
138
174
|
|
139
175
|
def trace(oper, url, params)
|
140
|
-
return unless
|
176
|
+
return unless trace_level
|
141
177
|
par_str = " params: " + params.map { |p| "#{p[0]}=#{p[1]}" }.join(", ") if params and !params.empty?
|
142
178
|
puts "#{oper}: #{url}#{par_str}"
|
143
179
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fcoury-octopi
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Felipe Coury
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-04-
|
12
|
+
date: 2009-04-22 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|
@@ -65,7 +65,7 @@ requirements: []
|
|
65
65
|
rubyforge_project:
|
66
66
|
rubygems_version: 1.2.0
|
67
67
|
signing_key:
|
68
|
-
specification_version:
|
68
|
+
specification_version: 3
|
69
69
|
summary: A Ruby interface to GitHub API v2
|
70
70
|
test_files: []
|
71
71
|
|