overrides_tracker 0.1.12 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 66085bc82fe4b27b6fc5672a257751effdac97f3ee0492b2764b6a6ccd721ae3
4
- data.tar.gz: 2f93dc7369c1b9dc2cf87c737d037167c44bc6e42e83e708aebd56d1b3b4d477
3
+ metadata.gz: 43cf4d931371c4f3781a672310dc100f2a6ec14ebff9d75113c3d0d1b5c336fb
4
+ data.tar.gz: ab49ef6c8b619543497708efd105451ad718450900a0d171ff2dde092b045239
5
5
  SHA512:
6
- metadata.gz: 501e4191f85c326858b8dac38f5db8a6f434f2d0dd49131e0b8bd72ce276e652296a97bac278609424c25475d6626fec7101939a01294387da0376274455b2c4
7
- data.tar.gz: de27da503a2ad558f38d186b1d3056771029e907cde457f2de62ff37857e5285a53a1849de67322e2e37ffb9ef97b17bb30d6c655d3474ae9eabdf9c5759a13e
6
+ metadata.gz: d84a9f391b0c4b25fe4f6c661fe001eb081265b8adb8d03913481382e9387e86598aa90dff56b16808ab5793a7f493cd88e0a86f3bd2ecdaefb8fc5b86d1f362
7
+ data.tar.gz: 7fd010bfa2cc019ff906bbe192005deaf43234f9772f27c5eed835ac031ae7679cff57662f840b5a4a102257c4a6cbb8f9c9767af90e28c13d06763724f1f590
@@ -0,0 +1,20 @@
1
+ version: 2.1
2
+ orbs:
3
+ ruby: circleci/ruby@1.0.4
4
+ coveralls: coveralls/coveralls@1.0.6
5
+ jobs:
6
+ test:
7
+ docker:
8
+ - image: cimg/ruby:2.7.2-node
9
+ steps:
10
+ - checkout
11
+ - ruby/install-deps
12
+ - run:
13
+ name: Run tests
14
+ command: bundle exec rspec
15
+
16
+ workflows:
17
+ version: 2
18
+ deploy:
19
+ jobs:
20
+ - test
data/Gemfile.lock ADDED
@@ -0,0 +1,109 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ overrides_tracker (0.1.13)
5
+ activesupport
6
+ method_source
7
+
8
+ GEM
9
+ remote: https://rubygems.org/
10
+ specs:
11
+ activesupport (6.1.7.2)
12
+ concurrent-ruby (~> 1.0, >= 1.0.2)
13
+ i18n (>= 1.6, < 2)
14
+ minitest (>= 5.1)
15
+ tzinfo (~> 2.0)
16
+ zeitwerk (~> 2.3)
17
+ addressable (2.8.1)
18
+ public_suffix (>= 2.0.2, < 6.0)
19
+ ast (2.4.2)
20
+ concurrent-ruby (1.2.0)
21
+ coveralls_reborn (0.25.0)
22
+ simplecov (>= 0.18.1, < 0.22.0)
23
+ term-ansicolor (~> 1.6)
24
+ thor (>= 0.20.3, < 2.0)
25
+ tins (~> 1.16)
26
+ crack (0.4.5)
27
+ rexml
28
+ diff-lcs (1.5.0)
29
+ docile (1.4.0)
30
+ hashdiff (1.0.1)
31
+ i18n (1.12.0)
32
+ concurrent-ruby (~> 1.0)
33
+ json (2.6.3)
34
+ method_source (1.0.0)
35
+ minitest (5.17.0)
36
+ parallel (1.22.1)
37
+ parser (3.1.3.0)
38
+ ast (~> 2.4.1)
39
+ public_suffix (5.0.1)
40
+ rainbow (3.1.1)
41
+ regexp_parser (2.6.1)
42
+ rexml (3.2.5)
43
+ rspec (3.12.0)
44
+ rspec-core (~> 3.12.0)
45
+ rspec-expectations (~> 3.12.0)
46
+ rspec-mocks (~> 3.12.0)
47
+ rspec-core (3.12.0)
48
+ rspec-support (~> 3.12.0)
49
+ rspec-expectations (3.12.0)
50
+ diff-lcs (>= 1.2.0, < 2.0)
51
+ rspec-support (~> 3.12.0)
52
+ rspec-mocks (3.12.1)
53
+ diff-lcs (>= 1.2.0, < 2.0)
54
+ rspec-support (~> 3.12.0)
55
+ rspec-support (3.12.0)
56
+ rspec_junit_formatter (0.6.0)
57
+ rspec-core (>= 2, < 4, != 2.12.0)
58
+ rubocop (1.40.0)
59
+ json (~> 2.3)
60
+ parallel (~> 1.10)
61
+ parser (>= 3.1.2.1)
62
+ rainbow (>= 2.2.2, < 4.0)
63
+ regexp_parser (>= 1.8, < 3.0)
64
+ rexml (>= 3.2.5, < 4.0)
65
+ rubocop-ast (>= 1.23.0, < 2.0)
66
+ ruby-progressbar (~> 1.7)
67
+ unicode-display_width (>= 1.4.0, < 3.0)
68
+ rubocop-ast (1.24.0)
69
+ parser (>= 3.1.1.0)
70
+ ruby-progressbar (1.11.0)
71
+ simplecov (0.21.2)
72
+ docile (~> 1.1)
73
+ simplecov-html (~> 0.11)
74
+ simplecov_json_formatter (~> 0.1)
75
+ simplecov-html (0.12.3)
76
+ simplecov-lcov (0.8.0)
77
+ simplecov_json_formatter (0.1.4)
78
+ sync (0.5.0)
79
+ term-ansicolor (1.7.1)
80
+ tins (~> 1.0)
81
+ thor (1.2.1)
82
+ tins (1.32.1)
83
+ sync
84
+ tzinfo (2.0.6)
85
+ concurrent-ruby (~> 1.0)
86
+ unicode-display_width (2.3.0)
87
+ vcr (6.1.0)
88
+ webmock (3.18.1)
89
+ addressable (>= 2.8.0)
90
+ crack (>= 0.3.2)
91
+ hashdiff (>= 0.4.0, < 2.0.0)
92
+ zeitwerk (2.6.6)
93
+
94
+ PLATFORMS
95
+ ruby
96
+
97
+ DEPENDENCIES
98
+ coveralls_reborn (~> 0.25.0)
99
+ overrides_tracker!
100
+ rspec
101
+ rspec_junit_formatter
102
+ rubocop
103
+ simplecov
104
+ simplecov-lcov (~> 0.8.0)
105
+ vcr (>= 2.9)
106
+ webmock (>= 1.20)
107
+
108
+ BUNDLED WITH
109
+ 2.1.4
data/README.md CHANGED
@@ -20,7 +20,7 @@ Getting started
20
20
  ```ruby
21
21
  gem 'overrides_tracker', group: [:test, :development]
22
22
  ```
