meta_commit 0.1.0.alpha → 0.2.0.pre.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.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +3 -0
  3. data/CONTRIBUTING.md +61 -0
  4. data/README.md +36 -5
  5. data/Rakefile +7 -1
  6. data/config/default.yml +11 -0
  7. data/exe/meta_commit +5 -1
  8. data/lib/meta_commit/changelog/adapters/changelog.rb +94 -0
  9. data/lib/meta_commit/changelog/commands/commit_diff_examiner.rb +50 -0
  10. data/lib/meta_commit/changelog/formatters/keep_a_changelog_ver_report_builder.rb +123 -0
  11. data/lib/meta_commit/cli.rb +71 -17
  12. data/lib/meta_commit/configuration.rb +45 -0
  13. data/lib/meta_commit/configuration_store.rb +27 -0
  14. data/lib/meta_commit/container.rb +80 -0
  15. data/lib/meta_commit/errors.rb +12 -0
  16. data/lib/meta_commit/factories/contextual_ast_node_factory.rb +61 -0
  17. data/lib/meta_commit/factories/diff_factory.rb +37 -0
  18. data/lib/meta_commit/factories/parser_factory.rb +30 -0
  19. data/lib/meta_commit/git/repo.rb +124 -2
  20. data/lib/meta_commit/index/adapters/git_notes.rb +34 -0
  21. data/lib/meta_commit/index/commands/diff_examiner.rb +58 -0
  22. data/lib/meta_commit/message/commands/diff_index_examiner.rb +48 -0
  23. data/lib/meta_commit/message/formatters/commit_message_builder.rb +16 -0
  24. data/lib/meta_commit/models/changes/commit.rb +24 -0
  25. data/lib/meta_commit/models/changes/repository.rb +12 -0
  26. data/lib/meta_commit/models/contextual_ast_node.rb +9 -0
  27. data/lib/meta_commit/models/diffs/diff.rb +31 -3
  28. data/lib/meta_commit/services/change_saver.rb +3 -26
  29. data/lib/meta_commit/services/parse.rb +21 -0
  30. data/lib/meta_commit/version.rb +1 -1
  31. data/lib/meta_commit.rb +34 -27
  32. data/meta_commit.gemspec +5 -0
  33. metadata +90 -23
  34. data/lib/meta_commit/adapters/dump.rb +0 -31
  35. data/lib/meta_commit/adapters/git_notes.rb +0 -28
  36. data/lib/meta_commit/models/ast_path.rb +0 -111
  37. data/lib/meta_commit/models/changes/file.rb +0 -27
  38. data/lib/meta_commit/models/diffs/addition.rb +0 -34
  39. data/lib/meta_commit/models/diffs/changes_in_method.rb +0 -14
  40. data/lib/meta_commit/models/diffs/class_creation.rb +0 -20
  41. data/lib/meta_commit/models/diffs/class_deletion.rb +0 -16
  42. data/lib/meta_commit/models/diffs/class_rename.rb +0 -11
  43. data/lib/meta_commit/models/diffs/deletion.rb +0 -37
  44. data/lib/meta_commit/models/diffs/method_creation.rb +0 -22
  45. data/lib/meta_commit/models/diffs/method_deletion.rb +0 -22
  46. data/lib/meta_commit/models/diffs/module_creation.rb +0 -14
  47. data/lib/meta_commit/models/diffs/module_deletion.rb +0 -14
  48. data/lib/meta_commit/models/diffs/module_rename.rb +0 -11
  49. data/lib/meta_commit/models/diffs/replacement.rb +0 -19
  50. data/lib/meta_commit/models/factories/ast_path_factory.rb +0 -40
  51. data/lib/meta_commit/models/factories/diff_factory.rb +0 -39
  52. data/lib/meta_commit/services/commit_message_builder.rb +0 -23
  53. data/lib/meta_commit/services/diff_examiner.rb +0 -121
  54. data/lib/meta_commit/services/diff_index_examiner.rb +0 -112
