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 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
- The following examples requires a valid user authenticated with GitHub using login and API token. This information can be found on our profile (the link is inside the "badge" that is displayed on the upper right corner when you're logged in).
7
+ === Seamless authentication using .gitconfig defaults
8
8
 
9
- Once you found your login and token you can run authenticated commands using:
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
- You can also create a YAML file with your information, with the following format:
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
- And change the way you connect to:
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
- == Copyright
151
+ == Contributors
152
+
153
+ In alphabetical order:
154
+
155
+ * Brandon Calloway - http://github.com/bcalloway
156
+ * runpaint - http://github.com/runpaint
113
157
 
114
- DISCLAIMER: The name of this library is pronounced <i>octo-pie</i> but no Octocats were harmed during its creation. It's not really an Octo Pie, but a contraction of the words Octocat and API.
158
+ Thanks guys!
159
+
160
+ == Copyright
115
161
 
116
162
  Copyright (c) 2009 Felipe Coury. See LICENSE for details.
data/VERSION.yml CHANGED
@@ -1,4 +1,4 @@
1
1
  ---
2
- :minor: 0
3
- :patch: 6
4
2
  :major: 0
3
+ :minor: 0
4
+ :patch: 7
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
- self.class.send :define_method, "#{k}=" do |v|
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, k do
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
- raise "State should be either 'open' or 'closed'" unless ['open', 'closed'].include? state
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
@@ -22,11 +22,19 @@ module Octopi
22
22
  find_plural(user, :resource)
23
23
  end
24
24
 
25
- def self.find(user, name)
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
- name = repo.name if name.is_a? Repository
28
- self.validate_args(user => :user, name => :repo)
29
- super [user, name]
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
@@ -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(*s)
32
- s = s.join('/') if s.is_a? Array
33
- result = ANONYMOUS_API.find(path_for(:resource), @resource_name[:singular], s)
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 do |r|
37
- new(ANONYMOUS_API, r)
38
- end
38
+ result[key].map { |r| new(api, r) }
39
39
  else
40
- Resource.for(key).new(ANONYMOUS_API, result[key])
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
- ANONYMOUS_API.find_all(path_for(path), @resource_name[:plural], s).
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(ANONYMOUS_API, payload)
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.trace = trace if trace
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, :trace, :read_only
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(login, name)
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 { |k,v| path = path.gsub(":#{k.to_s}", v) }
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 @trace
108
- case @trace
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 @trace
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.6
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-21 00:00:00 -07:00
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: 2
68
+ specification_version: 3
69
69
  summary: A Ruby interface to GitHub API v2
70
70
  test_files: []
71
71