23
- 2. Add `overrides_tracker/*.otf` to your .gitignore file because you do won't to keep hold of your report file when changing branches.
23
+ 2. Add `overrides_tracker/*.otf` to your .gitignore file because you want to keep hold of your report file when switching branches.
24
24
 
25
25
  3. Track you overrides by running:
26
26
  ```ruby
@@ -47,7 +47,7 @@ Getting started
47
47
  Report saved to /PATH_TO_PROJECT/overrides_tracker/BRANCH_NAME#LAST_COMMIT_ID.otf
48
48
  ```
49
49
 
50
- 4. This will create a folder called overrides_tracker and creates a file containing all overriding methods of your branch.
50
+ 4. This will create a folder called overrides_tracker and a file containing all methods you override as well as your overrides in that branch.
51
51
 
52
52
  5. Switch branch and follow steps 1-3 again. If you want to compare multiple branches you need to redo these steps for every branch.
53
53
 
@@ -63,65 +63,110 @@ Getting started
63
63
  ```
64
64
  ===========================================================================================
65
65
 
66
- 1) BClass#a_instance_method_override: No Changes
66
+ 1) Override: OrdinaryGem::AnotherTypicalClass#a_singleton_method_that_stays_the_same
67
67
 
68
- ===========================================================================================
68
+ ...........................................................................................
69
69
 
70
- 2)....
71
- .
72
- .
73
- .
70
+ main#cc5a31dc4833734a177f01bd161047f8c7909e16.otf
71
+ -------------------------------------------------------------------------------------------
74
72
 
75
- ===========================================================================================
73
+ Original:
76
74
 
77
- 26) YClass#a_singelton_method_override: Changes between files
75
+ def self.a_singleton_method_that_stays_the_same
76
+ "This is the implementation of a simple singleton method."
77
+ "This method will stay the same in the next version."
78
+ end
78
79
 
79
- in: master#528a0206d8f7cfe08737193659f85e28ccb260eb.otf
80
- YClass#a_singelton_method_override:
81
80
 
82
- Source:
83
- def self.a_singelton_method_override
84
- does_stuff_one_way
85
- end
81
+ in BUNDLE_PATH/bundler/gems/ordinary-gem-e67e062189bb/lib/ordinary_gem/another_typical_class.rb:19
82
+
86
83
 
87
- ../.rbenv/versions/2.3.8/lib/ruby/gems/2.3.0/bundler/gems/some_gem/lib/some_gem/y_class.rb:2
84
+ -------------------------------------------------------------------------------------------
88
85
 
89
86
  Override:
90
- def self.a_singelton_method_override
91
- does_stuff_one_way_but_slitly_different
87
+
88
+ def self.a_singleton_method_that_stays_the_same
89
+ "This is our override of a simple singleton method."
90
+ "This method should stay the same in the next version."
92
91
  end
93
92
 
94
- /PATH_TO_PROJECT/app/models/decorators/y_class_decorator.rb:13
93
+
94
+ in: APP_PATH/app/models/ordinary_gem/another_typical_class_monkey_patch.rb:2
95
95
 
96
96
 
97
- in: upgrade_to_latest#beadcdd8e07a2c9dc2aefddeef04fc42e6fff0d5.otf
98
- YClass#a_singelton_method_override:
99
97
 
100
- Source:
101
- def self.a_singelton_method_override
102
- does_stuff_in_a_different_way
98
+ ...........................................................................................
99
+
100
+ attached-to-next-version#a7231014c006a4a5848eb4d92bb465eb5c89ee01.otf
101
+ -------------------------------------------------------------------------------------------
102
+
103
+ Original:
104
+
105
+ def self.a_singleton_method_that_stays_the_same
106
+ "This is the implementation of a simple singleton method."
107
+ "This method will stay the same in the next version."
103
108
  end
104
109
 
105
- ../.rbenv/versions/2.3.8/lib/ruby/gems/2.3.0/bundler/gems/some_gem/lib/some_gem/y_class.rb:2
110
+
111
+ in BUNDLE_PATH/bundler/gems/ordinary-gem-f92e5a1a70a6/lib/ordinary_gem/another_typical_class.rb:13
112
+
113
+
114
+ -------------------------------------------------------------------------------------------
106
115
 
107
116
  Override:
108
- def self.a_singelton_method_override
109
- does_stuff_one_way_but_slitly_different
117
+
118
+ def self.a_singleton_method_that_stays_the_same
119
+ "This is our override of a simple singleton method."
120
+ "This method should stay the same in the next version."
110
121
  end
111
122
 
112
- /PATH_TO_PROJECT/app/models/decorators/y_class_decorator.rb:13
113
123
 
124
+ in: APP_PATH/app/models/ordinary_gem/another_typical_class_monkey_patch.rb:2
125
+
126
+
127
+
128
+ ...........................................................................................
129
+
130
+ main#1d279724b26c9491e6e5a01e9711b61a73e9f7e0.otf
131
+ Method not available
132
+
133
+
134
+
135
+
136
+
137
+ ...........................................................................................
138
+ .
139
+ .
140
+ .
141
+ .
114
142
  ===========================================================================================
115
143
 
116
144
  Summary:
117
- Found 29 distinct overridden methods
118
- 10 overridden methods have not changed
119
- 19 overridden methods have changed
120
- 1 where method is not an override
121
- 4 where method is not in codebase
122
- 15 source method bodies have changed
145
+
146
+ Investigated methods: 70
147
+ Diffences on overrides: 42
148
+ Diffences on added methods: 28
149
+
123
150
  ```
