git_stats 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +21 -0
- data/.gitmodules +3 -0
- data/.rspec +1 -0
- data/Gemfile +13 -0
- data/LICENSE.txt +22 -0
- data/README.md +44 -0
- data/Rakefile +1 -0
- data/bin/git_stats +11 -0
- data/config/locales/en.yml +56 -0
- data/config/locales/pl.yml +56 -0
- data/config/locales/pl_default.yml +224 -0
- data/git_stats.gemspec +27 -0
- data/lib/git_stats.rb +15 -0
- data/lib/git_stats/base.rb +30 -0
- data/lib/git_stats/by_field_finder.rb +7 -0
- data/lib/git_stats/cli.rb +17 -0
- data/lib/git_stats/core_extensions/hash.rb +9 -0
- data/lib/git_stats/core_extensions/string.rb +6 -0
- data/lib/git_stats/core_extensions/symbol.rb +6 -0
- data/lib/git_stats/generator.rb +32 -0
- data/lib/git_stats/git_data/activity.rb +78 -0
- data/lib/git_stats/git_data/author.rb +67 -0
- data/lib/git_stats/git_data/blob.rb +38 -0
- data/lib/git_stats/git_data/command_parser.rb +33 -0
- data/lib/git_stats/git_data/command_runner.rb +10 -0
- data/lib/git_stats/git_data/commit.rb +63 -0
- data/lib/git_stats/git_data/repo.rb +137 -0
- data/lib/git_stats/git_data/short_stat.rb +33 -0
- data/lib/git_stats/hash_initializable.rb +7 -0
- data/lib/git_stats/i18n.rb +2 -0
- data/lib/git_stats/stats_view/charts/activity_charts.rb +70 -0
- data/lib/git_stats/stats_view/charts/authors_charts.rb +35 -0
- data/lib/git_stats/stats_view/charts/chart.rb +119 -0
- data/lib/git_stats/stats_view/charts/charts.rb +35 -0
- data/lib/git_stats/stats_view/charts/repo_charts.rb +53 -0
- data/lib/git_stats/stats_view/template.rb +20 -0
- data/lib/git_stats/stats_view/view.rb +72 -0
- data/lib/git_stats/stats_view/view_data.rb +31 -0
- data/lib/git_stats/version.rb +4 -0
- data/spec/by_field_finder_spec.rb +25 -0
- data/spec/factories.rb +25 -0
- data/spec/git_data/activity_spec.rb +38 -0
- data/spec/git_data/author_spec.rb +25 -0
- data/spec/git_data/blob_spec.rb +25 -0
- data/spec/git_data/cli_spec.rb +20 -0
- data/spec/git_data/command_observer_spec.rb +35 -0
- data/spec/git_data/commit_range_spec.rb +47 -0
- data/spec/git_data/commit_spec.rb +48 -0
- data/spec/git_data/generator_spec.rb +46 -0
- data/spec/git_data/repo_spec.rb +46 -0
- data/spec/git_data/short_stat_spec.rb +28 -0
- data/spec/hash_extension_spec.rb +26 -0
- data/spec/integration/activity_spec.rb +33 -0
- data/spec/integration/author_spec.rb +67 -0
- data/spec/integration/file_spec.rb +31 -0
- data/spec/integration/repo_spec.rb +68 -0
- data/spec/integration/shared.rb +37 -0
- data/spec/spec_helper.rb +13 -0
- data/templates/activity/_activity.haml +101 -0
- data/templates/activity/by_date.haml +1 -0
- data/templates/activity/day_of_week.haml +1 -0
- data/templates/activity/hour_of_day.haml +1 -0
- data/templates/activity/hour_of_week.haml +1 -0
- data/templates/activity/month_of_year.haml +1 -0
- data/templates/activity/year.haml +1 -0
- data/templates/activity/year_month.haml +1 -0
- data/templates/assets/bootstrap/css/bootstrap-responsive.css +1058 -0
- data/templates/assets/bootstrap/css/bootstrap-responsive.min.css +9 -0
- data/templates/assets/bootstrap/css/bootstrap.css +5774 -0
- data/templates/assets/bootstrap/css/bootstrap.min.css +9 -0
- data/templates/assets/bootstrap/img/glyphicons-halflings-white.png +0 -0
- data/templates/assets/bootstrap/img/glyphicons-halflings.png +0 -0
- data/templates/assets/bootstrap/js/bootstrap.js +2027 -0
- data/templates/assets/bootstrap/js/bootstrap.min.js +6 -0
- data/templates/assets/highstock.js +305 -0
- data/templates/assets/jquery.min.js +2 -0
- data/templates/authors/_authors.haml +66 -0
- data/templates/authors/best_authors.haml +1 -0
- data/templates/authors/changed_lines_by_author_by_date.haml +1 -0
- data/templates/authors/commits_sum_by_author_by_date.haml +1 -0
- data/templates/authors/deletions_by_author_by_date.haml +1 -0
- data/templates/authors/insertions_by_author_by_date.haml +1 -0
- data/templates/files/_files.haml +15 -0
- data/templates/files/by_date.haml +1 -0
- data/templates/files/by_extension.haml +1 -0
- data/templates/general.haml +28 -0
- data/templates/layout.haml +29 -0
- data/templates/lines/_lines.haml +15 -0
- data/templates/lines/by_date.haml +1 -0
- data/templates/lines/by_extension.haml +1 -0
- data/templates/static/index.html +5 -0
- metadata +268 -0
@@ -0,0 +1,53 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
module GitStats
|
3
|
+
module StatsView
|
4
|
+
module Charts
|
5
|
+
class RepoCharts
|
6
|
+
def initialize(repo)
|
7
|
+
@repo = repo
|
8
|
+
end
|
9
|
+
|
10
|
+
def files_by_extension
|
11
|
+
Chart.new do |f|
|
12
|
+
f.column_hash_chart(
|
13
|
+
data: @repo.files_by_extension_count,
|
14
|
+
title: :files_by_extension.t,
|
15
|
+
y_text: :files.t
|
16
|
+
)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def lines_by_extension
|
21
|
+
Chart.new do |f|
|
22
|
+
f.column_hash_chart(
|
23
|
+
data: @repo.lines_by_extension,
|
24
|
+
title: :lines_by_extension.t,
|
25
|
+
y_text: :lines.t
|
26
|
+
)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def files_by_date
|
31
|
+
Chart.new do |f|
|
32
|
+
f.date_chart(
|
33
|
+
data: @repo.files_count_by_date,
|
34
|
+
title: :files_by_date.t,
|
35
|
+
y_text: :files.t
|
36
|
+
)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def lines_by_date
|
41
|
+
Chart.new do |f|
|
42
|
+
f.date_chart(
|
43
|
+
data: @repo.lines_count_by_date,
|
44
|
+
title: :lines_by_date.t,
|
45
|
+
y_text: :lines.t
|
46
|
+
)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
module GitStats
|
3
|
+
module StatsView
|
4
|
+
class Template
|
5
|
+
def initialize(name, layout=nil)
|
6
|
+
@name = name
|
7
|
+
@layout = layout
|
8
|
+
@template = Tilt.new("../../../../templates/#@name.haml".absolute_path)
|
9
|
+
end
|
10
|
+
|
11
|
+
def render(data, params={})
|
12
|
+
if @layout
|
13
|
+
@layout.render(data, :active_page => params[:active_page] || @name, :links => params[:links]) { @template.render(data, params) }
|
14
|
+
else
|
15
|
+
@template.render(data, params)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
module GitStats
|
3
|
+
module StatsView
|
4
|
+
class View
|
5
|
+
def initialize(view_data, out_path)
|
6
|
+
@view_data, @out_path = view_data, out_path
|
7
|
+
@layout = Tilt.new("../../../../templates/layout.haml".absolute_path)
|
8
|
+
end
|
9
|
+
|
10
|
+
def render_all
|
11
|
+
prepare_static_content
|
12
|
+
prepare_assets
|
13
|
+
|
14
|
+
all_templates.each do |template|
|
15
|
+
output = Template.new(template, @layout).render(@view_data, author: @view_data.repo, links: links)
|
16
|
+
write(output, "#@out_path/#{template}.html")
|
17
|
+
end
|
18
|
+
|
19
|
+
render_authors_activity
|
20
|
+
end
|
21
|
+
|
22
|
+
def render_authors_activity
|
23
|
+
done = []
|
24
|
+
@view_data.repo.authors.sort_by { |a| -a.commits.size }.each do |author|
|
25
|
+
next if done.include? author.dirname
|
26
|
+
done << author.dirname
|
27
|
+
all_templates('activity/').each do |template|
|
28
|
+
output = Template.new(template, @layout).render(@view_data,
|
29
|
+
author: author,
|
30
|
+
links: links,
|
31
|
+
active_page: "/authors/#{author.dirname}/#{template}")
|
32
|
+
write(output, "#@out_path/authors/#{author.dirname}/#{template}.html")
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def all_templates(root = '')
|
38
|
+
Dir["../../../../templates/#{root}**/[^_]*.haml".absolute_path].map {
|
39
|
+
|f| Pathname.new(f)
|
40
|
+
}.map { |f|
|
41
|
+
f.relative_path_from(Pathname.new('../../../../templates'.absolute_path)).sub_ext('')
|
42
|
+
}.map(&:to_s) - %w(layout)
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def write(output, write_file)
|
48
|
+
FileUtils.mkdir_p(File.dirname(write_file))
|
49
|
+
File.open(write_file, 'w') { |f| f.write output }
|
50
|
+
end
|
51
|
+
|
52
|
+
def links
|
53
|
+
{
|
54
|
+
general: 'general.html',
|
55
|
+
activity: 'activity/by_date.html',
|
56
|
+
authors: 'authors/best_authors.html',
|
57
|
+
files: 'files/by_date.html',
|
58
|
+
lines: 'lines/by_date.html'
|
59
|
+
}
|
60
|
+
end
|
61
|
+
|
62
|
+
def prepare_static_content
|
63
|
+
FileUtils.cp_r(Dir["../../../../templates/static/*".absolute_path], @out_path)
|
64
|
+
end
|
65
|
+
|
66
|
+
def prepare_assets
|
67
|
+
FileUtils.cp_r('../../../../templates/assets'.absolute_path, @out_path)
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
module GitStats
|
3
|
+
module StatsView
|
4
|
+
class ViewData
|
5
|
+
include ActionView::Helpers::TagHelper
|
6
|
+
include LazyHighCharts::LayoutHelper
|
7
|
+
attr_reader :repo
|
8
|
+
|
9
|
+
def initialize(repo)
|
10
|
+
@repo = repo
|
11
|
+
end
|
12
|
+
|
13
|
+
def charts
|
14
|
+
@charts ||= Charts::All.new(repo)
|
15
|
+
end
|
16
|
+
|
17
|
+
def render_partial(template_name, params = {})
|
18
|
+
Template.new(template_name).render(self, params)
|
19
|
+
end
|
20
|
+
|
21
|
+
def asset_path(asset, active_page)
|
22
|
+
Pathname.new("/assets/#{asset}").relative_path_from(Pathname.new("/#{active_page}").dirname)
|
23
|
+
end
|
24
|
+
|
25
|
+
def link_to(href, active_page)
|
26
|
+
Pathname.new("/#{href}").relative_path_from(Pathname.new("/#{active_page}").dirname)
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
describe ByFieldFinder do
|
5
|
+
let(:sut) { [double(field1: 'aa', field2: 'bb'), double(field1: 'cc', field2: 'bb'), double(field1: 'aa', field2: 'dd')].extend(ByFieldFinder) }
|
6
|
+
|
7
|
+
[
|
8
|
+
{field: :field1, search_value: 'aa', matching_index: 0},
|
9
|
+
{field: :field1, search_value: 'cc', matching_index: 1},
|
10
|
+
{field: :field2, search_value: 'bb', matching_index: 0},
|
11
|
+
{field: :field2, search_value: 'dd', matching_index: 2},
|
12
|
+
].each do |test_params|
|
13
|
+
it 'should return first matching object' do
|
14
|
+
sut.send("by_#{test_params[:field]}", test_params[:search_value]).should == sut[test_params[:matching_index]]
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'should return nil if no object matches' do
|
19
|
+
sut.by_field1('xx').should == nil
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'should throw exception if elements doesnt respond to given field' do
|
23
|
+
expect { sut.by_non_existing_field }.to raise_error
|
24
|
+
end
|
25
|
+
end
|
data/spec/factories.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
FactoryGirl.define do
|
3
|
+
initialize_with { new(attributes) }
|
4
|
+
|
5
|
+
factory :repo, class: GitStats::GitData::Repo do
|
6
|
+
path "repo_path"
|
7
|
+
factory :test_repo do
|
8
|
+
path 'spec/integration/test_repo'
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
factory :author, class: GitStats::GitData::Author do
|
13
|
+
sequence(:name) { |i| "author#{i}" }
|
14
|
+
sequence(:email) { |i| "author#{i}@gmail.com" }
|
15
|
+
association :repo, strategy: :build
|
16
|
+
end
|
17
|
+
|
18
|
+
factory :commit, class: GitStats::GitData::Commit do
|
19
|
+
sequence(:sha) { |i| i }
|
20
|
+
sequence(:stamp) { |i| i }
|
21
|
+
sequence(:date) { |i| Date.new(i) }
|
22
|
+
association :repo, strategy: :build
|
23
|
+
association :author, strategy: :build
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
describe GitStats::GitData::Activity do
|
5
|
+
let(:dates) { [
|
6
|
+
'10.05.2012 12:37',
|
7
|
+
'10.05.2012 13:53',
|
8
|
+
'06.05.2012 13:23',
|
9
|
+
'15.06.2011 15:02',
|
10
|
+
'27.09.2011 15:34'
|
11
|
+
] }
|
12
|
+
let(:commits) { dates.map { |d| GitStats::GitData::Commit.new(:date => DateTime.parse(d)) } }
|
13
|
+
let(:activity) { GitStats::GitData::Activity.new(commits) }
|
14
|
+
|
15
|
+
it 'by_hour should count commits by hour' do
|
16
|
+
activity.by_hour.should == {12 => 1, 13 => 2, 15 => 2}
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'by_wday should count commits by day of week where 0 = sunday, 1 = monday, ...' do
|
20
|
+
activity.by_wday.should == {0 => 1, 2 => 1, 3 => 1, 4 => 2}
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'by_wday_hour should count commits by day of week and by hour' do
|
24
|
+
activity.by_wday_hour.should == {0 => {13 => 1}, 2 => {15 => 1}, 3 => {15 => 1}, 4 => {12 => 1, 13 => 1}}
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'by_month should count commits by month' do
|
28
|
+
activity.by_month.should == {5 => 3, 6 => 1, 9 => 1}
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'by_year should count commits by year' do
|
32
|
+
activity.by_year.should == {2011 => 2, 2012 => 3}
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'by_year_month should count commits by day of year and by month' do
|
36
|
+
activity.by_year_month.should == {2011 => {6 => 1, 9 => 1}, 2012 => {5 => 3}}
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
describe GitStats::GitData::Author do
|
5
|
+
let(:repo) { build(:repo) }
|
6
|
+
let(:author) { build(:author, repo: repo) }
|
7
|
+
let(:other_author) { build(:author, repo: repo) }
|
8
|
+
let(:my_commits) { 10.times.map { |i| double("my_commit #{i}", author: author, short_stat: double("my_short_stat #{i}", insertions: 5, deletions: 10)) } }
|
9
|
+
let(:other_commits) { 10.times.map { |i| double("other_commit #{i}", author: other_author) } }
|
10
|
+
|
11
|
+
before { repo.stub(:commits => my_commits + other_commits) }
|
12
|
+
|
13
|
+
it 'commits should give repo commits filtered to this author' do
|
14
|
+
author.commits.should == my_commits
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'should count lines added from short stat' do
|
18
|
+
author.insertions.should == 50
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'should count lines deleted from short stat' do
|
22
|
+
author.deletions.should == 100
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
describe GitStats::GitData::Blob do
|
5
|
+
let(:repo) { double }
|
6
|
+
let(:png_blob) { GitStats::GitData::Blob.new(filename: 'abc.png', sha: 'hash_png', repo: repo) }
|
7
|
+
let(:txt_blob) { GitStats::GitData::Blob.new(filename: 'abc.txt', sha: 'hash_txt', repo: repo) }
|
8
|
+
|
9
|
+
it 'should return 0 as lines count when files is binary' do
|
10
|
+
png_blob.should_receive(:binary?).and_return true
|
11
|
+
png_blob.lines_count.should == 0
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'should return actual lines count when files is not binary' do
|
15
|
+
txt_blob.should_receive(:binary?).and_return false
|
16
|
+
repo.should_receive(:run).with("git cat-file blob hash_txt | wc -l").and_return 42
|
17
|
+
txt_blob.lines_count.should == 42
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'should invoke grep to check if file is binary' do
|
21
|
+
repo.should_receive(:run).with("git cat-file blob hash_png | grep -m 1 '^'").and_return "Binary file matches"
|
22
|
+
png_blob.should be_binary
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
describe GitStats::CLI do
|
5
|
+
let(:repo_path) { 'repo_path' }
|
6
|
+
let(:out_path) { 'out_path' }
|
7
|
+
|
8
|
+
it 'should invoke generator with console arguments given' do
|
9
|
+
generator = double('generator')
|
10
|
+
GitStats::Generator.should_receive(:new).with(repo_path, out_path).and_return(generator)
|
11
|
+
generator.should_receive(:render_all)
|
12
|
+
|
13
|
+
subject.start(repo_path, out_path)
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'should raise error when 2 arguments are not given' do
|
17
|
+
expect { subject.start("only one argument") }.to raise_error
|
18
|
+
expect { subject.start("too", "much", "arguments") }.to raise_error
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
describe GitStats::GitData::Repo do
|
5
|
+
let(:repo) { build(:repo) }
|
6
|
+
|
7
|
+
describe 'command observers' do
|
8
|
+
context 'should be invoked after every command' do
|
9
|
+
it 'should accept block' do
|
10
|
+
command_runner = double('command_runner')
|
11
|
+
repo = build(:repo, command_runner: command_runner)
|
12
|
+
|
13
|
+
observer = double('observer')
|
14
|
+
repo.add_command_observer { |command, result| observer.invoked(command, result) }
|
15
|
+
command_runner.should_receive(:run).with(repo.path, 'aa').and_return('bb')
|
16
|
+
observer.should_receive(:invoked).with('aa', 'bb')
|
17
|
+
|
18
|
+
repo.run('aa')
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'should accept Proc' do
|
22
|
+
command_runner = double('command_runner')
|
23
|
+
repo = build(:repo, command_runner: command_runner)
|
24
|
+
|
25
|
+
observer = double('observer')
|
26
|
+
repo.add_command_observer(observer)
|
27
|
+
command_runner.should_receive(:run).with(repo.path, 'aa').and_return('bb')
|
28
|
+
observer.should_receive(:call).with('aa', 'bb')
|
29
|
+
|
30
|
+
repo.run('aa')
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
describe GitStats::GitData::Repo do
|
5
|
+
let(:repo) { build(:repo) }
|
6
|
+
|
7
|
+
describe 'commit range' do
|
8
|
+
it 'should return HEAD by default' do
|
9
|
+
repo.commit_range.should == 'HEAD'
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'should return last_commit if it was given' do
|
13
|
+
repo = build(:repo, last_commit_sha: 'abc')
|
14
|
+
repo.commit_range.should == 'abc'
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'should return range from first_commit to HEAD if first_commit was given' do
|
18
|
+
repo = build(:repo, first_commit_sha: 'abc')
|
19
|
+
repo.commit_range.should == 'abc..HEAD'
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'should return range from first to last commit if both were given' do
|
23
|
+
repo = build(:repo, first_commit_sha: 'abc', last_commit_sha: 'def')
|
24
|
+
repo.commit_range.should == 'abc..def'
|
25
|
+
end
|
26
|
+
|
27
|
+
context 'git commands using range' do
|
28
|
+
let(:repo) { build(:repo, first_commit_sha: 'abc', last_commit_sha: 'def') }
|
29
|
+
|
30
|
+
it 'should affect authors command' do
|
31
|
+
repo.should_receive(:run).with('git shortlog -se abc..def').and_return("")
|
32
|
+
repo.authors
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'should affect commits command' do
|
36
|
+
repo.should_receive(:run).with("git rev-list --pretty=format:'%h|%at|%ai|%aE' abc..def | grep -v commit").and_return("")
|
37
|
+
repo.commits
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'should affect project version command' do
|
41
|
+
repo.should_receive(:run).with('git rev-parse --short abc..def').and_return("")
|
42
|
+
repo.project_version
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
describe GitStats::GitData::Commit do
|
5
|
+
let(:commit) { build(:commit, sha: 'abc') }
|
6
|
+
|
7
|
+
describe 'git output parsing' do
|
8
|
+
context 'parsing git ls-tree output' do
|
9
|
+
before {
|
10
|
+
commit.repo.should_receive(:run).with('git ls-tree -r abc').and_return("100644 blob 5ade7ad51a75ee7db4eb06cecd3918d38134087d lib/git_stats/git_data/commit.rb
|
11
|
+
100644 blob db01e94677a8f72289848e507a52a43de2ea109a lib/git_stats/git_data/repo.rb
|
12
|
+
100644 blob 1463eacb3ac9f95f21f360f1eb935a84a9ee0895 templates/index.haml
|
13
|
+
100644 blob 31d8b960a67f195bdedaaf9e7aa70b2389f3f1a8 templates/assets/bootstrap/css/bootstrap.min.css
|
14
|
+
") }
|
15
|
+
|
16
|
+
it 'should be parsed to files' do
|
17
|
+
commit.files.should == [
|
18
|
+
GitStats::GitData::Blob.new(repo: commit.repo, sha: "5ade7ad51a75ee7db4eb06cecd3918d38134087d", filename: "lib/git_stats/git_data/commit.rb"),
|
19
|
+
GitStats::GitData::Blob.new(repo: commit.repo, sha: "db01e94677a8f72289848e507a52a43de2ea109a", filename: "lib/git_stats/git_data/repo.rb"),
|
20
|
+
GitStats::GitData::Blob.new(repo: commit.repo, sha: "1463eacb3ac9f95f21f360f1eb935a84a9ee0895", filename: "templates/index.haml"),
|
21
|
+
GitStats::GitData::Blob.new(repo: commit.repo, sha: "31d8b960a67f195bdedaaf9e7aa70b2389f3f1a8", filename: "templates/assets/bootstrap/css/bootstrap.min.css"),
|
22
|
+
]
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'should group files by extension' do
|
26
|
+
commit.files_by_extension.should == {'.rb' => [
|
27
|
+
GitStats::GitData::Blob.new(repo: commit.repo, sha: "5ade7ad51a75ee7db4eb06cecd3918d38134087d", filename: "lib/git_stats/git_data/commit.rb"),
|
28
|
+
GitStats::GitData::Blob.new(repo: commit.repo, sha: "db01e94677a8f72289848e507a52a43de2ea109a", filename: "lib/git_stats/git_data/repo.rb")
|
29
|
+
], '.haml' => [
|
30
|
+
GitStats::GitData::Blob.new(repo: commit.repo, sha: "1463eacb3ac9f95f21f360f1eb935a84a9ee0895", filename: "templates/index.haml")
|
31
|
+
], '.css' => [
|
32
|
+
GitStats::GitData::Blob.new(repo: commit.repo, sha: "31d8b960a67f195bdedaaf9e7aa70b2389f3f1a8", filename: "templates/assets/bootstrap/css/bootstrap.min.css")
|
33
|
+
]
|
34
|
+
}
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'should count lines by extension excluding empty or binary files' do
|
38
|
+
GitStats::GitData::Blob.should_receive(:new).and_return(
|
39
|
+
double(lines_count: 40, extension: '.rb'),
|
40
|
+
double(lines_count: 60, extension: '.rb'),
|
41
|
+
double(lines_count: 0, extension: '.haml'),
|
42
|
+
double(lines_count: 20, extension: '.css'),
|
43
|
+
)
|
44
|
+
commit.lines_by_extension.should == {'.rb' => 100, '.css' => 20}
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|