git_stats 1.0.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/.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,46 @@
|
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
|
2
|
+
require 'spec_helper'
|
|
3
|
+
|
|
4
|
+
describe GitStats::Generator do
|
|
5
|
+
let(:repo_path) { 'repo_path' }
|
|
6
|
+
let(:out_path) { 'out_path' }
|
|
7
|
+
let(:generator) { GitStats::Generator.new(repo_path, out_path) }
|
|
8
|
+
|
|
9
|
+
before { Dir.stub!(:exists? => true) }
|
|
10
|
+
|
|
11
|
+
it 'should raise exception if given repo path is not a git repository' do
|
|
12
|
+
Dir.should_receive(:exists?).with("#{repo_path}/.git").and_return(false)
|
|
13
|
+
expect { generator }.to raise_error(ArgumentError)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
it "should raise exception if given out directory doesn't exist" do
|
|
17
|
+
Dir.should_receive(:exists?).with(out_path).and_return(false)
|
|
18
|
+
expect { generator }.to raise_error(ArgumentError)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
it 'should pass command observer to repo' do
|
|
22
|
+
repo = double('repo')
|
|
23
|
+
GitStats::GitData::Repo.should_receive(:new).with(path: repo_path).and_return(repo)
|
|
24
|
+
|
|
25
|
+
generator = GitStats::Generator.new(repo_path, out_path)
|
|
26
|
+
|
|
27
|
+
observer = double('observer')
|
|
28
|
+
repo.should_receive(:add_command_observer).with(observer)
|
|
29
|
+
|
|
30
|
+
generator.add_command_observer observer
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
it 'should render all templates with view data for this repo' do
|
|
34
|
+
repo = double('repo')
|
|
35
|
+
GitStats::GitData::Repo.should_receive(:new).with(path: repo_path).and_return(repo)
|
|
36
|
+
|
|
37
|
+
view_data = double('view_data')
|
|
38
|
+
GitStats::StatsView::ViewData.should_receive(:new).with(repo).and_return(view_data)
|
|
39
|
+
|
|
40
|
+
view = double('view')
|
|
41
|
+
GitStats::StatsView::View.should_receive(:new).with(view_data, out_path).and_return(view)
|
|
42
|
+
view.should_receive(:render_all)
|
|
43
|
+
|
|
44
|
+
generator.render_all
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
|
2
|
+
require 'spec_helper'
|
|
3
|
+
|
|
4
|
+
describe GitStats::GitData::Repo do
|
|
5
|
+
let(:repo) { build(:repo) }
|
|
6
|
+
|
|
7
|
+
describe 'git output parsing' do
|
|
8
|
+
context 'invoking authors command' do
|
|
9
|
+
before do
|
|
10
|
+
repo.should_receive(:run).with('git shortlog -se HEAD').and_return(" 156 John Doe <john.doe@gmail.com>
|
|
11
|
+
53 Joe Doe <joe.doe@gmail.com>
|
|
12
|
+
")
|
|
13
|
+
end
|
|
14
|
+
it 'should parse git shortlog output to authors hash' do
|
|
15
|
+
repo.authors.should == [
|
|
16
|
+
build(:author, repo: repo, name: "John Doe", email: "john.doe@gmail.com"),
|
|
17
|
+
build(:author, repo: repo, name: "Joe Doe", email: "joe.doe@gmail.com")
|
|
18
|
+
]
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
it 'should parse git revlist output to date sorted commits array' do
|
|
22
|
+
repo.should_receive(:run).with("git rev-list --pretty=format:'%h|%at|%ai|%aE' HEAD | grep -v commit").and_return(
|
|
23
|
+
"e4412c3|1348603824|2012-09-25 22:10:24 +0200|john.doe@gmail.com
|
|
24
|
+
ce34874|1347482927|2012-09-12 22:48:47 +0200|joe.doe@gmail.com
|
|
25
|
+
5eab339|1345835073|2012-08-24 21:04:33 +0200|john.doe@gmail.com
|
|
26
|
+
")
|
|
27
|
+
|
|
28
|
+
repo.commits.should == [
|
|
29
|
+
GitStats::GitData::Commit.new(
|
|
30
|
+
repo: repo, sha: "5eab339", stamp: "1345835073", date: DateTime.parse("2012-08-24 21:04:33 +0200"),
|
|
31
|
+
author: repo.authors.by_email("john.doe@gmail.com")),
|
|
32
|
+
GitStats::GitData::Commit.new(
|
|
33
|
+
repo: repo, sha: "ce34874", stamp: "1347482927", date: DateTime.parse("2012-09-12 22:48:47 +0200"),
|
|
34
|
+
author: repo.authors.by_email("joe.doe@gmail.com")),
|
|
35
|
+
GitStats::GitData::Commit.new(
|
|
36
|
+
repo: repo, sha: "e4412c3", stamp: "1348603824", date: DateTime.parse("2012-09-25 22:10:24 +0200"),
|
|
37
|
+
author: repo.authors.by_email("john.doe@gmail.com"))
|
|
38
|
+
]
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
it 'should parse git rev-parse command to project version' do
|
|
42
|
+
repo.should_receive(:run).with('git rev-parse --short HEAD').and_return('xyz')
|
|
43
|
+
repo.project_version.should == 'xyz'
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
|
2
|
+
require 'spec_helper'
|
|
3
|
+
|
|
4
|
+
describe GitStats::GitData::ShortStat do
|
|
5
|
+
let(:commit) { build(:commit, sha: 'abc') }
|
|
6
|
+
|
|
7
|
+
describe 'git output parsing' do
|
|
8
|
+
context 'parsing git show output' do
|
|
9
|
+
[
|
|
10
|
+
{content: '2 files changed, 17 insertions(+), 3 deletions(-)', expect: [2, 17, 3]},
|
|
11
|
+
{content: '1 file changed, 1 insertion(+), 1 deletion(-)', expect: [1, 1, 1]},
|
|
12
|
+
{content: '2 files changed, 3 deletions(-)', expect: [2, 0, 3]},
|
|
13
|
+
{content: '2 files changed, 5 insertions(+)', expect: [2, 5, 0]},
|
|
14
|
+
{content: '', expect: [0, 0, 0]},
|
|
15
|
+
].each do |test|
|
|
16
|
+
it "#{test[:content]} parsing" do
|
|
17
|
+
commit.repo.should_receive(:run).with("git show --shortstat --oneline abc").and_return("abc some commit\n#{test[:content]}")
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
commit.short_stat.should be_a(GitStats::GitData::ShortStat)
|
|
21
|
+
commit.short_stat.files_changed.should == test[:expect][0]
|
|
22
|
+
commit.short_stat.insertions.should == test[:expect][1]
|
|
23
|
+
commit.short_stat.deletions.should == test[:expect][2]
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
|
2
|
+
require 'spec_helper'
|
|
3
|
+
|
|
4
|
+
describe Hash do
|
|
5
|
+
context 'to_key_indexed_array' do
|
|
6
|
+
it 'should convert hash to array using keys as indexes' do
|
|
7
|
+
hash = {1 => 'x', 2 => 1, 5 => 'a'}
|
|
8
|
+
hash.to_key_indexed_array.should == [nil, 'x', 1, nil, nil, 'a']
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
it 'should throw exception if not all of the keys are numbers' do
|
|
12
|
+
hash = {1 => 'x', 'b' => 2}
|
|
13
|
+
expect { hash.to_key_indexed_array }.to raise_error(ArgumentError)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
context 'should take optional min_size and default parameters' do
|
|
17
|
+
let(:hash) { {1 => 'x', 2 => 1, 5 => 'a'} }
|
|
18
|
+
it 'should fill array with defaults up to min_size' do
|
|
19
|
+
hash.to_key_indexed_array(min_size: 8, default: 0).should == [0, 'x', 1, 0, 0, 'a', 0, 0]
|
|
20
|
+
end
|
|
21
|
+
it 'should use default value where key is not in hash' do
|
|
22
|
+
hash.to_key_indexed_array(min_size: 2, default: 0).should == [0, 'x', 1, 0, 0, 'a']
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
|
2
|
+
require 'integration/shared'
|
|
3
|
+
|
|
4
|
+
describe GitStats::GitData::Activity do
|
|
5
|
+
include_context "shared"
|
|
6
|
+
|
|
7
|
+
let(:activity) { repo.activity }
|
|
8
|
+
|
|
9
|
+
it 'should count commits by hour' do
|
|
10
|
+
activity.by_hour.should == {10 => 4, 12 => 3, 13 => 1, 15 => 1, 17 => 1}
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
it 'should count commits by day of week' do
|
|
14
|
+
activity.by_wday.should == {0 => 3, 3 => 1, 5 => 5, 6 => 1}
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
it 'should count commits by day of week and hour' do
|
|
18
|
+
activity.by_wday_hour.should == {0 => {12 => 2, 13 => 1}, 3 => {15 => 1}, 5 => {10 => 4, 17 => 1}, 6 => {12 => 1}}
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
it 'should count commits by month' do
|
|
22
|
+
activity.by_month.should == {10 => 10}
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
it 'should count commits by year' do
|
|
26
|
+
activity.by_year.should == {2012 => 10}
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
it 'should count commits by year and month' do
|
|
30
|
+
activity.by_year_month.should == {2012 => {10 => 10}}
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
end
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
|
2
|
+
require 'integration/shared'
|
|
3
|
+
|
|
4
|
+
describe GitStats::GitData::Activity do
|
|
5
|
+
include_context "shared"
|
|
6
|
+
|
|
7
|
+
let(:tg) { repo.authors.by_email('tomasz.gieniusz@gmail.com') }
|
|
8
|
+
let(:jd) { repo.authors.by_email('john.doe@gmail.com') }
|
|
9
|
+
|
|
10
|
+
it 'should filter commits to author' do
|
|
11
|
+
tg.commits.map(&:sha).should =~ %w(b3b4f81 d60b5ec ab47ef8 2c11f5e c87ecf9 b621a5d 4e7d0e9 872955c)
|
|
12
|
+
jd.commits.map(&:sha).should =~ %w(fd66657 81e8bef)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
context 'activity' do
|
|
16
|
+
it 'should count commits by hour' do
|
|
17
|
+
tg.activity.by_hour.should == {10 => 4, 12 => 2, 13 => 1, 17 => 1}
|
|
18
|
+
jd.activity.by_hour.should == {12 => 1, 15 => 1}
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
it 'should count commits by day of week' do
|
|
22
|
+
tg.activity.by_wday.should == {0 => 2, 5 => 5, 6 => 1}
|
|
23
|
+
jd.activity.by_wday.should == {0 => 1, 3 => 1}
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
it 'should count commits by day of week and hour' do
|
|
27
|
+
tg.activity.by_wday_hour.should == {0 => {12 => 1, 13 => 1}, 5 => {10 => 4, 17 => 1}, 6 => {12 => 1}}
|
|
28
|
+
jd.activity.by_wday_hour.should == {0 => {12 => 1}, 3 => {15 => 1}}
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
it 'should count commits by month' do
|
|
32
|
+
tg.activity.by_month.should == {10 => 8}
|
|
33
|
+
jd.activity.by_month.should == {10 => 2}
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
it 'should count commits by year' do
|
|
37
|
+
tg.activity.by_year.should == {2012 => 8}
|
|
38
|
+
jd.activity.by_year.should == {2012 => 2}
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
it 'should count commits by year and month' do
|
|
42
|
+
tg.activity.by_year_month.should == {2012 => {10 => 8}}
|
|
43
|
+
jd.activity.by_year_month.should == {2012 => {10 => 2}}
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
it 'should count commits_sum_by_date' do
|
|
47
|
+
tg.commits_sum_by_date.map { |d, s| d }.should == tg_commit_dates
|
|
48
|
+
tg.commits_sum_by_date.map { |d, s| s }.should == [1, 2, 3, 4, 5, 6, 7, 8]
|
|
49
|
+
jd.commits_sum_by_date.map { |d, s| d }.should == jd_commit_dates
|
|
50
|
+
jd.commits_sum_by_date.map { |d, s| s }.should == [1, 2]
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
it 'should count insertions_by_date' do
|
|
54
|
+
tg.insertions_by_date.map { |d, s| d }.should == tg_commit_dates
|
|
55
|
+
tg.insertions_by_date.map { |d, s| s }.should == [4, 9, 14, 15, 20, 1020, 1021, 1021]
|
|
56
|
+
jd.insertions_by_date.map { |d, s| d }.should == jd_commit_dates
|
|
57
|
+
jd.insertions_by_date.map { |d, s| s }.should == [3, 103]
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
it 'should count deletions_by_date' do
|
|
61
|
+
tg.deletions_by_date.map { |d, s| d }.should == tg_commit_dates
|
|
62
|
+
tg.deletions_by_date.map { |d, s| s }.should == [0, 0, 4, 4, 9, 9, 10, 10]
|
|
63
|
+
jd.deletions_by_date.map { |d, s| d }.should == jd_commit_dates
|
|
64
|
+
jd.deletions_by_date.map { |d, s| s }.should == [0, 0]
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
|
2
|
+
require 'integration/shared'
|
|
3
|
+
|
|
4
|
+
describe GitStats::GitData::Repo do
|
|
5
|
+
include_context "shared"
|
|
6
|
+
|
|
7
|
+
it 'should gather all files in repo' do
|
|
8
|
+
repo.files.map(&:filename).should =~ %w(long_second.haml long.txt second.txt test2.rb test.rb test.txt)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
it 'should retrieve correct file content for old file' do
|
|
12
|
+
repo.commits.by_sha('c87ecf9').files.by_filename('test.txt').content.should == "bb
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
test
|
|
17
|
+
"
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
it 'should retrieve correct file content for the newest file' do
|
|
21
|
+
file = repo.files.by_filename('test.txt')
|
|
22
|
+
file.content.should == "bb
|
|
23
|
+
|
|
24
|
+
testtest
|
|
25
|
+
|
|
26
|
+
test
|
|
27
|
+
"
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
end
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
|
2
|
+
require 'integration/shared'
|
|
3
|
+
|
|
4
|
+
describe GitStats::GitData::Repo do
|
|
5
|
+
include_context "shared"
|
|
6
|
+
|
|
7
|
+
it 'should gather all authors' do
|
|
8
|
+
repo.authors.should =~ expected_authors
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
it 'should calculate correct commits period' do
|
|
12
|
+
repo.commits_period.should == [DateTime.parse('2012-10-19 10:44:34 +0200'), DateTime.parse('2012-10-26 17:05:25 +0200')]
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
it 'should gather all commits sorted by date' do
|
|
16
|
+
repo.commits.map(&:sha).should =~ %w(b3b4f81 d60b5ec ab47ef8 2c11f5e c87ecf9 b621a5d fd66657 81e8bef 4e7d0e9 872955c)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
it 'should return project name from dir' do
|
|
20
|
+
repo.project_name.should == 'test_repo'
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
it 'should return project version as last commit hash' do
|
|
24
|
+
repo.project_version.should == '872955c'
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
it 'should count files in repo' do
|
|
28
|
+
repo.files_count.should == 6
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
it 'should count files by date' do
|
|
32
|
+
repo.files_count_by_date.keys.should == commit_dates
|
|
33
|
+
repo.files_count_by_date.values.should == [1, 2, 2, 3, 3, 4, 5, 5, 6, 6]
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
it 'should count lines by date' do
|
|
37
|
+
repo.lines_count_by_date.keys.should == commit_dates
|
|
38
|
+
repo.files_count_by_date.values.should == [1, 2, 2, 3, 3, 4, 5, 5, 6, 6]
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
it 'should count all lines in repo' do
|
|
42
|
+
repo.lines_count.should == 1114
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
it 'should count files by extension in repo' do
|
|
46
|
+
repo.files_by_extension_count.should == {'.haml' => 1, '.txt' => 3, '.rb' => 2}
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
it 'should count lines by extension in repo' do
|
|
50
|
+
repo.lines_by_extension.should == {'.haml' => 100, '.txt' => 1008, '.rb' => 6}
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
it 'should count commits_count_by_author' do
|
|
54
|
+
repo.commits_count_by_author.keys.should == expected_authors
|
|
55
|
+
repo.commits_count_by_author.values.should == [8, 2]
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
it 'should count lines_added_by_author' do
|
|
59
|
+
repo.insertions_by_author.keys.should == expected_authors
|
|
60
|
+
repo.insertions_by_author.values.should == [1021, 103]
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
it 'should count lines_deleted_by_author' do
|
|
64
|
+
repo.deletions_by_author.keys.should == expected_authors
|
|
65
|
+
repo.deletions_by_author.values.should == [10, 0]
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
|
2
|
+
require 'spec_helper'
|
|
3
|
+
|
|
4
|
+
shared_context "shared" do
|
|
5
|
+
let(:repo) { build(:test_repo, last_commit_sha: '872955c') }
|
|
6
|
+
let(:commit_dates) { [
|
|
7
|
+
DateTime.parse('2012-10-19 10:44:34 +0200'),
|
|
8
|
+
DateTime.parse('2012-10-19 10:46:10 +0200'),
|
|
9
|
+
DateTime.parse('2012-10-19 10:46:56 +0200'),
|
|
10
|
+
DateTime.parse('2012-10-19 10:47:35 +0200'),
|
|
11
|
+
DateTime.parse('2012-10-20 12:49:02 +0200'),
|
|
12
|
+
DateTime.parse('2012-10-21 12:49:02 +0200'),
|
|
13
|
+
DateTime.parse('2012-10-21 12:54:02 +0200'),
|
|
14
|
+
DateTime.parse('2012-10-21 13:20:00 +0200'),
|
|
15
|
+
DateTime.parse('2012-10-24 15:49:02 +0200'),
|
|
16
|
+
DateTime.parse('2012-10-26 17:05:25 +0200'),
|
|
17
|
+
] }
|
|
18
|
+
let(:tg_commit_dates) { [
|
|
19
|
+
DateTime.parse('2012-10-19 10:44:34 +0200'),
|
|
20
|
+
DateTime.parse('2012-10-19 10:46:10 +0200'),
|
|
21
|
+
DateTime.parse('2012-10-19 10:46:56 +0200'),
|
|
22
|
+
DateTime.parse('2012-10-19 10:47:35 +0200'),
|
|
23
|
+
DateTime.parse('2012-10-20 12:49:02 +0200'),
|
|
24
|
+
DateTime.parse('2012-10-21 12:49:02 +0200'),
|
|
25
|
+
DateTime.parse('2012-10-21 13:20:00 +0200'),
|
|
26
|
+
DateTime.parse('2012-10-26 17:05:25 +0200'),
|
|
27
|
+
] }
|
|
28
|
+
let(:jd_commit_dates) { [
|
|
29
|
+
DateTime.parse('2012-10-21 12:54:02 +0200'),
|
|
30
|
+
DateTime.parse('2012-10-24 15:49:02 +0200'),
|
|
31
|
+
] }
|
|
32
|
+
|
|
33
|
+
let(:expected_authors) { [
|
|
34
|
+
build(:author, repo: repo, name: "Tomasz Gieniusz", email: "tomasz.gieniusz@gmail.com"),
|
|
35
|
+
build(:author, repo: repo, name: "John Doe", email: "john.doe@gmail.com"),
|
|
36
|
+
] }
|
|
37
|
+
end
|
data/spec/spec_helper.rb
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
.tabbable.tabs-left
|
|
2
|
+
%ul.nav.nav-tabs
|
|
3
|
+
%li{class: page == :activity_by_date ? "active" : "" }
|
|
4
|
+
%a{href: "by_date.html"}= :activity_by_date.t
|
|
5
|
+
%li{class: page == :hour_of_day ? "active" : "" }
|
|
6
|
+
%a{href: "hour_of_day.html"}= :hour_of_day.t
|
|
7
|
+
%li{class: page == :day_of_week ? "active" : "" }
|
|
8
|
+
%a{href: "day_of_week.html"}= :day_of_week.t
|
|
9
|
+
%li{class: page == :hour_of_week ? "active" : "" }
|
|
10
|
+
%a{href: "hour_of_week.html"}= :hour_of_week.t
|
|
11
|
+
%li{class: page == :month_of_year ? "active" : "" }
|
|
12
|
+
%a{href: "month_of_year.html"}= :month_of_year.t
|
|
13
|
+
%li{class: page == :year ? "active" : "" }
|
|
14
|
+
%a{href: "year.html"}= :year.t
|
|
15
|
+
%li{class: page == :year_month ? "active" : "" }
|
|
16
|
+
%a{href: "year_month.html"}= :year_month.t
|
|
17
|
+
|
|
18
|
+
.tab-content
|
|
19
|
+
.tab-pane.active
|
|
20
|
+
.page-header.pagination-centered
|
|
21
|
+
%h1= page.t
|
|
22
|
+
%h3= "#{author.respond_to?(:name) ? author.name : ""} #{author.respond_to?(:email) ? "<#{author.email}>" : ""}"
|
|
23
|
+
- if page == :activity_by_date
|
|
24
|
+
= high_stock("charts.activity_by_date", charts.activity_by_date(author))
|
|
25
|
+
|
|
26
|
+
- elsif page == :hour_of_day
|
|
27
|
+
%table{:class => "table table-bordered table-condensed"}
|
|
28
|
+
%tr
|
|
29
|
+
%th= :hour.t
|
|
30
|
+
- (0..23).each do |h|
|
|
31
|
+
%th= h
|
|
32
|
+
%tr
|
|
33
|
+
%th= :commits.t
|
|
34
|
+
- author.activity.by_hour_array.each do |commits|
|
|
35
|
+
%td= commits
|
|
36
|
+
%tr
|
|
37
|
+
%th= :percentage.t
|
|
38
|
+
- author.activity.by_hour_array.each do |commits|
|
|
39
|
+
%td= (commits * 100.0 / author.activity.by_hour_array.sum).round(1)
|
|
40
|
+
= high_chart("charts.activity_by_hour", charts.activity_by_hour(author))
|
|
41
|
+
|
|
42
|
+
- elsif page == :day_of_week
|
|
43
|
+
%table{:class => "table table-bordered table-condensed"}
|
|
44
|
+
%tr
|
|
45
|
+
%th= :day.t
|
|
46
|
+
- I18n.t('date.abbr_day_names').each do |d|
|
|
47
|
+
%th= d
|
|
48
|
+
%tr
|
|
49
|
+
%th= :commits.t
|
|
50
|
+
- author.activity.by_wday_array.each do |commits|
|
|
51
|
+
%td= commits
|
|
52
|
+
%tr
|
|
53
|
+
%th= :percentage.t
|
|
54
|
+
- author.activity.by_wday_array.each do |commits|
|
|
55
|
+
%td= (commits * 100.0 / author.activity.by_wday_array.sum).round(1)
|
|
56
|
+
= high_chart("charts.activity_by_wday", charts.activity_by_wday(author))
|
|
57
|
+
|
|
58
|
+
- elsif page == :hour_of_week
|
|
59
|
+
%table{:class => "table table-bordered table-condensed"}
|
|
60
|
+
%tr
|
|
61
|
+
%th
|
|
62
|
+
- (0..23).each do |h|
|
|
63
|
+
%th= h
|
|
64
|
+
- max = author.activity.by_wday_hour.values.map {|h| h.values.empty? ? 0 : h.values.max }.max
|
|
65
|
+
- (0..6).each do |day|
|
|
66
|
+
%tr
|
|
67
|
+
%th= I18n.t('date.abbr_day_names')[day]
|
|
68
|
+
- (0..23).each do |hour|
|
|
69
|
+
- color = max ? "%02x" % (255 - author.activity.by_wday_hour[day][hour] * 100 / max) : "FF"
|
|
70
|
+
%td{style: "background-color: ##{color}#{color}#{color};"}= author.activity.by_wday_hour[day][hour]
|
|
71
|
+
|
|
72
|
+
- elsif page == :month_of_year
|
|
73
|
+
%table{:class => "table table-bordered table-condensed"}
|
|
74
|
+
%tr
|
|
75
|
+
%th= :month.t
|
|
76
|
+
- I18n.t('date.abbr_month_names')[1..-1].each do |m|
|
|
77
|
+
%th= m
|
|
78
|
+
%tr
|
|
79
|
+
%th= :commits.t
|
|
80
|
+
- author.activity.by_month_array.each do |commits|
|
|
81
|
+
%td= commits
|
|
82
|
+
%tr
|
|
83
|
+
%th= :percentage.t
|
|
84
|
+
- author.activity.by_month_array.each do |commits|
|
|
85
|
+
%td= (commits * 100.0 / author.activity.by_month_array.sum).round(1)
|
|
86
|
+
= high_chart("charts.activity_by_month", charts.activity_by_month(author))
|
|
87
|
+
|
|
88
|
+
- elsif page == :year
|
|
89
|
+
= high_chart("charts.activity_by_year", charts.activity_by_year(author))
|
|
90
|
+
|
|
91
|
+
- elsif page == :year_month
|
|
92
|
+
%table{:class => "table table-bordered table-condensed"}
|
|
93
|
+
%tr
|
|
94
|
+
%th
|
|
95
|
+
- I18n.t('date.abbr_month_names')[1..-1].each do |h|
|
|
96
|
+
%th= h
|
|
97
|
+
- author.activity.by_year_month.each do |year, months|
|
|
98
|
+
%tr
|
|
99
|
+
%th= year
|
|
100
|
+
- (1..12).each do |month|
|
|
101
|
+
%td= months[month]
|