124
-
151
+
152
+ ## Overrides.io integration
153
+ <img width="1000" alt="Bildschirm­foto 2023-01-10 um 21 39 42" src="https://user-images.githubusercontent.com/9799974/211657428-c2a7e272-ae86-4c1c-8e77-0a07acc1a4a0.png">
154
+
155
+ Overrides.io is a service that monitors code you override for changes. It notifies you whenever those changes occur.
156
+ Additionally it gives you a beautiful overview of all the methods you have overridden as well as your overrides side by side.
157
+ <p float="left">
158
+ <img width="500" alt="Bildschirm­foto 2023-01-10 um 21 39 15" src="https://user-images.githubusercontent.com/9799974/211658325-60c21057-1a07-4b55-a4d5-3d82470fb3ee.png">
159
+ <img width="500" alt="Bildschirm­foto 2023-01-10 um 21 39 28" src="https://user-images.githubusercontent.com/9799974/211658362-f50435dd-56c5-498b-9038-f702addb0717.png">
160
+ </p>
161
+ Overrides Tracker can easily be integrated into you CI/CD pipeline and configured to send the result files to overrides.io.
162
+
163
+ You basically just have to set OVERRIDES_API_TOKEN environment variable and call 'bundle exec overrides_tracker track'.
164
+ To push it to overrides.io locally you could also just call 'bundle exec overrides_tracker track YOUR_OVERRIDES_API_TOKEN'.
165
+
166
+ You can find a detailed description how to integrate it with CircleCI, GitHub Action and Jenkins here:
167
+
168
+ https://www.overrides.io/continuous_integration
169
+
125
170
  ## GEM support
