meta_commit 0.1.0.alpha
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.
- checksums.yaml +7 -0
- data/.gitignore +10 -0
- data/.travis.yml +4 -0
- data/CODE_OF_CONDUCT.md +13 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +40 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +7 -0
- data/exe/meta_commit +5 -0
- data/lib/meta_commit/adapters/dump.rb +31 -0
- data/lib/meta_commit/adapters/git_notes.rb +28 -0
- data/lib/meta_commit/cli.rb +32 -0
- data/lib/meta_commit/git/repo.rb +60 -0
- data/lib/meta_commit/models/ast_path.rb +111 -0
- data/lib/meta_commit/models/changes/commit.rb +27 -0
- data/lib/meta_commit/models/changes/file.rb +27 -0
- data/lib/meta_commit/models/changes/repository.rb +18 -0
- data/lib/meta_commit/models/diffs/addition.rb +34 -0
- data/lib/meta_commit/models/diffs/changes_in_method.rb +14 -0
- data/lib/meta_commit/models/diffs/class_creation.rb +20 -0
- data/lib/meta_commit/models/diffs/class_deletion.rb +16 -0
- data/lib/meta_commit/models/diffs/class_rename.rb +11 -0
- data/lib/meta_commit/models/diffs/deletion.rb +37 -0
- data/lib/meta_commit/models/diffs/diff.rb +34 -0
- data/lib/meta_commit/models/diffs/method_creation.rb +22 -0
- data/lib/meta_commit/models/diffs/method_deletion.rb +22 -0
- data/lib/meta_commit/models/diffs/module_creation.rb +14 -0
- data/lib/meta_commit/models/diffs/module_deletion.rb +14 -0
- data/lib/meta_commit/models/diffs/module_rename.rb +11 -0
- data/lib/meta_commit/models/diffs/replacement.rb +19 -0
- data/lib/meta_commit/models/factories/ast_path_factory.rb +40 -0
- data/lib/meta_commit/models/factories/diff_factory.rb +39 -0
- data/lib/meta_commit/models/line.rb +5 -0
- data/lib/meta_commit/services/change_saver.rb +41 -0
- data/lib/meta_commit/services/commit_message_builder.rb +23 -0
- data/lib/meta_commit/services/diff_examiner.rb +121 -0
- data/lib/meta_commit/services/diff_index_examiner.rb +112 -0
- data/lib/meta_commit/version.rb +3 -0
- data/lib/meta_commit.rb +35 -0
- data/meta_commit.gemspec +30 -0
- metadata +200 -0
@@ -0,0 +1,22 @@
|
|
1
|
+
module MetaCommit::Models::Diffs
|
2
|
+
class MethodCreation < Diff
|
3
|
+
def supports_change(type, old_file_name, new_file_name, old_ast_path, new_ast_path)
|
4
|
+
type == MetaCommit::Models::Diffs::Diff::TYPE_ADDITION && !new_ast_path.empty_ast? && (new_ast_path.is_method? || new_ast_path.is_in_context_of_method?)
|
5
|
+
end
|
6
|
+
|
7
|
+
def string_representation
|
8
|
+
if @new_ast_path.is_method?
|
9
|
+
if @new_ast_path.is_in_context_of_module?
|
10
|
+
if @new_ast_path.is_in_context_of_class?
|
11
|
+
return "created #{new_ast_path.name_of_context_module}::#{new_ast_path.name_of_context_class}##{new_ast_path.method_name}"
|
12
|
+
end
|
13
|
+
return "created #{new_ast_path.name_of_context_module}##{new_ast_path.method_name}"
|
14
|
+
end
|
15
|
+
if @new_ast_path.is_in_context_of_class?
|
16
|
+
return "created #{new_ast_path.name_of_context_class}##{new_ast_path.method_name}"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
"changes in method #{new_ast_path.name_of_context_method}"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module MetaCommit::Models::Diffs
|
2
|
+
class MethodDeletion < Diff
|
3
|
+
def supports_change(type, old_file_name, new_file_name, old_ast_path, new_ast_path)
|
4
|
+
type == MetaCommit::Models::Diffs::Diff::TYPE_DELETION && !old_ast_path.empty_ast? && (old_ast_path.is_method? || old_ast_path.is_in_context_of_method?)
|
5
|
+
end
|
6
|
+
|
7
|
+
def string_representation
|
8
|
+
if @old_ast_path.is_method?
|
9
|
+
if @old_ast_path.is_in_context_of_module?
|
10
|
+
if @old_ast_path.is_in_context_of_class?
|
11
|
+
return "removed #{old_ast_path.name_of_context_module}::#{old_ast_path.name_of_context_class}##{old_ast_path.method_name}"
|
12
|
+
end
|
13
|
+
return "removed method #{old_ast_path.method_name} from module #{old_ast_path.name_of_context_module}"
|
14
|
+
end
|
15
|
+
if @old_ast_path.is_in_context_of_class?
|
16
|
+
return "removed #{old_ast_path.name_of_context_class}##{old_ast_path.method_name}"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
"changes in method #{old_ast_path.name_of_context_method}"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module MetaCommit::Models::Diffs
|
2
|
+
class ModuleCreation < Diff
|
3
|
+
def supports_change(type, old_file_name, new_file_name, old_ast_path, new_ast_path)
|
4
|
+
type == MetaCommit::Models::Diffs::Diff::TYPE_ADDITION && !new_ast_path.empty_ast? && (new_ast_path.is_module? || new_ast_path.is_name_of_module?)
|
5
|
+
end
|
6
|
+
|
7
|
+
def string_representation
|
8
|
+
if @new_ast_path.is_module?
|
9
|
+
return "created module #{new_ast_path.module_name}"
|
10
|
+
end
|
11
|
+
"created module #{new_ast_path.name_of_context_module}"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module MetaCommit::Models::Diffs
|
2
|
+
class ModuleDeletion < Diff
|
3
|
+
def supports_change(type, old_file_name, new_file_name, old_ast_path, new_ast_path)
|
4
|
+
type == MetaCommit::Models::Diffs::Diff::TYPE_DELETION && !old_ast_path.empty_ast? && (old_ast_path.is_module? || old_ast_path.is_name_of_module?)
|
5
|
+
end
|
6
|
+
|
7
|
+
def string_representation
|
8
|
+
if @old_ast_path.is_module?
|
9
|
+
return "removed module #{old_ast_path.module_name}"
|
10
|
+
end
|
11
|
+
"removed module #{old_ast_path.name_of_context_module}"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module MetaCommit::Models::Diffs
|
2
|
+
class ModuleRename < Diff
|
3
|
+
def supports_change(type, old_file_name, new_file_name, old_ast_path, new_ast_path)
|
4
|
+
type == MetaCommit::Models::Diffs::Diff::TYPE_REPLACE && !old_ast_path.empty_ast? && !new_ast_path.empty_ast? && old_ast_path.is_name_of_module? && new_ast_path.is_name_of_module?
|
5
|
+
end
|
6
|
+
|
7
|
+
def string_representation
|
8
|
+
"renamed module #{old_ast_path.name_of_context_module} to #{new_ast_path.name_of_context_module}"
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module MetaCommit::Models::Diffs
|
2
|
+
class Replacement < Diff
|
3
|
+
def string_representation
|
4
|
+
if @old_ast_path.is_name_of_module? && @new_ast_path.is_name_of_module?
|
5
|
+
return "renamed module #{old_ast_path.name_of_context_module} to #{new_ast_path.name_of_context_module}"
|
6
|
+
end
|
7
|
+
if @old_ast_path.is_name_of_class? && @new_ast_path.is_name_of_class?
|
8
|
+
return "renamed class #{old_ast_path.name_of_context_class} to #{new_ast_path.name_of_context_class}"
|
9
|
+
end
|
10
|
+
if @old_ast_path.is_in_context_of_method? && @new_ast_path.is_in_context_of_method?
|
11
|
+
if @new_ast_path.is_in_context_of_class?
|
12
|
+
return "changes in #{new_ast_path.name_of_context_class}##{new_ast_path.name_of_context_method}"
|
13
|
+
end
|
14
|
+
return "changes in ##{new_ast_path.name_of_context_method}"
|
15
|
+
end
|
16
|
+
'replacing was performed'
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module MetaCommit::Models::Factories
|
2
|
+
class AstPathFactory
|
3
|
+
def create_ast_path(source_ast, line_number)
|
4
|
+
visited_nodes = []
|
5
|
+
ast_path = MetaCommit::Models::AstPath.new
|
6
|
+
ast_path.ast = collect_path_to_ast_at_line(source_ast, line_number, visited_nodes)
|
7
|
+
ast_path.path = visited_nodes
|
8
|
+
ast_path
|
9
|
+
end
|
10
|
+
|
11
|
+
protected
|
12
|
+
def get_ast_at_line(ast, lineno)
|
13
|
+
return nil unless ast_covers_line(ast, lineno)
|
14
|
+
closest_ast = ast
|
15
|
+
ast.children.each do |child|
|
16
|
+
found_ast = get_ast_at_line(child, lineno)
|
17
|
+
closest_ast = found_ast unless found_ast.nil?
|
18
|
+
end
|
19
|
+
closest_ast
|
20
|
+
end
|
21
|
+
|
22
|
+
protected
|
23
|
+
def collect_path_to_ast_at_line(ast, lineno, accumulator)
|
24
|
+
return nil unless ast_covers_line(ast, lineno)
|
25
|
+
closest_ast = ast
|
26
|
+
accumulator.push(closest_ast)
|
27
|
+
ast.children.each do |child|
|
28
|
+
found_ast = collect_path_to_ast_at_line(child, lineno, accumulator)
|
29
|
+
closest_ast = found_ast unless found_ast.nil?
|
30
|
+
end
|
31
|
+
closest_ast
|
32
|
+
end
|
33
|
+
|
34
|
+
protected
|
35
|
+
def ast_covers_line(ast, line)
|
36
|
+
return false unless (ast.respond_to?(:loc) && ast.loc.respond_to?(:expression) && !ast.loc.expression.nil?)
|
37
|
+
(ast.loc.first_line <= line) && (ast.loc.last_line >= line)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module MetaCommit::Models::Factories
|
2
|
+
class DiffFactory
|
3
|
+
attr_accessor :available_diff_classes
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
@available_diff_classes = [
|
7
|
+
MetaCommit::Models::Diffs::ClassCreation,
|
8
|
+
MetaCommit::Models::Diffs::ClassDeletion,
|
9
|
+
MetaCommit::Models::Diffs::ClassRename,
|
10
|
+
MetaCommit::Models::Diffs::MethodCreation,
|
11
|
+
MetaCommit::Models::Diffs::MethodDeletion,
|
12
|
+
MetaCommit::Models::Diffs::ChangesInMethod,
|
13
|
+
MetaCommit::Models::Diffs::ModuleCreation,
|
14
|
+
MetaCommit::Models::Diffs::ModuleDeletion,
|
15
|
+
MetaCommit::Models::Diffs::ModuleRename,
|
16
|
+
MetaCommit::Models::Diffs::Diff,
|
17
|
+
]
|
18
|
+
end
|
19
|
+
|
20
|
+
def create_diff_of_type(type, options)
|
21
|
+
@available_diff_classes.each do |diff_class|
|
22
|
+
diff = diff_class.new
|
23
|
+
if diff.supports_change(type, options[:old_file_path], options[:new_file_path], options[:old_ast_path], options[:new_ast_path])
|
24
|
+
line = options[:line]
|
25
|
+
diff.diff_type = line.line_origin
|
26
|
+
diff.commit_old = options[:commit_id_old]
|
27
|
+
diff.commit_new = options[:commit_id_new]
|
28
|
+
diff.old_file = options[:old_file_path]
|
29
|
+
diff.new_file = options[:new_file_path]
|
30
|
+
diff.old_lineno = line.old_lineno
|
31
|
+
diff.new_lineno = line.new_lineno
|
32
|
+
diff.old_ast_path = options[:old_ast_path]
|
33
|
+
diff.new_ast_path = options[:new_ast_path]
|
34
|
+
return diff
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module MetaCommit::Services
|
2
|
+
class ChangeSaver
|
3
|
+
attr_accessor :repo
|
4
|
+
|
5
|
+
def initialize(repo)
|
6
|
+
@repo = repo
|
7
|
+
end
|
8
|
+
|
9
|
+
def meta_adapter
|
10
|
+
# @TODO fetch adapter from config
|
11
|
+
MetaCommit::Adapters::GitNotes.new(@repo.repo.path)
|
12
|
+
end
|
13
|
+
|
14
|
+
def store_meta(changes_of_repo)
|
15
|
+
store_repository_changes(changes_of_repo)
|
16
|
+
end
|
17
|
+
|
18
|
+
def store_repository_changes(changes_of_repo)
|
19
|
+
meta_adapter.write_repository_change_chunk(repo, changes_of_repo)
|
20
|
+
end
|
21
|
+
|
22
|
+
def store_commit_changes(changes_of_commit)
|
23
|
+
meta_adapter.write_commit_change_chunk(repo.repo, changes_of_repo, changes_of_commit)
|
24
|
+
changes_of_commit.each do |changes_of_file|
|
25
|
+
store_file_changes(changes_of_file)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def store_file_changes(changes_of_file)
|
30
|
+
meta_adapter.write_file_change_chunk(changes_of_file)
|
31
|
+
uniques_file_changes = changes_of_file.changes.uniq { |diff| diff.to_s }
|
32
|
+
uniques_file_changes.each do |diff|
|
33
|
+
store_diff(diff)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def store_diff(diff)
|
38
|
+
meta_adapter.write_diff(diff)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module MetaCommit::Services
|
2
|
+
class CommitMessageBuilder
|
3
|
+
attr_accessor :repo
|
4
|
+
|
5
|
+
def initialize(repo)
|
6
|
+
@repo = repo
|
7
|
+
end
|
8
|
+
|
9
|
+
def build(commit_change)
|
10
|
+
message = []
|
11
|
+
commit_change.each do |file_change|
|
12
|
+
file_change.each do |diff|
|
13
|
+
message.push(build_message_for_diff(diff))
|
14
|
+
end
|
15
|
+
end
|
16
|
+
message.join("\n")
|
17
|
+
end
|
18
|
+
|
19
|
+
def build_message_for_diff(diff)
|
20
|
+
diff.to_s
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,121 @@
|
|
1
|
+
require "parser/current"
|
2
|
+
|
3
|
+
module MetaCommit::Services
|
4
|
+
class DiffExaminer
|
5
|
+
DIFF_OPTIONS = {:context_lines => 0, :ignore_whitespace => true}
|
6
|
+
FILE_NOT_EXISTS_OID = '0000000000000000000000000000000000000000'
|
7
|
+
|
8
|
+
def initialize(repo)
|
9
|
+
@repo = repo
|
10
|
+
end
|
11
|
+
|
12
|
+
# region meta
|
13
|
+
def meta
|
14
|
+
changes = MetaCommit::Models::Changes::Repository.new(@repo.repo.path)
|
15
|
+
@repo.walk_by_commits do |previous_commit, current_commit|
|
16
|
+
diff = @repo.diff(previous_commit, current_commit, DIFF_OPTIONS)
|
17
|
+
changes.push(examine_commits_diff(diff, previous_commit, current_commit))
|
18
|
+
end
|
19
|
+
changes
|
20
|
+
end
|
21
|
+
|
22
|
+
def examine_commits_diff(diff, commit_old, commit_new)
|
23
|
+
old_id = commit_old.oid
|
24
|
+
new_id = commit_new.oid
|
25
|
+
diffs = MetaCommit::Models::Changes::Commit.new(old_id, new_id)
|
26
|
+
diff.deltas.zip(diff.patches).each do |delta, patch|
|
27
|
+
# file check here
|
28
|
+
# build parser using factory and pass like argument
|
29
|
+
diffs.push(examine_delta(delta, patch, old_id, new_id))
|
30
|
+
end
|
31
|
+
diffs
|
32
|
+
end
|
33
|
+
|
34
|
+
def examine_delta(delta, patch, commit_id_old, commit_id_new)
|
35
|
+
old_file_path = delta.old_file[:path]
|
36
|
+
new_file_path = delta.new_file[:path]
|
37
|
+
|
38
|
+
diffs = MetaCommit::Models::Changes::File.new(old_file_path, new_file_path)
|
39
|
+
|
40
|
+
return diffs unless (can_examine(old_file_path) and can_examine(new_file_path))
|
41
|
+
|
42
|
+
old_file_content = @repo.get_blob_at(commit_id_old, old_file_path, '')
|
43
|
+
new_file_content = @repo.get_blob_at(commit_id_new, new_file_path, '')
|
44
|
+
|
45
|
+
begin
|
46
|
+
old_file_ast = Parser::CurrentRuby.parse(old_file_content)
|
47
|
+
new_file_ast = Parser::CurrentRuby.parse(new_file_content)
|
48
|
+
rescue Parser::SyntaxError
|
49
|
+
return diffs
|
50
|
+
end
|
51
|
+
|
52
|
+
lines_to_walk = organize_lines(delta, patch)
|
53
|
+
|
54
|
+
lines_to_walk.each do |line|
|
55
|
+
old_ast_path = MetaCommit::Models::Factories::AstPathFactory.new.create_ast_path(old_file_ast, line.old_lineno)
|
56
|
+
new_ast_path = MetaCommit::Models::Factories::AstPathFactory.new.create_ast_path(new_file_ast, line.new_lineno)
|
57
|
+
|
58
|
+
factory = MetaCommit::Models::Factories::DiffFactory.new
|
59
|
+
diff = factory.create_diff_of_type(line.line_origin, {
|
60
|
+
:line => line,
|
61
|
+
:commit_id_old => commit_id_old,
|
62
|
+
:commit_id_new => commit_id_new,
|
63
|
+
:old_ast_path => old_ast_path,
|
64
|
+
:new_ast_path => new_ast_path,
|
65
|
+
:old_file_path => old_file_path,
|
66
|
+
:new_file_path => new_file_path,
|
67
|
+
})
|
68
|
+
diffs.push(diff)
|
69
|
+
end
|
70
|
+
diffs
|
71
|
+
end
|
72
|
+
|
73
|
+
# endregion
|
74
|
+
|
75
|
+
# region helpers
|
76
|
+
def can_examine(file_path)
|
77
|
+
file_path.end_with?('.rb')
|
78
|
+
end
|
79
|
+
|
80
|
+
def organize_lines(delta, patch)
|
81
|
+
lines_to_walk = []
|
82
|
+
# if whole file was changed examine one time only
|
83
|
+
whole_file_changed = (delta.old_file[:oid] == FILE_NOT_EXISTS_OID) || (delta.new_file[:oid] == FILE_NOT_EXISTS_OID)
|
84
|
+
skip_walking = false
|
85
|
+
skip_next_line = false
|
86
|
+
patch.hunks.each_with_index do |hunk|
|
87
|
+
break if skip_walking
|
88
|
+
hunk.lines.each_with_index do |line, line_index|
|
89
|
+
break if skip_walking
|
90
|
+
|
91
|
+
if skip_next_line
|
92
|
+
skip_next_line = false
|
93
|
+
next
|
94
|
+
end
|
95
|
+
|
96
|
+
next_line = hunk.lines[line_index + 1]
|
97
|
+
is_replace_change = (line.deletion?) && (!next_line.nil? && next_line.addition?) && (line.old_lineno && next_line.new_lineno)
|
98
|
+
|
99
|
+
line_to_walk = MetaCommit::Models::Line.new
|
100
|
+
if is_replace_change
|
101
|
+
line_to_walk.line_origin=:replace
|
102
|
+
line_to_walk.old_lineno=line.old_lineno
|
103
|
+
line_to_walk.new_lineno=next_line.new_lineno
|
104
|
+
else
|
105
|
+
line_to_walk.line_origin=line.line_origin
|
106
|
+
line_to_walk.old_lineno=line.old_lineno
|
107
|
+
line_to_walk.new_lineno=line.new_lineno
|
108
|
+
end
|
109
|
+
if is_replace_change
|
110
|
+
skip_next_line = true
|
111
|
+
end
|
112
|
+
lines_to_walk.push(line_to_walk)
|
113
|
+
|
114
|
+
skip_walking = true if whole_file_changed
|
115
|
+
end
|
116
|
+
end
|
117
|
+
lines_to_walk
|
118
|
+
end
|
119
|
+
# endregion
|
120
|
+
end
|
121
|
+
end
|
@@ -0,0 +1,112 @@
|
|
1
|
+
require "parser/current"
|
2
|
+
|
3
|
+
module MetaCommit::Services
|
4
|
+
class DiffIndexExaminer
|
5
|
+
DIFF_OPTIONS = {:context_lines => 0, :ignore_whitespace => true}
|
6
|
+
FILE_NOT_EXISTS_OID = '0000000000000000000000000000000000000000'
|
7
|
+
|
8
|
+
def initialize(repo)
|
9
|
+
@repo = repo
|
10
|
+
end
|
11
|
+
|
12
|
+
# region index_meta
|
13
|
+
def index_meta
|
14
|
+
diff = @repo.index_diff(DIFF_OPTIONS)
|
15
|
+
|
16
|
+
diffs = MetaCommit::Models::Changes::Commit.new(@repo.repo.last_commit.oid, "staged")
|
17
|
+
|
18
|
+
diff.deltas.zip(diff.patches).each do |delta, patch|
|
19
|
+
diffs.push(examine_index_delta(delta, patch, @repo.repo.last_commit.oid))
|
20
|
+
end
|
21
|
+
diffs
|
22
|
+
end
|
23
|
+
|
24
|
+
def examine_index_delta(delta, patch, commit_id_old)
|
25
|
+
old_file_path = delta.old_file[:path]
|
26
|
+
new_file_path = delta.new_file[:path]
|
27
|
+
|
28
|
+
diffs = MetaCommit::Models::Changes::File.new(old_file_path, new_file_path)
|
29
|
+
|
30
|
+
return diffs unless (can_examine(old_file_path) and can_examine(new_file_path))
|
31
|
+
|
32
|
+
old_file_content = @repo.get_blob_at(commit_id_old, old_file_path, '')
|
33
|
+
# @TODO get content of staged changes only
|
34
|
+
new_file_content = @repo.get_content_of(new_file_path, '')
|
35
|
+
|
36
|
+
begin
|
37
|
+
old_file_ast = Parser::CurrentRuby.parse(old_file_content)
|
38
|
+
new_file_ast = Parser::CurrentRuby.parse(new_file_content)
|
39
|
+
rescue Parser::SyntaxError
|
40
|
+
return diffs
|
41
|
+
end
|
42
|
+
|
43
|
+
lines_to_walk = organize_lines(delta, patch)
|
44
|
+
|
45
|
+
lines_to_walk.each do |line|
|
46
|
+
old_ast_path = MetaCommit::Models::Factories::AstPathFactory.new.create_ast_path(old_file_ast, line.old_lineno)
|
47
|
+
new_ast_path = MetaCommit::Models::Factories::AstPathFactory.new.create_ast_path(new_file_ast, line.new_lineno)
|
48
|
+
|
49
|
+
factory = MetaCommit::Models::Factories::DiffFactory.new
|
50
|
+
diff = factory.create_diff_of_type(line.line_origin, {
|
51
|
+
:line => line,
|
52
|
+
:commit_id_old => commit_id_old,
|
53
|
+
:commit_id_new => 'workdir',
|
54
|
+
:old_ast_path => old_ast_path,
|
55
|
+
:new_ast_path => new_ast_path,
|
56
|
+
:old_file_path => old_file_path,
|
57
|
+
:new_file_path => new_file_path,
|
58
|
+
})
|
59
|
+
diffs.push(diff)
|
60
|
+
end
|
61
|
+
|
62
|
+
diffs
|
63
|
+
end
|
64
|
+
|
65
|
+
# endregion
|
66
|
+
|
67
|
+
# region helpers
|
68
|
+
def can_examine(file_path)
|
69
|
+
file_path.end_with?('.rb')
|
70
|
+
end
|
71
|
+
def organize_lines(delta, patch)
|
72
|
+
lines_to_walk = []
|
73
|
+
# if whole file was changed examine one time only
|
74
|
+
whole_file_changed = (delta.old_file[:oid] == FILE_NOT_EXISTS_OID) || (delta.new_file[:oid] == FILE_NOT_EXISTS_OID)
|
75
|
+
skip_walking = false
|
76
|
+
skip_next_line = false
|
77
|
+
patch.hunks.each_with_index do |hunk|
|
78
|
+
break if skip_walking
|
79
|
+
hunk.lines.each_with_index do |line, line_index|
|
80
|
+
break if skip_walking
|
81
|
+
|
82
|
+
if skip_next_line
|
83
|
+
skip_next_line = false
|
84
|
+
next
|
85
|
+
end
|
86
|
+
|
87
|
+
next_line = hunk.lines[line_index + 1]
|
88
|
+
is_replace_change = (line.deletion?) && (!next_line.nil? && next_line.addition?) && (line.old_lineno && next_line.new_lineno)
|
89
|
+
|
90
|
+
line_to_walk = MetaCommit::Models::Line.new
|
91
|
+
if is_replace_change
|
92
|
+
line_to_walk.line_origin=:replace
|
93
|
+
line_to_walk.old_lineno=line.old_lineno
|
94
|
+
line_to_walk.new_lineno=next_line.new_lineno
|
95
|
+
else
|
96
|
+
line_to_walk.line_origin=line.line_origin
|
97
|
+
line_to_walk.old_lineno=line.old_lineno
|
98
|
+
line_to_walk.new_lineno=line.new_lineno
|
99
|
+
end
|
100
|
+
if is_replace_change
|
101
|
+
skip_next_line = true
|
102
|
+
end
|
103
|
+
lines_to_walk.push(line_to_walk)
|
104
|
+
|
105
|
+
skip_walking = true if whole_file_changed
|
106
|
+
end
|
107
|
+
end
|
108
|
+
lines_to_walk
|
109
|
+
end
|
110
|
+
# endregion
|
111
|
+
end
|
112
|
+
end
|
data/lib/meta_commit.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
require "meta_commit/version"
|
2
|
+
|
3
|
+
require "meta_commit/cli"
|
4
|
+
require "meta_commit/git/repo"
|
5
|
+
|
6
|
+
require "meta_commit/adapters/dump"
|
7
|
+
require "meta_commit/adapters/git_notes"
|
8
|
+
|
9
|
+
require "meta_commit/models/ast_path"
|
10
|
+
require "meta_commit/models/line"
|
11
|
+
require "meta_commit/models/changes/commit"
|
12
|
+
require "meta_commit/models/changes/file"
|
13
|
+
require "meta_commit/models/changes/repository"
|
14
|
+
|
15
|
+
require "meta_commit/models/diffs/diff"
|
16
|
+
require "meta_commit/models/diffs/class_creation"
|
17
|
+
require "meta_commit/models/diffs/class_deletion"
|
18
|
+
require "meta_commit/models/diffs/class_rename"
|
19
|
+
require "meta_commit/models/diffs/method_creation"
|
20
|
+
require "meta_commit/models/diffs/method_deletion"
|
21
|
+
require "meta_commit/models/diffs/changes_in_method"
|
22
|
+
require "meta_commit/models/diffs/module_creation"
|
23
|
+
require "meta_commit/models/diffs/module_deletion"
|
24
|
+
require "meta_commit/models/diffs/module_rename"
|
25
|
+
|
26
|
+
require "meta_commit/models/factories/diff_factory"
|
27
|
+
require "meta_commit/models/factories/ast_path_factory"
|
28
|
+
|
29
|
+
require "meta_commit/services/diff_examiner"
|
30
|
+
require "meta_commit/services/diff_index_examiner"
|
31
|
+
require "meta_commit/services/change_saver"
|
32
|
+
require "meta_commit/services/commit_message_builder"
|
33
|
+
|
34
|
+
module MetaCommit
|
35
|
+
end
|
data/meta_commit.gemspec
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'meta_commit/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "meta_commit"
|
8
|
+
spec.version = MetaCommit::VERSION
|
9
|
+
spec.authors = ["Stanislav Dobrovolskiy","Vitalii Shwetz"]
|
10
|
+
spec.email = ["uusername@protonmail.ch","vitsw86@gmail.com"]
|
11
|
+
|
12
|
+
spec.summary = %q{Enrich commit diffs with programing language insights}
|
13
|
+
spec.homepage = "https://github.com/usernam3/meta_commit"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
17
|
+
spec.bindir = "exe"
|
18
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_runtime_dependency "rugged", "~> 0.25"
|
22
|
+
spec.add_runtime_dependency "parser", "~> 2.4"
|
23
|
+
spec.add_runtime_dependency "thor", "~> 0.19"
|
24
|
+
|
25
|
+
spec.add_development_dependency "bundler", "~> 1.10"
|
26
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
27
|
+
spec.add_development_dependency "rspec", "~> 3.6"
|
28
|
+
spec.add_development_dependency "rspec-mocks", "~> 3.6"
|
29
|
+
spec.add_development_dependency "byebug", "~> 9.0"
|
30
|
+
end
|