@@ -0,0 +1,80 @@
1
+ require 'dry/container'
2
+ module MetaCommit
3
+ class Container
4
+ include Dry::Container::Mixin
5
+
6
+ def initialize
7
+ super
8
+ register :parser_classes, []
9
+ register :diff_classes, []
10
+ end
11
+
12
+ # @param [MetaCommit::ConfigStore] config_store
13
+ # @return [MetaCommit::Container]
14
+ def boot(config_store)
15
+ load_packages(config_store.get(:extensions))
16
+
17
+ register :diff_factory, MetaCommit::Factories::DiffFactory.new(self[:diff_classes])
18
+ register :parser_factory, MetaCommit::Factories::ParserFactory.new(self[:parser_classes])
19
+ register :parse_command, MetaCommit::Services::Parse.new(self[:parser_factory])
20
+ register :contextual_ast_node_factory, MetaCommit::Factories::ContextualAstNodeFactory.new
21
+
22
+ self
23
+ end
24
+
25
+ # @param [Array<String>] extensions_to_load
26
+ def load_packages(extensions_to_load)
27
+ # @TODO refactor so it search in GEM_HOME dir (?)
28
+ required_extensions(extensions_to_load).each do |gem|
29
+ gem.require_paths.each do |path|
30
+ gem_source_path = File.join(gem.full_gem_path, path)
31
+ $LOAD_PATH.unshift gem_source_path
32
+ require gem.name
33
+ end
34
+
35
+ extension = extension_class(camelize(without_extension_prefix(gem.name))).new
36
+
37
+ self[:parser_classes].concat(extension.parsers)
38
+ self[:diff_classes].concat(extension.diffs)
39
+ end
40
+ end
41
+
42
+ protected :load_packages
43
+
44
+ # @param [Array<String>] extensions_to_load
45
+ # @return [Array<String>]
46
+ def required_extensions(extensions_to_load)
47
+ extensions = Gem::Specification.find_all.select do |gem|
48
+ gem.name =~ /^meta_commit_/ && gem.name != 'meta_commit_contracts' && extensions_to_load.include?(without_extension_prefix gem.name)
49
+ end
50
+ extensions.uniq {|gem| gem.name}
51
+ end
52
+
53
+ protected :required_extensions
54
+
55
+ # @param [String] extension name
56
+ # @return [Class] extension class
57
+ def extension_class(extension)
58
+ "MetaCommit::Extension::#{extension}::Locator".split('::').inject(Object) {|o, c| o.const_get(c)}
59
+ end
60
+
61
+ protected :extension_class
62
+
63
+ # @param [String] extension_name
64
+ # @return [String]
65
+ def camelize(extension_name)
66
+ return extension_name.slice(0, 1).capitalize + extension_name.slice(1..-1) unless extension_name.include?('_') # capitalize only first letter if name is not in snake case
67
+ extension_name.split('_').collect(&:capitalize).join
68
+ end
69
+
70
+ protected :camelize
71
+
72
+ # @param [String] extension_name
73
+ # @return [String]
74
+ def without_extension_prefix(extension_name)
75
+ extension_name.sub('meta_commit_', '')
76
+ end
77
+
78
+ protected :without_extension_prefix
79
+ end
80
+ end
@@ -0,0 +1,12 @@
1
+ module MetaCommit::Errors
2
+ class MissingRepoError < StandardError
3
+ def initialize(msg='Passed directory is not a git repo')
4
+ super(msg)
5
+ end
6
+ end
7
+ class MissingConfigError < StandardError
8
+ def initialize(msg='Passed config file does not exist')
9
+ super(msg)
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,61 @@
1
+ module MetaCommit::Factories
2
+ # Factory that builds ContextualAstNode from ast nodes
3
+ class ContextualAstNodeFactory
4
+
5
+ # @param [MetaCommit::Contracts::Ast] source_ast
6
+ # @param [Integer] line_number
7
+ # @return [MetaCommit::Models::ContextualAstNode]
8
+ def create_ast_path(source_ast, line_number)
9
+ visited_nodes = []
10
+ ast_path = MetaCommit::Models::ContextualAstNode.new
11
+ ast_path.parser_class = source_ast.parser_class
12
+ ast_path.target_node = collect_path_to_ast_at_line(source_ast, line_number, visited_nodes)
13
+ ast_path.context_nodes = visited_nodes
14
+ ast_path
15
+ end
16
+
17
+ # @param [MetaCommit::Contracts::Ast] ast
18
+ # @param [Integer] lineno
19
+ # @param [Array<MetaCommit::Contracts::Ast>] accumulator
20
+ # @return [MetaCommit::Contracts::Ast]
21
+ def collect_path_to_ast_at_line(ast, lineno, accumulator)
22
+ return nil if ast.nil? or not covers_line(ast, lineno)
23
+ closest_ast = ast
24
+ accumulator.push(closest_ast)
25
+ ast.children.each do |child|
26
+ found_ast = collect_path_to_ast_at_line(child, lineno, accumulator)
27
+ closest_ast = found_ast unless found_ast.nil?
28
+ end
29
+ closest_ast
30
+ end
31
+
32
+ protected :collect_path_to_ast_at_line
33
+
34
+
35
+ # @param [MetaCommit::Contracts::Ast] ast
36
+ # @param [Integer] lineno
37
+ # @return [MetaCommit::Contracts::Ast]
38
+ def get_ast_at_line(ast, lineno)
39
+ return nil unless covers_line(ast, lineno)
40
+ closest_ast = ast
41
+ ast.children.each do |child|
42
+ found_ast = get_ast_at_line(child, lineno)
43
+ closest_ast = found_ast unless found_ast.nil?
44
+ end
45
+ closest_ast
46
+ end
47
+
48
+ protected :get_ast_at_line
49
+
50
+
51
+ # @param [MetaCommit::Contracts::Ast] ast
52
+ # @param [Integer] line
53
+ # @return [Boolean]
54
+ def covers_line(ast, line)
55
+ return false if ((ast.first_line.nil?) && (ast.last_line.nil?))
56
+ ((ast.first_line <= line) && (ast.last_line >= line))
57
+ end
58
+
59
+ protected :covers_line
60
+ end
61
+ end
@@ -0,0 +1,37 @@
1
+ module MetaCommit::Factories
2
+ # Diff factory
3
+ # @attr [Array<Class>] available_diff_classes diff classes that factory can build
4
+ class DiffFactory
5
+ attr_accessor :available_diff_classes
6
+
7
+ def initialize(diff_classes)
8
+ @available_diff_classes = diff_classes
9
+ end
10
+
11
+ # Factory method
12
+ # @param [Symbol] type
13
+ # @param [Hash] options
14
+ # @return [Diff, nil] created diff or nil if matched diff not found
15
+ def create_diff_of_type(type, options)
16
+ @available_diff_classes.each do |diff_class|
17
+ diff = diff_class.new
18
+ if diff.supports_parser?(options[:old_ast_path].parser_class) &&
19
+ diff.supports_parser?(options[:new_ast_path].parser_class) &&
20
+ diff.supports_change(type, options[:old_file_path], options[:new_file_path], options[:old_ast_path], options[:new_ast_path])
21
+ line = options[:line]
22
+ diff.diff_type = line.line_origin
23
+ diff.commit_old = options[:commit_id_old]
24
+ diff.commit_new = options[:commit_id_new]
25
+ diff.old_file = options[:old_file_path]
26
+ diff.new_file = options[:new_file_path]
27
+ diff.old_lineno = line.old_lineno
28
+ diff.new_lineno = line.new_lineno
29
+ diff.old_ast_path = options[:old_ast_path]
30
+ diff.new_ast_path = options[:new_ast_path]
31
+ return diff
32
+ end
33
+ end
34
+ nil
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,30 @@
1
+ module MetaCommit::Factories
2
+ # Parser factory
3
+ # @attr [Array<Class>] available_parser_classes parser classes that factory can build
4
+ class ParserFactory
5
+ attr_accessor :available_parser_classes
6
+
7
+ # @param [Array<Class>] parser_classes
8
+ def initialize(parser_classes)
9
+ @available_parser_classes = parser_classes
10
+ end
11
+
12
+ # @param [String] filename
13
+ # @param [String] content
14
+ # @return [MetaCommit::Contracts::Parser, Nil]
15
+ def create_parser_for(filename, content)
16
+ @available_parser_classes.each do |parser|
17
+ return parser.new if parser_supports(parser, filename, content)
18
+ end
19
+ nil
20
+ end
21
+
22
+ # @param [Class] parser
23
+ # @param [String] filename
24
+ # @param [String] content
25
+ # @return [Boolean]
26
+ def parser_supports(parser, filename, content)
27
+ (parser.supported_file_extensions.any? {|ext| filename.end_with?(ext)}) && (parser.supports_syntax?(content))
28
+ end
29
+ end
30
+ end
@@ -1,13 +1,26 @@
1
1
  require 'rugged'
