renamed hash to sha && refactor

This commit is contained in:
Tomasz Gieniusz 2012-10-20 22:38:11 +02:00
parent 6d45e3fd57
commit 35d03d9392
17 changed files with 116 additions and 81 deletions

View File

@ -5,14 +5,14 @@ module GitStats
class Blob
include HashInitializable
attr_reader :repo, :hash, :filename
attr_reader :repo, :sha, :filename
def lines_count
@lines_count ||= binary? ? 0 : repo.run("git cat-file blob #{self.hash} | wc -l").to_i
@lines_count ||= binary? ? 0 : repo.run("git cat-file blob #{self.sha} | wc -l").to_i
end
def content
@content ||= repo.run("git cat-file blob #{self.hash}")
@content ||= repo.run("git cat-file blob #{self.sha}")
end
def extension
@ -20,15 +20,15 @@ module GitStats
end
def binary?
repo.run("git cat-file blob #{self.hash} | grep -m 1 '^'") =~ /Binary file/
repo.run("git cat-file blob #{self.sha} | grep -m 1 '^'") =~ /Binary file/
end
def to_s
"#{self.class} #@hash #@filename"
"#{self.class} #@sha #@filename"
end
def ==(other)
[self.repo, self.hash, self.filename] == [other.repo, other.hash, other.filename]
[self.repo, self.sha, self.filename] == [other.repo, other.sha, other.filename]
end
end

View File

@ -15,15 +15,15 @@ module GitStats
def parse_ls_tree(result, params)
result.lines.map do |line|
mode, type, hash, filename = line.scan(/(.*) (.*) (.*)\t(.*)/).first.map(&:strip)
{mode: mode, type: type, hash: hash, filename: filename}
mode, type, sha, filename = line.scan(/(.*) (.*) (.*)\t(.*)/).first.map(&:strip)
{mode: mode, type: type, sha: sha, filename: filename}
end
end
def parse_rev_list(result, params)
result.lines.map do |line|
hash, stamp, date, author_email = line.split('|').map(&:strip)
{hash: hash, stamp: stamp, date: date, author_email: author_email}
sha, stamp, date, author_email = line.split('|').map(&:strip)
{sha: sha, stamp: stamp, date: date, author_email: author_email}
end
end

View File

@ -5,14 +5,22 @@ module GitStats
class Commit
include HashInitializable
attr_reader :repo, :hash, :stamp, :date, :author
attr_reader :repo, :sha, :stamp, :date, :author
def files
@files ||= repo.run_and_parse("git ls-tree -r #{self.hash}").map do |file|
Blob.new(repo: repo, filename: file[:filename], hash: file[:hash])
@files ||= repo.run_and_parse("git ls-tree -r #{self.sha}").map do |file|
Blob.new(repo: repo, filename: file[:filename], sha: file[:sha])
end.extend(ByFieldFinder)
end
def binary_files
@binary_files ||= files.select { |f| f.binary? }
end
def text_files
@text_files ||= files - binary_files
end
def files_by_extension
@files_by_extension ||= files.inject({}) { |acc, f| acc[f.extension] ||= []; acc[f.extension] << f; acc }
end
@ -28,19 +36,11 @@ module GitStats
end
def files_count
@files_count ||= repo.run("git ls-tree -r --name-only #{self.hash} | wc -l").to_i
end
def binary_files_count
files.find_all { |f| f.binary? }.size
end
def text_files_count
files_count - binary_files_count
@files_count ||= repo.run("git ls-tree -r --name-only #{self.sha} | wc -l").to_i
end
def lines_count
@lines_count ||= repo.run("git diff --shortstat `git hash-object -t tree /dev/null` #{self.hash}").lines.map do |line|
@lines_count ||= repo.run("git diff --shortstat `git hash-object -t tree /dev/null` #{self.sha}").lines.map do |line|
line[/(\d+) insertions?/, 1].to_i
end.sum
end
@ -50,12 +50,12 @@ module GitStats
end
def to_s
"#{self.class} #@hash"
"#{self.class} #@sha"
end
def ==(other)
[self.repo, self.hash, self.stamp, self.date, self.author] ==
[other.repo, other.hash, other.stamp, other.date, other.author]
[self.repo, self.sha, self.stamp, self.date, self.author] ==
[other.repo, other.sha, other.stamp, other.date, other.author]
end
end
end

