opsb-octopussy 0.3.0

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/lib/octopussy.rb ADDED
@@ -0,0 +1,62 @@
1
+ require 'forwardable'
2
+
3
+ require 'httparty'
4
+ require 'hashie'
5
+ Hash.send :include, Hashie::HashExtensions
6
+
7
+ libdir = File.dirname(__FILE__)
8
+ $LOAD_PATH.unshift(libdir) unless $LOAD_PATH.include?(libdir)
9
+
10
+ require 'octopussy/repo'
11
+ require 'octopussy/event'
12
+ require 'octopussy/client'
13
+
14
+ module Octopussy
15
+ extend SingleForwardable
16
+
17
+ VERSION = "0.3.0".freeze
18
+
19
+ class OctopussyError < StandardError
20
+ attr_reader :data
21
+
22
+ def initialize(data)
23
+ @data = data
24
+ super
25
+ end
26
+ end
27
+
28
+ class ClientError < StandardError; end
29
+ class ServerError < OctopussyError; end
30
+ class General < OctopussyError; end
31
+
32
+ class RateLimitExceeded < ClientError; end
33
+ class Unauthorized < ClientError; end
34
+ class NotFound < ClientError; end
35
+
36
+ class Unavailable < StandardError; end
37
+ class InformOctopussy < StandardError; end
38
+
39
+ def self.client; Client.new end
40
+
41
+ # Users
42
+ def_delegators :client, :search_users, :user, :followers, :following, :follows?, :watched
43
+
44
+ # Issues
45
+ def_delegators :client, :search_issues, :issues, :issue
46
+
47
+ # Repos
48
+ def_delegators :client, :branches, :collaborators, :contributors, :languages, :list_repos,
49
+ :network, :repo, :search_repos, :tags
50
+
51
+ # Network Meta
52
+ def_delegators :client, :network_meta, :network_data
53
+
54
+ # Trees
55
+ def_delegators :client, :tree, :blob, :raw
56
+
57
+ # Commits
58
+ def_delegators :client, :list_commits, :commit
59
+
60
+ # Timeline
61
+ def_delegators :client, :public_timeline
62
+ end
@@ -0,0 +1,402 @@
1
+ require 'cgi'
2
+ module Octopussy
3
+ class Client
4
+ include HTTParty
5
+ format :json
6
+ base_uri "http://github.com/api/v2/json"
7
+
8
+ attr_reader :login, :token
9
+
10
+ # :login => 'pengwynn', :token => 'your_github_api_key'
11
+ def initialize(auth={})
12
+ if auth[:password].nil?
13
+ @login = auth[:login]
14
+ @token = auth[:token]
15
+ self.class.basic_auth(nil, nil)
16
+ else
17
+ @login = auth[:login]
18
+ self.class.basic_auth(@login, auth[:password])
19
+ end
20
+
21
+ end
22
+
23
+ def search_users(q)
24
+ q = CGI.escape(q)
25
+ response = self.class.get("/user/search/#{q}")
26
+ Hashie::Mash.new(response).users
27
+ end
28
+
29
+ def user(login=self.login)
30
+ response = self.class.get("/user/show/#{login}", :query => auth_params)
31
+ Hashie::Mash.new(response).user
32
+ end
33
+
34
+
35
+ def update_user(values={})
36
+ response = self.class.post("/user/show/#{self.login}", :query => auth_params, :body => {:values => values})
37
+ Hashie::Mash.new(response).user
38
+ end
39
+
40
+ def followers(login=self.login)
41
+ response = self.class.get("/user/show/#{login}/followers")
42
+ Hashie::Mash.new(response).users
43
+ end
44
+
45
+ def following(login=self.login)
46
+ response = self.class.get("/user/show/#{login}/following")
47
+ Hashie::Mash.new(response).users
48
+ end
49
+
50
+ def follow!(username)
51
+ response = self.class.post("/user/follow/#{username}", :query => auth_params)
52
+ Hashie::Mash.new(response).users
53
+ end
54
+
55
+ def unfollow!(username)
56
+ response = self.class.post("/user/unfollow/#{username}", :query => auth_params)
57
+ Hashie::Mash.new(response).users
58
+ end
59
+
60
+ def follows?(*args)
61
+ target = args.pop
62
+ username = args.first
63
+ username ||= self.login
64
+ return if username.nil?
65
+ self.following(username).include?(target)
66
+ end
67
+
68
+ def watched(login=self.login)
69
+ response = self.class.get("/repos/watched/#{login}")
70
+ Hashie::Mash.new(response).repositories
71
+ end
72
+
73
+ def emails
74
+ response = self.class.get("/user/emails", :query => auth_params)
75
+ Hashie::Mash.new(response).emails
76
+ end
77
+
78
+ def add_email(email)
79
+ response = self.class.post("/user/email/add", :query => auth_params, :body => {:email => email})
80
+ Hashie::Mash.new(response).emails
81
+ end
82
+
83
+ def remove_email(email)
84
+ response = self.class.post("/user/email/remove", :query => auth_params, :body => {:email => email})
85
+ Hashie::Mash.new(response).emails
86
+ end
87
+
88
+ def keys
89
+ response = self.class.get("/user/keys", :query => auth_params)
90
+ Hashie::Mash.new(response).public_keys
91
+ end
92
+
93
+ def add_key(title, key)
94
+ response = self.class.post("/user/key/add", :query => auth_params, :body => {:title => title, :key => key})
95
+ Hashie::Mash.new(response).public_keys
96
+ end
97
+
98
+ def remove_key(id)
99
+ response = self.class.post("/user/key/remove", :query => auth_params, :body => {:id => id})
100
+ Hashie::Mash.new(response).public_keys
101
+ end
102
+
103
+ # Issues
104
+
105
+ def search_issues(repo, state, q)
106
+ repo = Repo.new(repo)
107
+ response = self.class.get("/issues/search/#{repo.username}/#{repo.name}/#{state}/#{q}")
108
+ Hashie::Mash.new(response).issues
109
+ end
110
+
111
+ def issues(repo, state)
112
+ repo = Repo.new(repo)
113
+ response = self.class.get("/issues/list/#{repo.username}/#{repo.name}/#{state}")
114
+ Hashie::Mash.new(response).issues
115
+ end
116
+
117
+ def issue(repo, id)
118
+ repo = Repo.new(repo)
119
+ response = self.class.get("/issues/show/#{repo.username}/#{repo.name}/#{id}")
120
+ Hashie::Mash.new(response).issue
121
+ end
122
+
123
+ def open_issue(repo, title, body)
124
+ repo = Repo.new(repo)
125
+ response = self.class.post("/issues/open/#{repo.username}/#{repo.name}", :body => {:title => title, :body => body})
126
+ Hashie::Mash.new(response).issue
127
+ end
128
+
129
+ def close_issue(repo, number)
130
+ repo = Repo.new(repo)
131
+ response = self.class.post("/issues/close/#{repo.username}/#{repo.name}/#{number}")
132
+ Hashie::Mash.new(response).issue
133
+ end
134
+
135
+ def reopen_issue(repo, number)
136
+ repo = Repo.new(repo)
137
+ response = self.class.post("/issues/reopen/#{repo.username}/#{repo.name}/#{number}")
138
+ Hashie::Mash.new(response).issue
139
+ end
140
+
141
+ def update_issue(repo, number, title, body)
142
+ repo = Repo.new(repo)
143
+ response = self.class.post("/issues/edit/#{repo.username}/#{repo.name}/#{number}", :body => {:title => title, :body => body})
144
+ Hashie::Mash.new(response).issue
145
+ end
146
+
147
+ def labels(repo)
148
+ repo = Repo.new(repo)
149
+ response = self.class.get("/issues/labels/#{repo.username}/#{repo.name}")
150
+ Hashie::Mash.new(response).labels
151
+ end
152
+
153
+ def add_label(repo, number, label)
154
+ repo = Repo.new(repo)
155
+ response = self.class.post("/issues/label/add/#{repo.username}/#{repo.name}/#{label}/#{number}")
156
+ Hashie::Mash.new(response).labels
157
+ end
158
+
159
+ def remove_label(repo, number, label)
160
+ repo = Repo.new(repo)
161
+ response = self.class.post("/issues/label/remove/#{repo.username}/#{repo.name}/#{label}/#{number}")
162
+ Hashie::Mash.new(response).labels
163
+ end
164
+
165
+ def add_comment(repo, number, comment)
166
+ repo = Repo.new(repo)
167
+ response = self.class.post("/issues/comment/#{repo.username}/#{repo.name}/#{number}", :body => {:comment => comment})
168
+ Hashie::Mash.new(response).comment
169
+ end
170
+
171
+ # Repos
172
+
173
+ def search_repos(q)
174
+ q = CGI.escape(q)
175
+ response = self.class.get("/repos/search/#{q}")
176
+ Hashie::Mash.new(response).repositories
177
+ end
178
+
179
+ def watch(repo)
180
+ repo = Repo.new(repo)
181
+ response = self.class.post("/repos/watch/#{repo.username}/#{repo.name}", :query => auth_params)
182
+ Hashie::Mash.new(response).repository
183
+ end
184
+
185
+ def unwatch(repo)
186
+ repo = Repo.new(repo)
187
+ response = self.class.post("/repos/unwatch/#{repo.username}/#{repo.name}", :query => auth_params)
188
+ Hashie::Mash.new(response).repository
189
+ end
190
+
191
+ def fork(repo)
192
+ repo = Repo.new(repo)
193
+ response = self.class.post("/repos/fork/#{repo.username}/#{repo.name}", :query => auth_params)
194
+ Hashie::Mash.new(response).repository
195
+ end
196
+
197
+ # :name, :description, :homepage, :public
198
+ def create(options)
199
+ response = self.class.post("/repos/create", :query => auth_params, :body => options)
200
+ Hashie::Mash.new(response).repository
201
+ end
202
+
203
+ def delete(repo, delete_token={})
204
+ repo = Repo.new(repo)
205
+ response = self.class.post("/repos/delete/#{repo.name}", :query => auth_params, :body => {:delete_token => delete_token})
206
+ Hashie::Mash.new(response).repository
207
+ end
208
+
209
+ def confirm_delete(repo, delete_token)
210
+ delete(repo, delete_token)
211
+ end
212
+
213
+ def set_private(repo)
214
+ repo = Repo.new(repo)
215
+ response = self.class.post("/repos/set/private/#{repo.name}", :query => auth_params)
216
+ Hashie::Mash.new(response).repository
217
+ end
218
+
219
+ def set_public(repo)
220
+ repo = Repo.new(repo)
221
+ response = self.class.post("/repos/set/public/#{repo.name}", :query => auth_params)
222
+ Hashie::Mash.new(response).repository
223
+ end
224
+
225
+ def deploy_keys(repo)
226
+ repo = Repo.new(repo)
227
+ response = self.class.get("/repos/keys/#{repo.name}", :query => auth_params)
228
+ Hashie::Mash.new(response).public_keys
229
+ end
230
+
231
+ def add_deploy_key(repo, key, title='')
232
+ repo = Repo.new(repo)
233
+ response = self.class.post("/repos/key/#{repo.name}/add", :query => auth_params, :body => {:title => title, :key => key})
234
+ Hashie::Mash.new(response).public_keys
235
+ end
236
+
237
+ def remove_deploy_key(repo, id)
238
+ repo = Repo.new(repo)
239
+ response = self.class.post("/repos/key/#{repo.name}/remove", :query => auth_params, :body => {:id => id})
240
+ Hashie::Mash.new(response).public_keys
241
+ end
242
+
243
+ def collaborators(repo)
244
+ repo = Repo.new(repo)
245
+ response = self.class.post("/repos/show/#{repo.username}/#{repo.name}/collaborators", :query => auth_params)
246
+ Hashie::Mash.new(response).collaborators
247
+ end
248
+
249
+ def contributors(repo)
250
+ repo = Repo.new(repo)
251
+ response = self.class.get("/repos/show/#{repo.username}/#{repo.name}/contributors")
252
+ Hashie::Mash.new(response).contributors
253
+ end
254
+
255
+ def repo(repo)
256
+ repo = Repo.new(repo)
257
+ response = self.class.get("/repos/show/#{repo.username}/#{repo.name}", :query => auth_params)
258
+ Hashie::Mash.new(response).repository
259
+ end
260
+
261
+ # pass options without the "values[x]" descriped in the API docs:
262
+ # set_repo_info('user/repo', :description => "hey!", :has_wiki => false)
263
+ def set_repo_info(repo, options)
264
+ repo = Repo.new(repo)
265
+ # post body needs to be "values[has_wiki]=false"
266
+ response = self.class.post("/repos/show/#{repo.username}/#{repo.name}",
267
+ :body => options.keys.reduce({}) { |a,v| a["values[#{v}]"] = options[v]; a }.merge(auth_params))
268
+ Hashie::Mash.new(response).repository
269
+ end
270
+
271
+ def list_repos(username = nil)
272
+ if username.nil? && !@login.nil?
273
+ username = login
274
+ elsif username.nil?
275
+ raise ArgumentError, 'you must provide a username'
276
+ end
277
+ response = self.class.get("/repos/show/#{username}", :query => auth_params)
278
+ Hashie::Mash.new(response).repositories
279
+ end
280
+
281
+ def add_collaborator(repo, collaborator)
282
+ repo = Repo.new(repo)
283
+ response = self.class.post("/repos/collaborators/#{repo.name}/add/#{collaborator}", :query => auth_params)
284
+ Hashie::Mash.new(response).collaborators
285
+ end
286
+
287
+ def remove_collaborator(repo, collaborator)
288
+ repo = Repo.new(repo)
289
+ response = self.class.post("/repos/collaborators/#{repo.name}/remove/#{collaborator}", :query => auth_params)
290
+ Hashie::Mash.new(response).collaborators
291
+ end
292
+
293
+ def network(repo)
294
+ repo = Repo.new(repo)
295
+ response = self.class.get("/repos/show/#{repo.username}/#{repo.name}/network")
296
+ Hashie::Mash.new(response).network
297
+ end
298
+
299
+ def languages(repo)
300
+ repo = Repo.new(repo)
301
+ response = self.class.get("/repos/show/#{repo.username}/#{repo.name}/languages")
302
+ Hashie::Mash.new(response).languages
303
+ end
304
+
305
+ def tags(repo)
306
+ repo = Repo.new(repo)
307
+ response = self.class.get("/repos/show/#{repo.username}/#{repo.name}/tags")
308
+ Hashie::Mash.new(response).tags
309
+ end
310
+
311
+ def branches(repo)
312
+ repo = Repo.new(repo)
313
+ response = self.class.get("/repos/show/#{repo.username}/#{repo.name}/branches", :query => auth_params)
314
+ Hashie::Mash.new(response).branches
315
+ end
316
+
317
+ # Network
318
+
319
+ def network_meta(repo)
320
+ repo = Repo.new(repo)
321
+ response = self.class.get("http://github.com/#{repo.username}/#{repo.name}/network_meta")
322
+ Hashie::Mash.new(response)
323
+ end
324
+
325
+ def network_data(repo, nethash)
326
+ repo = Repo.new(repo)
327
+ response = self.class.get("http://github.com/#{repo.username}/#{repo.name}/network_data_chunk", :query => {:nethash => nethash})
328
+ Hashie::Mash.new(response).commits
329
+ end
330
+
331
+ # Trees
332
+
333
+ def tree(repo, sha)
334
+ repo = Repo.new(repo)
335
+ response = self.class.get("http://github.com/api/v2/json/tree/show/#{repo.username}/#{repo.name}/#{sha}", :query => auth_params)
336
+ Hashie::Mash.new(response).tree
337
+ end
338
+
339
+ def blob(repo, sha, path)
340
+ repo = Repo.new(repo)
341
+ response = self.class.get("http://github.com/api/v2/json/blob/show/#{repo.username}/#{repo.name}/#{sha}/#{path}", :query => auth_params)
342
+ Hashie::Mash.new(response).blob
343
+ end
344
+
345
+ def raw(repo, sha)
346
+ repo = Repo.new(repo)
347
+ response = self.class.get("http://github.com/api/v2/yaml/blob/show/#{repo.username}/#{repo.name}/#{sha}", :query => auth_params)
348
+ response.body
349
+ end
350
+
351
+ # Commits
352
+
353
+ def list_commits(repo, branch="master")
354
+ repo = Repo.new(repo)
355
+ response = self.class.get("http://github.com/api/v2/json/commits/list/#{repo.username}/#{repo.name}/#{branch}")
356
+ Hashie::Mash.new(response).commits
357
+ end
358
+
359
+ def commit(repo, sha)
360
+ repo = Repo.new(repo)
361
+ response = self.class.get("http://github.com/api/v2/json/commits/show/#{repo.username}/#{repo.name}/#{sha}")
362
+ Hashie::Mash.new(response).commit
363
+ end
364
+
365
+ def public_timeline(username = nil)
366
+ username ||= @login
367
+ if username.nil?
368
+ path = "http://github.com/timeline.json"
369
+ else
370
+ path = "http://github.com/#{username}.json"
371
+ end
372
+ response = self.class.get(path)
373
+ response.map{|item| Hashie::Mash.new(item)}
374
+ end
375
+
376
+ def timeline
377
+ response = self.class.get("http://github.com/#{@login}.private.json", :query => auth_params)
378
+ response.map{|item| Hashie::Mash.new(item)}
379
+ end
380
+
381
+ private
382
+
383
+ def auth_params
384
+ @token.nil? ? {} : {:login => @login, :token => @token}
385
+ end
386
+
387
+ def self.get(*args); handle_response super end
388
+ def self.post(*args); handle_response super end
389
+
390
+ def self.handle_response(response)
391
+ case response.code
392
+ when 401; raise Unauthorized.new
393
+ when 403; raise RateLimitExceeded.new
394
+ when 404; raise NotFound.new
395
+ when 400...500; raise ClientError.new
396
+ when 500...600; raise ServerError.new(response.code)
397
+ else; response
398
+ end
399
+ end
400
+
401
+ end
402
+ end