2
2
 
3
3
  module MetaCommit::Git
4
+ # Rugged::Repository wrapper
5
+ # @attr [Rugged::Repository] repo
4
6
  class Repo
7
+ DIFF_OPTIONS = {:context_lines => 0, :ignore_whitespace => true}
8
+ FILE_NOT_EXISTS_OID = '0000000000000000000000000000000000000000'
9
+
5
10
  attr_accessor :repo
6
11
 
12
+ # @param [String] repo_path
7
13
  def initialize(repo_path)
8
- @repo = Rugged::Repository.new(repo_path)
14
+ begin
15
+ @repo = Rugged::Repository.new(repo_path)
16
+ rescue Rugged::OSError
17
+ raise MetaCommit::Errors::MissingRepoError
18
+ rescue Rugged::RepositoryError
19
+ raise MetaCommit::Errors::MissingRepoError
20
+ end
9
21
  end
10
22
 
23
+ # @return [Rugged::Walker] commit iterator
11
24
  def walker
12
25
  walker = Rugged::Walker.new(@repo)
13
26
  walker.sorting(Rugged::SORT_REVERSE)
@@ -15,6 +28,8 @@ module MetaCommit::Git
15
28
  walker
16
29
  end
17
30
 
31
+ # Starts commit walker and yields following commits for easier iteration
32
+ # @yield [previous_commit, current_commit]
18
33
  def walk_by_commits
