git-forks 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/LICENSE +20 -0
- data/bin/git-forks +8 -0
- data/lib/git-forks.rb +281 -0
- metadata +80 -0
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2010 Scott Chacon
|
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/bin/git-forks
ADDED
data/lib/git-forks.rb
ADDED
@@ -0,0 +1,281 @@
|
|
1
|
+
# Octokit is used to access GitHub's API.
|
2
|
+
require 'octokit'
|
3
|
+
# Time is used to parse time strings from git back into Time objects.
|
4
|
+
require 'time'
|
5
|
+
# JSON is used to cache GitHub API response data.
|
6
|
+
require 'json'
|
7
|
+
|
8
|
+
class GitForks
|
9
|
+
|
10
|
+
CACHE_FILE = '.git/forks_cache.json'
|
11
|
+
|
12
|
+
def initialize(args)
|
13
|
+
@command = args.shift
|
14
|
+
@user, @repo = repo_info
|
15
|
+
@args = args
|
16
|
+
@branch_pattern = branch_pattern
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.start(args)
|
20
|
+
GitForks.new(args).run
|
21
|
+
end
|
22
|
+
|
23
|
+
def run
|
24
|
+
configure
|
25
|
+
if @command && self.respond_to?(@command)
|
26
|
+
# If the cache file doesn't exist, make sure we run update
|
27
|
+
# before any other command. git-forks will otherwise crash
|
28
|
+
# with an exception.
|
29
|
+
update unless File.exists?(CACHE_FILE) || @command == 'update'
|
30
|
+
|
31
|
+
self.send @command
|
32
|
+
elsif %w(-h --help).include?(@command)
|
33
|
+
usage
|
34
|
+
else
|
35
|
+
help
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
#-----------------------------------------------------------------------------
|
40
|
+
# Commands
|
41
|
+
#-----------------------------------------------------------------------------
|
42
|
+
|
43
|
+
# Get the latest GitHub data.
|
44
|
+
def update
|
45
|
+
cache('forks', fetch_fork_info)
|
46
|
+
update_branches
|
47
|
+
end
|
48
|
+
|
49
|
+
# Fetch and cache all branches for each fork.
|
50
|
+
def update_branches(pattern=nil)
|
51
|
+
pattern ||= @branch_pattern
|
52
|
+
forks = get_cached_data('forks')
|
53
|
+
|
54
|
+
forks.each do |fork|
|
55
|
+
fork_user = fork['owner']['login']
|
56
|
+
puts "Checking for new branches matching '#{pattern}' in '#{fork_user}/#{@repo}'"
|
57
|
+
|
58
|
+
branches = fetch_fork_branches(fork_user, pattern)
|
59
|
+
|
60
|
+
fork['branches'] = branches
|
61
|
+
end
|
62
|
+
|
63
|
+
cache('forks', forks)
|
64
|
+
end
|
65
|
+
|
66
|
+
# List all forks.
|
67
|
+
#
|
68
|
+
# Example::
|
69
|
+
#
|
70
|
+
# --------------------------------------------------------------------------------
|
71
|
+
# Forks of 'doubleotoo/foo/master'
|
72
|
+
#
|
73
|
+
# Owner Branches Updated
|
74
|
+
# ------ -------- -------
|
75
|
+
# justintoo 2 01-May-12
|
76
|
+
# rose-compiler 3 27-Apr-12
|
77
|
+
#
|
78
|
+
def list
|
79
|
+
forks = get_cached_data('forks')
|
80
|
+
forks.reverse! if @args.shift == '--reverse'
|
81
|
+
|
82
|
+
output = forks.collect do |f|
|
83
|
+
line = ""
|
84
|
+
line << l(f['owner']['login'], 25)
|
85
|
+
line << l(f['branches'].size, 12)
|
86
|
+
line << strftime(clean(f['updated_at']))
|
87
|
+
end
|
88
|
+
|
89
|
+
if output.compact.empty?
|
90
|
+
puts "No forks of '#{@user}/#{@repo}'"
|
91
|
+
else
|
92
|
+
puts '-' * 80
|
93
|
+
puts "Forks of '#{@user}/#{@repo}'"
|
94
|
+
puts
|
95
|
+
puts l('Owner', 25) + l('Branches', 12) + 'Updated'
|
96
|
+
puts l('------', 25) + l('--------', 12) + '-------'
|
97
|
+
puts output.compact
|
98
|
+
puts
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
# Show details of one fork.
|
103
|
+
#
|
104
|
+
# Example::
|
105
|
+
#
|
106
|
+
# -------------------------------------------------------------------------------
|
107
|
+
# Owner : justintoo
|
108
|
+
# Created : 01-May-12
|
109
|
+
# Updated : 01-May-12
|
110
|
+
# Branches : 2
|
111
|
+
# 444a867d338cafc0c82d058b458b4fe268fa14d6 master
|
112
|
+
# 14178fe5b204c38650de8ddaf5d9fb80aa834e74 foo
|
113
|
+
#
|
114
|
+
def show
|
115
|
+
owner = @args.shift
|
116
|
+
option = @args.shift
|
117
|
+
if f = fork(owner)
|
118
|
+
puts '-' * 80
|
119
|
+
puts "Owner : #{f['owner']['login']}"
|
120
|
+
puts "Created : #{strftime(f['created_at'])}"
|
121
|
+
puts "Updated : #{strftime(f['updated_at'])}"
|
122
|
+
puts "Branches : #{f['branches'].size}"
|
123
|
+
f['branches'].each do |b|
|
124
|
+
puts " #{b['commit']['sha']} #{b['name']}"
|
125
|
+
end
|
126
|
+
puts
|
127
|
+
else
|
128
|
+
puts "No such fork: #{owner}/#{@repo}"
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
# Show a quick reference of available commands.
|
133
|
+
def usage
|
134
|
+
puts 'Usage: git forks <command>'
|
135
|
+
puts 'Get GitHub project forks information.'
|
136
|
+
puts
|
137
|
+
puts 'Available commands:'
|
138
|
+
puts ' update Retrieve fork info from GitHub API v3.'
|
139
|
+
puts ' list [--reverse] List all forks.'
|
140
|
+
puts ' show <owner> Show details for a single fork.'
|
141
|
+
puts
|
142
|
+
puts 'Git configurations:'
|
143
|
+
puts ' github.forks.branchpattern Only grab branches matching this Ruby Regexp.'
|
144
|
+
end
|
145
|
+
|
146
|
+
#-----------------------------------------------------------------------------
|
147
|
+
# Cache
|
148
|
+
#-----------------------------------------------------------------------------
|
149
|
+
|
150
|
+
def cache(group, json)
|
151
|
+
save_data({group => json}, CACHE_FILE)
|
152
|
+
end
|
153
|
+
|
154
|
+
# get_cached_data('forks')
|
155
|
+
def get_cached_data(group=nil)
|
156
|
+
data = JSON.parse(File.read(CACHE_FILE))
|
157
|
+
if group
|
158
|
+
data[group]
|
159
|
+
else
|
160
|
+
data
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
def save_data(data, file)
|
165
|
+
File.open(file, "w+") do |f|
|
166
|
+
f.puts data.to_json
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
# Get a fork by owner name.
|
171
|
+
def fork(owner)
|
172
|
+
forks = get_cached_data('forks')
|
173
|
+
forks.select {|f| f['owner']['login'] == owner }.first
|
174
|
+
end
|
175
|
+
|
176
|
+
#-----------------------------------------------------------------------------
|
177
|
+
# GitHub API v3 (using Octokit gem)
|
178
|
+
#-----------------------------------------------------------------------------
|
179
|
+
|
180
|
+
def fetch_fork_info
|
181
|
+
forks = Octokit.forks("#{@user}/#{@repo}")
|
182
|
+
end
|
183
|
+
|
184
|
+
def fetch_fork_branches(fork_user, pattern)
|
185
|
+
pattern ||= @branch_pattern
|
186
|
+
branches = Octokit.branches("#{fork_user}/#{@repo}")
|
187
|
+
.select {|b| not b.name.match(pattern).nil? }
|
188
|
+
end
|
189
|
+
|
190
|
+
#-----------------------------------------------------------------------------
|
191
|
+
# Display Helper Functions
|
192
|
+
#-----------------------------------------------------------------------------
|
193
|
+
|
194
|
+
def l(info, size)
|
195
|
+
clean(info)[0, size].ljust(size)
|
196
|
+
end
|
197
|
+
|
198
|
+
def r(info, size)
|
199
|
+
clean(info)[0, size].rjust(size)
|
200
|
+
end
|
201
|
+
|
202
|
+
def clean(info)
|
203
|
+
info.to_s.gsub("\n", ' ')
|
204
|
+
end
|
205
|
+
|
206
|
+
def strftime(time_string)
|
207
|
+
Time.parse(time_string).strftime('%d-%b-%y')
|
208
|
+
end
|
209
|
+
|
210
|
+
#-----------------------------------------------------------------------------
|
211
|
+
private
|
212
|
+
#-----------------------------------------------------------------------------
|
213
|
+
|
214
|
+
def help
|
215
|
+
puts "No command: #{@command}"
|
216
|
+
puts "Try: update, list, show"
|
217
|
+
puts "or call with '-h' for usage information"
|
218
|
+
end
|
219
|
+
|
220
|
+
def configure
|
221
|
+
Octokit.configure do |config|
|
222
|
+
#config.login = github_login
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
#def github_login
|
227
|
+
# git("config --get-all github.user")
|
228
|
+
#end
|
229
|
+
|
230
|
+
def branch_pattern
|
231
|
+
patterns = git("config --get-all github.forks.branchpattern")
|
232
|
+
if patterns.empty?
|
233
|
+
Regexp.new(/.+/) # match anything
|
234
|
+
else
|
235
|
+
Regexp.new(patterns.gsub("\n", "|"))
|
236
|
+
end
|
237
|
+
end
|
238
|
+
|
239
|
+
def repo_info
|
240
|
+
c = {}
|
241
|
+
config = git('config --list')
|
242
|
+
config.split("\n").each do |line|
|
243
|
+
k, v = line.split('=')
|
244
|
+
c[k] = v
|
245
|
+
end
|
246
|
+
u = c['remote.origin.url']
|
247
|
+
|
248
|
+
user, proj = github_user_and_proj(u)
|
249
|
+
if !(user and proj)
|
250
|
+
short, base = github_insteadof_matching(c, u)
|
251
|
+
if short and base
|
252
|
+
u = u.sub(short, base)
|
253
|
+
user, proj = github_user_and_proj(u)
|
254
|
+
end
|
255
|
+
end
|
256
|
+
[user, proj]
|
257
|
+
end
|
258
|
+
|
259
|
+
def github_insteadof_matching(c, u)
|
260
|
+
first = c.collect {|k,v| [v, /url\.(.*github\.com.*)\.insteadof/.match(k)]}.
|
261
|
+
find {|v,m| u.index(v) and m != nil}
|
262
|
+
if first
|
263
|
+
return first[0], first[1][1]
|
264
|
+
end
|
265
|
+
return nil, nil
|
266
|
+
end
|
267
|
+
|
268
|
+
def github_user_and_proj(u)
|
269
|
+
# Trouble getting optional ".git" at end to work, so put that logic below
|
270
|
+
m = /github\.com.(.*?)\/(.*)/.match(u)
|
271
|
+
if m
|
272
|
+
return m[1], m[2].sub(/\.git\Z/, "")
|
273
|
+
end
|
274
|
+
return nil, nil
|
275
|
+
end
|
276
|
+
|
277
|
+
def git(command)
|
278
|
+
`git #{command}`.chomp
|
279
|
+
end
|
280
|
+
|
281
|
+
end # GitForks
|
metadata
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: git-forks
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Justin Too
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-05-01 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: json
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: octokit
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - '='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: 0.6.5
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - '='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: 0.6.5
|
46
|
+
description: git-forks gets info about a GitHub project's forks.
|
47
|
+
email: doubleotoo@gmail.com
|
48
|
+
executables:
|
49
|
+
- git-forks
|
50
|
+
extensions: []
|
51
|
+
extra_rdoc_files: []
|
52
|
+
files:
|
53
|
+
- LICENSE
|
54
|
+
- lib/git-forks.rb
|
55
|
+
- bin/git-forks
|
56
|
+
homepage: http://github.com/doubleotoo/git-forks
|
57
|
+
licenses: []
|
58
|
+
post_install_message:
|
59
|
+
rdoc_options: []
|
60
|
+
require_paths:
|
61
|
+
- lib
|
62
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
63
|
+
none: false
|
64
|
+
requirements:
|
65
|
+
- - ! '>='
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: '0'
|
68
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
69
|
+
none: false
|
70
|
+
requirements:
|
71
|
+
- - ! '>='
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
version: '0'
|
74
|
+
requirements: []
|
75
|
+
rubyforge_project:
|
76
|
+
rubygems_version: 1.8.24
|
77
|
+
signing_key:
|
78
|
+
specification_version: 3
|
79
|
+
summary: gets info about a GitHub project's forks
|
80
|
+
test_files: []
|