View File

@ -8,7 +8,7 @@ module GitStats
attr_reader :path
delegate :files, :files_by_extension, :files_by_extension_count, :lines_by_extension,
:files_count, :binary_files_count, :text_files_count, :lines_count, to: :last_commit
:files_count, :binary_files, :text_files, :lines_count, to: :last_commit
def initialize(params)
super(params)
@ -25,7 +25,7 @@ module GitStats
@commits ||= run_and_parse("git rev-list --pretty=format:'%h|%at|%ai|%aE' #{commit_range} | grep -v commit").map do |commit_line|
Commit.new(
repo: self,
hash: commit_line[:hash],
sha: commit_line[:sha],
stamp: commit_line[:stamp],
date: DateTime.parse(commit_line[:date]),
author: authors.by_email(commit_line[:author_email])
@ -74,11 +74,11 @@ module GitStats
end
def commit_range
@first_commit_hash ? "#@first_commit_hash..#{last_commit_hash}" : last_commit_hash
@first_commit_sha ? "#@first_commit_sha..#{last_commit_sha}" : last_commit_sha
end
def last_commit_hash
@last_commit_hash ||= 'HEAD'
def last_commit_sha
@last_commit_sha ||= 'HEAD'
end
def short_stats

View File

@ -14,7 +14,7 @@ module GitStats
private
def calculate_stat
stat_line = commit.repo.run("git show --shortstat --oneline #{commit.hash}").lines.to_a[1]
stat_line = commit.repo.run("git show --shortstat --oneline #{commit.sha}").lines.to_a[1]
if stat_line.blank?
@files_changed = @insertions = @deletions = 0
else

View File

@ -15,7 +15,7 @@ FactoryGirl.define do
end
factory :commit, class: GitStats::GitData::Commit do
sequence(:hash) { |i| i }
sequence(:sha) { |i| i }
sequence(:stamp) { |i| i }
sequence(:date) { |i| Date.new(i) }
association :repo, strategy: :build

View File

@ -4,8 +4,8 @@ describe GitStats::GitData::Author do
let(:repo) { build(:repo) }
let(:author) { build(:author, repo: repo) }
let(:other_author) { build(:author, repo: repo) }
let(:my_commits) { 10.times.map { |i| double("my_commit #{i}", :author => author) } }
let(:other_commits) { 10.times.map { |i| double("other_commit #{i}", :author => other_author) } }
let(:my_commits) { 10.times.map { |i| double("my_commit #{i}", author: author, short_stat: double("my_short_stat #{i}", insertions: 5, deletions: 10)) } }
let(:other_commits) { 10.times.map { |i| double("other_commit #{i}", author: other_author) } }
before { repo.stub(:commits => my_commits + other_commits) }
@ -13,5 +13,12 @@ describe GitStats::GitData::Author do
author.commits.should == my_commits
end
it 'should count lines added from short stat' do
author.lines_added.should == 50
end
it 'should count lines deleted from short stat' do
author.lines_deleted.should == 100
end
end

View File

@ -2,8 +2,8 @@ require 'spec_helper'
describe GitStats::GitData::Blob do
let(:repo) { double }
let(:png_blob) { GitStats::GitData::Blob.new(filename: 'abc.png', hash: 'hash_png', repo: repo) }
let(:txt_blob) { GitStats::GitData::Blob.new(filename: 'abc.txt', hash: 'hash_txt', repo: repo) }
let(:png_blob) { GitStats::GitData::Blob.new(filename: 'abc.png', sha: 'hash_png', repo: repo) }
let(:txt_blob) { GitStats::GitData::Blob.new(filename: 'abc.txt', sha: 'hash_txt', repo: repo) }
it 'should return 0 as lines count when files is binary' do
png_blob.should_receive(:binary?).and_return true

View File

@ -9,22 +9,22 @@ describe GitStats::GitData::Repo do
end
it 'should return last_commit if it was given' do
repo = build(:repo, last_commit_hash: 'abc')
repo = build(:repo, last_commit_sha: 'abc')
repo.commit_range.should == 'abc'
end
it 'should return range from first_commit to HEAD if first_commit was given' do
repo = build(:repo, first_commit_hash: 'abc')
repo = build(:repo, first_commit_sha: 'abc')
repo.commit_range.should == 'abc..HEAD'
end
it 'should return range from first to last commit if both were given' do
repo = build(:repo, first_commit_hash: 'abc', last_commit_hash: 'def')
repo = build(:repo, first_commit_sha: 'abc', last_commit_sha: 'def')
repo.commit_range.should == 'abc..def'
end
context 'git commands using range' do
let(:repo) { build(:repo, first_commit_hash: 'abc', last_commit_hash: 'def') }
let(:repo) { build(:repo, first_commit_sha: 'abc', last_commit_sha: 'def') }
it 'should affect authors command' do
repo.should_receive(:run).with('git shortlog -se abc..def').and_return("")

View File

@ -1,7 +1,7 @@
require 'spec_helper'
describe GitStats::GitData::Commit do
let(:commit) { build(:commit, hash: 'abc') }
let(:commit) { build(:commit, sha: 'abc') }
describe 'git output parsing' do
context 'parsing git ls-tree output' do
@ -14,26 +14,26 @@ describe GitStats::GitData::Commit do
it 'should be parsed to files' do
commit.files.should == [
GitStats::GitData::Blob.new(repo: commit.repo, hash: "5ade7ad51a75ee7db4eb06cecd3918d38134087d", filename: "lib/git_stats/git_data/commit.rb"),
GitStats::GitData::Blob.new(repo: commit.repo, hash: "db01e94677a8f72289848e507a52a43de2ea109a", filename: "lib/git_stats/git_data/repo.rb"),
GitStats::GitData::Blob.new(repo: commit.repo, hash: "1463eacb3ac9f95f21f360f1eb935a84a9ee0895", filename: "templates/activity.haml"),
GitStats::GitData::Blob.new(repo: commit.repo, hash: "31d8b960a67f195bdedaaf9e7aa70b2389f3f1a8", filename: "templates/assets/bootstrap/css/bootstrap.min.css"),
GitStats::GitData::Blob.new(repo: commit.repo, sha: "5ade7ad51a75ee7db4eb06cecd3918d38134087d", filename: "lib/git_stats/git_data/commit.rb"),
GitStats::GitData::Blob.new(repo: commit.repo, sha: "db01e94677a8f72289848e507a52a43de2ea109a", filename: "lib/git_stats/git_data/repo.rb"),
GitStats::GitData::Blob.new(repo: commit.repo, sha: "1463eacb3ac9f95f21f360f1eb935a84a9ee0895", filename: "templates/activity.haml"),
GitStats::GitData::Blob.new(repo: commit.repo, sha: "31d8b960a67f195bdedaaf9e7aa70b2389f3f1a8", filename: "templates/assets/bootstrap/css/bootstrap.min.css"),
]
end
it 'should group files by extension' do
commit.files_by_extension.should == {'.rb' => [
GitStats::GitData::Blob.new(repo: commit.repo, hash: "5ade7ad51a75ee7db4eb06cecd3918d38134087d", filename: "lib/git_stats/git_data/commit.rb"),
GitStats::GitData::Blob.new(repo: commit.repo, hash: "db01e94677a8f72289848e507a52a43de2ea109a", filename: "lib/git_stats/git_data/repo.rb")
GitStats::GitData::Blob.new(repo: commit.repo, sha: "5ade7ad51a75ee7db4eb06cecd3918d38134087d", filename: "lib/git_stats/git_data/commit.rb"),
GitStats::GitData::Blob.new(repo: commit.repo, sha: "db01e94677a8f72289848e507a52a43de2ea109a", filename: "lib/git_stats/git_data/repo.rb")
], '.haml' => [
GitStats::GitData::Blob.new(repo: commit.repo, hash: "1463eacb3ac9f95f21f360f1eb935a84a9ee0895", filename: "templates/activity.haml")
GitStats::GitData::Blob.new(repo: commit.repo, sha: "1463eacb3ac9f95f21f360f1eb935a84a9ee0895", filename: "templates/activity.haml")
], '.css' => [
GitStats::GitData::Blob.new(repo: commit.repo, hash: "31d8b960a67f195bdedaaf9e7aa70b2389f3f1a8", filename: "templates/assets/bootstrap/css/bootstrap.min.css")
GitStats::GitData::Blob.new(repo: commit.repo, sha: "31d8b960a67f195bdedaaf9e7aa70b2389f3f1a8", filename: "templates/assets/bootstrap/css/bootstrap.min.css")
]
}
end
it 'should count lines by extension' do
it 'should count lines by extension excluding empty or binary files' do
GitStats::GitData::Blob.should_receive(:new).and_return(
double(lines_count: 40, extension: '.rb'),
double(lines_count: 60, extension: '.rb'),

View File

@ -26,13 +26,13 @@ ce34874|1347482927|2012-09-12 22:48:47 +0200|joe.doe@gmail.com
repo.commits.should == [
GitStats::GitData::Commit.new(
repo: repo, hash: "5eab339", stamp: "1345835073", date: DateTime.parse("2012-08-24 21:04:33 +0200"),
repo: repo, sha: "5eab339", stamp: "1345835073", date: DateTime.parse("2012-08-24 21:04:33 +0200"),
author: repo.authors.by_email("john.doe@gmail.com")),
GitStats::GitData::Commit.new(
repo: repo, hash: "ce34874", stamp: "1347482927", date: DateTime.parse("2012-09-12 22:48:47 +0200"),
repo: repo, sha: "ce34874", stamp: "1347482927", date: DateTime.parse("2012-09-12 22:48:47 +0200"),
author: repo.authors.by_email("joe.doe@gmail.com")),
GitStats::GitData::Commit.new(
repo: repo, hash: "e4412c3", stamp: "1348603824", date: DateTime.parse("2012-09-25 22:10:24 +0200"),
repo: repo, sha: "e4412c3", stamp: "1348603824", date: DateTime.parse("2012-09-25 22:10:24 +0200"),
author: repo.authors.by_email("john.doe@gmail.com"))
]
end

View File

@ -1,7 +1,7 @@
require 'spec_helper'
describe GitStats::GitData::ShortStat do
let(:commit) { build(:commit, hash: 'abc') }
let(:commit) { build(:commit, sha: 'abc') }
describe 'git output parsing' do
context 'parsing git show output' do

View File

@ -7,8 +7,8 @@ describe GitStats::GitData::Activity do
let(:jd) { repo.authors.by_email('john.doe@gmail.com') }
it 'should filter commits to author' do
tg.commits.map(&:hash).should =~ %w(b3b4f81 d60b5ec ab47ef8 2c11f5e c87ecf9 b621a5d 4e7d0e9 872955c)
jd.commits.map(&:hash).should =~ %w(fd66657 81e8bef)
tg.commits.map(&:sha).should =~ %w(b3b4f81 d60b5ec ab47ef8 2c11f5e c87ecf9 b621a5d 4e7d0e9 872955c)
jd.commits.map(&:sha).should =~ %w(fd66657 81e8bef)
end
context 'activity' do

View File

@ -8,7 +8,7 @@ describe GitStats::GitData::Repo do
end
it 'should retrieve correct file content for old file' do
repo.commits.by_hash('c87ecf9').files.by_filename('test.txt').content.should == "bb
repo.commits.by_sha('c87ecf9').files.by_filename('test.txt').content.should == "bb

View File

@ -1,7 +1,7 @@
require 'spec_helper'
describe GitStats::GitData::Repo do
let(:repo) { build(:test_repo, last_commit_hash: '872955c') }
let(:repo) { build(:test_repo, last_commit_sha: '872955c') }
it 'should gather all authors' do
repo.authors.should =~ [
@ -15,7 +15,7 @@ describe GitStats::GitData::Repo do
end
it 'should gather all commits sorted by date' do
repo.commits.map(&:hash).should =~ %w(b3b4f81 d60b5ec ab47ef8 2c11f5e c87ecf9 b621a5d fd66657 81e8bef 4e7d0e9 872955c)
repo.commits.map(&:sha).should =~ %w(b3b4f81 d60b5ec ab47ef8 2c11f5e c87ecf9 b621a5d fd66657 81e8bef 4e7d0e9 872955c)
end
it 'should return project name from dir' do

View File

@ -1,16 +1,27 @@
require 'spec_helper'
shared_examples_for "column_chart" do
it 'should be a column chart' do
chart.should be_a GitStats::StatsView::Charts::Chart
chart.options[:chart][:type].should == "column"
end
end
shared_examples_for "datetime_chart" do
it 'should be a datetime chart' do
chart.should be_a GitStats::StatsView::Charts::Chart
chart.options[:xAxis][:type].should == "datetime"
end
end
describe GitStats::StatsView::Charts::RepoCharts do
let(:charts) { GitStats::StatsView::Charts::All.new(repo) }
context 'files_by_extension chart' do
let(:repo) { double(files_by_extension_count: {'.rb' => 5, '.txt' => 3}) }
let(:chart) { charts.repo_charts.files_by_extension }
let(:chart) { charts.files_by_extension }
it 'should be a column chart' do
chart.should be_a GitStats::StatsView::Charts::Chart
chart.options[:chart][:type].should == "column"
end
it_behaves_like "column_chart"
it 'should have 1 data series with files_by_extension_count' do
chart.should have(1).data
@ -21,12 +32,9 @@ describe GitStats::StatsView::Charts::RepoCharts do
context 'lines_by_extension chart' do
let(:repo) { double(lines_by_extension: {'.rb' => 50, '.txt' => 30}) }
let(:chart) { charts.repo_charts.lines_by_extension }
let(:chart) { charts.lines_by_extension }
it 'should be a column chart' do
chart.should be_a GitStats::StatsView::Charts::Chart
chart.options[:chart][:type].should == "column"
end
it_behaves_like "column_chart"
it 'should have 1 data series with lines_by_extension' do
chart.should have(1).data
@ -37,12 +45,9 @@ describe GitStats::StatsView::Charts::RepoCharts do
context 'files_by_date chart' do
let(:repo) { double(commits: [double(date: 5)], files_count_each_day: [10, 15, 12, 20]) }
let(:chart) { charts.repo_charts.files_by_date }
let(:chart) { charts.files_by_date }
it 'should be a datetime chart' do
chart.should be_a GitStats::StatsView::Charts::Chart
chart.options[:chart][:type].should == "datetime"
end
it_behaves_like "datetime_chart"
it 'should have 1 data series with files_by_date' do
chart.should have(1).data
@ -53,12 +58,9 @@ describe GitStats::StatsView::Charts::RepoCharts do
context 'lines_by_date chart' do
let(:repo) { double(commits: [double(date: 6)], lines_count_each_day: [100, 150, 120, 200]) }
let(:chart) { charts.repo_charts.lines_by_date }
let(:chart) { charts.lines_by_date }
it 'should be a datetime chart' do
chart.should be_a GitStats::StatsView::Charts::Chart
chart.options[:chart][:type].should == "datetime"
end
it_behaves_like "datetime_chart"
it 'should have 1 data series with lines_by_date' do
chart.should have(1).data
@ -66,4 +68,30 @@ describe GitStats::StatsView::Charts::RepoCharts do
chart.data[0][:pointStart].should == 6000
end
end
context 'lines_added_by_author chart' do
let(:repo) { double(commits: [double(date: 6)], lines_added_by_author: {double(email: 'author1') => 50, double(email: 'author2') => 30}) }
let(:chart) { charts.lines_added_by_author }
it_behaves_like "column_chart"
it 'should have 1 data series with lines_added_by_author' do
chart.should have(1).data
chart.options[:xAxis][:categories].should == %w(author1 author2)
chart.data[0][:data].should == [50, 30]
end
end
context 'lines_deleted_by_author chart' do
let(:repo) { double(commits: [double(date: 6)], lines_deleted_by_author: {double(email: 'author1') => 30, double(email: 'author2') => 50}) }
let(:chart) { charts.lines_deleted_by_author }
it_behaves_like "column_chart"
it 'should have 1 data series with lines_deleted_by_author' do
chart.should have(1).data
chart.options[:xAxis][:categories].should == %w(author1 author2)
chart.data[0][:data].should == [30, 50]
end
end
end

View File

@ -16,7 +16,7 @@
%td= repo.commits_period.map {|d| d.to_formatted_s(:long)}.join(" .. ")
%tr
%td= :total_files.t
%td= "#{repo.files_count} (binary: #{repo.binary_files_count}, text: #{repo.text_files_count})"
%td= "#{repo.files_count} (binary: #{repo.binary_files.size}, text: #{repo.text_files.size})"
%tr
%td= :total_lines.t
%td= "#{repo.lines_count} lines (#{repo.short_stats.map(&:insertions).sum} insertions, #{repo.short_stats.map(&:deletions).sum} deletions)"