19
34
  walker = Rugged::Walker.new(@repo)
20
35
  walker.sorting(Rugged::SORT_REVERSE)
@@ -29,22 +44,64 @@ module MetaCommit::Git
29
44
  end
30
45
  end
31
46
 
47
+ # Proxy to Rugged::Repository#diff
48
+ # @param [Object] left
49
+ # @param [Object] right
50
+ # @param [Hash] options
51
+ # @return [Rugged::Diff::Delta]
32
52
  def diff(left, right, options)
33
53
  @repo.diff(left, right, options)
34
54
  end
35
55
 
56
+ # Iterates over optimized lines in diff
57
+ # @param [Object] left
58
+ # @param [Object] right
59
+ # @yield [old_file_path, new_file_path, patch, line]
60
+ # @return [Object]
61
+ def diff_with_optimized_lines(left, right)
62
+ diff = @repo.diff(left, right, DIFF_OPTIONS)
63
+ diff.deltas.zip(diff.patches).each do |delta, patch|
64
+ lines = organize_lines(delta, patch)
65
+ lines.each do |line|
66
+ yield(delta.old_file[:path], delta.new_file[:path], patch, line)
67
+ end
68
+ end
69
+ end
70
+
71
+ # Iterates over optimized lines in index diff
72
+ # @yield [old_file_path, new_file_path, patch, line]
73
+ # @return [Object]
74
+ def index_diff_with_optimized_lines
75
+ diff = index_diff(DIFF_OPTIONS)
76
+ diff.deltas.zip(diff.patches).each do |delta, patch|
77
+ lines = organize_lines(delta, patch)
78
+ lines.each do |line|
79
+ yield(delta.old_file[:path], delta.new_file[:path], patch, line)
80
+ end
81
+ end
82
+ end
83
+
84
+ # Proxy to Rugged::Index#diff
85
+ # @param [Hash] options
86
+ # @return [Rugged::Diff::Delta]
36
87
  def index_diff(options)
37
88
  @repo.index.diff(@repo.head.target.tree, options)
38
89
  end
39
90
 
91
+ # @param [String] revision commit hash
92
+ # @param [String] path
93
+ # @param [String] default value to be returned if error appears
40
94
  def get_blob_at(revision, path, default = nil)
41
95
  blob = @repo.blob_at(revision, path)
42
96
  return blob.content unless blob.nil?
43
97
  default
44
98
  end
45
99
 
100
+ # @param [String] rel_repo_file_path file path relative to repository root
101
+ # @param [String] default value to be returned if error appears
102
+ # @return [String] file content or default value
46
103
  def get_content_of(rel_repo_file_path, default = nil)
47
- absolute_file_path = @repo.path.reverse.sub('/.git'.reverse, '').reverse + rel_repo_file_path
104
+ absolute_file_path = dir + rel_repo_file_path
48
105
  begin
49
106
  content = open(absolute_file_path).read
50
107
  rescue Errno::ENOENT
