diff --git a/lib/git_diff_parser.rb b/lib/git_diff_parser.rb index d6254d0..61abcfd 100644 --- a/lib/git_diff_parser.rb +++ b/lib/git_diff_parser.rb @@ -2,6 +2,8 @@ require 'git_diff_parser/line' require 'git_diff_parser/patch' require 'git_diff_parser/patches' +require 'git_diff_parser/commit' +require 'git_diff_parser/commits' require 'git_diff_parser/diff_parser' # Parse `git diff` into patches and lines @@ -12,4 +14,8 @@ module GitDiffParser def self.parse(contents) Patches.parse(contents) end + + def self.parselog(contents) + Commits.parse(contents) + end end diff --git a/lib/git_diff_parser/commit.rb b/lib/git_diff_parser/commit.rb new file mode 100644 index 0000000..b9228e8 --- /dev/null +++ b/lib/git_diff_parser/commit.rb @@ -0,0 +1,28 @@ +module GitDiffParser + # Parsed commit + class Commit + attr_accessor :hash, :mhash, :author, :date, :comment, :files + + def debug_output + puts '-----new Commit----' + puts @hash + puts @mhash + puts @author + puts @date + puts @comment + puts @files + puts '-----end----' + end + + def initialize( options = {}) + @hash = options[:hash].dup if options[:hash] + @mhash = options[:mhash].dup if options[:mhash] + @author = options[:author].dup if options[:author] + @date = options[:date].dup if options[:date] + @comment = options[:comment].dup if options[:comment] + @files = options[:files].dup if options[:files] + +# debug_output + end + end +end diff --git a/lib/git_diff_parser/commits.rb b/lib/git_diff_parser/commits.rb new file mode 100644 index 0000000..0f734b2 --- /dev/null +++ b/lib/git_diff_parser/commits.rb @@ -0,0 +1,97 @@ +require 'delegate' +module GitDiffParser + # The array of commit + class Commits < DelegateClass(Array) + # @return [Commits] + def self.[](*ary) + new(ary) + end + + # @param contents [String] `git diff` result + # + # @return [Commits] parsed object + def self.parse(contents) + body = false + consume = false + author = '' + date = '' + chash = '' + mhash = '' + file = '' + files = [] + comments = [] + commit = [] + lines = contents.lines + line_count = lines.count + parsed = new + lines.each_with_index do |line, count| + case line.chomp + when %r{^commit (?.*)} + if body == true + parsed << Commit.new(hash: chash, mhash: mhash, author: author, date: date, comment: comments, files: files) + comments.clear + files.clear + mhash.clear + body = false + end + chash = Regexp.last_match[:hash] + consume = true + when %r{^Author:\s+(?.*)} + if consume + author = Regexp.last_match[:author] + body = true + end + when %r{^Date: (?.*)} + if consume == true + date = Regexp.last_match[:date] + body = true + end + when %r{^Merge: (?.*)} + if consume == true + mhash = Regexp.last_match[:mhash] + body = true + end + when %r{^[ACDMRTUXB]\s(?.*)} + if consume == true + file = Regexp.last_match[:file] + files << file + body = true + if line_count == count + 1 + parsed << Commit.new(hash: chash, mergeh: mhash, author: author, date: date, comment: comments, files: files) + end + end + else + if consume == true + comments << line + body = true + end + end + end + parsed + end + + # @return [Commits] + def initialize(*args) + super Array.new(*args) + end + + # @return [Array] file path + def hashes + map(&:chash) + end + + # @param file [String] file path + # + # @return [Commit, nil] + def find_commit_by_file(file) + find { |commit| commit.file == file } + end + + # @param secure_hash [String] target sha1 hash + # + # @return [Commit, nil] + def find_commit_by_secure_hash(secure_hash) + find { |commit| commit.secure_hash == secure_hash } + end + end +end diff --git a/lib/git_diff_parser/commits_by_file.rb b/lib/git_diff_parser/commits_by_file.rb new file mode 100644 index 0000000..a2e0ba8 --- /dev/null +++ b/lib/git_diff_parser/commits_by_file.rb @@ -0,0 +1,49 @@ +require 'git_diff_parser.rb' +module GitDiffParser + class CommitsByFile + def initialize(commit_log) + commits = GitDiffParser.parselog(commit_log) + @merge_commits = {} + commits.each { |commit| + if !commit.mhash.nil? + orig_hash = commit.mhash.split(" ").last + @merge_commits[orig_hash] = commit + end + } + + @commits_by_file = Hash.new {|h,k| h[k]=[]} + @prs = [] + commits.each { |commit| + commit.files.each { |file| + short_chash = commit.hash[0...7] + if !@merge_commits[short_chash].nil? + c = @merge_commits[short_chash] + #c.comment << commit.comment + @commits_by_file[file] << c + else + @commits_by_file[file] << commit + end + } + + if !(commit.mhash.nil? || commit.mhash.empty?) + commit.comment.each { |comment| + if comment =~ /Merge pull request/ + id = comment[/\d+/].to_i + text = comment.split(" from ").last + @prs << {:id => id, :text => text, :author => commit.author} + end + } + end + } + end + + def get_commits(file_name) + return @commits_by_file[file_name] + end + + def get_prs() + return @prs + end + end +end + diff --git a/lib/git_diff_parser/diff_parser.rb b/lib/git_diff_parser/diff_parser.rb index 2d7835a..9d5c328 100644 --- a/lib/git_diff_parser/diff_parser.rb +++ b/lib/git_diff_parser/diff_parser.rb @@ -14,5 +14,8 @@ def self.parse(contents) warn '[DEPRECATION] `DiffParser.parse` is deprecated. Please use `Patches.parse` instead.' Patches.parse(contents) end + def self.parselog(contents) + Commits.parse(contents) + end end end diff --git a/lib/git_diff_parser/patch.rb b/lib/git_diff_parser/patch.rb index 26011b6..5f9ecdb 100644 --- a/lib/git_diff_parser/patch.rb +++ b/lib/git_diff_parser/patch.rb @@ -90,8 +90,6 @@ def find_patch_position_by_line_number(line_number) target.patch_position end - private - def lines @body.lines end diff --git a/lib/git_diff_parser/patches.rb b/lib/git_diff_parser/patches.rb index 342de7e..277b677 100644 --- a/lib/git_diff_parser/patches.rb +++ b/lib/git_diff_parser/patches.rb @@ -26,7 +26,9 @@ def self.parse(contents) file_name = '' end body = false - when /^\-\-\-/ + when %r{^\-\-\- a/(?.*)} + file_name = Regexp.last_match[:file_name] + body = true when %r{^\+\+\+ b/(?.*)} file_name = Regexp.last_match[:file_name] body = true