git_stats 1.0.11 → 1.0.12
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitmodules +3 -0
- data/README.md +16 -10
- data/config/locales/de.yml +2 -0
- data/config/locales/en.yml +4 -1
- data/lib/git_stats/base.rb +3 -1
- data/lib/git_stats/cli.rb +5 -3
- data/lib/git_stats/core_extensions/enumerable.rb +10 -0
- data/lib/git_stats/generator.rb +4 -4
- data/lib/git_stats/git_data/comment_stat.rb +38 -0
- data/lib/git_stats/git_data/commit.rb +8 -4
- data/lib/git_stats/git_data/repo.rb +46 -13
- data/lib/git_stats/git_data/short_stat.rb +1 -1
- data/lib/git_stats/git_data/tree.rb +23 -0
- data/lib/git_stats/i18n.rb +1 -0
- data/lib/git_stats/stats_view/charts/authors_charts.rb +6 -4
- data/lib/git_stats/stats_view/charts/charts.rb +1 -1
- data/lib/git_stats/stats_view/charts/repo_charts.rb +10 -0
- data/lib/git_stats/stats_view/view.rb +2 -1
- data/lib/git_stats/version.rb +1 -1
- data/spec/factories.rb +8 -0
- data/spec/git_data/commit_range_spec.rb +2 -2
- data/spec/git_data/commit_spec.rb +1 -1
- data/spec/git_data/generator_spec.rb +5 -7
- data/spec/git_data/repo_spec.rb +5 -5
- data/spec/git_data/short_stat_spec.rb +1 -1
- data/spec/git_data/tree_spec.rb +41 -0
- data/spec/integration/author_spec.rb +2 -2
- data/spec/integration/file_spec.rb +2 -2
- data/spec/integration/shared.rb +91 -0
- data/spec/integration/tree_spec.rb +197 -0
- data/templates/author_details/_author_details.haml +4 -4
- data/templates/authors/_authors.haml +5 -5
- data/templates/comments/_comments.haml +11 -0
- data/templates/comments/by_date.haml +1 -0
- data/templates/general.haml +3 -0
- metadata +31 -25
- data/lib/git_stats/by_field_finder.rb +0 -7
- data/spec/by_field_finder_spec.rb +0 -25
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2fdf7c3f12067e71e3eddbd26ece408572f6d0bf
|
4
|
+
data.tar.gz: 79b20aeae19c213893f447432a34bd81bb89880e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3286e2ccc323720aa0532f0112d77ff103136646ac14f64e425c7787e3c9b67bc91eee7e0f23e22cfe15a0d0ca02796a61f9e7aa8fab0fae5cc23f4aa9194a7d
|
7
|
+
data.tar.gz: 87b139080a6f5420c7267cc858d73ba4494c745e40b60e599fe2ac2f763a615b08e28d67f89c235c7f85bad73a6b3891ec3148c7b3542035fedf7129edb4d1bb
|
data/.gitmodules
CHANGED
@@ -1,3 +1,6 @@
|
|
1
1
|
[submodule "spec/integration/test_repo"]
|
2
2
|
path = spec/integration/test_repo
|
3
3
|
url = git://github.com/tomgi/git_stats_test_repo.git
|
4
|
+
[submodule "spec/integration/test_repo_tree"]
|
5
|
+
path = spec/integration/test_repo_tree
|
6
|
+
url = git://github.com/irevert/git_stats_test_repo_tree
|
data/README.md
CHANGED
@@ -34,16 +34,22 @@ It browses the repository and outputs html page with statistics.
|
|
34
34
|
git_stats generate
|
35
35
|
|
36
36
|
Options:
|
37
|
-
p, [--path=PATH]
|
38
|
-
|
39
|
-
o, [--
|
40
|
-
|
41
|
-
l, [--language=LANGUAGE]
|
42
|
-
|
43
|
-
f, [--from=FROM]
|
44
|
-
t, [--to=TO]
|
45
|
-
|
46
|
-
s, [--silent]
|
37
|
+
p, [--path=PATH] # Path to repository from which statistics should be generated.
|
38
|
+
# Default: .
|
39
|
+
o, [--out-path=OUT_PATH] # Output path where statistics should be written.
|
40
|
+
# Default: ./git_stats
|
41
|
+
l, [--language=LANGUAGE] # Language of written statistics.
|
42
|
+
# Default: en
|
43
|
+
f, [--from=FROM] # Commit from where statistics should start.
|
44
|
+
t, [--to=TO] # Commit where statistics should stop.
|
45
|
+
# Default: HEAD
|
46
|
+
s, [--silent], [--no-silent] # Silent mode. Don't output anything.
|
47
|
+
d, [--tree=TREE] # Tree where statistics should be generated.
|
48
|
+
# Default: .
|
49
|
+
c, [--comment=COMMENT] # The string which is used for comments.
|
50
|
+
# Default: //
|
51
|
+
|
52
|
+
|
47
53
|
|
48
54
|
#### Start generator with default settings
|
49
55
|
|
data/config/locales/de.yml
CHANGED
@@ -12,8 +12,10 @@ de:
|
|
12
12
|
commits_by_hour: Commits in der Stunde
|
13
13
|
files: Dateien
|
14
14
|
lines: Zeilen
|
15
|
+
comments: Kommentare
|
15
16
|
files_by_date: Dateien nach Datum
|
16
17
|
lines_by_date: Zeilen nach Datum
|
18
|
+
comments_by_date: Kommentare nach Datum
|
17
19
|
files_by_extension: Dateien nach Erweiterungen
|
18
20
|
lines_by_extension: Zeilen nach Erweiterungen
|
19
21
|
hour_of_day: Tagesstunden
|
data/config/locales/en.yml
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
en:
|
2
2
|
project_name: Project name
|
3
3
|
project_version: Project version
|
4
|
+
tree_path: Tree path
|
4
5
|
generated_at: Generated at
|
5
6
|
generator: Generator
|
6
7
|
report_period: Report period
|
@@ -12,8 +13,10 @@ en:
|
|
12
13
|
commits_by_hour: Commits by hour
|
13
14
|
files: Files
|
14
15
|
lines: Lines
|
16
|
+
comments: Comments
|
15
17
|
files_by_date: Files by date
|
16
18
|
lines_by_date: Lines by date
|
19
|
+
comments_by_date: Comments by date
|
17
20
|
files_by_extension: Files by extension
|
18
21
|
lines_by_extension: Lines by extension
|
19
22
|
hour_of_day: Hour of day
|
@@ -57,4 +60,4 @@ en:
|
|
57
60
|
details: Details
|
58
61
|
insertions_by_date: Lines added by date
|
59
62
|
deletions_by_date: Lines deleted by date
|
60
|
-
changed_lines_by_date: Changed lines by date
|
63
|
+
changed_lines_by_date: Changed lines by date
|
data/lib/git_stats/base.rb
CHANGED
@@ -2,10 +2,10 @@
|
|
2
2
|
require 'git_stats/core_extensions/hash'
|
3
3
|
require 'git_stats/core_extensions/string'
|
4
4
|
require 'git_stats/core_extensions/symbol'
|
5
|
+
require 'git_stats/core_extensions/enumerable'
|
5
6
|
|
6
7
|
require 'git_stats/version'
|
7
8
|
require 'git_stats/i18n'
|
8
|
-
require 'git_stats/by_field_finder'
|
9
9
|
require 'git_stats/cli'
|
10
10
|
require 'git_stats/generator'
|
11
11
|
require 'git_stats/validator'
|
@@ -18,6 +18,8 @@ require 'git_stats/git_data/command_runner'
|
|
18
18
|
require 'git_stats/git_data/commit'
|
19
19
|
require 'git_stats/git_data/repo'
|
20
20
|
require 'git_stats/git_data/short_stat'
|
21
|
+
require 'git_stats/git_data/comment_stat'
|
22
|
+
require 'git_stats/git_data/tree'
|
21
23
|
|
22
24
|
require 'git_stats/stats_view/template'
|
23
25
|
require 'git_stats/stats_view/view'
|
data/lib/git_stats/cli.rb
CHANGED
@@ -4,16 +4,18 @@ require "thor"
|
|
4
4
|
|
5
5
|
class GitStats::CLI < Thor
|
6
6
|
option :path, :aliases => :p, :default => '.', :desc => 'Path to repository from which statistics should be generated.'
|
7
|
-
option :
|
7
|
+
option :out_path, :aliases => :o, :default => './git_stats', :desc => 'Output path where statistics should be written.'
|
8
8
|
option :language, :aliases => :l, :default => 'en', :desc => 'Language of written statistics.'
|
9
9
|
option :from, :aliases => :f, :desc => 'Commit from where statistics should start.'
|
10
10
|
option :to, :aliases => :t, :default => 'HEAD', :desc => 'Commit where statistics should stop.'
|
11
11
|
option :silent, :aliases => :s, :type => :boolean, :desc => 'Silent mode. Don\'t output anything.'
|
12
|
-
|
12
|
+
option :tree, :aliases => :d, :default => '.', :desc => 'Tree where statistics should be generated.'
|
13
|
+
option :comment, :aliases => :c, :default => '//', :desc => 'The string which is used for comments.'
|
14
|
+
|
13
15
|
desc 'generate', 'Generates the statistics of a repository'
|
14
16
|
def generate
|
15
17
|
I18n.locale = options[:language]
|
16
|
-
GitStats::Generator.new(options
|
18
|
+
GitStats::Generator.new(options) { |g|
|
17
19
|
g.add_command_observer { |command, result| puts "#{command}" } unless options[:silent]
|
18
20
|
}.render_all
|
19
21
|
end
|
data/lib/git_stats/generator.rb
CHANGED
@@ -4,12 +4,12 @@ module GitStats
|
|
4
4
|
delegate :add_command_observer, to: :@repo
|
5
5
|
delegate :render_all, to: :@view
|
6
6
|
|
7
|
-
def initialize(
|
8
|
-
validate_repo_path(
|
7
|
+
def initialize(options)
|
8
|
+
validate_repo_path(options[:path])
|
9
9
|
|
10
|
-
@repo = GitData::Repo.new(
|
10
|
+
@repo = GitData::Repo.new(options)
|
11
11
|
view_data = StatsView::ViewData.new(@repo)
|
12
|
-
@view = StatsView::View.new(view_data, out_path)
|
12
|
+
@view = StatsView::View.new(view_data, options[:out_path])
|
13
13
|
|
14
14
|
yield self if block_given?
|
15
15
|
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
module GitStats
|
3
|
+
module GitData
|
4
|
+
class CommentStat
|
5
|
+
attr_reader :commit, :insertions, :deletions
|
6
|
+
|
7
|
+
def initialize(commit)
|
8
|
+
@commit = commit
|
9
|
+
calculate_stat
|
10
|
+
end
|
11
|
+
|
12
|
+
def changed_lines
|
13
|
+
insertions + deletions
|
14
|
+
end
|
15
|
+
|
16
|
+
def to_s
|
17
|
+
"#{self.class} #@commit"
|
18
|
+
end
|
19
|
+
|
20
|
+
def escape_characters_in_string(string)
|
21
|
+
pattern = /(\'|\"|\.|\*|\/|\-|\\)/
|
22
|
+
string.gsub(pattern){|match|"\\" + match}
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
def calculate_stat
|
27
|
+
escaped_string = escape_characters_in_string(commit.repo.comment_string)
|
28
|
+
stat_line = commit.repo.run("git show #{commit.sha} | awk 'BEGIN {adds=0; dels=0} {if ($0 ~ /^\\+#{escaped_string}/) adds++; if ($0 ~ /^\-#{escaped_string}/) dels++} END {print adds \" insertions \" dels \" deletes\"}'").lines.to_a[0]
|
29
|
+
if stat_line.blank?
|
30
|
+
@insertions = @deletions = 0
|
31
|
+
else
|
32
|
+
@insertions = stat_line[/(\d+) insertions?/, 1].to_i
|
33
|
+
@deletions = stat_line[/(\d+) deletes?/, 1].to_i
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -9,9 +9,9 @@ module GitStats
|
|
9
9
|
attr_reader :repo, :sha, :stamp, :date, :author
|
10
10
|
|
11
11
|
def files
|
12
|
-
@files ||= repo.run_and_parse("git ls-tree -r #{self.sha}").map do |file|
|
12
|
+
@files ||= repo.run_and_parse("git ls-tree -r #{self.sha} -- #{repo.tree_path}").map do |file|
|
13
13
|
Blob.new(repo: repo, filename: file[:filename], sha: file[:sha])
|
14
|
-
end
|
14
|
+
end
|
15
15
|
end
|
16
16
|
|
17
17
|
def binary_files
|
@@ -37,11 +37,11 @@ module GitStats
|
|
37
37
|
end
|
38
38
|
|
39
39
|
def files_count
|
40
|
-
@files_count ||= repo.run("git ls-tree -r --name-only #{self.sha} | wc -l").to_i
|
40
|
+
@files_count ||= repo.run("git ls-tree -r --name-only #{self.sha} -- #{repo.tree_path}| wc -l").to_i
|
41
41
|
end
|
42
42
|
|
43
43
|
def lines_count
|
44
|
-
@lines_count ||= repo.run("git diff --shortstat `git hash-object -t tree /dev/null` #{self.sha}").lines.map do |line|
|
44
|
+
@lines_count ||= repo.run("git diff --shortstat `git hash-object -t tree /dev/null` #{self.sha} -- #{repo.tree_path}").lines.map do |line|
|
45
45
|
line[/(\d+) insertions?/, 1].to_i
|
46
46
|
end.sum
|
47
47
|
end
|
@@ -50,6 +50,10 @@ module GitStats
|
|
50
50
|
@short_stat ||= ShortStat.new(self)
|
51
51
|
end
|
52
52
|
|
53
|
+
def comment_stat
|
54
|
+
@comment_stat ||= CommentStat.new(self)
|
55
|
+
end
|
56
|
+
|
53
57
|
def to_s
|
54
58
|
"#{self.class} #@sha"
|
55
59
|
end
|
@@ -6,32 +6,51 @@ module GitStats
|
|
6
6
|
class Repo
|
7
7
|
include HashInitializable
|
8
8
|
|
9
|
-
attr_reader :path, :first_commit_sha, :last_commit_sha
|
10
|
-
|
11
9
|
delegate :files, :files_by_extension, :files_by_extension_count, :lines_by_extension,
|
12
|
-
:files_count, :binary_files, :text_files, :lines_count, to: :last_commit
|
10
|
+
:files_count, :binary_files, :text_files, :lines_count, :comments_count, to: :last_commit
|
13
11
|
|
14
12
|
def initialize(params)
|
15
13
|
super(params)
|
16
14
|
@path = File.expand_path(@path)
|
15
|
+
@tree_path ||= "."
|
16
|
+
end
|
17
|
+
|
18
|
+
def path
|
19
|
+
@path ||= '.'
|
20
|
+
end
|
21
|
+
|
22
|
+
def first_commit_sha
|
23
|
+
@first_commit_sha
|
24
|
+
end
|
25
|
+
|
26
|
+
def last_commit_sha
|
27
|
+
@last_commit_sha ||= 'HEAD'
|
28
|
+
end
|
29
|
+
|
30
|
+
def tree_path
|
31
|
+
@tree_path ||= '.'
|
32
|
+
end
|
33
|
+
|
34
|
+
def comment_string
|
35
|
+
@comment_string ||= '//'
|
17
36
|
end
|
18
37
|
|
19
38
|
def authors
|
20
|
-
@authors ||= run_and_parse("git shortlog -se #{commit_range}").map do |author|
|
39
|
+
@authors ||= run_and_parse("git shortlog -se #{commit_range} #{tree_path}").map do |author|
|
21
40
|
Author.new(repo: self, name: author[:name], email: author[:email])
|
22
|
-
end
|
41
|
+
end
|
23
42
|
end
|
24
43
|
|
25
44
|
def commits
|
26
|
-
@commits ||= run_and_parse("git rev-list --pretty=format:'%h|%at|%ai|%aE' #{commit_range} | grep -v commit").map do |commit_line|
|
45
|
+
@commits ||= run_and_parse("git rev-list --pretty=format:'%h|%at|%ai|%aE' #{commit_range} #{tree_path} | grep -v commit").map do |commit_line|
|
27
46
|
Commit.new(
|
28
47
|
repo: self,
|
29
48
|
sha: commit_line[:sha],
|
30
49
|
stamp: commit_line[:stamp],
|
31
50
|
date: DateTime.parse(commit_line[:date]),
|
32
|
-
author: authors.
|
51
|
+
author: authors.first! { |a| a.email == commit_line[:author_email] }
|
33
52
|
)
|
34
|
-
end.sort_by! { |e| e.date }
|
53
|
+
end.sort_by! { |e| e.date }
|
35
54
|
end
|
36
55
|
|
37
56
|
def commits_period
|
@@ -63,6 +82,15 @@ module GitStats
|
|
63
82
|
}]
|
64
83
|
end
|
65
84
|
|
85
|
+
def comments_count_by_date
|
86
|
+
sum = 0
|
87
|
+
@comment_count_each_day ||= Hash[commits.map { |commit|
|
88
|
+
sum += commit.comment_stat.insertions
|
89
|
+
sum -= commit.comment_stat.deletions
|
90
|
+
[commit.date.to_date, sum]
|
91
|
+
}].fill_empty_days!(aggregated: true)
|
92
|
+
end
|
93
|
+
|
66
94
|
def last_commit
|
67
95
|
commits.last
|
68
96
|
end
|
@@ -71,14 +99,14 @@ module GitStats
|
|
71
99
|
@first_commit_sha.blank? ? last_commit_sha : "#@first_commit_sha..#{last_commit_sha}"
|
72
100
|
end
|
73
101
|
|
74
|
-
def last_commit_sha
|
75
|
-
@last_commit_sha ||= 'HEAD'
|
76
|
-
end
|
77
|
-
|
78
102
|
def short_stats
|
79
103
|
@short_stats ||= commits.map(&:short_stat)
|
80
104
|
end
|
81
105
|
|
106
|
+
def comment_stats
|
107
|
+
@comment_stats ||= commits.map(&:comment_stat)
|
108
|
+
end
|
109
|
+
|
82
110
|
def activity
|
83
111
|
@activity ||= Activity.new(commits)
|
84
112
|
end
|
@@ -87,8 +115,12 @@ module GitStats
|
|
87
115
|
@project_version ||= run("git rev-parse --short #{commit_range}").strip
|
88
116
|
end
|
89
117
|
|
118
|
+
def tree
|
119
|
+
@tree ||= Tree.new(repo: self, relative_path: @tree_path)
|
120
|
+
end
|
121
|
+
|
90
122
|
def project_name
|
91
|
-
@project_name ||= File.basename(path)
|
123
|
+
@project_name ||= (File.expand_path(File.join(path, tree_path)).sub(File.dirname(File.expand_path(path))+File::SEPARATOR,"") || File.basename(path))
|
92
124
|
end
|
93
125
|
|
94
126
|
def run(command)
|
@@ -132,6 +164,7 @@ module GitStats
|
|
132
164
|
command_observers.each { |o| o.call(command, result) }
|
133
165
|
end
|
134
166
|
|
167
|
+
|
135
168
|
end
|
136
169
|
end
|
137
170
|
end
|
@@ -19,7 +19,7 @@ module GitStats
|
|
19
19
|
|
20
20
|
private
|
21
21
|
def calculate_stat
|
22
|
-
stat_line = commit.repo.run("git show --shortstat --oneline #{commit.sha}").lines.to_a[1]
|
22
|
+
stat_line = commit.repo.run("git show --shortstat --oneline #{commit.sha} -- #{commit.repo.tree_path}").lines.to_a[1]
|
23
23
|
if stat_line.blank?
|
24
24
|
@files_changed = @insertions = @deletions = 0
|
25
25
|
else
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
require 'git_stats/hash_initializable'
|
3
|
+
|
4
|
+
module GitStats
|
5
|
+
module GitData
|
6
|
+
class Tree
|
7
|
+
include HashInitializable
|
8
|
+
|
9
|
+
attr_reader :repo, :relative_path
|
10
|
+
|
11
|
+
def authors
|
12
|
+
@authors ||= run_and_parse("git shortlog -se #{commit_range}").map do |author|
|
13
|
+
Author.new(repo: self, name: author[:name], email: author[:email])
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def ==(other)
|
18
|
+
((self.repo == other.repo) && (self.relative_path == other.relative_path))
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
data/lib/git_stats/i18n.rb
CHANGED
@@ -3,14 +3,16 @@ module GitStats
|
|
3
3
|
module StatsView
|
4
4
|
module Charts
|
5
5
|
class AuthorsCharts
|
6
|
+
AUTHORS_ON_CHART_LIMIT = 4
|
7
|
+
|
6
8
|
def initialize(authors)
|
7
9
|
@authors = authors
|
8
10
|
end
|
9
11
|
|
10
|
-
def commits_sum_by_author_by_date(
|
12
|
+
def commits_sum_by_author_by_date(authors = nil)
|
11
13
|
Chart.new do |f|
|
12
14
|
f.multi_date_chart(
|
13
|
-
data: (authors || @authors.sort_by { |author| -author.commits.size }[0..
|
15
|
+
data: (authors || @authors.sort_by { |author| -author.commits.size }[0..AUTHORS_ON_CHART_LIMIT]).map { |author| {name: author.name, data: author.commits_sum_by_date} },
|
14
16
|
title: :lines_by_date.t,
|
15
17
|
y_text: :lines.t
|
16
18
|
)
|
@@ -18,10 +20,10 @@ module GitStats
|
|
18
20
|
end
|
19
21
|
|
20
22
|
[:insertions, :deletions, :changed_lines].each do |method|
|
21
|
-
define_method "#{method}_by_author_by_date" do |
|
23
|
+
define_method "#{method}_by_author_by_date" do |authors = nil|
|
22
24
|
Chart.new do |f|
|
23
25
|
f.multi_date_chart(
|
24
|
-
data: (authors || @authors.sort_by { |author| -author.send(method) }[0..
|
26
|
+
data: (authors || @authors.sort_by { |author| -author.send(method) }[0..AUTHORS_ON_CHART_LIMIT]).map { |author| {name: author.name, data: author.send("#{method}_by_date")} },
|
25
27
|
title: :lines_by_date.t,
|
26
28
|
y_text: :lines.t
|
27
29
|
)
|
@@ -3,7 +3,7 @@ module GitStats
|
|
3
3
|
module StatsView
|
4
4
|
module Charts
|
5
5
|
class All
|
6
|
-
delegate :files_by_extension, :lines_by_extension, :files_by_date, :lines_by_date, to: :repo_charts
|
6
|
+
delegate :files_by_extension, :lines_by_extension, :files_by_date, :lines_by_date, :comments_by_date, to: :repo_charts
|
7
7
|
|
8
8
|
delegate :commits_sum_by_author_by_date, :changed_lines_by_author_by_date,
|
9
9
|
:insertions_by_author_by_date, :deletions_by_author_by_date, to: :authors_charts
|