@@ -53,8 +110,73 @@ module MetaCommit::Git
53
110
  content
54
111
  end
55
112
 
113
+ # @return [String] path to .git folder of repository
56
114
  def path
57
115
  @repo.path
58
116
  end
117
+
118
+ # @return [String] directory of repository
119
+ def dir
120
+ @repo.path.reverse.sub('/.git'.reverse, '').reverse
121
+ end
122
+
123
+ # @param [String] search_tag
124
+ # @return [Rugged::Commit, nil]
125
+ def commit_of_tag(search_tag)
126
+ @repo.tags.each do |tag|
127
+ return tag.target if tag.name == search_tag
128
+ end
129
+ end
130
+
131
+ # @return [String] last commit oid
132
+ def last_commit_oid
133
+ @repo.last_commit.oid
134
+ end
135
+
136
+ # @param [Object] delta
137
+ # @param [Object] patch
138
+ # @return [Array<MetaCommit::Models::Line>]
139
+ def organize_lines(delta, patch)
140
+ lines_to_walk = []
141
+ # if whole file was changed examine one time only
142
+ whole_file_changed = (delta.old_file[:oid] == FILE_NOT_EXISTS_OID) || (delta.new_file[:oid] == FILE_NOT_EXISTS_OID)
143
+ skip_walking = false
144
+ skip_next_line = false
145
+ patch.hunks.each_with_index do |hunk|
146
+ break if skip_walking
147
+ hunk.lines.each_with_index do |line, line_index|
148
+ break if skip_walking
149
+
150
+ if skip_next_line
151
+ skip_next_line = false
152
+ next
153
+ end
154
+
155
+ next_line = hunk.lines[line_index + 1]
156
+ is_replace_change = (line.deletion?) && (!next_line.nil? && next_line.addition?) && (line.old_lineno && next_line.new_lineno)
157
+
158
+ line_to_walk = MetaCommit::Models::Line.new
159
+ if is_replace_change
160
+ line_to_walk.line_origin=:replace
161
+ line_to_walk.old_lineno=line.old_lineno
162
+ line_to_walk.new_lineno=next_line.new_lineno
163
+ else
164
+ line_to_walk.line_origin=line.line_origin
165
+ line_to_walk.old_lineno=line.old_lineno
166
+ line_to_walk.new_lineno=line.new_lineno
167
+ end
168
+ if is_replace_change
169
+ skip_next_line = true
170
+ end
171
+ lines_to_walk.push(line_to_walk)
172
+
173
+ skip_walking = true if whole_file_changed
174
+ end
175
+ end
176
+ lines_to_walk
177
+ end
178
+
179
+ private :organize_lines
180
+
59
181
  end
60
182
  end
