git_statistics 0.1.2
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 +18 -0
- data/.travis.yml +7 -0
- data/Gemfile +10 -0
- data/Gemfile.lock +30 -0
- data/LICENSE +19 -0
- data/README.md +34 -0
- data/Rakefile +14 -0
- data/bin/git_statistics +5 -0
- data/git_statistics.gemspec +20 -0
- data/lib/git_statistics/collector.rb +155 -0
- data/lib/git_statistics/commits.rb +129 -0
- data/lib/git_statistics/initialize.rb +3 -0
- data/lib/git_statistics/version.rb +3 -0
- data/lib/git_statistics.rb +44 -0
- data/spec/collector_spec.rb +6 -0
- data/spec/commits_spec.rb +381 -0
- data/spec/fixtures/many_authors.json +62 -0
- data/spec/fixtures/single_author.json +26 -0
- data/spec/fixtures/single_author_unpretty.json +1 -0
- data/spec/spec_helper.rb +11 -0
- metadata +97 -0
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
GEM
|
2
|
+
remote: https://rubygems.org/
|
3
|
+
specs:
|
4
|
+
diff-lcs (1.1.3)
|
5
|
+
json (1.6.6)
|
6
|
+
multi_json (1.2.0)
|
7
|
+
rake (0.9.2.2)
|
8
|
+
rspec (2.9.0)
|
9
|
+
rspec-core (~> 2.9.0)
|
10
|
+
rspec-expectations (~> 2.9.0)
|
11
|
+
rspec-mocks (~> 2.9.0)
|
12
|
+
rspec-core (2.9.0)
|
13
|
+
rspec-expectations (2.9.1)
|
14
|
+
diff-lcs (~> 1.1.3)
|
15
|
+
rspec-mocks (2.9.0)
|
16
|
+
simplecov (0.6.1)
|
17
|
+
multi_json (~> 1.0)
|
18
|
+
simplecov-html (~> 0.5.3)
|
19
|
+
simplecov-html (0.5.3)
|
20
|
+
trollop (1.16.2)
|
21
|
+
|
22
|
+
PLATFORMS
|
23
|
+
ruby
|
24
|
+
|
25
|
+
DEPENDENCIES
|
26
|
+
json
|
27
|
+
rake
|
28
|
+
rspec
|
29
|
+
simplecov
|
30
|
+
trollop
|
data/LICENSE
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
Copyright (c) 2012 Kevin Jalbert
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
of this software and associated documentation files (the "Software"), to deal
|
5
|
+
in the Software without restriction, including without limitation the rights
|
6
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
+
copies of the Software, and to permit persons to whom the Software is
|
8
|
+
furnished to do so, subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in
|
11
|
+
all copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
[](http://travis-ci.org/kevinjalbert/git_statistics)
|
2
|
+
|
3
|
+
# Instructions
|
4
|
+
|
5
|
+
### Using the gem
|
6
|
+
1. Acquire gem (`gem install git_statistics`)
|
7
|
+
2. Run `git_statistics` in any directory that is a git repository (use -h for options)
|
8
|
+
|
9
|
+
### Working with source
|
10
|
+
1. Clone the repository
|
11
|
+
2. Install dependencies (`bundle install`)
|
12
|
+
3. Run tests `bundle exec rake`
|
13
|
+
4. Build and install local gem `bundle exec rake install`
|
14
|
+
|
15
|
+
# Statistics
|
16
|
+
|
17
|
+
The following statistics are collected (organized by author name or author email):
|
18
|
+
|
19
|
+
* Total number of commits
|
20
|
+
* Total number of merge commits
|
21
|
+
* Total source line insertions
|
22
|
+
* Total source line deletions
|
23
|
+
* Total file creates
|
24
|
+
* Total file deletes
|
25
|
+
* Total file renames
|
26
|
+
* Total file copies
|
27
|
+
|
28
|
+
## Contributing
|
29
|
+
|
30
|
+
1. Fork it
|
31
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
32
|
+
3. Commit your changes (`git commit -am 'Added some feature'`)
|
33
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
34
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
|
3
|
+
require 'rake/clean'
|
4
|
+
require 'rspec/core/rake_task'
|
5
|
+
require "bundler/gem_tasks"
|
6
|
+
|
7
|
+
CLOBBER.include('coverage')
|
8
|
+
|
9
|
+
desc "Run all specs"
|
10
|
+
RSpec::Core::RakeTask.new do |t|
|
11
|
+
t.pattern = "./spec/**/*spec.rb"
|
12
|
+
end
|
13
|
+
|
14
|
+
task :default => :spec
|
data/bin/git_statistics
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/git_statistics/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.homepage = 'https://github.com/kevinjalbert/git_statistics'
|
6
|
+
gem.authors = ["Kevin Jalbert"]
|
7
|
+
gem.email = ["kevin.j.jalbert@gmail.com"]
|
8
|
+
gem.name = 'git_statistics'
|
9
|
+
gem.version = GitStatistics::VERSION
|
10
|
+
gem.summary = "Gem that provides the ability to gather detailed git statistics"
|
11
|
+
gem.description = "git_statistics is a gem that provides detailed git statistics"
|
12
|
+
gem.require_paths = ["lib"]
|
13
|
+
gem.files = `git ls-files`.split($\)
|
14
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
15
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
16
|
+
gem.executables << 'git_statistics'
|
17
|
+
gem.required_ruby_version = '>= 1.9.1'
|
18
|
+
gem.add_dependency('json')
|
19
|
+
gem.add_dependency('trollop')
|
20
|
+
end
|
@@ -0,0 +1,155 @@
|
|
1
|
+
module GitStatistics
|
2
|
+
class Collector
|
3
|
+
|
4
|
+
attr_accessor :commits
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
@commits = Commits.new
|
8
|
+
end
|
9
|
+
|
10
|
+
def collect(branch, since="")
|
11
|
+
|
12
|
+
# Collect branches to use for git log
|
13
|
+
branches = collect_branches
|
14
|
+
branches = ["", ""] if branch
|
15
|
+
|
16
|
+
pipe = open("|git --no-pager log #{branches.join(' ')} --date=iso --reverse"\
|
17
|
+
" --no-color --numstat --summary #{since}"\
|
18
|
+
" --format=\"%H,%an,%ae,%ad,%p\"")
|
19
|
+
|
20
|
+
buffer = []
|
21
|
+
pipe.each do |line|
|
22
|
+
|
23
|
+
line = line.force_encoding("ISO-8859-1").encode("UTF-8")
|
24
|
+
|
25
|
+
if line.split(',').size == 5 # Matches the number of ',' in the format
|
26
|
+
extract_buffer(buffer) if not buffer.empty?
|
27
|
+
buffer = []
|
28
|
+
end
|
29
|
+
|
30
|
+
buffer << line.strip
|
31
|
+
end
|
32
|
+
|
33
|
+
# Extract the last commit
|
34
|
+
extract_buffer(buffer) if not buffer.empty?
|
35
|
+
end
|
36
|
+
|
37
|
+
def collect_branches
|
38
|
+
|
39
|
+
pipe = open("|git --no-pager branch --no-color")
|
40
|
+
|
41
|
+
branches = []
|
42
|
+
pipe.each do |line|
|
43
|
+
|
44
|
+
# Remove the '* ' leading the current branch
|
45
|
+
line = line[1..-1] if line[0] == '*'
|
46
|
+
branches << line.strip
|
47
|
+
end
|
48
|
+
|
49
|
+
return branches
|
50
|
+
end
|
51
|
+
|
52
|
+
def extract_buffer(buffer)
|
53
|
+
|
54
|
+
commit_info = buffer[0].split(',')
|
55
|
+
|
56
|
+
commit = (@commits[ commit_info[0] ] ||= Hash.new)
|
57
|
+
commit[:author] = commit_info[1]
|
58
|
+
commit[:author_email] = commit_info[2]
|
59
|
+
commit[:time] = commit_info[3]
|
60
|
+
commit[:insertions] = 0
|
61
|
+
commit[:deletions] = 0
|
62
|
+
commit[:creates] = 0
|
63
|
+
commit[:deletes] = 0
|
64
|
+
commit[:renames] = 0
|
65
|
+
commit[:copies] = 0
|
66
|
+
|
67
|
+
if commit_info[4] == nil or commit_info[4].split(' ').size == 1
|
68
|
+
commit[:merge] = false
|
69
|
+
else
|
70
|
+
commit[:merge] = true
|
71
|
+
end
|
72
|
+
|
73
|
+
# Only extract diff details if they exist
|
74
|
+
if buffer.size > 1
|
75
|
+
|
76
|
+
buffer[2..-1].each do |line|
|
77
|
+
|
78
|
+
next if extract_changes(commit, line)
|
79
|
+
next if extract_create_delete_file(commit, line)
|
80
|
+
next if extract_rename_copy_file(commit, line)
|
81
|
+
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def extract_changes(commit, line)
|
87
|
+
changes = line.scan( /(\d+)\s(\d+)\s(.*)/ )[0]
|
88
|
+
|
89
|
+
if changes != nil and changes.size == 3
|
90
|
+
commit[:insertions] += changes[0].to_i
|
91
|
+
commit[:deletions] += changes[1].to_i
|
92
|
+
return true
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def extract_create_delete_file(commit, line)
|
97
|
+
changes = line.scan(/(create|delete) mode \d+ ([^\\\n]*)/)[0]
|
98
|
+
|
99
|
+
if changes != nil and changes.size == 2
|
100
|
+
commit[:creates] += 1 if changes[0] == "create"
|
101
|
+
commit[:deletes] += 1 if changes[0] == "delete"
|
102
|
+
return true
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def extract_rename_copy_file(commit, line)
|
107
|
+
changes = line.scan(/(rename|copy)([^(]*)/)[0]
|
108
|
+
|
109
|
+
if changes != nil and changes.size == 2
|
110
|
+
commit[:renames] += 1 if changes[0] == "rename"
|
111
|
+
commit[:copies] += 1 if changes[0] == "copy"
|
112
|
+
end
|
113
|
+
return true
|
114
|
+
end
|
115
|
+
|
116
|
+
def print_summary(sort_type, email, n=0)
|
117
|
+
n = 0 if n < 0
|
118
|
+
|
119
|
+
data = @commits.author_top_n_type(email, sort_type, n)
|
120
|
+
|
121
|
+
if data == nil
|
122
|
+
puts "ERROR: Parameter for --sort is not valid"
|
123
|
+
return
|
124
|
+
end
|
125
|
+
|
126
|
+
# Find the longest name/email (used for string formatting)
|
127
|
+
total_authors = @commits.author_list.length
|
128
|
+
author_length = 17
|
129
|
+
data.each do |key,value|
|
130
|
+
author_length = key.length if key.length > author_length
|
131
|
+
end
|
132
|
+
|
133
|
+
# Print header information
|
134
|
+
if n > 0 and n < total_authors
|
135
|
+
puts "Top #{n} authors(#{total_authors}) sorted by #{sort_type.to_s}\n\n"
|
136
|
+
else
|
137
|
+
puts "All authors(#{total_authors}) sorted by #{sort_type.to_s}\n\n"
|
138
|
+
end
|
139
|
+
|
140
|
+
pattern = "%-#{author_length}s|%7s|%10s|%9s|%7s|%7s|%7s|%6s|%6s|"
|
141
|
+
puts pattern % ['Name/email', 'commits', 'insertions', 'deletions', 'creates', 'deletes', 'renames', 'copies', 'merges']
|
142
|
+
puts "-"*68 + "-"*author_length
|
143
|
+
|
144
|
+
data.each do |key,value|
|
145
|
+
puts pattern % [key, value[:commits], value[:insertions], value[:deletions],
|
146
|
+
value[:creates], value[:deletes], value[:renames], value[:copies], value[:merges]]
|
147
|
+
end
|
148
|
+
|
149
|
+
puts "-"*68 + "-"*author_length
|
150
|
+
puts pattern % ["Repository Totals", @commits.totals[:commits],
|
151
|
+
@commits.totals[:insertions], @commits.totals[:deletions], @commits.totals[:creates],
|
152
|
+
@commits.totals[:deletes], @commits.totals[:renames], @commits.totals[:copies], @commits.totals[:merges]]
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
@@ -0,0 +1,129 @@
|
|
1
|
+
module GitStatistics
|
2
|
+
class Commits < Hash
|
3
|
+
|
4
|
+
attr_accessor :author_list, :data_authors, :data_authors_email, :totals
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
super
|
8
|
+
end
|
9
|
+
|
10
|
+
def authors
|
11
|
+
author_list = []
|
12
|
+
self.each do |key,value|
|
13
|
+
if not author_list.include?(value[:author])
|
14
|
+
author_list << value[:author]
|
15
|
+
end
|
16
|
+
end
|
17
|
+
return author_list
|
18
|
+
end
|
19
|
+
|
20
|
+
def authors_email
|
21
|
+
author_list = []
|
22
|
+
self.each do |key,value|
|
23
|
+
if not author_list.include?(value[:author_email])
|
24
|
+
author_list << value[:author_email]
|
25
|
+
end
|
26
|
+
end
|
27
|
+
return author_list
|
28
|
+
end
|
29
|
+
|
30
|
+
def authors_statistics(email, merge)
|
31
|
+
|
32
|
+
# Identify authors and author type
|
33
|
+
if email
|
34
|
+
@author_list = authors_email
|
35
|
+
type = :author_email
|
36
|
+
else
|
37
|
+
@author_list = authors
|
38
|
+
type = :author
|
39
|
+
end
|
40
|
+
|
41
|
+
# Initialize the stats hash
|
42
|
+
stats = Hash.new
|
43
|
+
@author_list.each do |author|
|
44
|
+
stats[author] = Hash.new
|
45
|
+
stats[author][:commits] = 0
|
46
|
+
stats[author][:insertions] = 0
|
47
|
+
stats[author][:deletions] = 0
|
48
|
+
stats[author][:creates] = 0
|
49
|
+
stats[author][:deletes] = 0
|
50
|
+
stats[author][:renames] = 0
|
51
|
+
stats[author][:copies] = 0
|
52
|
+
stats[author][:merges] = 0
|
53
|
+
end
|
54
|
+
|
55
|
+
# Collect the stats for each author
|
56
|
+
self.each do |key,value|
|
57
|
+
if not merge and value[:merge]
|
58
|
+
next
|
59
|
+
else
|
60
|
+
stats[value[type]][:merges] += 1 if value[:merge]
|
61
|
+
stats[value[type]][:commits] += 1
|
62
|
+
stats[value[type]][:insertions] += value[:insertions]
|
63
|
+
stats[value[type]][:deletions] += value[:deletions]
|
64
|
+
stats[value[type]][:creates] += value[:creates]
|
65
|
+
stats[value[type]][:deletes] += value[:deletes]
|
66
|
+
stats[value[type]][:renames] += value[:renames]
|
67
|
+
stats[value[type]][:copies] += value[:copies]
|
68
|
+
end
|
69
|
+
end
|
70
|
+
return stats
|
71
|
+
end
|
72
|
+
|
73
|
+
def author_top_n_type(email, type, n=0)
|
74
|
+
n = 0 if n < 0
|
75
|
+
|
76
|
+
if email
|
77
|
+
data = @data_authors_email
|
78
|
+
else
|
79
|
+
data = @data_authors
|
80
|
+
end
|
81
|
+
|
82
|
+
return nil if data == nil || !data.first[1].has_key?(type)
|
83
|
+
return data.sorted_hash {|a,b| b[1][type.to_sym] <=> a[1][type]}.to_a[0..n-1]
|
84
|
+
end
|
85
|
+
|
86
|
+
def calculate_statistics(email, merge)
|
87
|
+
|
88
|
+
# Calculate author statistics
|
89
|
+
@data_authors_email = authors_statistics(true, merge) if email
|
90
|
+
@data_authors = authors_statistics(false, merge) if not email
|
91
|
+
|
92
|
+
# Calculate totals
|
93
|
+
@totals = Hash.new(0)
|
94
|
+
self.each do |key,value|
|
95
|
+
if not merge and value[:merge]
|
96
|
+
next
|
97
|
+
else
|
98
|
+
@totals[:merges] += 1 if value[:merge]
|
99
|
+
@totals[:commits] += 1
|
100
|
+
@totals[:insertions] += value[:insertions]
|
101
|
+
@totals[:deletions] += value[:deletions]
|
102
|
+
@totals[:creates] += value[:creates]
|
103
|
+
@totals[:deletes] += value[:deletes]
|
104
|
+
@totals[:renames] += value[:renames]
|
105
|
+
@totals[:copies] += value[:copies]
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def load(file)
|
111
|
+
self.merge!(JSON.parse(File.read(file), :symbolize_names => true))
|
112
|
+
end
|
113
|
+
|
114
|
+
def save(file, pretty)
|
115
|
+
if pretty
|
116
|
+
File.open(file, 'w') {|file| file.write(JSON.pretty_generate(self))}
|
117
|
+
else
|
118
|
+
File.open(file, 'w') {|file| file.write(self.to_json)}
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
class Hash < Hash
|
124
|
+
|
125
|
+
def sorted_hash(&block)
|
126
|
+
self.class[sort(&block)]
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'git_statistics/initialize'
|
2
|
+
|
3
|
+
module GitStatistics
|
4
|
+
class GitStatistics
|
5
|
+
def initialize(args=nil)
|
6
|
+
@opts = Trollop::options do
|
7
|
+
opt :email, "Use author's email instead of name", :default => false
|
8
|
+
opt :merges, "Factor in merges when calculating statistics", :default => false
|
9
|
+
opt :save, "Save the commits as commits.json", :default => false
|
10
|
+
opt :pretty, "Pretty print saved commits (larger file size)", :default => false
|
11
|
+
opt :load, "Load commits.json instead of re-collecting data", :default => false
|
12
|
+
opt :update, "Update commits.json with new data (same as save and load together)", :default => false
|
13
|
+
opt :sort, "Sort authors by {commits, insertions, deletions, creates, deletes, renames, copies, merges}", :default => "commits"
|
14
|
+
opt :top, "Show the top N authors in results", :default => 0
|
15
|
+
opt :branch, "Use current branch for statistics (otherwise all branches)", :default => false
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def execute
|
20
|
+
collector = Collector.new
|
21
|
+
|
22
|
+
# Collect commit data
|
23
|
+
if @opts[:load] || @opts[:update]
|
24
|
+
collector.commits.load("commits.json")
|
25
|
+
else
|
26
|
+
collector.collect(@opts[:branch])
|
27
|
+
end
|
28
|
+
|
29
|
+
# Collect incremental recent data
|
30
|
+
if @opts[:update]
|
31
|
+
collector.collect(@opts[:branch], "--since=\"`date -r commits.json \"+%F %T\"`\"")
|
32
|
+
end
|
33
|
+
|
34
|
+
# Save data
|
35
|
+
if @opts[:save] || @opts[:update]
|
36
|
+
collector.commits.save("commits.json", @opts[:pretty])
|
37
|
+
end
|
38
|
+
|
39
|
+
collector.commits.calculate_statistics(@opts[:email], @opts[:merges])
|
40
|
+
|
41
|
+
collector.print_summary(@opts[:sort].to_sym, @opts[:email], @opts[:top])
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,381 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
include GitStatistics
|
3
|
+
|
4
|
+
describe Commits do
|
5
|
+
describe "#authors" do
|
6
|
+
context "with one author" do
|
7
|
+
commits = Commits.new
|
8
|
+
commits.load(fixture("single_author.json"))
|
9
|
+
author_list = commits.authors
|
10
|
+
|
11
|
+
|
12
|
+
it { author_list.size.should be(1) }
|
13
|
+
it { author_list[0].should == "Kevin Jalbert" }
|
14
|
+
end
|
15
|
+
|
16
|
+
context "with many authors" do
|
17
|
+
commits = Commits.new
|
18
|
+
commits.load(fixture("many_authors.json"))
|
19
|
+
author_list = commits.authors
|
20
|
+
|
21
|
+
it { author_list.size.should be(3) }
|
22
|
+
it { author_list[0].should == "Bart Simpson" }
|
23
|
+
it { author_list[1].should == "Kevin Jalbert" }
|
24
|
+
it { author_list[2].should == "Maggie Simpson" }
|
25
|
+
end
|
26
|
+
|
27
|
+
context "with no authors" do
|
28
|
+
commits = Commits.new
|
29
|
+
author_list = commits.authors
|
30
|
+
|
31
|
+
it { author_list.size.should be(0) }
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
describe "#authors_email" do
|
36
|
+
context "with one author" do
|
37
|
+
commits = Commits.new
|
38
|
+
commits.load(fixture("single_author.json"))
|
39
|
+
author_list = commits.authors_email
|
40
|
+
|
41
|
+
it { author_list.size.should be(1) }
|
42
|
+
it { author_list[0].should == "kevin.j.jalbert@gmail.com" }
|
43
|
+
end
|
44
|
+
|
45
|
+
context "with many authors" do
|
46
|
+
commits = Commits.new
|
47
|
+
commits.load(fixture("many_authors.json"))
|
48
|
+
author_list = commits.authors_email
|
49
|
+
|
50
|
+
it { author_list.size.should be(3) }
|
51
|
+
it { author_list[0].should == "bart.simpson@gmail.com" }
|
52
|
+
it { author_list[1].should == "kevin.j.jalbert@gmail.com" }
|
53
|
+
it { author_list[2].should == "maggie.simpson@gmail.com" }
|
54
|
+
end
|
55
|
+
|
56
|
+
context "with no authors" do
|
57
|
+
commits = Commits.new
|
58
|
+
author_list = commits.authors_email
|
59
|
+
|
60
|
+
it { author_list.size.should be(0) }
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
describe "#authors_statistics" do
|
65
|
+
context "with email" do
|
66
|
+
context "with merge" do
|
67
|
+
commits = Commits.new
|
68
|
+
commits.load(fixture("many_authors.json"))
|
69
|
+
results = commits.authors_statistics(true, true)
|
70
|
+
|
71
|
+
it {results.size.should be(3)}
|
72
|
+
it {results["bart.simpson@gmail.com"][:commits].should be(2)}
|
73
|
+
it {results["bart.simpson@gmail.com"][:insertions].should be(13)}
|
74
|
+
it {results["bart.simpson@gmail.com"][:deletions].should be(3)}
|
75
|
+
it {results["bart.simpson@gmail.com"][:creates].should be(2)}
|
76
|
+
it {results["bart.simpson@gmail.com"][:deletes].should be(0)}
|
77
|
+
it {results["bart.simpson@gmail.com"][:renames].should be(2)}
|
78
|
+
it {results["bart.simpson@gmail.com"][:copies].should be(0)}
|
79
|
+
it {results["bart.simpson@gmail.com"][:merges].should be(1)}
|
80
|
+
|
81
|
+
it {results["kevin.j.jalbert@gmail.com"][:commits].should be(1)}
|
82
|
+
it {results["kevin.j.jalbert@gmail.com"][:insertions].should be(62)}
|
83
|
+
it {results["kevin.j.jalbert@gmail.com"][:deletions].should be(6)}
|
84
|
+
it {results["kevin.j.jalbert@gmail.com"][:creates].should be(0)}
|
85
|
+
it {results["kevin.j.jalbert@gmail.com"][:deletes].should be(1)}
|
86
|
+
it {results["kevin.j.jalbert@gmail.com"][:renames].should be(0)}
|
87
|
+
it {results["kevin.j.jalbert@gmail.com"][:copies].should be(0)}
|
88
|
+
it {results["kevin.j.jalbert@gmail.com"][:merges].should be(1)}
|
89
|
+
|
90
|
+
it {results["maggie.simpson@gmail.com"][:commits].should be(2)}
|
91
|
+
it {results["maggie.simpson@gmail.com"][:insertions].should be(211)}
|
92
|
+
it {results["maggie.simpson@gmail.com"][:deletions].should be(192)}
|
93
|
+
it {results["maggie.simpson@gmail.com"][:creates].should be(7)}
|
94
|
+
it {results["maggie.simpson@gmail.com"][:deletes].should be(2)}
|
95
|
+
it {results["maggie.simpson@gmail.com"][:renames].should be(3)}
|
96
|
+
it {results["maggie.simpson@gmail.com"][:copies].should be(1)}
|
97
|
+
it {results["maggie.simpson@gmail.com"][:merges].should be(0)}
|
98
|
+
|
99
|
+
end
|
100
|
+
|
101
|
+
context "no merge" do
|
102
|
+
commits = Commits.new
|
103
|
+
commits.load(fixture("many_authors.json"))
|
104
|
+
results = commits.authors_statistics(true, false)
|
105
|
+
|
106
|
+
it {results.size.should be(3)}
|
107
|
+
it {results["bart.simpson@gmail.com"][:commits].should be(1)}
|
108
|
+
it {results["bart.simpson@gmail.com"][:insertions].should be(3)}
|
109
|
+
it {results["bart.simpson@gmail.com"][:deletions].should be(2)}
|
110
|
+
it {results["bart.simpson@gmail.com"][:creates].should be(2)}
|
111
|
+
it {results["bart.simpson@gmail.com"][:deletes].should be(0)}
|
112
|
+
it {results["bart.simpson@gmail.com"][:renames].should be(0)}
|
113
|
+
it {results["bart.simpson@gmail.com"][:copies].should be(0)}
|
114
|
+
it {results["bart.simpson@gmail.com"][:merges].should be(0)}
|
115
|
+
|
116
|
+
it {results["kevin.j.jalbert@gmail.com"][:commits].should be(0)}
|
117
|
+
it {results["kevin.j.jalbert@gmail.com"][:insertions].should be(0)}
|
118
|
+
it {results["kevin.j.jalbert@gmail.com"][:deletions].should be(0)}
|
119
|
+
it {results["kevin.j.jalbert@gmail.com"][:creates].should be(0)}
|
120
|
+
it {results["kevin.j.jalbert@gmail.com"][:deletes].should be(0)}
|
121
|
+
it {results["kevin.j.jalbert@gmail.com"][:renames].should be(0)}
|
122
|
+
it {results["kevin.j.jalbert@gmail.com"][:copies].should be(0)}
|
123
|
+
it {results["kevin.j.jalbert@gmail.com"][:merges].should be(0)}
|
124
|
+
|
125
|
+
it {results["maggie.simpson@gmail.com"][:commits].should be(2)}
|
126
|
+
it {results["maggie.simpson@gmail.com"][:insertions].should be(211)}
|
127
|
+
it {results["maggie.simpson@gmail.com"][:deletions].should be(192)}
|
128
|
+
it {results["maggie.simpson@gmail.com"][:creates].should be(7)}
|
129
|
+
it {results["maggie.simpson@gmail.com"][:deletes].should be(2)}
|
130
|
+
it {results["maggie.simpson@gmail.com"][:renames].should be(3)}
|
131
|
+
it {results["maggie.simpson@gmail.com"][:copies].should be(1)}
|
132
|
+
it {results["maggie.simpson@gmail.com"][:merges].should be(0)}
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
context "no email" do
|
137
|
+
context "with merge" do
|
138
|
+
commits = Commits.new
|
139
|
+
commits.load(fixture("many_authors.json"))
|
140
|
+
results = commits.authors_statistics(false, true)
|
141
|
+
|
142
|
+
it {results.size.should be(3)}
|
143
|
+
it {results["Bart Simpson"][:commits].should be(2)}
|
144
|
+
it {results["Bart Simpson"][:insertions].should be(13)}
|
145
|
+
it {results["Bart Simpson"][:deletions].should be(3)}
|
146
|
+
it {results["Bart Simpson"][:creates].should be(2)}
|
147
|
+
it {results["Bart Simpson"][:deletes].should be(0)}
|
148
|
+
it {results["Bart Simpson"][:renames].should be(2)}
|
149
|
+
it {results["Bart Simpson"][:copies].should be(0)}
|
150
|
+
it {results["Bart Simpson"][:merges].should be(1)}
|
151
|
+
|
152
|
+
it {results["Kevin Jalbert"][:commits].should be(1)}
|
153
|
+
it {results["Kevin Jalbert"][:insertions].should be(62)}
|
154
|
+
it {results["Kevin Jalbert"][:deletions].should be(6)}
|
155
|
+
it {results["Kevin Jalbert"][:creates].should be(0)}
|
156
|
+
it {results["Kevin Jalbert"][:deletes].should be(1)}
|
157
|
+
it {results["Kevin Jalbert"][:renames].should be(0)}
|
158
|
+
it {results["Kevin Jalbert"][:copies].should be(0)}
|
159
|
+
it {results["Kevin Jalbert"][:merges].should be(1)}
|
160
|
+
|
161
|
+
it {results["Maggie Simpson"][:commits].should be(2)}
|
162
|
+
it {results["Maggie Simpson"][:insertions].should be(211)}
|
163
|
+
it {results["Maggie Simpson"][:deletions].should be(192)}
|
164
|
+
it {results["Maggie Simpson"][:creates].should be(7)}
|
165
|
+
it {results["Maggie Simpson"][:deletes].should be(2)}
|
166
|
+
it {results["Maggie Simpson"][:renames].should be(3)}
|
167
|
+
it {results["Maggie Simpson"][:copies].should be(1)}
|
168
|
+
it {results["Maggie Simpson"][:merges].should be(0)}
|
169
|
+
|
170
|
+
end
|
171
|
+
|
172
|
+
context "no merge" do
|
173
|
+
commits = Commits.new
|
174
|
+
commits.load(fixture("many_authors.json"))
|
175
|
+
results = commits.authors_statistics(false, false)
|
176
|
+
|
177
|
+
it {results.size.should be(3)}
|
178
|
+
it {results["Bart Simpson"][:commits].should be(1)}
|
179
|
+
it {results["Bart Simpson"][:insertions].should be(3)}
|
180
|
+
it {results["Bart Simpson"][:deletions].should be(2)}
|
181
|
+
it {results["Bart Simpson"][:creates].should be(2)}
|
182
|
+
it {results["Bart Simpson"][:deletes].should be(0)}
|
183
|
+
it {results["Bart Simpson"][:renames].should be(0)}
|
184
|
+
it {results["Bart Simpson"][:copies].should be(0)}
|
185
|
+
it {results["Bart Simpson"][:merges].should be(0)}
|
186
|
+
|
187
|
+
it {results["Kevin Jalbert"][:commits].should be(0)}
|
188
|
+
it {results["Kevin Jalbert"][:insertions].should be(0)}
|
189
|
+
it {results["Kevin Jalbert"][:deletions].should be(0)}
|
190
|
+
it {results["Kevin Jalbert"][:creates].should be(0)}
|
191
|
+
it {results["Kevin Jalbert"][:deletes].should be(0)}
|
192
|
+
it {results["Kevin Jalbert"][:renames].should be(0)}
|
193
|
+
it {results["Kevin Jalbert"][:copies].should be(0)}
|
194
|
+
it {results["Kevin Jalbert"][:merges].should be(0)}
|
195
|
+
|
196
|
+
it {results["Maggie Simpson"][:commits].should be(2)}
|
197
|
+
it {results["Maggie Simpson"][:insertions].should be(211)}
|
198
|
+
it {results["Maggie Simpson"][:deletions].should be(192)}
|
199
|
+
it {results["Maggie Simpson"][:creates].should be(7)}
|
200
|
+
it {results["Maggie Simpson"][:deletes].should be(2)}
|
201
|
+
it {results["Maggie Simpson"][:renames].should be(3)}
|
202
|
+
it {results["Maggie Simpson"][:copies].should be(1)}
|
203
|
+
it {results["Maggie Simpson"][:merges].should be(0)}
|
204
|
+
end
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
describe "#author_top_n_type" do
|
209
|
+
context "no data" do
|
210
|
+
context "with email" do
|
211
|
+
commits = Commits.new
|
212
|
+
results = commits.author_top_n_type(true, :commits)
|
213
|
+
|
214
|
+
it { results.should be(nil)}
|
215
|
+
end
|
216
|
+
|
217
|
+
context "without email" do
|
218
|
+
commits = Commits.new
|
219
|
+
results = commits.author_top_n_type(false, :commits)
|
220
|
+
|
221
|
+
it { results.should be(nil)}
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
context "with data" do
|
226
|
+
context "with email" do
|
227
|
+
context "n is negative" do
|
228
|
+
commits = Commits.new
|
229
|
+
commits.load(fixture("many_authors.json"))
|
230
|
+
commits.calculate_statistics(true, true)
|
231
|
+
results = commits.author_top_n_type(true, :commits, -1)
|
232
|
+
|
233
|
+
it { results.size.should be(3)}
|
234
|
+
it { results[0][0].should == "bart.simpson@gmail.com"}
|
235
|
+
it { results[1][0].should == "maggie.simpson@gmail.com"}
|
236
|
+
it { results[2][0].should == "kevin.j.jalbert@gmail.com"}
|
237
|
+
|
238
|
+
end
|
239
|
+
|
240
|
+
context "n is 0" do
|
241
|
+
commits = Commits.new
|
242
|
+
commits.load(fixture("many_authors.json"))
|
243
|
+
commits.calculate_statistics(true, true)
|
244
|
+
results = commits.author_top_n_type(true, :commits, 0)
|
245
|
+
|
246
|
+
it { results.size.should be(3)}
|
247
|
+
it { results[0][0].should == "bart.simpson@gmail.com"}
|
248
|
+
it { results[1][0].should == "maggie.simpson@gmail.com"}
|
249
|
+
it { results[2][0].should == "kevin.j.jalbert@gmail.com"}
|
250
|
+
end
|
251
|
+
|
252
|
+
context "n is less then total" do
|
253
|
+
commits = Commits.new
|
254
|
+
commits.load(fixture("many_authors.json"))
|
255
|
+
commits.calculate_statistics(true, true)
|
256
|
+
results = commits.author_top_n_type(true, :commits, 2)
|
257
|
+
|
258
|
+
it { results.size.should be(2)}
|
259
|
+
it { results[0][0].should == "bart.simpson@gmail.com"}
|
260
|
+
it { results[1][0].should == "maggie.simpson@gmail.com"}
|
261
|
+
end
|
262
|
+
|
263
|
+
context "n is greater then total" do
|
264
|
+
commits = Commits.new
|
265
|
+
commits.load(fixture("many_authors.json"))
|
266
|
+
commits.calculate_statistics(true, true)
|
267
|
+
results = commits.author_top_n_type(true, :commits, 20)
|
268
|
+
|
269
|
+
it { results.size.should be(3)}
|
270
|
+
it { results[0][0].should == "bart.simpson@gmail.com"}
|
271
|
+
it { results[1][0].should == "maggie.simpson@gmail.com"}
|
272
|
+
it { results[2][0].should == "kevin.j.jalbert@gmail.com"}
|
273
|
+
end
|
274
|
+
end
|
275
|
+
|
276
|
+
context "no email" do
|
277
|
+
context "n is negative" do
|
278
|
+
commits = Commits.new
|
279
|
+
commits.load(fixture("many_authors.json"))
|
280
|
+
commits.calculate_statistics(false, true)
|
281
|
+
results = commits.author_top_n_type(false, :commits, -1)
|
282
|
+
|
283
|
+
it { results.size.should be(3)}
|
284
|
+
it { results[0][0].should == "Bart Simpson"}
|
285
|
+
it { results[1][0].should == "Maggie Simpson"}
|
286
|
+
it { results[2][0].should == "Kevin Jalbert"}
|
287
|
+
|
288
|
+
end
|
289
|
+
|
290
|
+
context "n is 0" do
|
291
|
+
commits = Commits.new
|
292
|
+
commits.load(fixture("many_authors.json"))
|
293
|
+
commits.calculate_statistics(false, true)
|
294
|
+
results = commits.author_top_n_type(false, :commits, 0)
|
295
|
+
|
296
|
+
it { results.size.should be(3)}
|
297
|
+
it { results[0][0].should == "Bart Simpson"}
|
298
|
+
it { results[1][0].should == "Maggie Simpson"}
|
299
|
+
it { results[2][0].should == "Kevin Jalbert"}
|
300
|
+
end
|
301
|
+
|
302
|
+
context "n is less then total" do
|
303
|
+
commits = Commits.new
|
304
|
+
commits.load(fixture("many_authors.json"))
|
305
|
+
commits.calculate_statistics(false, true)
|
306
|
+
results = commits.author_top_n_type(false, :commits, 2)
|
307
|
+
|
308
|
+
it { results.size.should be(2)}
|
309
|
+
it { results[0][0].should == "Bart Simpson"}
|
310
|
+
it { results[1][0].should == "Maggie Simpson"}
|
311
|
+
end
|
312
|
+
|
313
|
+
context "n is greater then total" do
|
314
|
+
commits = Commits.new
|
315
|
+
commits.load(fixture("many_authors.json"))
|
316
|
+
commits.calculate_statistics(false, true)
|
317
|
+
results = commits.author_top_n_type(false, :commits, 20)
|
318
|
+
|
319
|
+
it { results.size.should be(3)}
|
320
|
+
it { results[0][0].should == "Bart Simpson"}
|
321
|
+
it { results[1][0].should == "Maggie Simpson"}
|
322
|
+
it { results[2][0].should == "Kevin Jalbert"}
|
323
|
+
end
|
324
|
+
end
|
325
|
+
end
|
326
|
+
end
|
327
|
+
|
328
|
+
describe "#calculate_statistics (totals)" do
|
329
|
+
context "with merge" do
|
330
|
+
commits = Commits.new
|
331
|
+
commits.load(fixture("many_authors.json"))
|
332
|
+
commits.calculate_statistics(true, true)
|
333
|
+
results = commits.totals
|
334
|
+
|
335
|
+
it {results[:commits].should be(5)}
|
336
|
+
it {results[:insertions].should be(286)}
|
337
|
+
it {results[:deletions].should be(201)}
|
338
|
+
it {results[:creates].should be(9)}
|
339
|
+
it {results[:deletes].should be(3)}
|
340
|
+
it {results[:renames].should be(5)}
|
341
|
+
it {results[:copies].should be(1)}
|
342
|
+
it {results[:merges].should be(2)}
|
343
|
+
end
|
344
|
+
|
345
|
+
context "no merge" do
|
346
|
+
commits = Commits.new
|
347
|
+
commits.load(fixture("many_authors.json"))
|
348
|
+
commits.calculate_statistics(false, false)
|
349
|
+
results = commits.totals
|
350
|
+
|
351
|
+
it {results[:commits].should be(3)}
|
352
|
+
it {results[:insertions].should be(214)}
|
353
|
+
it {results[:deletions].should be(194)}
|
354
|
+
it {results[:creates].should be(9)}
|
355
|
+
it {results[:deletes].should be(2)}
|
356
|
+
it {results[:renames].should be(3)}
|
357
|
+
it {results[:copies].should be(1)}
|
358
|
+
it {results[:merges].should be(0)}
|
359
|
+
end
|
360
|
+
end
|
361
|
+
|
362
|
+
describe "#save" do
|
363
|
+
context "with pretty" do
|
364
|
+
commits = Commits.new
|
365
|
+
commits.load(fixture("single_author.json"))
|
366
|
+
commits.save("tmp.json", true)
|
367
|
+
same = FileUtils.compare_file("tmp.json", fixture("single_author.json"))
|
368
|
+
FileUtils.remove_file("tmp.json")
|
369
|
+
it { same.should be_true }
|
370
|
+
end
|
371
|
+
|
372
|
+
context "no pretty" do
|
373
|
+
commits = Commits.new
|
374
|
+
commits.load(fixture("single_author.json"))
|
375
|
+
commits.save("tmp.json", false)
|
376
|
+
same = FileUtils.compare_file("tmp.json", fixture("single_author_unpretty.json"))
|
377
|
+
FileUtils.remove_file("tmp.json")
|
378
|
+
it { same.should be_true }
|
379
|
+
end
|
380
|
+
end
|
381
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
{
|
2
|
+
"49164f12e4cd3b253e5de31242bc716c9e7d6f95": {
|
3
|
+
"author": "Bart Simpson",
|
4
|
+
"author_email": "bart.simpson@gmail.com",
|
5
|
+
"time": "2012-04-06 11:58:16 -0400",
|
6
|
+
"insertions": 3,
|
7
|
+
"deletions": 2,
|
8
|
+
"creates": 2,
|
9
|
+
"deletes": 0,
|
10
|
+
"renames": 0,
|
11
|
+
"copies": 0,
|
12
|
+
"merge": false
|
13
|
+
},
|
14
|
+
"642276027055befb50999c7c155391402bb7c2e8": {
|
15
|
+
"author": "Kevin Jalbert",
|
16
|
+
"author_email": "kevin.j.jalbert@gmail.com",
|
17
|
+
"time": "2012-04-09 21:02:42 -0400",
|
18
|
+
"insertions": 62,
|
19
|
+
"deletions": 6,
|
20
|
+
"creates": 0,
|
21
|
+
"deletes": 1,
|
22
|
+
"renames": 0,
|
23
|
+
"copies": 0,
|
24
|
+
"merge": true
|
25
|
+
},
|
26
|
+
"754e18e83c748700d883048dbc889c7b0db7121d": {
|
27
|
+
"author": "Bart Simpson",
|
28
|
+
"author_email": "bart.simpson@gmail.com",
|
29
|
+
"time": "2012-04-09 21:15:46 -0400",
|
30
|
+
"insertions": 10,
|
31
|
+
"deletions": 1,
|
32
|
+
"creates": 0,
|
33
|
+
"deletes": 0,
|
34
|
+
"renames": 2,
|
35
|
+
"copies": 0,
|
36
|
+
"merge": true
|
37
|
+
},
|
38
|
+
"f9e638cd4bf18d4f6db27a9c085a9f558f762cc3": {
|
39
|
+
"author": "Maggie Simpson",
|
40
|
+
"author_email": "maggie.simpson@gmail.com",
|
41
|
+
"time": "2012-04-09 21:42:07 -0400",
|
42
|
+
"insertions": 8,
|
43
|
+
"deletions": 5,
|
44
|
+
"creates": 4,
|
45
|
+
"deletes": 1,
|
46
|
+
"renames": 2,
|
47
|
+
"copies": 1,
|
48
|
+
"merge": false
|
49
|
+
},
|
50
|
+
"fba10799b65b0e50c8dc355c9acae08d22b193ae": {
|
51
|
+
"author": "Maggie Simpson",
|
52
|
+
"author_email": "maggie.simpson@gmail.com",
|
53
|
+
"time": "2012-04-11 11:48:07 -0400",
|
54
|
+
"insertions": 203,
|
55
|
+
"deletions": 187,
|
56
|
+
"creates": 3,
|
57
|
+
"deletes": 1,
|
58
|
+
"renames": 1,
|
59
|
+
"copies": 0,
|
60
|
+
"merge": false
|
61
|
+
}
|
62
|
+
}
|
@@ -0,0 +1,26 @@
|
|
1
|
+
{
|
2
|
+
"f9e638cd4bf18d4f6db27a9c085a9f558f762cc3": {
|
3
|
+
"author": "Kevin Jalbert",
|
4
|
+
"author_email": "kevin.j.jalbert@gmail.com",
|
5
|
+
"time": "2012-04-09 21:42:07 -0400",
|
6
|
+
"insertions": 8,
|
7
|
+
"deletions": 5,
|
8
|
+
"creates": 0,
|
9
|
+
"deletes": 0,
|
10
|
+
"renames": 0,
|
11
|
+
"copies": 0,
|
12
|
+
"merge": false
|
13
|
+
},
|
14
|
+
"fba10799b65b0e50c8dc355c9acae08d22b193ae": {
|
15
|
+
"author": "Kevin Jalbert",
|
16
|
+
"author_email": "kevin.j.jalbert@gmail.com",
|
17
|
+
"time": "2012-04-11 11:48:07 -0400",
|
18
|
+
"insertions": 203,
|
19
|
+
"deletions": 187,
|
20
|
+
"creates": 3,
|
21
|
+
"deletes": 1,
|
22
|
+
"renames": 1,
|
23
|
+
"copies": 0,
|
24
|
+
"merge": false
|
25
|
+
}
|
26
|
+
}
|
@@ -0,0 +1 @@
|
|
1
|
+
{"f9e638cd4bf18d4f6db27a9c085a9f558f762cc3":{"author":"Kevin Jalbert","author_email":"kevin.j.jalbert@gmail.com","time":"2012-04-09 21:42:07 -0400","insertions":8,"deletions":5,"creates":0,"deletes":0,"renames":0,"copies":0,"merge":false},"fba10799b65b0e50c8dc355c9acae08d22b193ae":{"author":"Kevin Jalbert","author_email":"kevin.j.jalbert@gmail.com","time":"2012-04-11 11:48:07 -0400","insertions":203,"deletions":187,"creates":3,"deletes":1,"renames":1,"copies":0,"merge":false}}
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,97 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: git_statistics
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.2
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Kevin Jalbert
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-04-12 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: json
|
16
|
+
requirement: &14258420 !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: *14258420
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: trollop
|
27
|
+
requirement: &14257940 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ! '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0'
|
33
|
+
type: :runtime
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *14257940
|
36
|
+
description: git_statistics is a gem that provides detailed git statistics
|
37
|
+
email:
|
38
|
+
- kevin.j.jalbert@gmail.com
|
39
|
+
executables:
|
40
|
+
- git_statistics
|
41
|
+
extensions: []
|
42
|
+
extra_rdoc_files: []
|
43
|
+
files:
|
44
|
+
- .gitignore
|
45
|
+
- .travis.yml
|
46
|
+
- Gemfile
|
47
|
+
- Gemfile.lock
|
48
|
+
- LICENSE
|
49
|
+
- README.md
|
50
|
+
- Rakefile
|
51
|
+
- bin/git_statistics
|
52
|
+
- git_statistics.gemspec
|
53
|
+
- lib/git_statistics.rb
|
54
|
+
- lib/git_statistics/collector.rb
|
55
|
+
- lib/git_statistics/commits.rb
|
56
|
+
- lib/git_statistics/initialize.rb
|
57
|
+
- lib/git_statistics/version.rb
|
58
|
+
- spec/collector_spec.rb
|
59
|
+
- spec/commits_spec.rb
|
60
|
+
- spec/fixtures/many_authors.json
|
61
|
+
- spec/fixtures/single_author.json
|
62
|
+
- spec/fixtures/single_author_unpretty.json
|
63
|
+
- spec/spec_helper.rb
|
64
|
+
homepage: https://github.com/kevinjalbert/git_statistics
|
65
|
+
licenses: []
|
66
|
+
post_install_message:
|
67
|
+
rdoc_options: []
|
68
|
+
require_paths:
|
69
|
+
- lib
|
70
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
71
|
+
none: false
|
72
|
+
requirements:
|
73
|
+
- - ! '>='
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 1.9.1
|
76
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
77
|
+
none: false
|
78
|
+
requirements:
|
79
|
+
- - ! '>='
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
version: '0'
|
82
|
+
segments:
|
83
|
+
- 0
|
84
|
+
hash: -1773514383536300330
|
85
|
+
requirements: []
|
86
|
+
rubyforge_project:
|
87
|
+
rubygems_version: 1.8.15
|
88
|
+
signing_key:
|
89
|
+
specification_version: 3
|
90
|
+
summary: Gem that provides the ability to gather detailed git statistics
|
91
|
+
test_files:
|
92
|
+
- spec/collector_spec.rb
|
93
|
+
- spec/commits_spec.rb
|
94
|
+
- spec/fixtures/many_authors.json
|
95
|
+
- spec/fixtures/single_author.json
|
96
|
+
- spec/fixtures/single_author_unpretty.json
|
97
|
+
- spec/spec_helper.rb
|