git_statistics 0.6.0 → 0.7.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.
- checksums.yaml +7 -0
- data/bin/git-statistics +1 -1
- data/bin/git_statistics +1 -1
- data/lib/git_statistics.rb +48 -32
- data/lib/git_statistics/collector.rb +40 -187
- data/lib/git_statistics/commit_summary.rb +86 -0
- data/lib/git_statistics/commits.rb +18 -14
- data/lib/git_statistics/diff_summary.rb +79 -0
- data/lib/git_statistics/formatters/console.rb +31 -26
- data/lib/git_statistics/initialize.rb +7 -6
- data/lib/git_statistics/pipe.rb +1 -1
- data/lib/git_statistics/utilities.rb +28 -91
- data/lib/git_statistics/version.rb +1 -1
- data/spec/collector_spec.rb +41 -235
- data/spec/commit_summary_spec.rb +126 -0
- data/spec/commits_spec.rb +52 -58
- data/spec/formatters/console_spec.rb +11 -10
- data/spec/utilities_spec.rb +15 -128
- metadata +22 -75
- data/lib/git_statistics/blob.rb +0 -5
- data/lib/git_statistics/branches.rb +0 -35
- data/lib/git_statistics/commit_line_extractor.rb +0 -50
- data/lib/git_statistics/regex_matcher.rb +0 -23
- data/spec/branches_spec.rb +0 -44
- data/spec/commit_line_extractor_spec.rb +0 -70
- data/spec/regex_matcher_spec.rb +0 -35
@@ -33,7 +33,7 @@ module GitStatistics
|
|
33
33
|
Dir.entries(path).reject { |file| %w[. ..].include?(file) }
|
34
34
|
end
|
35
35
|
|
36
|
-
def flush_commits(force
|
36
|
+
def flush_commits(force=false)
|
37
37
|
if size >= limit || force
|
38
38
|
file_count = Utilities.number_of_matching_files(path, /\d+\.json/)
|
39
39
|
save(File.join(path, "#{file_count}.json"), @pretty)
|
@@ -54,13 +54,18 @@ module GitStatistics
|
|
54
54
|
# Identify authors and author type
|
55
55
|
type = email ? :author_email : :author
|
56
56
|
|
57
|
-
#
|
58
|
-
Dir.entries(path).
|
59
|
-
|
60
|
-
if file =~ /\d+\.json/
|
61
|
-
load(File.join(path, file))
|
57
|
+
# Process the commits from file or memory
|
58
|
+
files = Dir.entries(path) - [".", ".."]
|
59
|
+
if files.size == 0
|
62
60
|
process_commits(type, merge)
|
63
|
-
|
61
|
+
else
|
62
|
+
#Load commit file and extract the commits
|
63
|
+
files.each do |file|
|
64
|
+
if file =~ /\d+\.json/
|
65
|
+
load(File.join(path, file))
|
66
|
+
process_commits(type, merge)
|
67
|
+
clear
|
68
|
+
end
|
64
69
|
end
|
65
70
|
end
|
66
71
|
end
|
@@ -112,8 +117,9 @@ module GitStatistics
|
|
112
117
|
data[:languages][file[:language].to_sym][:additions] += file[:additions]
|
113
118
|
data[:languages][file[:language].to_sym][:deletions] += file[:deletions]
|
114
119
|
|
120
|
+
# Keep count of languages status (i.e., added, deleted) and keep keys consistent (i.e., added_files, deleted_files)
|
115
121
|
if file[:status] != nil
|
116
|
-
data[:languages][file[:language].to_sym][file[:status].to_sym] += 1
|
122
|
+
data[:languages][file[:language].to_sym][(file[:status]+'_files').to_sym] += 1
|
117
123
|
end
|
118
124
|
|
119
125
|
return data
|
@@ -125,10 +131,8 @@ module GitStatistics
|
|
125
131
|
data[:commits] += 1
|
126
132
|
data[:additions] += commit[:additions]
|
127
133
|
data[:deletions] += commit[:deletions]
|
128
|
-
data[:
|
129
|
-
data[:
|
130
|
-
data[:rename] += commit[:rename] if commit[:rename] != nil
|
131
|
-
data[:copy] += commit[:copy] if commit[:copy] != nil
|
134
|
+
data[:added_files] += commit[:added_files] if !commit[:added_files].nil?
|
135
|
+
data[:deleted_files] += commit[:deleted_files] if !commit[:deleted_files].nil?
|
132
136
|
return data
|
133
137
|
end
|
134
138
|
|
@@ -142,9 +146,9 @@ module GitStatistics
|
|
142
146
|
# Ensure the path to the file exists
|
143
147
|
FileUtils.mkdir_p(File.dirname(file))
|
144
148
|
# Save file in a simple or pretty format
|
145
|
-
File.open(file, 'w') do |
|
149
|
+
File.open(file, 'w') do |f|
|
146
150
|
json_content = pretty ? JSON.pretty_generate(self) : self.to_json
|
147
|
-
|
151
|
+
f.write(json_content)
|
148
152
|
end
|
149
153
|
end
|
150
154
|
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
module GitStatistics
|
2
|
+
class DiffSummary < SimpleDelegator
|
3
|
+
def initialize(repo, patch)
|
4
|
+
@repo = repo
|
5
|
+
super(patch)
|
6
|
+
end
|
7
|
+
|
8
|
+
# We flip these around since we are diffing in the opposite direction -- new.diff(old)
|
9
|
+
def additions
|
10
|
+
__getobj__.deletions
|
11
|
+
end
|
12
|
+
|
13
|
+
# We flip these around since we are diffing in the opposite direction -- new.diff(old)
|
14
|
+
def deletions
|
15
|
+
__getobj__.additions
|
16
|
+
end
|
17
|
+
|
18
|
+
def net
|
19
|
+
additions - deletions
|
20
|
+
end
|
21
|
+
|
22
|
+
# We flip these around since we are diffing in the opposite direction -- new.diff(old)
|
23
|
+
def status
|
24
|
+
if delta.status == :deleted
|
25
|
+
return :added
|
26
|
+
elsif delta.status == :added
|
27
|
+
return :deleted
|
28
|
+
else
|
29
|
+
return delta.status
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def similarity
|
34
|
+
delta.similarity
|
35
|
+
end
|
36
|
+
|
37
|
+
def filename
|
38
|
+
if (status == :deleted)
|
39
|
+
delta.old_file[:path]
|
40
|
+
else
|
41
|
+
delta.new_file[:path]
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# We flip these around since we are diffing in the opposite direction -- new.diff(old)
|
46
|
+
def blob
|
47
|
+
begin
|
48
|
+
if (status == :deleted)
|
49
|
+
blob = @repo.lookup(delta.new_file[:oid]) # Look at new instead of old
|
50
|
+
else
|
51
|
+
blob = @repo.lookup(delta.old_file[:oid]) # Look at old instead of new
|
52
|
+
end
|
53
|
+
rescue Rugged::OdbError
|
54
|
+
Log.warn "Could not find object (most likely a submodule)"
|
55
|
+
blob = nil
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def inspect
|
60
|
+
%Q{<GitStatistics::FileStat @filename=#{filename} @status=#{status} @similarity=#{similarity} @language=#{language} @additions=#{additions}, @deletions=#{deletions}, @net=#{net}>}
|
61
|
+
end
|
62
|
+
|
63
|
+
def to_json
|
64
|
+
{ filename: filename, status: status, similarity: similarity, language: language, additions: additions, deletions: deletions, net: net}
|
65
|
+
end
|
66
|
+
|
67
|
+
# Determine the language of the file from the blob
|
68
|
+
def language
|
69
|
+
language = "Unknown"
|
70
|
+
unless blob.nil?
|
71
|
+
detected_language = LanguageSniffer.detect(filename, :content => blob.content).language
|
72
|
+
unless detected_language.nil?
|
73
|
+
language = detected_language.name
|
74
|
+
end
|
75
|
+
end
|
76
|
+
language
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -2,10 +2,13 @@ module GitStatistics
|
|
2
2
|
module Formatters
|
3
3
|
class Console
|
4
4
|
|
5
|
+
attr_reader :output
|
5
6
|
attr_accessor :commits, :config
|
6
7
|
|
7
8
|
def initialize(commits)
|
8
9
|
@commits = commits
|
10
|
+
@config = {}
|
11
|
+
@output = []
|
9
12
|
end
|
10
13
|
|
11
14
|
def prepare_result_summary(sort, email, top_n = 0)
|
@@ -26,7 +29,7 @@ module GitStatistics
|
|
26
29
|
|
27
30
|
# Acquire formatting pattern for output
|
28
31
|
@pattern = "| %-#{config[:author_length]}s | %-#{config[:language_length]}s | %7s | %9s | %9s | %7s | %7s | %7s | %6s | %6s |"
|
29
|
-
config
|
32
|
+
@config
|
30
33
|
end
|
31
34
|
|
32
35
|
def print_summary(sort, email, top_n = 0)
|
@@ -35,47 +38,45 @@ module GitStatistics
|
|
35
38
|
config = prepare_result_summary(sort, email, top_n)
|
36
39
|
|
37
40
|
# Print query/header information
|
38
|
-
|
39
|
-
|
41
|
+
print_header
|
40
42
|
# Print per author information
|
41
43
|
config[:data].each do |name, commit_data|
|
42
|
-
|
43
|
-
|
44
|
+
print_row(name, commit_data)
|
45
|
+
print_language_data(commit_data)
|
44
46
|
end
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
47
|
+
add_row separator
|
48
|
+
print_row("Repository Totals", commit_totals)
|
49
|
+
print_language_data(commit_totals)
|
50
|
+
display!
|
51
|
+
end
|
52
|
+
|
53
|
+
def display!
|
54
|
+
output.join("\n")
|
49
55
|
end
|
50
56
|
|
51
57
|
def print_language_data(data)
|
52
|
-
output = []
|
53
58
|
# Print information of each language for the data
|
54
59
|
data[:languages].each do |language, commit_data|
|
55
|
-
|
60
|
+
print_row("", commit_data, language)
|
56
61
|
end
|
57
62
|
output
|
58
63
|
end
|
59
64
|
|
60
65
|
def print_row(name, commit_info, language = '')
|
61
|
-
format_for_row(name, language, commit_info[:commits],
|
62
|
-
commit_info[:additions], commit_info[:deletions], commit_info[:
|
63
|
-
commit_info[:
|
66
|
+
add_row format_for_row(name, language, commit_info[:commits],
|
67
|
+
commit_info[:additions], commit_info[:deletions], commit_info[:added_files],
|
68
|
+
commit_info[:deleted_files], commit_info[:renamed_files], commit_info[:copied_files], commit_info[:merges])
|
64
69
|
end
|
65
70
|
|
66
71
|
def print_header
|
67
|
-
|
68
|
-
|
69
|
-
output << get_header_info
|
70
|
-
output
|
72
|
+
get_author_info(@commits.stats.size)
|
73
|
+
get_header_info
|
71
74
|
end
|
72
75
|
|
73
76
|
def get_header_info
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
headers << separator
|
78
|
-
headers
|
77
|
+
add_row separator
|
78
|
+
add_row format_for_row('Name/Email', 'Language', 'Commits', 'Additions', 'Deletions', 'Creates', 'Deletes', 'Renames', 'Copies', 'Merges')
|
79
|
+
add_row separator
|
79
80
|
end
|
80
81
|
|
81
82
|
def format_for_row(*columns)
|
@@ -83,15 +84,19 @@ module GitStatistics
|
|
83
84
|
end
|
84
85
|
|
85
86
|
def separator
|
86
|
-
"-" * 89 + "-"*config[:author_length] + "-"*config[:language_length]
|
87
|
+
("-" * 89) + ("-" * config[:author_length]) + ("-" * config[:language_length])
|
87
88
|
end
|
88
89
|
|
89
90
|
def get_author_info(total_authors)
|
90
91
|
if config[:top_n] > 0 && config[:top_n] < total_authors
|
91
|
-
|
92
|
+
add_row "Top #{config[:top_n]} authors(#{total_authors}) sorted by #{config[:sort]}"
|
93
|
+
else
|
94
|
+
add_row "All authors(#{total_authors}) sorted by #{config[:sort]}"
|
92
95
|
end
|
96
|
+
end
|
93
97
|
|
94
|
-
|
98
|
+
def add_row(string_or_array)
|
99
|
+
output.concat Array(string_or_array)
|
95
100
|
end
|
96
101
|
end
|
97
102
|
end
|
@@ -1,10 +1,11 @@
|
|
1
1
|
require 'json'
|
2
|
-
require 'grit'
|
3
|
-
require 'linguist'
|
4
2
|
require 'pathname'
|
3
|
+
require 'ostruct'
|
4
|
+
require 'optparse'
|
5
|
+
require 'delegate'
|
6
|
+
require 'fileutils'
|
5
7
|
|
6
|
-
|
7
|
-
require '
|
8
|
-
require 'git_statistics/regex_matcher'
|
8
|
+
require 'rugged'
|
9
|
+
require 'language_sniffer'
|
9
10
|
|
10
|
-
Dir.glob(File.dirname(__FILE__) + '/**/*.rb') {|file| require file}
|
11
|
+
Dir.glob(File.dirname(__FILE__) + '/**/*.rb') { |file| require file }
|
data/lib/git_statistics/pipe.rb
CHANGED
@@ -3,103 +3,35 @@ require 'rbconfig'
|
|
3
3
|
module GitStatistics
|
4
4
|
module Utilities
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
raise NotInRepository unless repo_path
|
12
|
-
Grit::Repo.new(repo_path.to_s)
|
13
|
-
rescue NotInRepository
|
14
|
-
Log.error "You must be within a Git project to run git-statistics."
|
15
|
-
exit 0
|
16
|
-
end
|
17
|
-
|
18
|
-
def self.max_length_in_list(list, max = nil)
|
19
|
-
return nil if list.nil?
|
20
|
-
list.each do |key,value|
|
21
|
-
max = key.length if max.nil? || key.length > max
|
22
|
-
end
|
23
|
-
max
|
6
|
+
def self.max_length_in_list(list, min_length = nil)
|
7
|
+
list ||= []
|
8
|
+
min_length = min_length.to_i
|
9
|
+
list_max = list.map { |k,_| k.length }.max || 0
|
10
|
+
list_max >= min_length ? list_max : min_length
|
24
11
|
end
|
25
12
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
# Handle recombine the file splits into their whole paths)
|
32
|
-
if split_old.one? && split_new.one?
|
33
|
-
old_file = split_old[0]
|
34
|
-
new_file = split_new[0]
|
35
|
-
elsif split_new.one?
|
36
|
-
old_file = split_old[0] + split_old[1]
|
37
|
-
new_file = split_old[0] + split_new[0]
|
38
|
-
elsif split_old.one?
|
39
|
-
old_file = split_old[0] + split_new[1]
|
40
|
-
new_file = split_old[0] + split_new[0] + split_new[1]
|
41
|
-
else
|
42
|
-
old_file = split_old[0] + split_old[1] + split_new[1]
|
43
|
-
new_file = split_old[0] + split_new[0] + split_new[1]
|
44
|
-
end
|
45
|
-
|
46
|
-
# Return files, yet remove the '//' if present from combining splits
|
47
|
-
return {:old_file => old_file.gsub('//', '/'),
|
48
|
-
:new_file => new_file.gsub('//', '/')}
|
49
|
-
end
|
50
|
-
|
51
|
-
def self.find_blob_in_tree(tree, file)
|
52
|
-
# Check If cannot find tree in commit or if we found a submodule as the changed file
|
53
|
-
if tree.nil? || file.nil?
|
54
|
-
return nil
|
55
|
-
elsif tree.instance_of?(Grit::Submodule)
|
56
|
-
return tree
|
57
|
-
end
|
58
|
-
|
59
|
-
# If the blob is within the current directory (tree)
|
60
|
-
if file.one?
|
61
|
-
blob = tree / file.first
|
62
|
-
|
63
|
-
# Check if blob is nil (could not find changed file in tree)
|
64
|
-
if blob.nil?
|
65
|
-
|
66
|
-
# Try looking for submodules as they cannot be found using tree / file notation
|
67
|
-
tree.contents.each do |content|
|
68
|
-
if file.first == content.name
|
69
|
-
return tree
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
|
-
# Exit through recusion with the base case of a nil tree/blob
|
74
|
-
return find_blob_in_tree(blob, file)
|
75
|
-
end
|
76
|
-
return blob
|
77
|
-
else
|
78
|
-
# Explore deeper in the tree to find the blob of the changed file
|
79
|
-
return find_blob_in_tree(tree / file.first, file[1..-1])
|
80
|
-
end
|
81
|
-
end
|
13
|
+
COMMANDS = {
|
14
|
+
:windows => ->{ raise "`stat` is not supported on Windows" },
|
15
|
+
:mac => ->{ "-f %m" }
|
16
|
+
}
|
17
|
+
COMMANDS.default = ->{ "-c %Y" }
|
82
18
|
|
83
19
|
def self.get_modified_time(file)
|
84
|
-
|
85
|
-
raise "`stat` is not supported on the Windows operating system"
|
86
|
-
end
|
87
|
-
flags = os == :mac ? "-f %m" : "-c %Y"
|
20
|
+
flags = COMMANDS[os].()
|
88
21
|
time_at("stat #{flags} #{file}")
|
89
22
|
end
|
90
23
|
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
:
|
95
|
-
|
96
|
-
:
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
:unknown
|
24
|
+
class OperatingSystem
|
25
|
+
OPERATING_SYSTEMS = {
|
26
|
+
/mswin|msys|mingw|cygwin|bccwin|wince|emc/ => :windows,
|
27
|
+
/darwin|mac os/ => :mac,
|
28
|
+
/linux/ => :linux,
|
29
|
+
/solaris|bsd/ => :unix
|
30
|
+
}
|
31
|
+
OPERATING_SYSTEMS.default = :unknown
|
32
|
+
|
33
|
+
def self.determine(os_name)
|
34
|
+
OPERATING_SYSTEMS.select { |k,_| k =~ os_name }.first
|
103
35
|
end
|
104
36
|
end
|
105
37
|
|
@@ -107,11 +39,16 @@ module GitStatistics
|
|
107
39
|
Time.at(%x{#{cmd}}.to_i)
|
108
40
|
end
|
109
41
|
|
42
|
+
def self.os
|
43
|
+
OperatingSystem.determine(RbConfig::CONFIG['host_os'])
|
44
|
+
end
|
45
|
+
|
110
46
|
def self.number_of_matching_files(directory, pattern)
|
111
47
|
Dir.entries(directory).grep(pattern).size
|
112
48
|
rescue SystemCallError
|
113
|
-
|
49
|
+
Log.error "No such directory #{File.expand_path(directory)}"
|
114
50
|
0
|
115
51
|
end
|
52
|
+
|
116
53
|
end
|
117
54
|
end
|
data/spec/collector_spec.rb
CHANGED
@@ -5,33 +5,29 @@ describe Collector do
|
|
5
5
|
let(:limit) {100}
|
6
6
|
let(:fresh) {true}
|
7
7
|
let(:pretty) {false}
|
8
|
-
let(:
|
9
|
-
|
10
|
-
# Create buffer which is an array of cleaned lines
|
11
|
-
let(:buffer) {
|
12
|
-
fixture(fixture_file).lines
|
13
|
-
}
|
8
|
+
let(:repo) { GIT_REPO }
|
9
|
+
let(:collector) {Collector.new(repo, limit, fresh, pretty)}
|
14
10
|
|
15
11
|
describe "#collect" do
|
16
|
-
let(:branch) {
|
12
|
+
let(:branch) {CLI::DEFAULT_BRANCH}
|
17
13
|
let(:email) {false}
|
18
14
|
let(:merge) {true}
|
19
|
-
let(:time_since) {"
|
20
|
-
let(:time_until) {"
|
15
|
+
let(:time_since) {"Tue Sep 24 14:15:44 2012 -0400"}
|
16
|
+
let(:time_until) {"Tue Sep 26 14:45:05 2012 -0400"}
|
21
17
|
let(:author) {"Kevin Jalbert"}
|
22
18
|
|
23
19
|
let(:setup) {
|
24
|
-
collector.collect(branch, time_since, time_until)
|
20
|
+
collector.collect({:branch => branch, :time_since => time_since, :time_until => time_until})
|
25
21
|
collector.commits.calculate_statistics(email, merge)
|
26
22
|
@subject = collector.commits.stats[author]
|
27
23
|
}
|
28
24
|
|
29
25
|
context "with no merge commits" do
|
30
26
|
let(:merge) {false}
|
31
|
-
let(:time_since) {"
|
32
|
-
let(:time_until) {"
|
27
|
+
let(:time_since) {"Tue Sep 10 14:15:44 2012 -0400"}
|
28
|
+
let(:time_until) {"Tue Sep 11 14:45:05 2012 -0400"}
|
33
29
|
|
34
|
-
before(:all) {setup}
|
30
|
+
before(:all) { setup }
|
35
31
|
|
36
32
|
it{@subject[:additions].should == 276}
|
37
33
|
it{@subject[:deletions].should == 99}
|
@@ -40,279 +36,89 @@ describe Collector do
|
|
40
36
|
|
41
37
|
it{@subject[:languages][:Ruby][:additions].should == 270}
|
42
38
|
it{@subject[:languages][:Ruby][:deletions].should == 99}
|
43
|
-
it{@subject[:languages][:Ruby][:
|
44
|
-
it{@subject[:languages][:
|
45
|
-
it{@subject[:languages][:
|
46
|
-
it{@subject[:languages][:
|
39
|
+
it{@subject[:languages][:Ruby][:added_files].should == 2}
|
40
|
+
it{@subject[:languages][:Text][:additions].should == 6}
|
41
|
+
it{@subject[:languages][:Text][:deletions].should == 0}
|
42
|
+
it{@subject[:languages][:Text][:added_files].should == 1}
|
47
43
|
end
|
48
44
|
|
49
45
|
context "with merge commits and merge option" do
|
50
|
-
before(:all) {setup}
|
46
|
+
before(:all) { setup }
|
51
47
|
|
52
|
-
it{@subject[:additions].should ==
|
53
|
-
it{@subject[:deletions].should ==
|
54
|
-
it{@subject[:commits].should ==
|
48
|
+
it{@subject[:additions].should == 1240}
|
49
|
+
it{@subject[:deletions].should == 934}
|
50
|
+
it{@subject[:commits].should == 9}
|
55
51
|
it{@subject[:merges].should == 1}
|
56
52
|
|
57
53
|
it{@subject[:languages][:Markdown][:additions].should == 1}
|
58
54
|
it{@subject[:languages][:Markdown][:deletions].should == 0}
|
59
|
-
it{@subject[:languages][:Ruby][:additions].should ==
|
60
|
-
it{@subject[:languages][:Ruby][:deletions].should ==
|
55
|
+
it{@subject[:languages][:Ruby][:additions].should == 1227}
|
56
|
+
it{@subject[:languages][:Ruby][:deletions].should == 934}
|
61
57
|
it{@subject[:languages][:Unknown][:additions].should == 12}
|
62
58
|
it{@subject[:languages][:Unknown][:deletions].should == 0}
|
63
59
|
end
|
64
60
|
|
65
61
|
context "with merge commits and no merge option" do
|
66
62
|
let(:merge) {false}
|
67
|
-
before(:all) {setup}
|
63
|
+
before(:all) { setup }
|
68
64
|
|
69
|
-
it{@subject[:additions].should ==
|
70
|
-
it{@subject[:deletions].should ==
|
71
|
-
it{@subject[:commits].should ==
|
65
|
+
it{@subject[:additions].should == 581}
|
66
|
+
it{@subject[:deletions].should == 452}
|
67
|
+
it{@subject[:commits].should == 8}
|
72
68
|
it{@subject[:merges].should == 0}
|
73
69
|
|
74
70
|
it{@subject[:languages][:Markdown][:additions].should == 1}
|
75
71
|
it{@subject[:languages][:Markdown][:deletions].should == 0}
|
76
|
-
it{@subject[:languages][:Ruby][:additions].should ==
|
77
|
-
it{@subject[:languages][:Ruby][:deletions].should ==
|
72
|
+
it{@subject[:languages][:Ruby][:additions].should == 574}
|
73
|
+
it{@subject[:languages][:Ruby][:deletions].should == 452}
|
78
74
|
it{@subject[:languages][:Unknown][:additions].should == 6}
|
79
75
|
it{@subject[:languages][:Unknown][:deletions].should == 0}
|
80
76
|
end
|
81
77
|
end
|
82
78
|
|
83
|
-
describe "#acquire_commit_data" do
|
84
|
-
let(:data) {collector.acquire_commit_data(buffer.first)}
|
85
|
-
|
86
|
-
context "no parent, first commit" do
|
87
|
-
let(:fixture_file) {"commit_buffer_information_first.txt"}
|
88
|
-
it {data[:sha].should == "111111aa111a11111a11aa11aaaa11a111111a11"}
|
89
|
-
it {data[:data][:author].should == "Test Author"}
|
90
|
-
it {data[:data][:author_email].should == "author@test.com"}
|
91
|
-
it {data[:data][:time].should == "2011-01-11 11:11:11 +0000"}
|
92
|
-
it {data[:data][:merge].should be_false}
|
93
|
-
end
|
94
|
-
|
95
|
-
context "without merge, one parent" do
|
96
|
-
let(:fixture_file) {"commit_buffer_information.txt"}
|
97
|
-
it {data[:sha].should == "111111aa111a11111a11aa11aaaa11a111111a11"}
|
98
|
-
it {data[:data][:author].should == "Test Author"}
|
99
|
-
it {data[:data][:author_email].should == "author@test.com"}
|
100
|
-
it {data[:data][:time].should == "2011-01-11 11:11:11 +0000"}
|
101
|
-
it {data[:data][:merge].should be_false}
|
102
|
-
end
|
103
|
-
|
104
|
-
context "with merge, two parents" do
|
105
|
-
let(:fixture_file) {"commit_buffer_information_with_merge.txt"}
|
106
|
-
it {data[:sha].should == "111111aa111a11111a11aa11aaaa11a111111a11"}
|
107
|
-
it {data[:data][:author].should == "Test Author"}
|
108
|
-
it {data[:data][:author_email].should == "author@test.com"}
|
109
|
-
it {data[:data][:time].should == "2011-01-11 11:11:11 +0000"}
|
110
|
-
it {data[:data][:merge].should be_true}
|
111
|
-
end
|
112
|
-
end
|
113
|
-
|
114
|
-
describe "#identify_changed_files" do
|
115
|
-
let(:files) {collector.identify_changed_files(buffer)}
|
116
|
-
let(:fixture_file) {"commit_buffer_changes.txt"}
|
117
|
-
|
118
|
-
context "with no changes" do
|
119
|
-
let(:buffer) {[]}
|
120
|
-
it {files.size.should == 0}
|
121
|
-
it {files[0].should.nil?}
|
122
|
-
end
|
123
|
-
|
124
|
-
context "with all types (create,delete,rename,copy) of files" do
|
125
|
-
it {files.size.should == 5}
|
126
|
-
|
127
|
-
it {files[0][:additions].should == 45}
|
128
|
-
it {files[0][:deletions].should == 1}
|
129
|
-
it {files[0][:file].should == "dir/README"}
|
130
|
-
|
131
|
-
it {files[1][:additions].should == 6}
|
132
|
-
it {files[1][:deletions].should == 5}
|
133
|
-
it {files[1][:old_file].should == "dir/lib/old_dir/copy_file.rb"}
|
134
|
-
it {files[1][:file].should == "dir/lib/new_dir/copy_file.rb"}
|
135
|
-
it {files[1][:status].should == "copy"}
|
136
|
-
|
137
|
-
it {files[2][:additions].should == 0}
|
138
|
-
it {files[2][:deletions].should == 0}
|
139
|
-
it {files[2][:old_file].should == "dir/lib/rename/old_file.rb"}
|
140
|
-
it {files[2][:file].should == "dir/lib/rename/new_file.rb"}
|
141
|
-
it {files[2][:status].should == "rename"}
|
142
|
-
|
143
|
-
it {files[3][:additions].should == 0}
|
144
|
-
it {files[3][:deletions].should == 127}
|
145
|
-
it {files[3][:file].should == "dir/lib/delete_file.rb"}
|
146
|
-
it {files[3][:status].should == "delete"}
|
147
|
-
|
148
|
-
it {files[4][:additions].should == 60}
|
149
|
-
it {files[4][:deletions].should == 0}
|
150
|
-
it {files[4][:file].should == "dir/lib/create_file.rb"}
|
151
|
-
it {files[4][:status].should == "create"}
|
152
|
-
end
|
153
|
-
end
|
154
|
-
|
155
79
|
describe "#extract_commit" do
|
156
|
-
let(:
|
157
|
-
|
158
|
-
context "with valid buffer" do
|
159
|
-
let(:fixture_file) {"commit_buffer_whole.txt"}
|
80
|
+
let(:commit) {repo.lookup(sha)}
|
81
|
+
let(:data) {collector.extract_commit(commit, nil)}
|
160
82
|
|
83
|
+
context "with valid commit" do
|
84
|
+
let(:sha) {"260bc61e2c42930d91f3503c5849b0a2351275cf"}
|
161
85
|
it {data[:author].should == "Kevin Jalbert"}
|
162
86
|
it {data[:author_email].should == "kevin.j.jalbert@gmail.com"}
|
163
|
-
it {data[:time].should
|
87
|
+
it {data[:time].should match /\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2} [-|+]\d{4}/}
|
164
88
|
|
165
89
|
it {data[:merge].should == false}
|
166
90
|
it {data[:additions].should == 30}
|
167
91
|
it {data[:deletions].should == 2}
|
168
|
-
it {data[:
|
92
|
+
it {data[:added_files].should == 1}
|
93
|
+
it {data[:deleted_files].should == 0}
|
169
94
|
|
170
|
-
it {data[:files][0][:
|
95
|
+
it {data[:files][0][:filename].should == "Gemfile"}
|
171
96
|
it {data[:files][0][:additions].should == 0}
|
172
97
|
it {data[:files][0][:deletions].should == 1}
|
173
98
|
it {data[:files][0][:status].should.nil?}
|
174
|
-
it {data[:files][0][:binary].should == false}
|
175
|
-
it {data[:files][0][:image].should == false}
|
176
|
-
it {data[:files][0][:vendored].should == false}
|
177
|
-
it {data[:files][0][:generated].should == false}
|
178
99
|
it {data[:files][0][:language].should == "Ruby"}
|
179
100
|
|
180
|
-
it {data[:files][1][:
|
101
|
+
it {data[:files][1][:filename].should == "Gemfile.lock"}
|
181
102
|
it {data[:files][1][:additions].should == 30}
|
182
103
|
it {data[:files][1][:deletions].should == 0}
|
183
|
-
it {data[:files][1][:status].should
|
184
|
-
it {data[:files][1][:binary].should == false}
|
185
|
-
it {data[:files][1][:image].should == false}
|
186
|
-
it {data[:files][1][:vendored].should == false}
|
187
|
-
it {data[:files][1][:generated].should == true}
|
104
|
+
it {data[:files][1][:status].should eq(:added)}
|
188
105
|
it {data[:files][1][:language].should == "Unknown"}
|
189
106
|
|
190
|
-
it {data[:files][2][:
|
107
|
+
it {data[:files][2][:filename].should == "lib/git_statistics/initialize.rb"}
|
191
108
|
it {data[:files][2][:additions].should == 0}
|
192
109
|
it {data[:files][2][:deletions].should == 1}
|
193
110
|
it {data[:files][2][:status].should.nil?}
|
194
|
-
it {data[:files][2][:binary].should == false}
|
195
|
-
it {data[:files][2][:image].should == false}
|
196
|
-
it {data[:files][2][:vendored].should == false}
|
197
|
-
it {data[:files][2][:generated].should == false}
|
198
111
|
it {data[:files][2][:language].should == "Ruby"}
|
199
112
|
end
|
200
113
|
|
201
|
-
context "with
|
202
|
-
let(:
|
203
|
-
it {data.
|
204
|
-
end
|
205
|
-
|
206
|
-
context "with invalid buffer" do
|
207
|
-
let(:buffer) {"invalid input"}
|
208
|
-
it {data.should.nil?}
|
209
|
-
end
|
210
|
-
end
|
211
|
-
|
212
|
-
describe "#fall_back_collect_commit" do
|
213
|
-
subject { collector.fall_back_collect_commit(sha) }
|
214
|
-
context "with valid sha" do
|
215
|
-
let(:fixture_file) { "commit_buffer_whole.txt" }
|
216
|
-
let(:sha) { "260bc61e2c42930d91f3503c5849b0a2351275cf" }
|
217
|
-
it { should == buffer }
|
114
|
+
context "with invalid commit" do
|
115
|
+
let(:sha) {"111111aa111a11111a11aa11aaaa11a111111a11"}
|
116
|
+
it { expect {data}.to raise_error(Rugged::OdbError) }
|
218
117
|
end
|
219
118
|
|
220
119
|
context "with invalid sha" do
|
221
|
-
let(:sha) { "
|
222
|
-
it {
|
223
|
-
end
|
224
|
-
end
|
225
|
-
|
226
|
-
describe "#get_blob" do
|
227
|
-
let(:sha) { "695b487432e8a1ede765b4e3efda088ab87a77f8" } # Commit within repository
|
228
|
-
subject { collector.get_blob(sha, file) }
|
229
|
-
|
230
|
-
context "with valid blob" do
|
231
|
-
let(:file) {{:file => "Gemfile.lock"}}
|
232
|
-
it { should be_a Grit::Blob }
|
233
|
-
its(:name) { should == File.basename(file[:file]) }
|
234
|
-
end
|
235
|
-
|
236
|
-
context "with deleted file" do
|
237
|
-
let(:file) {{:file => "spec/collector_spec.rb"}}
|
238
|
-
it { should be_a Grit::Blob }
|
239
|
-
its(:name) { should == File.basename(file[:file]) }
|
240
|
-
end
|
241
|
-
|
242
|
-
context "with invalid blob" do
|
243
|
-
let(:file) {{:file => "dir/nothing.rb"}}
|
244
|
-
it { should be_nil }
|
245
|
-
end
|
246
|
-
end
|
247
|
-
|
248
|
-
describe "#process_blob" do
|
249
|
-
let(:sha) {"695b487432e8a1ede765b4e3efda088ab87a77f8"} # Commit within repository
|
250
|
-
let(:blob) {collector.get_blob(sha, file)}
|
251
|
-
let(:data) {
|
252
|
-
data = Hash.new(0)
|
253
|
-
data[:files] = []
|
254
|
-
collector.process_blob(data, blob, file)
|
255
|
-
}
|
256
|
-
let(:data_file) {data_file = data[:files].first}
|
257
|
-
|
258
|
-
context "with status (delete) blob" do
|
259
|
-
let(:file) {{:file => "spec/collector_spec.rb",
|
260
|
-
:additions => 0,
|
261
|
-
:deletions => 6,
|
262
|
-
:status => "delete"}}
|
263
|
-
|
264
|
-
it {data[:additions].should == file[:additions]}
|
265
|
-
it {data[:deletions].should == file[:deletions]}
|
266
|
-
|
267
|
-
it {data_file[:name].should == file[:file]}
|
268
|
-
it {data_file[:additions].should == file[:additions]}
|
269
|
-
it {data_file[:deletions].should == file[:deletions]}
|
270
|
-
it {data_file[:status].should == file[:status]}
|
271
|
-
it {data_file[:binary].should == false}
|
272
|
-
it {data_file[:image].should == false}
|
273
|
-
it {data_file[:vendored].should == false}
|
274
|
-
it {data_file[:generated].should == false}
|
275
|
-
it {data_file[:language].should == "Ruby"}
|
276
|
-
end
|
277
|
-
|
278
|
-
context "with invalid language blob" do
|
279
|
-
let(:file) {{:file => "Gemfile.lock",
|
280
|
-
:additions => 33,
|
281
|
-
:deletions => 11,
|
282
|
-
:status => nil}}
|
283
|
-
|
284
|
-
it {data[:additions].should == file[:additions]}
|
285
|
-
it {data[:deletions].should == file[:deletions]}
|
286
|
-
|
287
|
-
it {data_file[:name].should == file[:file]}
|
288
|
-
it {data_file[:additions].should == file[:additions]}
|
289
|
-
it {data_file[:deletions].should == file[:deletions]}
|
290
|
-
it {data_file[:status].should.nil?}
|
291
|
-
it {data_file[:binary].should == false}
|
292
|
-
it {data_file[:image].should == false}
|
293
|
-
it {data_file[:vendored].should == false}
|
294
|
-
it {data_file[:generated].should == true}
|
295
|
-
it {data_file[:language].should == "Unknown"}
|
296
|
-
end
|
297
|
-
|
298
|
-
context "with valid language blob" do
|
299
|
-
let(:file) {{:file => "README.md",
|
300
|
-
:additions => 7,
|
301
|
-
:deletions => 3,
|
302
|
-
:status => nil}}
|
303
|
-
|
304
|
-
it {data[:additions].should == file[:additions]}
|
305
|
-
it {data[:deletions].should == file[:deletions]}
|
306
|
-
|
307
|
-
it {data_file[:name].should == file[:file]}
|
308
|
-
it {data_file[:additions].should == file[:additions]}
|
309
|
-
it {data_file[:deletions].should == file[:deletions]}
|
310
|
-
it {data_file[:status].should.nil?}
|
311
|
-
it {data_file[:binary].should == false}
|
312
|
-
it {data_file[:image].should == false}
|
313
|
-
it {data_file[:vendored].should == false}
|
314
|
-
it {data_file[:generated].should == false}
|
315
|
-
it {data_file[:language].should == "Markdown"}
|
120
|
+
let(:sha) {"invalid input"}
|
121
|
+
it { expect {data}.to raise_error(Rugged::InvalidError) }
|
316
122
|
end
|
317
123
|
end
|
318
124
|
|