github_metadata 0.1.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/.gitignore +6 -0
- data/.rspec +2 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +31 -0
- data/LICENSE +20 -0
- data/README.rdoc +52 -0
- data/Rakefile +2 -0
- data/github_metadata.gemspec +25 -0
- data/lib/github_metadata/version.rb +3 -0
- data/lib/github_metadata.rb +98 -0
- data/spec/github_metadata_spec.rb +169 -0
- data/spec/spec_helper.rb +9 -0
- metadata +117 -0
data/.gitignore
ADDED
data/.rspec
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
github_metadata (0.1.0)
|
5
|
+
nokogiri
|
6
|
+
|
7
|
+
GEM
|
8
|
+
remote: http://rubygems.org/
|
9
|
+
specs:
|
10
|
+
diff-lcs (1.1.2)
|
11
|
+
nokogiri (1.4.4)
|
12
|
+
rspec (2.4.0)
|
13
|
+
rspec-core (~> 2.4.0)
|
14
|
+
rspec-expectations (~> 2.4.0)
|
15
|
+
rspec-mocks (~> 2.4.0)
|
16
|
+
rspec-core (2.4.0)
|
17
|
+
rspec-expectations (2.4.0)
|
18
|
+
diff-lcs (~> 1.1.2)
|
19
|
+
rspec-mocks (2.4.0)
|
20
|
+
simplecov (0.3.7)
|
21
|
+
simplecov-html (>= 0.3.7)
|
22
|
+
simplecov-html (0.3.9)
|
23
|
+
|
24
|
+
PLATFORMS
|
25
|
+
ruby
|
26
|
+
|
27
|
+
DEPENDENCIES
|
28
|
+
github_metadata!
|
29
|
+
nokogiri
|
30
|
+
rspec (>= 2.0.0)
|
31
|
+
simplecov
|
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2011 Christoph Olszowka
|
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/README.rdoc
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
= Github Metadata
|
2
|
+
|
3
|
+
The Github repository API does not include all the information available on the
|
4
|
+
web view of a repo. It also has some trouble reporting correctly the availability of
|
5
|
+
a wiki and issues.
|
6
|
+
|
7
|
+
The github_metadata gem is here to solve this. Currently it gives you, for any github repo:
|
8
|
+
|
9
|
+
* The availability and (if present) the count of wiki pages
|
10
|
+
* The availability and (if present) the count of issues
|
11
|
+
* The count of pull requests
|
12
|
+
* The list of contributors, with username and real name if available, and thereby also
|
13
|
+
the count of contributors
|
14
|
+
|
15
|
+
By the way: It goes very easy on the github servers in doing so, currently only performing 1 request
|
16
|
+
to fetch all of the information per instance.
|
17
|
+
|
18
|
+
== Usage
|
19
|
+
|
20
|
+
$ gem install github_metadata
|
21
|
+
$ irb
|
22
|
+
> require 'github_metadata'
|
23
|
+
> m = GithubMetadata.new('aslakhellesoy', 'cucumber')
|
24
|
+
> m.has_wiki?
|
25
|
+
=> true
|
26
|
+
> m.wiki_pages
|
27
|
+
=> 71
|
28
|
+
> m.has_issues?
|
29
|
+
=> false
|
30
|
+
> m.contributor_usernames
|
31
|
+
=> ['aslakhellesoy', ...]
|
32
|
+
|
33
|
+
Check out the full documentation to see all available methods.
|
34
|
+
|
35
|
+
== TODO
|
36
|
+
|
37
|
+
* Better (any?) error handling
|
38
|
+
* Merge with my very own first_github_commit gem, which retrieves the very first commit to a repo
|
39
|
+
|
40
|
+
== Note on Patches/Pull Requests
|
41
|
+
|
42
|
+
* Fork the project.
|
43
|
+
* Make your feature addition or bug fix.
|
44
|
+
* Add tests for it. This is important so I don't break it in a
|
45
|
+
future version unintentionally.
|
46
|
+
* Commit, do not mess with rakefile, version, or history.
|
47
|
+
(if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
|
48
|
+
* Send me a pull request. Bonus points for topic branches.
|
49
|
+
|
50
|
+
== Copyright
|
51
|
+
|
52
|
+
Copyright (c) 2011 Christoph Olszowka. See LICENSE for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "github_metadata/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "github_metadata"
|
7
|
+
s.version = GithubMetadata::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Christoph Olszowka"]
|
10
|
+
s.email = ["christoph at olszowka de"]
|
11
|
+
s.homepage = ""
|
12
|
+
s.summary = %q{Extracts additional information from Github repos that isn't available via API}
|
13
|
+
s.description = %q{Extracts additional information like amount of committers, issues and wiki pages from Github repos}
|
14
|
+
|
15
|
+
s.rubyforge_project = "github_metadata"
|
16
|
+
|
17
|
+
s.add_dependency 'nokogiri'
|
18
|
+
s.add_development_dependency 'rspec', '>= 2.0.0'
|
19
|
+
s.add_development_dependency 'simplecov'
|
20
|
+
|
21
|
+
s.files = `git ls-files`.split("\n")
|
22
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
23
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
24
|
+
s.require_paths = ["lib"]
|
25
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'open-uri'
|
3
|
+
require 'nokogiri'
|
4
|
+
|
5
|
+
# A simple scraper that fetches data from github repos that is not
|
6
|
+
# available via the API. See README for an introduction and overview.
|
7
|
+
class GithubMetadata
|
8
|
+
attr_reader :user, :repo
|
9
|
+
|
10
|
+
# Object representation of a github contributor
|
11
|
+
class Contributor
|
12
|
+
attr_reader :username, :realname
|
13
|
+
def initialize(username, realname=nil)
|
14
|
+
@username, @realname = username, realname
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def initialize(user, repo)
|
19
|
+
@user, @repo = user, repo
|
20
|
+
end
|
21
|
+
|
22
|
+
# Returns an array of GithubMetadata::Contributor instances, one for each
|
23
|
+
# contributor listed on the contributors page of github
|
24
|
+
def contributors
|
25
|
+
load_contributors unless @contributors
|
26
|
+
@contributors
|
27
|
+
end
|
28
|
+
|
29
|
+
# Shorthand form for getting an array of all contributor github usernames
|
30
|
+
def contributor_usernames
|
31
|
+
@contributor_usernames ||= contributors.map(&:username)
|
32
|
+
end
|
33
|
+
|
34
|
+
# Shorthand form for getting an array of all contributor github realnames,
|
35
|
+
# with users that don't have a realname specified filtered out
|
36
|
+
def contributor_realnames
|
37
|
+
@contributor_realnames ||= contributors.map(&:realname).compact
|
38
|
+
end
|
39
|
+
|
40
|
+
# Will return all contributor real names, falling back to the username when
|
41
|
+
# real name is not specified
|
42
|
+
def contributor_names
|
43
|
+
@contributor_names ||= contributors.map {|c| c.realname || c.username }
|
44
|
+
end
|
45
|
+
|
46
|
+
# Returns true when the repo has a wiki
|
47
|
+
def has_wiki?
|
48
|
+
!!wiki_pages
|
49
|
+
end
|
50
|
+
|
51
|
+
# Returns the amount of wiki pages or nil when no wiki is present
|
52
|
+
def wiki_pages
|
53
|
+
wiki_link = document.at_css('a[highlight="repo_wiki"]')
|
54
|
+
return nil unless wiki_link
|
55
|
+
wiki_link.text[/\d+/].to_i
|
56
|
+
end
|
57
|
+
|
58
|
+
# Returns true if the repo has issues enabled
|
59
|
+
def has_issues?
|
60
|
+
!!issues
|
61
|
+
end
|
62
|
+
|
63
|
+
# Returns issue count or nil if issues are disabled
|
64
|
+
def issues
|
65
|
+
issue_link = document.at_css('a[highlight="issues"]')
|
66
|
+
return nil unless issue_link
|
67
|
+
issue_link.text[/\d+/].to_i
|
68
|
+
end
|
69
|
+
|
70
|
+
# Returns amount of pull requests
|
71
|
+
def pull_requests
|
72
|
+
pull_request_link = document.at_css('a[highlight="repo_pulls"]')
|
73
|
+
return nil unless pull_request_link
|
74
|
+
pull_request_link.text[/\d+/].to_i
|
75
|
+
end
|
76
|
+
|
77
|
+
private
|
78
|
+
|
79
|
+
def document
|
80
|
+
@document ||= Nokogiri::HTML(open(contributors_url))
|
81
|
+
end
|
82
|
+
|
83
|
+
def contributors_url
|
84
|
+
"https://github.com/#{user}/#{repo}/contributors"
|
85
|
+
end
|
86
|
+
|
87
|
+
def load_contributors
|
88
|
+
@contributors = document.css('#repos #watchers.members li').map do |contributor|
|
89
|
+
line = contributor.text.gsub("\n", '').squeeze(' ').strip.chomp
|
90
|
+
username = line.match(/^([^\ ]+)/)[1]
|
91
|
+
|
92
|
+
name_match = line.match(/\(([^\)]+)\)/)
|
93
|
+
real_name = name_match ? name_match[1] : nil
|
94
|
+
|
95
|
+
GithubMetadata::Contributor.new(username, real_name)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
@@ -0,0 +1,169 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'spec_helper'
|
3
|
+
describe GithubMetadata do
|
4
|
+
context "initialized with aslakhellesoy/cucumber" do
|
5
|
+
before(:all) do
|
6
|
+
@metadata = GithubMetadata.new('aslakhellesoy', 'cucumber')
|
7
|
+
@raw = open("https://github.com/#{@metadata.user}/#{@metadata.repo}/contributors").read
|
8
|
+
end
|
9
|
+
subject { @metadata }
|
10
|
+
|
11
|
+
describe '#user' do
|
12
|
+
specify do
|
13
|
+
subject.user.should == 'aslakhellesoy'
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe '#repo' do
|
18
|
+
specify do
|
19
|
+
subject.repo.should == 'cucumber'
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
specify do
|
24
|
+
subject.should have_wiki
|
25
|
+
end
|
26
|
+
|
27
|
+
describe '#wiki_pages' do
|
28
|
+
specify do
|
29
|
+
expected = @raw.match(/Wiki \((\d+)\)/)[1].to_i
|
30
|
+
expected.should be > 50
|
31
|
+
subject.wiki_pages.should == expected
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
specify do
|
36
|
+
subject.should_not have_issues
|
37
|
+
end
|
38
|
+
|
39
|
+
describe '#issues' do
|
40
|
+
specify do
|
41
|
+
subject.issues.should == nil
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
describe '#pull_requests' do
|
46
|
+
specify do
|
47
|
+
expected = @raw.match(/Pull Requests \((\d+)\)/)[1].to_i
|
48
|
+
subject.pull_requests.should == expected
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe '#contributors' do
|
53
|
+
specify do
|
54
|
+
expected = @raw.match(/(\d+) contributors/)[1].to_i
|
55
|
+
subject.contributors.length.should == expected
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
describe '#contributor_usernames' do
|
60
|
+
specify do
|
61
|
+
subject.contributor_usernames.should include('aslakhellesoy')
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
describe '#contributor_realnames' do
|
66
|
+
specify do
|
67
|
+
subject.contributor_realnames.should include('Iain Hecker', 'Elliot Crosby-McCullough', 'Aslak Hellesøy')
|
68
|
+
end
|
69
|
+
|
70
|
+
specify do
|
71
|
+
subject.contributor_realnames.length.should < subject.contributor_usernames.length
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
describe '#contributor_names' do
|
76
|
+
specify do
|
77
|
+
subject.contributor_names.count.should == subject.contributors.count
|
78
|
+
end
|
79
|
+
|
80
|
+
specify do
|
81
|
+
subject.contributor_names.should include('Iain Hecker', 'Elliot Crosby-McCullough', 'Aslak Hellesøy')
|
82
|
+
end
|
83
|
+
|
84
|
+
specify do
|
85
|
+
subject.contributor_names.should include('marocchino')
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
context "initialized with colszowka/simplecov" do
|
91
|
+
before(:all) do
|
92
|
+
@metadata = GithubMetadata.new('colszowka', 'simplecov')
|
93
|
+
@raw = open("https://github.com/#{@metadata.user}/#{@metadata.repo}/contributors").read
|
94
|
+
end
|
95
|
+
subject { @metadata }
|
96
|
+
|
97
|
+
describe '#user' do
|
98
|
+
specify do
|
99
|
+
subject.user.should == 'colszowka'
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
describe '#repo' do
|
104
|
+
specify do
|
105
|
+
subject.repo.should == 'simplecov'
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
specify do
|
110
|
+
subject.should_not have_wiki
|
111
|
+
end
|
112
|
+
|
113
|
+
describe '#wiki_pages' do
|
114
|
+
specify do
|
115
|
+
subject.wiki_pages.should be nil
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
specify do
|
120
|
+
subject.should have_issues
|
121
|
+
end
|
122
|
+
|
123
|
+
describe '#issues' do
|
124
|
+
specify do
|
125
|
+
expected = @raw.match(/Issues \((\d+)\)/)[1].to_i
|
126
|
+
subject.issues.should == expected
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
describe '#pull_requests' do
|
131
|
+
specify do
|
132
|
+
subject.pull_requests.should be 0
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
describe '#contributors' do
|
137
|
+
specify do
|
138
|
+
expected = @raw.match(/(\d+) contributors/)[1].to_i
|
139
|
+
subject.contributors.length.should be expected
|
140
|
+
end
|
141
|
+
|
142
|
+
it 'should be all instance of Contributor' do
|
143
|
+
subject.contributors.should be_all {|c| c.instance_of?(GithubMetadata::Contributor)}
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
describe '#contributor_usernames' do
|
148
|
+
specify do
|
149
|
+
subject.contributor_usernames.should include('colszowka')
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
describe '#contributor_realnames' do
|
154
|
+
specify do
|
155
|
+
subject.contributor_realnames.should include('Christoph Olszowka')
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
describe '#contributor_names' do
|
160
|
+
specify do
|
161
|
+
subject.contributor_names.count.should be subject.contributors.count
|
162
|
+
end
|
163
|
+
specify do
|
164
|
+
subject.contributor_names.should include('Christoph Olszowka')
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,117 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: github_metadata
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 1
|
8
|
+
- 0
|
9
|
+
version: 0.1.0
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Christoph Olszowka
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2011-01-04 00:00:00 +01:00
|
18
|
+
default_executable:
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: nokogiri
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
none: false
|
25
|
+
requirements:
|
26
|
+
- - ">="
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
segments:
|
29
|
+
- 0
|
30
|
+
version: "0"
|
31
|
+
type: :runtime
|
32
|
+
version_requirements: *id001
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: rspec
|
35
|
+
prerelease: false
|
36
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
37
|
+
none: false
|
38
|
+
requirements:
|
39
|
+
- - ">="
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
segments:
|
42
|
+
- 2
|
43
|
+
- 0
|
44
|
+
- 0
|
45
|
+
version: 2.0.0
|
46
|
+
type: :development
|
47
|
+
version_requirements: *id002
|
48
|
+
- !ruby/object:Gem::Dependency
|
49
|
+
name: simplecov
|
50
|
+
prerelease: false
|
51
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
52
|
+
none: false
|
53
|
+
requirements:
|
54
|
+
- - ">="
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
segments:
|
57
|
+
- 0
|
58
|
+
version: "0"
|
59
|
+
type: :development
|
60
|
+
version_requirements: *id003
|
61
|
+
description: Extracts additional information like amount of committers, issues and wiki pages from Github repos
|
62
|
+
email:
|
63
|
+
- christoph at olszowka de
|
64
|
+
executables: []
|
65
|
+
|
66
|
+
extensions: []
|
67
|
+
|
68
|
+
extra_rdoc_files: []
|
69
|
+
|
70
|
+
files:
|
71
|
+
- .gitignore
|
72
|
+
- .rspec
|
73
|
+
- Gemfile
|
74
|
+
- Gemfile.lock
|
75
|
+
- LICENSE
|
76
|
+
- README.rdoc
|
77
|
+
- Rakefile
|
78
|
+
- github_metadata.gemspec
|
79
|
+
- lib/github_metadata.rb
|
80
|
+
- lib/github_metadata/version.rb
|
81
|
+
- spec/github_metadata_spec.rb
|
82
|
+
- spec/spec_helper.rb
|
83
|
+
has_rdoc: true
|
84
|
+
homepage: ""
|
85
|
+
licenses: []
|
86
|
+
|
87
|
+
post_install_message:
|
88
|
+
rdoc_options: []
|
89
|
+
|
90
|
+
require_paths:
|
91
|
+
- lib
|
92
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
93
|
+
none: false
|
94
|
+
requirements:
|
95
|
+
- - ">="
|
96
|
+
- !ruby/object:Gem::Version
|
97
|
+
segments:
|
98
|
+
- 0
|
99
|
+
version: "0"
|
100
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
101
|
+
none: false
|
102
|
+
requirements:
|
103
|
+
- - ">="
|
104
|
+
- !ruby/object:Gem::Version
|
105
|
+
segments:
|
106
|
+
- 0
|
107
|
+
version: "0"
|
108
|
+
requirements: []
|
109
|
+
|
110
|
+
rubyforge_project: github_metadata
|
111
|
+
rubygems_version: 1.3.7
|
112
|
+
signing_key:
|
113
|
+
specification_version: 3
|
114
|
+
summary: Extracts additional information from Github repos that isn't available via API
|
115
|
+
test_files:
|
116
|
+
- spec/github_metadata_spec.rb
|
117
|
+
- spec/spec_helper.rb
|