@@ -0,0 +1,34 @@
1
+ module MetaCommit::Index
2
+ module Adapters
3
+ # Adapter class to write repository changes to git notes
4
+ # @attr [String] git_folder_path
5
+ class GitNotes
6
+ attr_accessor :git_folder_path
7
+
8
+ # @param [String] git_folder_path
9
+ def initialize(git_folder_path)
10
+ @git_folder_path = git_folder_path
11
+ end
12
+
13
+ # @param [MetaCommit::Git::Repo] repo
14
+ # @param [MetaCommit::Models::Changes::Repository] repository_changes
15
+ def write_repository_change_chunk(repo, repository_changes)
16
+ repository_changes.each do |commit_changes|
17
+ diffs=[]
18
+ commit_changes.file_changes.uniq.each do |change|
19
+ diffs.push(" - #{change.string_representation}")
20
+ end
21
+ write_to_notes(commit_changes.new_commit_id, diffs.join("\n"))
22
+ end
23
+ end
24
+
25
+ # @param [String] commit_id
26
+ # @param [String] message
27
+ def write_to_notes(commit_id, message)
28
+ system("git --git-dir '#{@git_folder_path}' notes add -f -m '#{message}' #{commit_id}")
29
+ end
30
+
31
+ protected :write_to_notes
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,58 @@
1
+ module MetaCommit::Index
2
+ module Commands
3
+ class DiffExaminer
4
+ # @param [MetaCommit::Services::Parse] parse_command
5
+ # @param [MetaCommit::Factories::ContextualAstNodeFactory] ast_path_factory
6
+ # @param [MetaCommit::Factories::DiffFactory] diff_factory
7
+ def initialize(parse_command, ast_path_factory, diff_factory)
8
+ @parse_command = parse_command
9
+ @ast_path_factory = ast_path_factory
10
+ @diff_factory = diff_factory
11
+ end
12
+
13
+ # Creates diff objects with meta information of changes in repository commits
14
+ # @param [MetaCommit::Git::Repo] repo
15
+ def meta(repo)
16
+ repo_changes = MetaCommit::Models::Changes::Repository.new(repo.path)
17
+ repo.walk_by_commits do |left_commit, right_commit|
18
+ commit_changes = MetaCommit::Models::Changes::Commit.new(left_commit.oid, right_commit.oid)
19
+ diffs = examine_diff(repo, left_commit, right_commit)
20
+ commit_changes.push_changes(diffs)
21
+ repo_changes.push(commit_changes)
22
+ end
23
+ repo_changes
24
+ end
25
+
26
+ # @return [Array<MetaCommit::Models::Diffs::Diff>]
27
+ def examine_diff(repo, left_commit, right_commit)
28
+ diffs = []
29
+ repo.diff_with_optimized_lines(left_commit, right_commit) do |old_file_path, new_file_path, patch, line|
30
+ old_file_content = repo.get_blob_at(left_commit.oid, old_file_path, '')
31
+ new_file_content = repo.get_blob_at(right_commit.oid, new_file_path, '')
32
+
33
+ old_file_ast = @parse_command.execute(old_file_path, old_file_content)
34
+ next if old_file_ast.nil?
35
+ new_file_ast = @parse_command.execute(new_file_path, new_file_content)
36
+ next if new_file_ast.nil?
37
+
38
+ old_ast_path = @ast_path_factory.create_ast_path(old_file_ast, line.old_lineno)
39
+ new_ast_path = @ast_path_factory.create_ast_path(new_file_ast, line.new_lineno)
40
+
41
+ created_diff = @diff_factory.create_diff_of_type(line.line_origin, {
42
+ :line => line,
43
+ :commit_id_old => left_commit.oid,
44
+ :commit_id_new => right_commit.oid,
45
+ :old_ast_path => old_ast_path,
46
+ :new_ast_path => new_ast_path,
47
+ :old_file_path => old_file_path,
48
+ :new_file_path => new_file_path,
49
+ })
50
+ diffs.push(created_diff) unless created_diff.nil?
51
+ end
52
+ diffs
53
+ end
54
+
55
+ private :examine_diff
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,48 @@
1
+ module MetaCommit::Message
2
+ module Commands
3
+ class DiffIndexExaminer
4
+ # @param [MetaCommit::Services::Parse] parse_command
5
+ # @param [MetaCommit::Factories::ContextualAstNodeFactory] ast_path_factory
6
+ # @param [MetaCommit::Factories::DiffFactory] diff_factory
7
+ def initialize(parse_command, ast_path_factory, diff_factory)
8
+ @parse_command = parse_command
9
+ @ast_path_factory = ast_path_factory
10
+ @diff_factory = diff_factory
11
+ end
12
+
13
+ # Creates diff objects with meta information of changes in index staged files
14
+ # @param [MetaCommit::Git::Repo] repo
15
+ # @return [Array<MetaCommit::Models::Diffs::Diff>]
16
+ def index_meta(repo)
17
+ diffs = MetaCommit::Models::Changes::Commit.new(repo.last_commit_oid, 'staged')
18
+ repo.index_diff_with_optimized_lines do |old_file_path, new_file_path, patch, line|
19
+ commit_id_old = repo.last_commit_oid
20
+ commit_id_new = 'staged'
21
+
22
+ old_file_content = repo.get_blob_at(commit_id_old, old_file_path, '')
23
+ new_file_content = repo.get_content_of(new_file_path, '')
24
+
25
+ old_file_ast = @parse_command.execute(old_file_path, old_file_content)
26
+ next if old_file_ast.nil?
27
+ new_file_ast = @parse_command.execute(new_file_path, new_file_content)
28
+ next if new_file_ast.nil?
29
+
30
+ old_ast_path = @ast_path_factory.create_ast_path(old_file_ast, line.old_lineno)
31
+ new_ast_path = @ast_path_factory.create_ast_path(new_file_ast, line.new_lineno)
32
+
33
+ created_diff = @diff_factory.create_diff_of_type(line.line_origin, {
34
+ :line => line,
35
+ :commit_id_old => commit_id_old,
36
+ :commit_id_new => commit_id_new,
37
+ :old_ast_path => old_ast_path,
38
+ :new_ast_path => new_ast_path,
39
+ :old_file_path => old_file_path,
40
+ :new_file_path => new_file_path,
41
+ })
42
+ diffs.push(created_diff) unless created_diff.nil?
43
+ end
44
+ diffs
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,16 @@
1
+ module MetaCommit::Message
2
+ module Formatters
3
+ # Class builds message to commit changes
4
+ class CommitMessageBuilder
5
+ # @param [Array<MetaCommit::Models::Diffs::Diff>] diffs
6
+ # @return [String]
7
+ def build(diffs)
8
+ result = ''
9
+ diffs.each do |diff|
10
+ result << "- #{diff.string_representation} \n"
11
+ end
12
+ result
13
+ end
14
+ end
15
+ end
16
+ end
@@ -1,17 +1,30 @@
1
1
  module MetaCommit::Models::Changes
