gittycent 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/CHANGELOG +1 -0
- data/LICENSE +20 -0
- data/Manifest +7 -0
- data/README.rdoc +33 -0
- data/Rakefile +21 -0
- data/gittycent.gemspec +30 -0
- data/lib/gittycent.rb +262 -0
- metadata +69 -0
data/CHANGELOG
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
v0.0.1. Initial release.
|
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2008 Elijah Miller
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Manifest
ADDED
data/README.rdoc
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
= GittyCent
|
2
|
+
|
3
|
+
Up in the Hub.
|
4
|
+
|
5
|
+
== Examples
|
6
|
+
|
7
|
+
The following example adds a set of users to all projects of another user. We use it to add all of our company to each client project.
|
8
|
+
|
9
|
+
## Add this to your ~/.gitconfig
|
10
|
+
# [github-company]
|
11
|
+
# user = fastestforward
|
12
|
+
# token = ...
|
13
|
+
|
14
|
+
require 'rubygems'
|
15
|
+
require 'gittycent'
|
16
|
+
|
17
|
+
default_users = %w(jqr kristopher netshade)
|
18
|
+
|
19
|
+
GitHub.connect_with_git_config('github-company') do |github|
|
20
|
+
user = github.authenticated_user
|
21
|
+
user.repos.each do |repo|
|
22
|
+
repo.collaborators = repo.collaborators + default_users
|
23
|
+
puts "#{repo}: #{repo.collaborators.join(', ')}"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
== Install
|
29
|
+
|
30
|
+
gem install gittycent
|
31
|
+
|
32
|
+
Homepage:: http://github.com/fastestforward/gittycent
|
33
|
+
Copyright:: Copyright (c) 2008 Elijah Miller <mailto:elijah.miller@gmail.com>, released under the MIT license.
|
data/Rakefile
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'spec/rake/spectask'
|
2
|
+
|
3
|
+
require 'echoe'
|
4
|
+
Echoe.new 'gittycent' do |p|
|
5
|
+
p.description = "Up in the Hub."
|
6
|
+
p.url = "http://github.com/fastestforward/gittycent"
|
7
|
+
p.author = "Elijah Miller"
|
8
|
+
p.email = "elijah.miller@gmail.com"
|
9
|
+
p.retain_gemspec = true
|
10
|
+
p.need_tar_gz = false
|
11
|
+
p.extra_deps = [
|
12
|
+
]
|
13
|
+
end
|
14
|
+
|
15
|
+
desc 'Default: run specs'
|
16
|
+
task :default => :spec
|
17
|
+
Spec::Rake::SpecTask.new do |t|
|
18
|
+
t.spec_files = FileList["spec/**/*_spec.rb"]
|
19
|
+
end
|
20
|
+
|
21
|
+
task :test => :spec
|
data/gittycent.gemspec
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
Gem::Specification.new do |s|
|
4
|
+
s.name = %q{gittycent}
|
5
|
+
s.version = "0.0.1"
|
6
|
+
|
7
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
|
8
|
+
s.authors = ["Elijah Miller"]
|
9
|
+
s.date = %q{2010-03-12}
|
10
|
+
s.description = %q{Up in the Hub.}
|
11
|
+
s.email = %q{elijah.miller@gmail.com}
|
12
|
+
s.extra_rdoc_files = ["CHANGELOG", "LICENSE", "README.rdoc", "lib/gittycent.rb"]
|
13
|
+
s.files = ["CHANGELOG", "LICENSE", "Manifest", "README.rdoc", "Rakefile", "gittycent.gemspec", "lib/gittycent.rb"]
|
14
|
+
s.homepage = %q{http://github.com/fastestforward/gittycent}
|
15
|
+
s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Gittycent", "--main", "README.rdoc"]
|
16
|
+
s.require_paths = ["lib"]
|
17
|
+
s.rubyforge_project = %q{gittycent}
|
18
|
+
s.rubygems_version = %q{1.3.4}
|
19
|
+
s.summary = %q{Up in the Hub.}
|
20
|
+
|
21
|
+
if s.respond_to? :specification_version then
|
22
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
23
|
+
s.specification_version = 3
|
24
|
+
|
25
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
26
|
+
else
|
27
|
+
end
|
28
|
+
else
|
29
|
+
end
|
30
|
+
end
|
data/lib/gittycent.rb
ADDED
@@ -0,0 +1,262 @@
|
|
1
|
+
require 'active_support'
|
2
|
+
require 'httparty'
|
3
|
+
require 'pp'
|
4
|
+
|
5
|
+
class GitHub
|
6
|
+
API_VERSION = 'v2'
|
7
|
+
FORMAT = 'yaml'
|
8
|
+
NONE, WARNING, INFO, DEBUG = *1..10
|
9
|
+
|
10
|
+
attr_accessor :options
|
11
|
+
|
12
|
+
def self.connect(options)
|
13
|
+
connection = new(options)
|
14
|
+
if block_given?
|
15
|
+
yield(connection)
|
16
|
+
else
|
17
|
+
connection
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.connect_with_git_config(section = :github, &block)
|
22
|
+
config = Hash[*`git config -l`.scan(/^(.*?)=(.*)$/).flatten]
|
23
|
+
connect(:login => config["#{section}.user"], :token => config["#{section}.token"], &block)
|
24
|
+
end
|
25
|
+
|
26
|
+
def initialize(options)
|
27
|
+
self.options = options
|
28
|
+
debug "Login using login #{options[:login]} with token #{options[:token]}"
|
29
|
+
end
|
30
|
+
|
31
|
+
def verbosity
|
32
|
+
options[:verbosity] || NONE
|
33
|
+
end
|
34
|
+
|
35
|
+
def user(login)
|
36
|
+
if login == options[:login]
|
37
|
+
AuthenticatedUser.new(self, :login => options[:login])
|
38
|
+
else
|
39
|
+
User.new(self, :login => login)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def user_search(query)
|
44
|
+
get("/user/search/#{query}")['users'].map { |u| User.new(self, u) }
|
45
|
+
end
|
46
|
+
|
47
|
+
def authenticated_user
|
48
|
+
@authenticated_user ||= user(options[:login])
|
49
|
+
end
|
50
|
+
|
51
|
+
def inspect
|
52
|
+
"#<#{self.class}#{' ' + options[:login] if options[:login].present?}>"
|
53
|
+
end
|
54
|
+
|
55
|
+
def default_http_options
|
56
|
+
{
|
57
|
+
:query => {
|
58
|
+
:login => options[:login],
|
59
|
+
:token => options[:token]
|
60
|
+
}
|
61
|
+
}
|
62
|
+
end
|
63
|
+
|
64
|
+
def get(path)
|
65
|
+
with_retry do
|
66
|
+
url = "http://github.com/api/#{API_VERSION}/#{FORMAT}#{path}"
|
67
|
+
debug "GET #{url}"
|
68
|
+
response = HTTParty.get(url, default_http_options)
|
69
|
+
debug response.code
|
70
|
+
debug response.body
|
71
|
+
debug
|
72
|
+
response
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def post(path, params = {})
|
77
|
+
with_retry do
|
78
|
+
url = "http://github.com/api/#{API_VERSION}/#{FORMAT}#{path}"
|
79
|
+
debug "POST #{url}"
|
80
|
+
debug_inspect params
|
81
|
+
response = HTTParty.post(url, default_http_options.deep_merge(:query => params))
|
82
|
+
debug response.code
|
83
|
+
debug response.body
|
84
|
+
debug
|
85
|
+
response
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def debug(message = "")
|
90
|
+
puts message if verbosity >= DEBUG
|
91
|
+
end
|
92
|
+
|
93
|
+
def warn(message = "")
|
94
|
+
puts message if verbosity >= WARNING
|
95
|
+
end
|
96
|
+
|
97
|
+
def debug_inspect(object)
|
98
|
+
debug object.pretty_inspect
|
99
|
+
end
|
100
|
+
|
101
|
+
def with_retry
|
102
|
+
count = 0
|
103
|
+
loop do
|
104
|
+
response = yield
|
105
|
+
if response.code == 403 && response['error'].any? { |e| e['error'] == 'too many requests' }
|
106
|
+
count += 1
|
107
|
+
delay = 2 ** count
|
108
|
+
warn "too many requests, sleeping for #{delay} seconds"
|
109
|
+
sleep delay
|
110
|
+
else
|
111
|
+
return response
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
class Connectable
|
117
|
+
class_inheritable_accessor :identified_by
|
118
|
+
attr_accessor :connection, :name
|
119
|
+
|
120
|
+
def initialize(connection, options)
|
121
|
+
self.connection = connection
|
122
|
+
@attributes = options.dup
|
123
|
+
if self.class.identified_by && @attributes.include?(self.class.identified_by)
|
124
|
+
send("#{identified_by}=", @attributes.delete(self.class.identified_by))
|
125
|
+
end
|
126
|
+
self.connection = connection
|
127
|
+
end
|
128
|
+
|
129
|
+
def get(*args)
|
130
|
+
connection.get(*args)
|
131
|
+
end
|
132
|
+
|
133
|
+
def post(*args)
|
134
|
+
connection.post(*args)
|
135
|
+
end
|
136
|
+
|
137
|
+
def debug(*args)
|
138
|
+
connection.debug(*args)
|
139
|
+
end
|
140
|
+
|
141
|
+
def reload
|
142
|
+
@attributes = {}
|
143
|
+
load
|
144
|
+
end
|
145
|
+
|
146
|
+
def self.loadable_attributes(*attributes)
|
147
|
+
(attributes - [identified_by]).each do |attribute|
|
148
|
+
define_method(attribute) do
|
149
|
+
if !@attributes.include?(attributes)
|
150
|
+
load
|
151
|
+
end
|
152
|
+
@attributes[attribute]
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
end
|
158
|
+
|
159
|
+
class User < Connectable
|
160
|
+
attr_accessor :login
|
161
|
+
self.identified_by = :login
|
162
|
+
|
163
|
+
loadable_attributes :created_at, :gravatar_id, :public_repo_count,
|
164
|
+
:public_gist_count, :following_count, :followers_count
|
165
|
+
|
166
|
+
def to_s
|
167
|
+
login.to_s
|
168
|
+
end
|
169
|
+
|
170
|
+
def repos
|
171
|
+
@repos ||= get("/repos/show/#{login}")['repositories'].map { |r| Repo.new(connection, r) }
|
172
|
+
end
|
173
|
+
|
174
|
+
def watched_repos
|
175
|
+
@repos ||= get("/repos/watched/#{login}")['repositories'].map { |r| Repo.new(connection, r) }
|
176
|
+
end
|
177
|
+
|
178
|
+
# supported options include: :name, :description, :homepage, :public
|
179
|
+
def create_repo(options)
|
180
|
+
options = options.dup
|
181
|
+
Repo.new(connection, post("/repos/create", options)['repository'])
|
182
|
+
end
|
183
|
+
|
184
|
+
def load
|
185
|
+
@attributes = get("/user/show/#{login}")['user'].symbolize_keys
|
186
|
+
end
|
187
|
+
|
188
|
+
def followers
|
189
|
+
@followers ||= get("/user/show/#{login}/followers")['users'].map { |u| User.new(connection, :login => u) }
|
190
|
+
end
|
191
|
+
|
192
|
+
def following
|
193
|
+
@following||= get("/user/show/#{login}/following")['users'].map { |u| User.new(connection, :login => u) }
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
class AuthenticatedUser < User
|
198
|
+
loadable_attributes :followers_count, :owned_private_repo_count,
|
199
|
+
:created_at, :company, :private_gist_count, :plan, :gravatar_id,
|
200
|
+
:total_private_repo_count, :public_repo_count, :location, :email,
|
201
|
+
:collaborators, :public_gist_count, :blog, :name, :following_count,
|
202
|
+
:disk_usage
|
203
|
+
end
|
204
|
+
|
205
|
+
class Repo < Connectable
|
206
|
+
attr_accessor :name
|
207
|
+
self.identified_by = :name
|
208
|
+
|
209
|
+
loadable_attributes :owner, :open_issues, :description, :fork, :forks,
|
210
|
+
:private, :url, :homepage, :watchers
|
211
|
+
|
212
|
+
def to_s
|
213
|
+
name.to_s
|
214
|
+
end
|
215
|
+
|
216
|
+
def owner
|
217
|
+
@owner ||= User.new(connection, :login => @attributes[:owner])
|
218
|
+
end
|
219
|
+
|
220
|
+
def collaborators
|
221
|
+
@collaborators ||= get("/repos/show/#{owner.login}/#{name}/collaborators")['collaborators'] || []
|
222
|
+
end
|
223
|
+
|
224
|
+
def collaborators=(value)
|
225
|
+
value = value.dup.uniq
|
226
|
+
removals = collaborators - value
|
227
|
+
additions = value - collaborators
|
228
|
+
debug "removals: #{removals.join(', ')}"
|
229
|
+
debug "additions: #{additions.join(', ')}"
|
230
|
+
removals.each do |remove|
|
231
|
+
post("/repos/collaborators/#{name}/remove/#{remove}")
|
232
|
+
end
|
233
|
+
additions.each do |addition|
|
234
|
+
post("/repos/collaborators/#{name}/add/#{addition}")
|
235
|
+
end
|
236
|
+
@collaborators = nil
|
237
|
+
end
|
238
|
+
|
239
|
+
def initial_push_command
|
240
|
+
"git remote add origin git@github.com:#{owner.login}/#{name}.git &&\n" +
|
241
|
+
"git push origin master &&\n" +
|
242
|
+
"git config --add branch.master.remote origin &&\n" +
|
243
|
+
"git config --add branch.master.merge refs/heads/master"
|
244
|
+
end
|
245
|
+
|
246
|
+
def network
|
247
|
+
@network ||= get("/repos/show/#{owner.login}/#{name}/network")['network'].map { |r| Repo.new(connection, r) }
|
248
|
+
end
|
249
|
+
|
250
|
+
def languages
|
251
|
+
get("/repos/show/#{owner.login}/#{name}/languages")['languages']
|
252
|
+
end
|
253
|
+
|
254
|
+
def tags
|
255
|
+
get("/repos/show/#{owner.login}/#{name}/tags")['tags']
|
256
|
+
end
|
257
|
+
|
258
|
+
def branches
|
259
|
+
get("/repos/show/#{owner.login}/#{name}/branches")['branches']
|
260
|
+
end
|
261
|
+
end
|
262
|
+
end
|
metadata
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: gittycent
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Elijah Miller
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2010-03-12 00:00:00 -05:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description: Up in the Hub.
|
17
|
+
email: elijah.miller@gmail.com
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files:
|
23
|
+
- CHANGELOG
|
24
|
+
- LICENSE
|
25
|
+
- README.rdoc
|
26
|
+
- lib/gittycent.rb
|
27
|
+
files:
|
28
|
+
- CHANGELOG
|
29
|
+
- LICENSE
|
30
|
+
- Manifest
|
31
|
+
- README.rdoc
|
32
|
+
- Rakefile
|
33
|
+
- gittycent.gemspec
|
34
|
+
- lib/gittycent.rb
|
35
|
+
has_rdoc: true
|
36
|
+
homepage: http://github.com/fastestforward/gittycent
|
37
|
+
licenses: []
|
38
|
+
|
39
|
+
post_install_message:
|
40
|
+
rdoc_options:
|
41
|
+
- --line-numbers
|
42
|
+
- --inline-source
|
43
|
+
- --title
|
44
|
+
- Gittycent
|
45
|
+
- --main
|
46
|
+
- README.rdoc
|
47
|
+
require_paths:
|
48
|
+
- lib
|
49
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - ">="
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: "0"
|
54
|
+
version:
|
55
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
56
|
+
requirements:
|
57
|
+
- - ">="
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
version: "1.2"
|
60
|
+
version:
|
61
|
+
requirements: []
|
62
|
+
|
63
|
+
rubyforge_project: gittycent
|
64
|
+
rubygems_version: 1.3.4
|
65
|
+
signing_key:
|
66
|
+
specification_version: 3
|
67
|
+
summary: Up in the Hub.
|
68
|
+
test_files: []
|
69
|
+
|