git_stats 1.0.11 → 1.0.12

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.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/.gitmodules +3 -0
  3. data/README.md +16 -10
  4. data/config/locales/de.yml +2 -0
  5. data/config/locales/en.yml +4 -1
  6. data/lib/git_stats/base.rb +3 -1
  7. data/lib/git_stats/cli.rb +5 -3
  8. data/lib/git_stats/core_extensions/enumerable.rb +10 -0
  9. data/lib/git_stats/generator.rb +4 -4
  10. data/lib/git_stats/git_data/comment_stat.rb +38 -0
  11. data/lib/git_stats/git_data/commit.rb +8 -4
  12. data/lib/git_stats/git_data/repo.rb +46 -13
  13. data/lib/git_stats/git_data/short_stat.rb +1 -1
  14. data/lib/git_stats/git_data/tree.rb +23 -0
  15. data/lib/git_stats/i18n.rb +1 -0
  16. data/lib/git_stats/stats_view/charts/authors_charts.rb +6 -4
  17. data/lib/git_stats/stats_view/charts/charts.rb +1 -1
  18. data/lib/git_stats/stats_view/charts/repo_charts.rb +10 -0
  19. data/lib/git_stats/stats_view/view.rb +2 -1
  20. data/lib/git_stats/version.rb +1 -1
  21. data/spec/factories.rb +8 -0
  22. data/spec/git_data/commit_range_spec.rb +2 -2
  23. data/spec/git_data/commit_spec.rb +1 -1
  24. data/spec/git_data/generator_spec.rb +5 -7
  25. data/spec/git_data/repo_spec.rb +5 -5
  26. data/spec/git_data/short_stat_spec.rb +1 -1
  27. data/spec/git_data/tree_spec.rb +41 -0
  28. data/spec/integration/author_spec.rb +2 -2
  29. data/spec/integration/file_spec.rb +2 -2
  30. data/spec/integration/shared.rb +91 -0
  31. data/spec/integration/tree_spec.rb +197 -0
  32. data/templates/author_details/_author_details.haml +4 -4
  33. data/templates/authors/_authors.haml +5 -5
  34. data/templates/comments/_comments.haml +11 -0
  35. data/templates/comments/by_date.haml +1 -0
  36. data/templates/general.haml +3 -0
  37. metadata +31 -25
  38. data/lib/git_stats/by_field_finder.rb +0 -7
  39. data/spec/by_field_finder_spec.rb +0 -25
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 9f3520a3ad6f9c046a9b1764cedcf337dfadd229
4
- data.tar.gz: 8b48cb4ea3d79e15bc0bb2ecf67df7b67f5ed61a
3
+ metadata.gz: 2fdf7c3f12067e71e3eddbd26ece408572f6d0bf
4
+ data.tar.gz: 79b20aeae19c213893f447432a34bd81bb89880e
5
5
  SHA512:
6
- metadata.gz: 7decc1f75bd9778ddcb96d6c76c2751c92db8d7a88e04827ad7e4073476f2e2ac18b8136512253833160d837593994ed485e831da62ef3b32c5a329d348e2754
7
- data.tar.gz: c31d7266352df2493e81d6a93ecb0f0a1785e281c708f170fe5843c0b2e9230ee259feb5a4383206ff56822040550e1c73c0226170e2eff4f5594b6fc17821ca
6
+ metadata.gz: 3286e2ccc323720aa0532f0112d77ff103136646ac14f64e425c7787e3c9b67bc91eee7e0f23e22cfe15a0d0ca02796a61f9e7aa8fab0fae5cc23f4aa9194a7d
7
+ data.tar.gz: 87b139080a6f5420c7267cc858d73ba4494c745e40b60e599fe2ac2f763a615b08e28d67f89c235c7f85bad73a6b3891ec3148c7b3542035fedf7129edb4d1bb
@@ -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] # Path to repository from which statistics should be generated.
38
- # Default: .
39
- o, [--output=OUTPUT] # 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] # Silent mode. Don't output anything.
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
 
@@ -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
@@ -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
@@ -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'
@@ -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 :output, :aliases => :o, :default => './git_stats', :desc => 'Output path where statistics should be written.'
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[:path], options[:output], options[:from], options[:to]) { |g|
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
@@ -0,0 +1,10 @@
1
+ module Enumerable
2
+ def first!(&block)
3
+ matching = find(&block)
4
+ if matching.nil?
5
+ raise "Sequence contains no matching elements"
6
+ else
7
+ matching
8
+ end
9
+ end
10
+ end
@@ -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(repo_path, out_path, first_commit_sha = nil, last_commit_sha = "HEAD")
8
- validate_repo_path(repo_path)
7
+ def initialize(options)
8
+ validate_repo_path(options[:path])
9
9
 
10
- @repo = GitData::Repo.new(path: repo_path, first_commit_sha: first_commit_sha, last_commit_sha: last_commit_sha)
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.extend(ByFieldFinder)
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.extend(ByFieldFinder)
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.by_email(commit_line[:author_email])
51
+ author: authors.first! { |a| a.email == commit_line[:author_email] }
33
52
  )
34
- end.sort_by! { |e| e.date }.extend(ByFieldFinder)
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
@@ -1,2 +1,3 @@
1
1
  # -*- encoding : utf-8 -*-
2
2
  I18n.load_path += Dir['../../../../config/locales/*.yml'.absolute_path]
3
+ I18n.enforce_available_locales = true
@@ -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(limit = 4, authors = nil)
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..limit]).map { |author| {name: author.name, data: author.commits_sum_by_date} },
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 |limit = 4, authors = nil|
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..limit]).map { |author| {name: author.name, data: author.send("#{method}_by_date")} },
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
@@ -47,6 +47,16 @@ module GitStats
47
47
  end
48
48
  end
49
49
 
50
+ def comments_by_date
51
+ Chart.new do |f|
52
+ f.date_chart(
53
+ data: @repo.comments_count_by_date,
54
+ title: :comments_by_date.t,
55
+ y_text: :comments.t
56
+ )
57
+ end
58
+ end
59
+
50
60
  end
51
61
  end
52
62
  end