2012-10-13 17:20:06 +02:00
|
|
|
require 'git_stats/hash_initializable'
|
|
|
|
|
2012-10-09 22:34:02 +02:00
|
|
|
module GitStats
|
|
|
|
module GitData
|
|
|
|
class Repo
|
2012-10-13 17:20:06 +02:00
|
|
|
include HashInitializable
|
|
|
|
|
2012-10-19 17:35:33 +02:00
|
|
|
attr_reader :path
|
|
|
|
|
2012-10-20 21:28:25 +02:00
|
|
|
delegate :files, :files_by_extension, :files_by_extension_count, :lines_by_extension,
|
2012-10-20 22:38:11 +02:00
|
|
|
:files_count, :binary_files, :text_files, :lines_count, to: :last_commit
|
2012-10-09 22:34:02 +02:00
|
|
|
|
2012-10-13 17:20:06 +02:00
|
|
|
def initialize(params)
|
|
|
|
super(params)
|
|
|
|
@path = File.expand_path(@path)
|
2012-10-09 22:34:02 +02:00
|
|
|
end
|
|
|
|
|
2012-10-12 18:20:07 +02:00
|
|
|
def authors
|
2012-10-19 20:02:47 +02:00
|
|
|
@authors ||= run_and_parse("git shortlog -se #{commit_range}").map do |author|
|
2012-10-19 16:39:39 +02:00
|
|
|
Author.new(repo: self, name: author[:name], email: author[:email])
|
|
|
|
end.extend(ByFieldFinder)
|
2012-10-09 22:34:02 +02:00
|
|
|
end
|
|
|
|
|
2012-10-12 18:20:07 +02:00
|
|
|
def commits
|
2012-10-19 21:17:16 +02:00
|
|
|
@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,
|
2012-10-20 22:38:11 +02:00
|
|
|
sha: commit_line[:sha],
|
2012-10-19 21:17:16 +02:00
|
|
|
stamp: commit_line[:stamp],
|
|
|
|
date: DateTime.parse(commit_line[:date]),
|
|
|
|
author: authors.by_email(commit_line[:author_email])
|
|
|
|
)
|
2012-10-19 20:27:41 +02:00
|
|
|
end.sort_by! { |e| e.date }.extend(ByFieldFinder)
|
2012-10-13 14:31:52 +02:00
|
|
|
end
|
|
|
|
|
2012-10-19 22:01:01 +02:00
|
|
|
def commits_period
|
|
|
|
commits.map(&:date).minmax
|
|
|
|
end
|
|
|
|
|
2012-10-21 18:25:11 +02:00
|
|
|
def commits_count_by_author(limit = 4)
|
|
|
|
Hash[authors.map { |author| [author, author.commits.size] }.sort_by { |author, commits| -commits }[0..limit]]
|
2012-10-21 17:34:05 +02:00
|
|
|
end
|
|
|
|
|
2012-10-21 23:03:41 +02:00
|
|
|
[:insertions, :deletions].each do |method|
|
2012-10-21 22:41:54 +02:00
|
|
|
define_method "#{method}_by_author" do |limit = 4|
|
|
|
|
Hash[authors.map { |author| [author, author.send(method)] }.sort_by { |author, lines| -lines }[0..limit]]
|
|
|
|
end
|
2012-10-20 21:28:25 +02:00
|
|
|
end
|
|
|
|
|
2012-10-21 13:19:37 +02:00
|
|
|
def files_count_by_date
|
|
|
|
@files_count_each_day ||= Hash[commits.map { |commit|
|
|
|
|
[commit.date, commit.files_count]
|
|
|
|
}]
|
2012-10-20 00:30:00 +02:00
|
|
|
end
|
|
|
|
|
2012-10-21 13:19:37 +02:00
|
|
|
def lines_count_by_date
|
2012-10-21 20:48:33 +02:00
|
|
|
sum = 0
|
|
|
|
Hash[commits.map { |commit|
|
|
|
|
sum += commit.short_stat.insertions
|
|
|
|
sum -= commit.short_stat.deletions
|
|
|
|
[commit.date, sum]
|
2012-10-21 13:19:37 +02:00
|
|
|
}]
|
2012-10-20 00:30:00 +02:00
|
|
|
end
|
|
|
|
|
2012-10-19 17:35:33 +02:00
|
|
|
def last_commit
|
|
|
|
commits.last
|
|
|
|
end
|
|
|
|
|
2012-10-19 15:51:24 +02:00
|
|
|
def commit_range
|
2012-10-20 22:38:11 +02:00
|
|
|
@first_commit_sha ? "#@first_commit_sha..#{last_commit_sha}" : last_commit_sha
|
2012-10-19 15:51:24 +02:00
|
|
|
end
|
|
|
|
|
2012-10-20 22:38:11 +02:00
|
|
|
def last_commit_sha
|
|
|
|
@last_commit_sha ||= 'HEAD'
|
2012-10-19 15:51:24 +02:00
|
|
|
end
|
|
|
|
|
2012-10-13 14:31:52 +02:00
|
|
|
def short_stats
|
|
|
|
@short_stats ||= commits.map(&:short_stat)
|
2012-10-09 22:34:02 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
def activity
|
2012-10-12 18:24:28 +02:00
|
|
|
@activity ||= Activity.new(commits)
|
2012-10-09 22:34:02 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
def project_version
|
2012-10-19 20:02:47 +02:00
|
|
|
@project_version ||= run("git rev-parse --short #{commit_range}").strip
|
2012-10-09 22:34:02 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
def project_name
|
2012-10-13 15:32:06 +02:00
|
|
|
@project_name ||= File.basename(path)
|
2012-10-09 22:34:02 +02:00
|
|
|
end
|
2012-10-12 18:20:07 +02:00
|
|
|
|
2012-10-19 16:57:49 +02:00
|
|
|
def run(command)
|
2012-10-19 21:11:47 +02:00
|
|
|
result = command_runner.run(path, command)
|
|
|
|
invoke_command_observers(command, result)
|
|
|
|
result
|
2012-10-19 16:57:49 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
def run_and_parse(command)
|
|
|
|
result = run(command)
|
|
|
|
command_parser.parse(command, result)
|
|
|
|
end
|
|
|
|
|
2012-10-19 21:11:47 +02:00
|
|
|
def command_runner
|
|
|
|
@command_runner ||= CommandRunner.new
|
|
|
|
end
|
|
|
|
|
2012-10-19 16:57:49 +02:00
|
|
|
def command_parser
|
|
|
|
@command_parser ||= CommandParser.new
|
|
|
|
end
|
|
|
|
|
2012-10-19 21:11:47 +02:00
|
|
|
def add_command_observer(proc=nil, &block)
|
|
|
|
command_observers << block if block_given?
|
|
|
|
command_observers << proc if proc
|
2012-10-19 16:57:49 +02:00
|
|
|
end
|
|
|
|
|
2012-10-13 12:38:07 +02:00
|
|
|
def to_s
|
|
|
|
"#{self.class} #@path"
|
|
|
|
end
|
|
|
|
|
2012-10-13 13:27:15 +02:00
|
|
|
def ==(other)
|
|
|
|
self.path == other.path
|
|
|
|
end
|
|
|
|
|
2012-10-19 21:11:47 +02:00
|
|
|
private
|
|
|
|
def command_observers
|
|
|
|
@command_observers ||= []
|
|
|
|
end
|
|
|
|
|
|
|
|
def invoke_command_observers(command, result)
|
|
|
|
command_observers.each { |o| o.call(command, result) }
|
|
|
|
end
|
|
|
|
|
2012-10-09 22:34:02 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|