126
171
 
127
172
  Overrides Tracker can also be used on GEMs. It will autoload all classes in the lib and app folders.
@@ -135,7 +180,7 @@ You can also use the ['require_all'](https://github.com/jarmo/require_all) way t
135
180
 
136
181
  ## Ruby version compatibility
137
182
 
138
- OverridesTracker is built in [Continuous Integration] on Ruby 2.3+.
183
+ Overrides Tracker is built in [Continuous Integration] on Ruby 2.3+.
139
184
 
140
185
  ## Code of Conduct
141
186
 
@@ -152,4 +197,4 @@ Everyone participating in this project's development, issue trackers and other c
152
197
 
153
198
  ## Copyright
154
199
 
155
- Copyright (c) 2022 Simon Meyborg. See MIT-LICENSE for details.
200
+ Copyright (c) 2023 Simon Meyborg. See MIT-LICENSE for details.
@@ -29,6 +29,7 @@ if ARGV[0] == 'track'
29
29
  end
30
30
 
31
31
  OverridesTracker::MethodsCollector.instance.build_overrides_hash
32
+ OverridesTracker::MethodsCollector.instance.summarize_overrides
32
33
  OverridesTracker::MethodsCollector.instance.save_to_file
33
34
 
34
35
  if ENV['OVERRIDES_API_TOKEN']
@@ -0,0 +1,252 @@
1
+ #--
2
+ # Copyright (C)2009 Tony Arcieri
3
+ # You can redistribute this under the terms of the MIT license
4
+ # See file LICENSE for details
5
+ #++
6
+
7
+ module RequireAll
8
+ LoadError = Class.new(::LoadError)
9
+
10
+ # A wonderfully simple way to load your code.
11
+ #
12
+ # The easiest way to use require_all is to just point it at a directory
13
+ # containing a bunch of .rb files. These files can be nested under
14
+ # subdirectories as well:
15
+ #
16
+ # require_all 'lib'
17
+ #
18
+ # This will find all the .rb files under the lib directory and load them.
19
+ #
20
+ # If a file required by require_all references a constant that is not yet
21
+ # loaded, a RequireAll::LoadError will be thrown.
22
+ #
23
+ # You can also give it a glob, which will enumerate all the matching files:
24
+ #
25
+ # require_all 'lib/**/*.rb'
26
+ #
27
+ # It will also accept an array of files:
28
+ #
29
+ # require_all Dir.glob("blah/**/*.rb").reject { |f| stupid_file(f) }
30
+ #
31
+ # Or if you want, just list the files directly as arguments:
32
+ #
33
+ # require_all 'lib/a.rb', 'lib/b.rb', 'lib/c.rb', 'lib/d.rb'
34
+ #
35
+ def require_all(*args)
36
+ # Handle passing an array as an argument
37
+ args.flatten!
38
+
39
+ options = {method: :require}
40
+ options.merge!(args.pop) if args.last.is_a?(Hash)
41
+
42
+ if args.empty?
43
+ puts "no files were loaded due to an empty Array" if $DEBUG
44
+ return false
45
+ end
46
+
47
+ if args.size > 1
48
+ # Expand files below directories
49
+ files = args.map do |path|
50
+ if File.directory? path
51
+ Dir[File.join(path, '**', '*.rb')]
52
+ else
53
+ path
54
+ end
55
+ end.flatten
56
+ else
57
+ arg = args.first
58
+ begin
59
+ # Try assuming we're doing plain ol' require compat
60
+ stat = File.stat(arg)
61
+
62
+ if stat.file?
63
+ files = [arg]
64
+ elsif stat.directory?
65
+ files = Dir.glob File.join(arg, '**', '*.rb')
66
+ else
67
+ raise ArgumentError, "#{arg} isn't a file or directory"
68
+ end
69
+ rescue SystemCallError
70
+ # If the stat failed, maybe we have a glob!
71
+ files = Dir.glob arg
72
+
73
+ # Maybe it's an .rb file and the .rb was omitted
74
+ if File.file?(arg + '.rb')
75
+ file = arg + '.rb'
76
+ options[:method] != :autoload ? __require(options[:method], file) : __autoload(file, file, options)
77
+ return true
78
+ end
79
+
80
+ # If we ain't got no files, the glob failed
81
+ #raise LoadError, "no such file to load -- #{arg}" if files.empty?
82
+ end
83
+ end
84
+
85
+ return if files.empty?
86
+
87
+ if options[:method] == :autoload
88
+ files.map! { |file_| [file_, File.expand_path(file_)] }
89
+ files.each do |file_, full_path|
90
+ __autoload(file_, full_path, options)
91
+ end
92
+
93
+ return true
94
+ end
95
+
96
+ files.map { |file_| File.expand_path file_ }.sort.each do |file_|
97
+ begin
98
+ __require(options[:method], file_)
99
+ rescue NameError => e
100
+ # Only wrap NameError exceptions for uninitialized constants
101
+ #raise e unless e.instance_of?(NameError) && e.message.include?('uninitialized constant')
102
+ #raise LoadError, "Could not require #{file_} (#{e}). Please require the necessary files"
103
+ end
104
+ end
105
+
106
+ true
107
+ end
108
+
109
+ # Works like require_all, but paths are relative to the caller rather than
110
+ # the current working directory
111
+ def require_rel(*paths)
112
+ # Handle passing an array as an argument
113
+ paths.flatten!
114
+ return false if paths.empty?
115
+
116
+ source_directory = File.dirname caller.first.sub(/:\d+$/, '')
117
+ paths.each do |path|
118
+ require_all File.join(source_directory, path)
119
+ end
120
+ end
121
+
122
+ # Loads all files like require_all instead of requiring
123
+ def load_all(*paths)
124
+ require_all paths, method: :load
125
+ end
126
+
127
+ # Loads all files by using relative paths of the caller rather than
128
+ # the current working directory
129
+ def load_rel(*paths)
130
+ paths.flatten!
131
+ return false if paths.empty?
132
+
133
+ source_directory = File.dirname caller.first.sub(/:\d+$/, '')
134
+ paths.each do |path|
135
+ require_all File.join(source_directory, path), method: :load
136
+ end
137
+ end
138
+
139
+ # Performs Kernel#autoload on all of the files rather than requiring immediately.
140
+ #
141
+ # Note that all Ruby files inside of the specified directories should have same module name as
142
+ # the directory itself and file names should reflect the class/module names.
143
+ # For example if there is a my_file.rb in directories dir1/dir2/ then
144
+ # there should be a declaration like this in my_file.rb:
145
+ # module Dir1
146
+ # module Dir2
147
+ # class MyFile
148
+ # ...
149
+ # end
150
+ # end
151
+ # end
152
+ #
153
+ # If the filename and namespaces won't match then my_file.rb will be loaded into wrong module!
154
+ # Better to fix these files.
155
+ #
156
+ # Set $DEBUG=true to see how files will be autoloaded if experiencing any problems.
157
+ #
158
+ # If trying to perform autoload on some individual file or some inner module, then you'd have
159
+ # to always specify *:base_dir* option to specify where top-level namespace resides.
160
+ # Otherwise it's impossible to know the namespace of the loaded files.
161
+ #
162
+ # For example loading only my_file.rb from dir1/dir2 with autoload_all:
163
+ #
164
+ # autoload_all File.dirname(__FILE__) + '/dir1/dir2/my_file',
165
+ # base_dir: File.dirname(__FILE__) + '/dir1'
166
+ #
167
+ # WARNING: All modules will be created even if files themselves aren't loaded yet, meaning
168
+ # that all the code which depends of the modules being loaded or not will not work, like usages
169
+ # of define? and it's friends.
170
+ #
171
+ # Also, normal caveats of using Kernel#autoload apply - you have to remember that before
172
+ # applying any monkey-patches to code using autoload, you'll have to reference the full constant
173
+ # to load the code before applying your patch!
174
+
175
+ def autoload_all(*paths)
176
+ paths.flatten!
177
+ return false if paths.empty?
178
+ require "pathname"
179
+
180
+ options = {method: :autoload}
181
+ options.merge!(paths.pop) if paths.last.is_a?(Hash)
182
+
183
+ paths.each do |path|
184
+ require_all path, {base_dir: path}.merge(options)
185
+ end
186
+ end
187
+
188
+ # Performs autoloading relatively from the caller instead of using current working directory
189
+ def autoload_rel(*paths)
190
+ paths.flatten!
191
+ return false if paths.empty?
192
+ require "pathname"
193
+
194
+ options = {method: :autoload}
195
+ options.merge!(paths.pop) if paths.last.is_a?(Hash)
196
+
197
+ source_directory = File.dirname caller.first.sub(/:\d+$/, '')
198
+ paths.each do |path|
199
+ file_path = Pathname.new(source_directory).join(path).to_s
200
+ require_all file_path, {method: :autoload,
201
+ base_dir: source_directory}.merge(options)
202
+ end
203
+ end
204
+
205
+ private
206
+
207
+ def __require(method, file)
208
+ Kernel.send(method, file)
209
+ end
210
+
211
+ def __autoload(file, full_path, options)
212
+ last_module = "Object" # default constant where namespaces are created into
213
+ begin
214
+ base_dir = Pathname.new(options[:base_dir]).realpath
215
+ rescue Errno::ENOENT
216
+ raise LoadError, ":base_dir doesn't exist at #{options[:base_dir]}"
217
+ end
218
+ Pathname.new(file).realpath.descend do |entry|
219
+ # skip until *entry* is same as desired directory
220
+ # or anything inside of it avoiding to create modules
221
+ # from the top-level directories
222
+ next if (entry <=> base_dir) < 0
223
+
224
+ # get the module into which a new module is created or
225
+ # autoload performed
226
+ mod = Object.class_eval(last_module)
227
+
228
+ without_ext = entry.basename(entry.extname).to_s
229
+
230
+ const =
231
+ if defined? ActiveSupport::Inflector
232
+ ActiveSupport::Inflector.camelize(without_ext)
233
+ else
234
+ without_ext.split("_").map {|word| word.capitalize}.join
235
+ end
236
+
237
+ if entry.file? || (entry.directory? && entry.sub_ext('.rb').file?)
238
+ mod.class_eval do
239
+ puts "autoloading #{mod}::#{const} from #{full_path}" if $DEBUG
240
+ autoload const, full_path
241
+ end
242
+ else
243
+ mod.class_eval "module #{const} end" if entry.directory?
244
+ end
245
+
246
+ last_module += "::#{const}" if entry.directory?
247
+ end
248
+ end
249
+
250
+ end
251
+
252
+ include RequireAll
@@ -111,9 +111,11 @@ class OverridesTracker::Comparer
111
111
  if is_source_changed_flag
112
112
  line_differerence_array = []
113
113
  all_methods_collections.each do |build_id, all_methods_hash|
114
+ begin
115
+ line_differerence_array << method_result_hash[:builds][build_id][:original_body].split(/\n/)
116
+ rescue
114
117
 
115
- line_differerence_array << method_result_hash[:builds][build_id][:original_body].split(/\n/)
116
-
118
+ end
117
119
  if method_result_hash[:builds][build_id][:result] == 'override_has_changed'
118
120
  numbers[:overrides][:override_changed_count] -= 1
119
121
  numbers[:overrides][:source_changed_count] += 1
@@ -130,11 +132,13 @@ class OverridesTracker::Comparer
130
132
  if is_override_changed_flag
131
133
  line_differerence_array = []
132
134
  begin
135
+ begin
136
+ all_methods_collections.each do |build_id, all_methods_hash|
137
+ line_differerence_array << method_result_hash[:builds][build_id][:overriding_body].split(/\n/)
138
+ end
139
+ rescue
133
140
 
134
- all_methods_collections.each do |build_id, all_methods_hash|
135
- line_differerence_array << method_result_hash[:builds][build_id][:overriding_body].split(/\n/)
136
141
  end
137
-
138
142
  max_length = line_differerence_array.map(&:length).max
139
143
  transposed_array = line_differerence_array.map{|e| e.values_at(0...max_length)}.transpose
140
144
  method_result_hash[:overriding_mark_lines] = transposed_array.map.with_index{|val, index| val.uniq.size > 1 ? index : nil}.compact
@@ -0,0 +1,41 @@
1
+ # Adding deep merge functionality
2
+ Hash.class_eval do
3
+ def deep_merge(other_hash, &block)
4
+ dup.deep_merge!(other_hash, &block)
5
+ end
6
+
7
+ def deep_merge!(other_hash, &block)
8
+ merge!(other_hash) do |key, this_val, other_val|
9
+ if this_val.is_a?(Hash) && other_val.is_a?(Hash)
10
+ this_val.deep_merge(other_val, &block)
11
+ elsif block_given?
12
+ block.call(key, this_val, other_val)
13
+ else
14
+ other_val
15
+ end
16
+ end
17
+ end
18
+
19
+ def deep_stringify_keys!
20
+ deep_transform_keys!(&:to_s)
21
+ end
22
+
23
+ def deep_transform_keys!(&block)
24
+ _deep_transform_keys_in_object!(self, &block)
25
+ end
26
+
27
+ def _deep_transform_keys_in_object!(object, &block)
28
+ case object
29
+ when Hash
30
+ object.keys.each do |key|
31
+ value = object.delete(key)
32
+ object[yield(key)] = _deep_transform_keys_in_object!(value, &block)
33
+ end
34
+ object
35
+ when Array
36
+ object.map! { |e| _deep_transform_keys_in_object!(e, &block) }
37
+ else
38
+ object
39
+ end
40
+ end
41
+ end