2
+ # Collection of file changes
3
+ # @attr [Symbol] old_commit_id
4
+ # @attr [Symbol] new_commit_id
5
+ # @attr [Array<MetaCommit::Contracts::Diff>] file_changes
2
6
  class Commit
3
7
  attr_accessor :old_commit_id, :new_commit_id, :file_changes
4
8
 
9
+ # @param [Symbol] old_commit_id
10
+ # @param [Symbol] new_commit_id
5
11
  def initialize(old_commit_id, new_commit_id)
6
12
  @old_commit_id = old_commit_id
7
13
  @new_commit_id = new_commit_id
8
14
  @file_changes = []
9
15
  end
10
16
 
17
+ # @param [MetaCommit::Contracts::Diff] file_change
11
18
  def push(file_change)
12
19
  @file_changes.push(file_change)
13
20
  end
14
21
 
22
+ # @param [Array<MetaCommit::Contracts::Diff>] file_changes
23
+ def push_changes(file_changes)
24
+ @file_changes+=file_changes
25
+ end
26
+
27
+ # @return [String]
15
28
  def commit_id
16
29
  if @old_commit_id == @new_commit_id
17
30
  @new_commit_id
@@ -20,8 +33,19 @@ module MetaCommit::Models::Changes
20
33
  end
21
34
  end
22
35
 
36
+ # @yield file changes
23
37
  def each(&block)
24
38
  @file_changes.each(&block)
25
39
  end
40
+
41
+ # @return [Boolean]
42
+ def empty?
43
+ @file_changes.empty?
44
+ end
45
+
46
+ # @return [Boolean]
47
+ def include?(change)
48
+ @file_changes.include?(change)
49
+ end
26
50
  end
27
51
  end
@@ -1,18 +1,30 @@
1
1
  module MetaCommit::Models::Changes
2
+ # Collection of commit changes
3
+ # @attr [String] repo_id
4
+ # @attr [Array<MetaCommit::Models::Commit>] commit_changes
2
5
  class Repository
3
6
  attr_accessor :repo_id, :commit_changes
4
7
 
8
+ # @param [String] repo_id
5
9
  def initialize(repo_id)
6
10
  @repo_id = repo_id
7
11
  @commit_changes = []
8
12
  end
9
13
 
14
+
15
+ # @param [MetaCommit::Models::Commit] commit_change
10
16
  def push(commit_change)
11
17
  @commit_changes.push(commit_change)
12
18
  end
13
19
 
20
+ # @yield commit changes
14
21
  def each(&block)
15
22
  @commit_changes.each(&block)
16
23
  end
24
+
25
+ # @return [Boolean]
26
+ def empty?
27
+ @commit_changes.empty?
28
+ end
17
29
  end
18
30
  end
@@ -0,0 +1,9 @@
1
+ module MetaCommit::Models
2
+ # Stores specific node from ast and all nodes bypassed on the way to target node
3
+ # @attr [MetaCommit::Contracts::Ast] target_node Target node from AST
4
+ # @attr [Array<MetaCommit::Contracts::Ast>] context_nodes Nodes bypassed on the way to target node
5
+ # @attr [Class] parser_class
6
+ class ContextualAstNode
7
+ attr_accessor :target_node, :context_nodes, :parser_class
8
+ end
9
+ end