git_statistics 0.2.0 → 0.3.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/.travis.yml +7 -0
- data/CHANGELOG.md +6 -0
- data/Gemfile +11 -0
- data/Gemfile.lock +15 -0
- data/Guardfile +7 -0
- data/README.md +7 -2
- data/git_statistics.gemspec +1 -0
- data/lib/git_statistics/collector.rb +130 -245
- data/lib/git_statistics/commits.rb +19 -24
- data/lib/git_statistics/initialize.rb +1 -0
- data/lib/git_statistics/results.rb +96 -0
- data/lib/git_statistics/utilities.rb +108 -0
- data/lib/git_statistics/version.rb +1 -1
- data/lib/git_statistics.rb +7 -4
- data/spec/collector_spec.rb +365 -0
- data/spec/commits_spec.rb +238 -0
- data/spec/fixtures/commit_buffer_changes.txt +9 -0
- data/spec/fixtures/commit_buffer_information.txt +1 -0
- data/spec/fixtures/commit_buffer_information_first.txt +1 -0
- data/spec/fixtures/commit_buffer_information_with_merge.txt +1 -0
- data/spec/fixtures/commit_buffer_whole.txt +6 -0
- data/spec/fixtures/git_many_branches.txt +2 -0
- data/spec/fixtures/git_zero_branches.txt +1 -0
- data/spec/fixtures/header_output.txt +4 -0
- data/spec/fixtures/language_data_output.txt +2 -0
- data/spec/fixtures/multiple_authors.json +1 -0
- data/spec/fixtures/single_author_pretty.json +79 -0
- data/spec/fixtures/summary_output.txt +17 -0
- data/spec/results_spec.rb +143 -0
- data/spec/utilities_spec.rb +169 -0
- metadata +54 -2
data/.travis.yml
CHANGED
data/CHANGELOG.md
ADDED
@@ -0,0 +1,6 @@
|
|
1
|
+
# CHANGELOG
|
2
|
+
|
3
|
+
* [0.3.0 - September 12, 2012](https://github.com/kevinjalbert/git_statistics/compare/v0.2.0...v0.3.0)
|
4
|
+
* [0.2.0 - September 6, 2012](https://github.com/kevinjalbert/git_statistics/compare/v0.1.2...v0.2.0)
|
5
|
+
* [0.1.2 - April 12, 2012](https://github.com/kevinjalbert/git_statistics/compare/v0.1.1...v0.1.2)
|
6
|
+
* [0.1.1 - April 12, 2012](https://github.com/kevinjalbert/git_statistics/compare/0e82e507e5b64a1140623c702015b97b1b3f7f81...v0.1.1)
|
data/Gemfile
CHANGED
@@ -4,9 +4,20 @@ gem "json"
|
|
4
4
|
gem "trollop"
|
5
5
|
gem "grit"
|
6
6
|
gem "github-linguist"
|
7
|
+
gem "os"
|
7
8
|
|
8
9
|
group :test do
|
9
10
|
gem "simplecov"
|
10
11
|
gem "rspec"
|
11
12
|
gem "rake"
|
12
13
|
end
|
14
|
+
|
15
|
+
group :development do
|
16
|
+
gem "guard"
|
17
|
+
gem "guard-rspec"
|
18
|
+
end
|
19
|
+
|
20
|
+
group :darwin do
|
21
|
+
gem "rb-fsevent"
|
22
|
+
gem "terminal-notifier-guard"
|
23
|
+
end
|
data/Gemfile.lock
CHANGED
@@ -15,13 +15,21 @@ GEM
|
|
15
15
|
diff-lcs (~> 1.1)
|
16
16
|
mime-types (~> 1.15)
|
17
17
|
posix-spawn (~> 0.3.6)
|
18
|
+
guard (1.3.2)
|
19
|
+
listen (>= 0.4.2)
|
20
|
+
thor (>= 0.14.6)
|
21
|
+
guard-rspec (1.2.1)
|
22
|
+
guard (>= 1.1)
|
18
23
|
json (1.7.5)
|
24
|
+
listen (0.5.0)
|
19
25
|
mime-types (1.19)
|
20
26
|
multi_json (1.3.6)
|
27
|
+
os (0.9.6)
|
21
28
|
posix-spawn (0.3.6)
|
22
29
|
pygments.rb (0.2.13)
|
23
30
|
rubypython (~> 0.5.3)
|
24
31
|
rake (0.9.2.2)
|
32
|
+
rb-fsevent (0.9.1)
|
25
33
|
rspec (2.11.0)
|
26
34
|
rspec-core (~> 2.11.0)
|
27
35
|
rspec-expectations (~> 2.11.0)
|
@@ -37,6 +45,8 @@ GEM
|
|
37
45
|
multi_json (~> 1.0)
|
38
46
|
simplecov-html (~> 0.5.3)
|
39
47
|
simplecov-html (0.5.3)
|
48
|
+
terminal-notifier-guard (1.5.3)
|
49
|
+
thor (0.16.0)
|
40
50
|
trollop (2.0)
|
41
51
|
|
42
52
|
PLATFORMS
|
@@ -45,8 +55,13 @@ PLATFORMS
|
|
45
55
|
DEPENDENCIES
|
46
56
|
github-linguist
|
47
57
|
grit
|
58
|
+
guard
|
59
|
+
guard-rspec
|
48
60
|
json
|
61
|
+
os
|
49
62
|
rake
|
63
|
+
rb-fsevent
|
50
64
|
rspec
|
51
65
|
simplecov
|
66
|
+
terminal-notifier-guard
|
52
67
|
trollop
|
data/Guardfile
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
# A sample Guardfile
|
2
|
+
# More info at https://github.com/guard/guard#readme
|
3
|
+
guard :rspec, :version => 2, :all_on_start => false do
|
4
|
+
watch(%r{^spec/.+_spec\.rb$})
|
5
|
+
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
|
6
|
+
watch('spec/spec_helper.rb') { "spec" }
|
7
|
+
end
|
data/README.md
CHANGED
@@ -26,11 +26,16 @@ This gem will analyze every commit within a git repository using `git log` and [
|
|
26
26
|
* Total file renames
|
27
27
|
* Total file copies
|
28
28
|
|
29
|
-
This gem also uses [github/linguist](https://github.com/github/linguist) to determine the
|
29
|
+
This gem also uses [github/linguist](https://github.com/github/linguist) to determine the language of each individual file within commits. This augments the reported statistics by breaking down the author's statistics by languages.
|
30
30
|
|
31
31
|
This gem also has the ability to save the acquired data into a JSON file (in either a compressed or pretty format). If a saved file is present for the repository you can use the gem to load the data from the file, thus saving time for re-displaying the statistics using a different set of display flags (what statistic to sort on, number of authors to show, consider merges, etc...). In the event that a repository updates with new commits the gem allows you to update the saved file with the new commits.
|
32
32
|
|
33
|
-
|
33
|
+
# Example Output
|
34
|
+
The following is the output produced by *git_statistics* when used on the [pengwynn/octokit](https://github.com/pengwynn/octokit) (at commit [95a9de3](https://github.com/pengwynn/octokit/commit/95a9de325bee4ca03c9c1d61de2d643666c90037)) git repository. In this output we show the top three authors in rankings based on number of commits (merge commits are excluded from these results).
|
35
|
+
|
36
|
+

|
37
|
+
|
38
|
+
# Contributing
|
34
39
|
|
35
40
|
1. Fork it
|
36
41
|
2. Create your feature branch (`git checkout -b my-new-feature`)
|
data/git_statistics.gemspec
CHANGED
@@ -6,16 +6,7 @@ module GitStatistics
|
|
6
6
|
def initialize(verbose)
|
7
7
|
@commits = Commits.new
|
8
8
|
@verbose = verbose
|
9
|
-
|
10
|
-
# Connect to git repository if it exists
|
11
|
-
directory = Pathname.new(Dir.pwd)
|
12
|
-
while @repo == nil && !directory.root? do
|
13
|
-
begin
|
14
|
-
@repo = Grit::Repo.new(directory)
|
15
|
-
rescue
|
16
|
-
directory = directory.parent
|
17
|
-
end
|
18
|
-
end
|
9
|
+
@repo = Utilities.get_repository
|
19
10
|
|
20
11
|
# Abort if no git repository is found
|
21
12
|
if @repo == nil
|
@@ -23,86 +14,134 @@ module GitStatistics
|
|
23
14
|
end
|
24
15
|
end
|
25
16
|
|
26
|
-
def collect(branch,
|
17
|
+
def collect(branch, time_since="", time_until="")
|
18
|
+
# Create pipe for git log to acquire branches
|
19
|
+
pipe = open("|git --no-pager branch --no-color")
|
20
|
+
|
27
21
|
# Collect branches to use for git log
|
28
|
-
branches = collect_branches
|
22
|
+
branches = collect_branches(pipe)
|
29
23
|
branches = ["", ""] if branch
|
30
24
|
|
31
25
|
# Create pipe for the git log to acquire commits
|
32
26
|
pipe = open("|git --no-pager log #{branches.join(' ')} --date=iso --reverse"\
|
33
27
|
" --no-color --find-copies-harder --numstat --encoding=utf-8 "\
|
34
|
-
"--summary #{
|
28
|
+
"--summary #{time_since} #{time_until} "\
|
29
|
+
"--format=\"%H,%an,%ae,%ad,%p\"")
|
35
30
|
|
36
31
|
# Use a buffer approach to queue up lines from the log for each commit
|
37
32
|
buffer = []
|
38
33
|
pipe.each do |line|
|
39
34
|
|
40
|
-
line = clean_string(line)
|
35
|
+
line = Utilities.clean_string(line)
|
41
36
|
|
42
37
|
# Extract the buffer (commit) when we match ','x5 in the log format (delimeter)
|
43
38
|
if line.split(',').size == 5
|
39
|
+
|
40
|
+
# Sometimes 'git log' doesn't populate the buffer, try fallback option if so
|
41
|
+
buffer = fall_back_collect_commit(line.split(',').first) if buffer.size == 1
|
42
|
+
|
44
43
|
extract_commit(buffer) if not buffer.empty?
|
45
44
|
buffer = []
|
46
45
|
end
|
47
46
|
|
48
|
-
buffer << line
|
47
|
+
buffer << line
|
49
48
|
end
|
50
49
|
|
51
50
|
# Extract the last commit
|
52
51
|
extract_commit(buffer) if not buffer.empty?
|
53
52
|
end
|
54
53
|
|
55
|
-
def
|
56
|
-
|
57
|
-
pipe
|
54
|
+
def fall_back_collect_commit(sha)
|
55
|
+
|
56
|
+
# Create pipe for the git log to acquire commits
|
57
|
+
pipe = open("|git --no-pager show #{sha} --date=iso --reverse"\
|
58
|
+
" --no-color --find-copies-harder --numstat --encoding=utf-8 "\
|
59
|
+
"--summary --format=\"%H,%an,%ae,%ad,%p\"")
|
60
|
+
|
61
|
+
buffer = []
|
62
|
+
pipe.each do |line|
|
63
|
+
buffer << Utilities.clean_string(line)
|
64
|
+
end
|
58
65
|
|
59
|
-
#
|
66
|
+
# Check that the buffer has valid information (i.e., sha was valid)
|
67
|
+
if buffer.empty?
|
68
|
+
return nil
|
69
|
+
elsif buffer.first.split(',').first == sha
|
70
|
+
return buffer
|
71
|
+
else
|
72
|
+
return nil
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def collect_branches(pipe)
|
77
|
+
# Acquire all available branches from repository
|
60
78
|
branches = []
|
61
79
|
pipe.each do |line|
|
62
80
|
|
63
81
|
# Remove the '*' leading the current branch
|
64
82
|
line = line[1..-1] if line[0] == '*'
|
65
|
-
branches << clean_string(line)
|
83
|
+
branches << Utilities.clean_string(line)
|
66
84
|
end
|
67
85
|
|
68
86
|
return branches
|
69
87
|
end
|
70
88
|
|
71
|
-
def
|
72
|
-
#
|
73
|
-
commit_info =
|
74
|
-
sha = commit_info[0]
|
89
|
+
def acquire_commit_data(line)
|
90
|
+
# Split up formated line
|
91
|
+
commit_info = line.split(',')
|
75
92
|
|
76
93
|
# Initialize commit data
|
77
|
-
data = (@commits[
|
94
|
+
data = (@commits[commit_info[0]] ||= Hash.new(0))
|
78
95
|
data[:author] = commit_info[1]
|
79
96
|
data[:author_email] = commit_info[2]
|
80
97
|
data[:time] = commit_info[3]
|
81
98
|
data[:files] = []
|
82
99
|
|
83
|
-
# Flag commit as merge if
|
100
|
+
# Flag commit as merge if necessary (determined if two parents)
|
84
101
|
if commit_info[4] == nil or commit_info[4].split(' ').size == 1
|
85
102
|
data[:merge] = false
|
86
103
|
else
|
87
104
|
data[:merge] = true
|
88
105
|
end
|
89
106
|
|
90
|
-
|
107
|
+
return {:sha => commit_info[0], :data => data}
|
108
|
+
end
|
109
|
+
|
110
|
+
def extract_commit(buffer)
|
111
|
+
# Acquire general commit information
|
112
|
+
commit_data = acquire_commit_data(buffer[0])
|
113
|
+
|
114
|
+
puts "Extracting #{commit_data[:sha]}" if @verbose
|
115
|
+
|
116
|
+
# Abort if the commit sha extracted form the buffer is invalid
|
117
|
+
if commit_data[:sha].scan(/[\d|a-f]{40}/)[0] == nil
|
118
|
+
puts "Invalid buffer containing commit information"
|
119
|
+
return
|
120
|
+
end
|
91
121
|
|
92
122
|
# Identify all changed files for this commit
|
93
|
-
files = identify_changed_files(buffer)
|
123
|
+
files = identify_changed_files(buffer[2..-1])
|
124
|
+
|
125
|
+
# No files were changed in this commit, abort commit
|
126
|
+
if files == nil
|
127
|
+
puts "No files were changed"
|
128
|
+
return
|
129
|
+
end
|
94
130
|
|
95
131
|
# Acquire blob for each changed file and process it
|
96
132
|
files.each do |file|
|
97
|
-
blob = get_blob(sha, file)
|
133
|
+
blob = get_blob(commit_data[:sha], file)
|
98
134
|
|
99
|
-
# Only process blobs,
|
135
|
+
# Only process blobs, or log the submodules and problematic files
|
100
136
|
if blob.instance_of?(Grit::Blob)
|
101
|
-
process_blob(data, blob, file)
|
137
|
+
process_blob(commit_data[:data], blob, file)
|
138
|
+
elsif blob.instance_of?(Grit::Submodule)
|
139
|
+
puts "Ignoring submodule #{blob.name}"
|
102
140
|
else
|
103
141
|
puts "Problem processing file #{file[:file]}"
|
104
142
|
end
|
105
143
|
end
|
144
|
+
return commit_data[:data]
|
106
145
|
end
|
107
146
|
|
108
147
|
def get_blob(sha, file)
|
@@ -110,7 +149,7 @@ module GitStatistics
|
|
110
149
|
file = file[:file].split(File::Separator)
|
111
150
|
|
112
151
|
# Acquire blob of the file for this specific commit
|
113
|
-
blob = find_blob_in_tree(
|
152
|
+
blob = Utilities.find_blob_in_tree(@repo.tree(sha), file)
|
114
153
|
|
115
154
|
# If we cannot find blob in current commit (deleted file), check previous commit
|
116
155
|
if blob == nil || blob.instance_of?(Grit::Tree)
|
@@ -118,94 +157,60 @@ module GitStatistics
|
|
118
157
|
return nil if prev_commit == nil
|
119
158
|
|
120
159
|
prev_tree = @repo.tree(prev_commit.id)
|
121
|
-
blob = find_blob_in_tree(
|
160
|
+
blob = Utilities.find_blob_in_tree(prev_tree, file)
|
122
161
|
end
|
123
162
|
return blob
|
124
163
|
end
|
125
164
|
|
126
165
|
def identify_changed_files(buffer)
|
127
|
-
|
128
|
-
changed_files = []
|
129
|
-
if buffer.size > 2
|
130
|
-
|
131
|
-
# For each modification extract the details
|
132
|
-
buffer[2..-1].each do |line|
|
166
|
+
return buffer if buffer == nil
|
133
167
|
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
changed_files << data
|
138
|
-
next # This line is processed, skip to next
|
139
|
-
end
|
168
|
+
# For each modification extract the details
|
169
|
+
changed_files = []
|
170
|
+
buffer.each do |line|
|
140
171
|
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
if file[:file] == data[:file]
|
148
|
-
file[:status] = data[:status]
|
149
|
-
augmented = true
|
150
|
-
break
|
151
|
-
end
|
152
|
-
end
|
153
|
-
changed_files << data if !augmented
|
154
|
-
next # This line is processed, skip to next
|
155
|
-
end
|
172
|
+
# Extract changed file information if it exists
|
173
|
+
data = extract_change_file(line)
|
174
|
+
if data != nil
|
175
|
+
changed_files << data
|
176
|
+
next # This line is processed, skip to next
|
177
|
+
end
|
156
178
|
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
augmented = true
|
168
|
-
break
|
169
|
-
end
|
179
|
+
# Extract details of create/delete files if it exists
|
180
|
+
data = extract_create_delete_file(line)
|
181
|
+
if data != nil
|
182
|
+
augmented = false
|
183
|
+
# Augment changed file with create/delete information if possible
|
184
|
+
changed_files.each do |file|
|
185
|
+
if file[:file] == data[:file]
|
186
|
+
file[:status] = data[:status]
|
187
|
+
augmented = true
|
188
|
+
break
|
170
189
|
end
|
171
|
-
changed_files << data if !augmented
|
172
|
-
next # This line is processed, skip to next
|
173
190
|
end
|
191
|
+
changed_files << data if !augmented
|
192
|
+
next # This line is processed, skip to next
|
174
193
|
end
|
175
|
-
end
|
176
|
-
return changed_files
|
177
|
-
end
|
178
|
-
|
179
|
-
def find_blob_in_tree(sha, tree, file)
|
180
|
-
# Check If cannot find tree in commit or if we found a submodule as the changed file
|
181
|
-
if tree == nil
|
182
|
-
return nil
|
183
|
-
elsif tree.instance_of?(Grit::Submodule)
|
184
|
-
return tree
|
185
|
-
end
|
186
|
-
|
187
|
-
# If the blob is within the current directory (tree)
|
188
|
-
if file.size == 1
|
189
|
-
blob = tree / file.first
|
190
|
-
|
191
|
-
# Check if blob is nil (could not find changed file in tree)
|
192
|
-
if blob == nil
|
193
194
|
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
195
|
+
# Extract details of rename/copy files if it exists
|
196
|
+
data = extract_rename_copy_file(line)
|
197
|
+
if data != nil
|
198
|
+
augmented = false
|
199
|
+
# Augment changed file with rename/copy information if possible
|
200
|
+
changed_files.each do |file|
|
201
|
+
if file[:file] == data[:new_file]
|
202
|
+
file[:status] = data[:status]
|
203
|
+
file[:old_file] = data[:old_file]
|
204
|
+
file[:similar] = data[:similar]
|
205
|
+
augmented = true
|
206
|
+
break
|
198
207
|
end
|
199
208
|
end
|
200
|
-
|
201
|
-
#
|
202
|
-
return find_blob_in_tree(sha, blob, file)
|
209
|
+
changed_files << data if !augmented
|
210
|
+
next # This line is processed, skip to next
|
203
211
|
end
|
204
|
-
return blob
|
205
|
-
else
|
206
|
-
# Explore deeper in the tree to find the blob of the changed file
|
207
|
-
return find_blob_in_tree(sha, tree / file.first, file[1..-1])
|
208
212
|
end
|
213
|
+
return changed_files
|
209
214
|
end
|
210
215
|
|
211
216
|
def process_blob(data, blob, file)
|
@@ -221,36 +226,21 @@ module GitStatistics
|
|
221
226
|
data[:additions] += file[:additions]
|
222
227
|
data[:deletions] += file[:deletions]
|
223
228
|
|
224
|
-
#
|
225
|
-
|
226
|
-
|
229
|
+
# Acquire specifics on blob
|
230
|
+
file_hash[:binary] = blob.binary?
|
231
|
+
file_hash[:image] = blob.image?
|
232
|
+
file_hash[:vendored] = blob.vendored?
|
233
|
+
file_hash[:generated] = blob.generated?
|
234
|
+
|
235
|
+
# Identify the language of the blob if possible
|
236
|
+
if blob.language == nil
|
237
|
+
file_hash[:language] = "Unknown"
|
227
238
|
else
|
228
|
-
file_hash[:
|
229
|
-
file_hash[:image] = blob.image?
|
230
|
-
file_hash[:vendored] = blob.vendored?
|
231
|
-
file_hash[:generated] = blob.generated?
|
232
|
-
|
233
|
-
# Identify the language of the blob if possible
|
234
|
-
if blob.language == nil
|
235
|
-
file_hash[:language] = "Unknown"
|
236
|
-
else
|
237
|
-
file_hash[:language] = blob.language.name
|
238
|
-
end
|
239
|
+
file_hash[:language] = blob.language.name
|
239
240
|
end
|
240
241
|
data[:files] << file_hash
|
241
|
-
end
|
242
242
|
|
243
|
-
|
244
|
-
#if file_name.include?("foo")
|
245
|
-
#blob = @repo.tree("1ec5c2674fd792e8f9ddbff5afcacc3e1f7c506d") / "actionpack" / "test" / "fixtures" / "public" / "foo"
|
246
|
-
#ap "=-=-=-=-=-=-="
|
247
|
-
#ap file_name
|
248
|
-
#ap "--------------------"
|
249
|
-
#ap blob.contents[2].name
|
250
|
-
#ap "=-=-=-=-=-=-="
|
251
|
-
#end
|
252
|
-
# Clean up a string and force utf-8 encoding
|
253
|
-
return file_name.strip.gsub('"', '').gsub("\\\\", "\\").force_encoding("utf-8")
|
243
|
+
return data
|
254
244
|
end
|
255
245
|
|
256
246
|
def extract_change_file(line)
|
@@ -258,11 +248,11 @@ module GitStatistics
|
|
258
248
|
changes = line.scan(/^([-|\d]+)\s+([-|\d]+)\s+(.+)\s+=>\s+(.+)/)[0]
|
259
249
|
if changes != nil and changes.size == 4
|
260
250
|
# Split up the file into the old and new file
|
261
|
-
split_file = split_old_new_file(changes[2], changes[3])
|
251
|
+
split_file = Utilities.split_old_new_file(changes[2], changes[3])
|
262
252
|
return {:additions => changes[0].to_i,
|
263
253
|
:deletions => changes[1].to_i,
|
264
|
-
:file => clean_string(split_file[:new_file]),
|
265
|
-
:old_file => clean_string(split_file[:old_file])}
|
254
|
+
:file => Utilities.clean_string(split_file[:new_file]),
|
255
|
+
:old_file => Utilities.clean_string(split_file[:old_file])}
|
266
256
|
end
|
267
257
|
|
268
258
|
# Use regex to detect a changed file | 1 2 /path/test/file.txt
|
@@ -270,7 +260,7 @@ module GitStatistics
|
|
270
260
|
if changes != nil and changes.size == 3
|
271
261
|
return {:additions => changes[0].to_i,
|
272
262
|
:deletions => changes[1].to_i,
|
273
|
-
:file => clean_string(changes[2])}
|
263
|
+
:file => Utilities.clean_string(changes[2])}
|
274
264
|
end
|
275
265
|
return nil
|
276
266
|
end
|
@@ -279,8 +269,8 @@ module GitStatistics
|
|
279
269
|
# Use regex to detect a create/delete file | create mode 100644 /path/test/file.txt
|
280
270
|
changes = line.scan(/^(create|delete) mode \d+ ([^\\\n]*)/)[0]
|
281
271
|
if changes != nil and changes.size == 2
|
282
|
-
return {:status => clean_string(changes[0]),
|
283
|
-
:file => clean_string(changes[1])}
|
272
|
+
return {:status => Utilities.clean_string(changes[0]),
|
273
|
+
:file => Utilities.clean_string(changes[1])}
|
284
274
|
end
|
285
275
|
return nil
|
286
276
|
end
|
@@ -290,118 +280,13 @@ module GitStatistics
|
|
290
280
|
changes = line.scan(/^(rename|copy)\s+(.+)\s+=>\s+(.+)\s+\((\d+)/)[0]
|
291
281
|
if changes != nil and changes.size == 4
|
292
282
|
# Split up the file into the old and new file
|
293
|
-
split_file = split_old_new_file(changes[1], changes[2])
|
294
|
-
return {:status => clean_string(changes[0]),
|
295
|
-
:old_file => clean_string(split_file[:old_file]),
|
296
|
-
:new_file => clean_string(split_file[:new_file]),
|
283
|
+
split_file = Utilities.split_old_new_file(changes[1], changes[2])
|
284
|
+
return {:status => Utilities.clean_string(changes[0]),
|
285
|
+
:old_file => Utilities.clean_string(split_file[:old_file]),
|
286
|
+
:new_file => Utilities.clean_string(split_file[:new_file]),
|
297
287
|
:similar => changes[3].to_i}
|
298
288
|
end
|
299
289
|
return nil
|
300
290
|
end
|
301
|
-
|
302
|
-
def split_old_new_file(old, new)
|
303
|
-
# Split the old and new chunks up (separted by the =>)
|
304
|
-
split_old = old.split('{')
|
305
|
-
split_new = new.split('}')
|
306
|
-
|
307
|
-
# Handle recombine the file splits into their whole paths)
|
308
|
-
if split_old.size == 1 && split_new.size == 1
|
309
|
-
old_file = split_old[0]
|
310
|
-
new_file = split_new[0]
|
311
|
-
elsif split_new.size == 1
|
312
|
-
old_file = split_old[0] + split_old[1] + split_new[0]
|
313
|
-
new_file = split_old[0] + split_new[0]
|
314
|
-
elsif split_old.size == 1
|
315
|
-
old_file = split_old[0] + split_new[1]
|
316
|
-
new_file = split_old[0] + split_new[0] + split_new[1]
|
317
|
-
else
|
318
|
-
old_file = split_old[0] + split_old[1] + split_new[1]
|
319
|
-
new_file = split_old[0] + split_new[0] + split_new[1]
|
320
|
-
end
|
321
|
-
|
322
|
-
# Return files, yet remove the '//' if present from combining splits
|
323
|
-
return {:old_file => old_file.gsub('//', '/'),
|
324
|
-
:new_file => new_file.gsub('//', '/')}
|
325
|
-
end
|
326
|
-
|
327
|
-
def print_summary(sort_type, email, n=0)
|
328
|
-
# Default to a 0 if given a negative number to display
|
329
|
-
n = 0 if n < 0
|
330
|
-
|
331
|
-
# Acquire data based on sorty type and top # to show
|
332
|
-
data = @commits.author_top_n_type(sort_type, n)
|
333
|
-
if data == nil
|
334
|
-
raise "Parameter for --sort is not valid"
|
335
|
-
end
|
336
|
-
|
337
|
-
# Acquire formatting pattern for output
|
338
|
-
author_length = find_longest_author(data)
|
339
|
-
language_length = find_longest_language(data)
|
340
|
-
pattern = "%-#{author_length}s | %-#{language_length}s | %7s | %9s | %9s | %7s | %7s | %7s | %6s | %6s |"
|
341
|
-
|
342
|
-
# Print query/header information
|
343
|
-
print_header(pattern, sort_type, n, author_length, language_length)
|
344
|
-
|
345
|
-
# Print per author information
|
346
|
-
data.each do |key,value|
|
347
|
-
puts pattern % [key, "", value[:commits], value[:additions],
|
348
|
-
value[:deletions], value[:create], value[:delete],
|
349
|
-
value[:rename], value[:copy], value[:merges]]
|
350
|
-
print_language_data(pattern, value)
|
351
|
-
end
|
352
|
-
|
353
|
-
# Reprint query/header for repository information
|
354
|
-
print_header(pattern, sort_type, n, author_length, language_length)
|
355
|
-
data = @commits.totals
|
356
|
-
puts pattern % ["Repository Totals", "", data[:commits],
|
357
|
-
data[:additions], data[:deletions], data[:create],
|
358
|
-
data[:delete], data[:rename], data[:copy], data[:merges]]
|
359
|
-
print_language_data(pattern, data)
|
360
|
-
end
|
361
|
-
|
362
|
-
def print_language_data(pattern, data)
|
363
|
-
# Print information of each language for the data
|
364
|
-
data[:languages].each do |key,value|
|
365
|
-
puts pattern % ["", key, "", value[:additions], value[:deletions],
|
366
|
-
value[:create], value[:delete], value[:rename],
|
367
|
-
value[:copy], value[:merges]]
|
368
|
-
end
|
369
|
-
end
|
370
|
-
|
371
|
-
def print_header(pattern, sort_type, n, author_length, language_length)
|
372
|
-
total_authors = @commits.author_list.length
|
373
|
-
|
374
|
-
# Print summary information of displayed results
|
375
|
-
if n > 0 and n < total_authors
|
376
|
-
puts "\nTop #{n} authors(#{total_authors}) sorted by #{sort_type.to_s}\n"
|
377
|
-
else
|
378
|
-
puts "\nAll authors(#{total_authors}) sorted by #{sort_type.to_s}\n"
|
379
|
-
end
|
380
|
-
|
381
|
-
# Print column headers
|
382
|
-
puts "-"*87 + "-"*author_length + "-"*language_length
|
383
|
-
puts pattern % ['Name/Email', 'Language', 'Commits', 'Additions', 'Deletions', 'Creates', 'Deletes', 'Renames', 'Copies', 'Merges']
|
384
|
-
puts "-"*87 + "-"*author_length + "-"*language_length
|
385
|
-
end
|
386
|
-
|
387
|
-
def find_longest_author(data)
|
388
|
-
# Find the longest author name/email (for string formatting)
|
389
|
-
total_authors = @commits.author_list.length
|
390
|
-
author_length = 17
|
391
|
-
data.each do |key,value|
|
392
|
-
author_length = key.length if key.length > author_length
|
393
|
-
end
|
394
|
-
return author_length
|
395
|
-
end
|
396
|
-
|
397
|
-
def find_longest_language(data)
|
398
|
-
# Find the longest language name (for string formatting)
|
399
|
-
total_language = @commits.language_list.length
|
400
|
-
language_length = 9
|
401
|
-
@commits.language_list.each do |key,value|
|
402
|
-
language_length = key.length if key.length > language_length
|
403
|
-
end
|
404
|
-
return language_length
|
405
|
-
end
|
406
291
|
end
|
407
292
|
end
|