Class: DeprecationTracker
- Inherits:
-
Object
- Object
- DeprecationTracker
show all
- Includes:
- KernelWarnTracker
- Defined in:
- lib/deprecation_tracker.rb,
lib/deprecation_tracker/shard_merger.rb
Overview
A shitlist for deprecation warnings during test runs. It has two modes: “save” and “compare”
DEPRECATION_TRACKER=save Record deprecation warnings, grouped by spec file. After the test run, save to a file.
DEPRECATION_TRACKER=compare Tracks deprecation warnings, grouped by spec file. After the test run, compare against shitlist of expected deprecation warnings. If anything is added or removed, raise an error with a diff of the changes.
Defined Under Namespace
Modules: KernelWarnTracker, MinitestExtension
Classes: ShardMerger
Constant Summary
collapse
- UnexpectedDeprecations =
Class.new(StandardError)
- DEFAULT_PATH =
"spec/support/deprecation_warning.shitlist.json"
Instance Attribute Summary collapse
Class Method Summary
collapse
Instance Method Summary
collapse
callbacks, #warn
Constructor Details
#initialize(shitlist_path, transform_message = nil, mode = :save, node_index: nil) ⇒ DeprecationTracker
Returns a new instance of DeprecationTracker.
139
140
141
142
143
144
145
146
147
148
|
# File 'lib/deprecation_tracker.rb', line 139
def initialize(shitlist_path, transform_message = nil, mode = :save, node_index: nil)
@shitlist_path = shitlist_path
@transform_message = transform_message || -> (message) { message }
@deprecation_messages = {}
@mode = mode ? mode.to_sym : :save
if @mode == :compare && node_index
raise ArgumentError, "node_index cannot be used with compare mode"
end
@node_index = node_index
end
|
Instance Attribute Details
#bucket ⇒ Object
Returns the value of attribute bucket.
137
138
139
|
# File 'lib/deprecation_tracker.rb', line 137
def bucket
@bucket
end
|
#deprecation_messages ⇒ Object
Returns the value of attribute deprecation_messages.
137
138
139
|
# File 'lib/deprecation_tracker.rb', line 137
def deprecation_messages
@deprecation_messages
end
|
#mode ⇒ Object
Returns the value of attribute mode.
137
138
139
|
# File 'lib/deprecation_tracker.rb', line 137
def mode
@mode
end
|
#node_index ⇒ Object
Returns the value of attribute node_index.
137
138
139
|
# File 'lib/deprecation_tracker.rb', line 137
def node_index
@node_index
end
|
#shitlist_path ⇒ Object
Returns the value of attribute shitlist_path.
137
138
139
|
# File 'lib/deprecation_tracker.rb', line 137
def shitlist_path
@shitlist_path
end
|
Returns the value of attribute transform_message.
137
138
139
|
# File 'lib/deprecation_tracker.rb', line 137
def transform_message
@transform_message
end
|
Class Method Details
.init_tracker(opts = {}) ⇒ Object
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
|
# File 'lib/deprecation_tracker.rb', line 78
def self.init_tracker(opts = {})
shitlist_path = opts[:shitlist_path] || DEFAULT_PATH
mode = opts[:mode] || ENV["DEPRECATION_TRACKER"] || :save
transform_message = opts[:transform_message]
node_index = opts[:node_index]
deprecation_tracker = DeprecationTracker.new(shitlist_path, transform_message, mode, node_index: node_index)
if defined?(Rails) && defined?(Rails.application) && defined?(Rails.application.deprecators)
Rails.application.deprecators.each do |deprecator|
deprecator.behavior << -> (message, _callstack = nil, _deprecation_horizon = nil, _gem_name = nil) {
deprecation_tracker.add(message)
}
end
elsif defined?(ActiveSupport)
ActiveSupport::Deprecation.behavior << -> (message, _callstack = nil, _deprecation_horizon = nil, _gem_name = nil) {
deprecation_tracker.add(message)
}
end
KernelWarnTracker.callbacks << -> (message) { deprecation_tracker.add(message) }
deprecation_tracker
end
|
.merge_shards(base_path, delete_shards: false) ⇒ Object
132
133
134
135
|
# File 'lib/deprecation_tracker.rb', line 132
def self.merge_shards(base_path, delete_shards: false)
require_relative "deprecation_tracker/shard_merger"
ShardMerger.new(base_path, delete_shards: delete_shards).merge[:result]
end
|
.track_minitest(opts = {}) ⇒ Object
122
123
124
125
126
127
128
129
130
|
# File 'lib/deprecation_tracker.rb', line 122
def self.track_minitest(opts = {})
tracker = init_tracker(opts)
Minitest.after_run do
tracker.after_run
end
ActiveSupport::TestCase.include(MinitestExtension.new(tracker))
end
|
.track_rspec(rspec_config, opts = {}) ⇒ Object
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
|
# File 'lib/deprecation_tracker.rb', line 104
def self.track_rspec(rspec_config, opts = {})
deprecation_tracker = init_tracker(opts)
rspec_config.around do |example|
deprecation_tracker.bucket = example.metadata.fetch(:rerun_file_path)
begin
example.run
ensure
deprecation_tracker.bucket = nil
end
end
rspec_config.after(:suite) do
deprecation_tracker.after_run
end
end
|
Instance Method Details
#add(message) ⇒ Object
163
164
165
166
167
|
# File 'lib/deprecation_tracker.rb', line 163
def add(message)
return if bucket.nil?
@deprecation_messages[bucket] << transform_message.(message)
end
|
#after_run ⇒ Object
174
175
176
177
178
179
180
|
# File 'lib/deprecation_tracker.rb', line 174
def after_run
if mode == :save
save
elsif mode == :compare
compare
end
end
|
#compare ⇒ Object
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
|
# File 'lib/deprecation_tracker.rb', line 182
def compare
stored = read_json(shitlist_path)
changed_buckets = []
normalized_deprecation_messages.each do |bucket, messages|
if stored[bucket] != messages
changed_buckets << bucket
end
end
if changed_buckets.any?
message = <<-MESSAGE
⚠️ Deprecation warnings have changed!
Code called by the following spec files is now generating different deprecation warnings:
#{changed_buckets.join("\n")}
To check your failures locally, you can run:
DEPRECATION_TRACKER=compare bundle exec rspec #{changed_buckets.join(" ")}
Here is a diff between what is expected and what was generated by this process:
#{diff}
See \e[4;37mdev-docs/testing/deprecation_tracker.md\e[0;31m for more information.
MESSAGE
raise UnexpectedDeprecations, NextRails::Tint(message).red
end
end
|
#create_if_path_does_not_exist(path) ⇒ Object
231
232
233
234
235
236
|
# File 'lib/deprecation_tracker.rb', line 231
def create_if_path_does_not_exist(path)
dirname = File.dirname(path)
unless File.directory?(dirname)
FileUtils.mkdir_p(dirname)
end
end
|
#create_temp_file ⇒ Object
238
239
240
241
242
243
244
|
# File 'lib/deprecation_tracker.rb', line 238
def create_temp_file
temp_file = Tempfile.new("temp-deprecation-tracker-shitlist")
temp_file.write(JSON.pretty_generate(normalized_deprecation_messages))
temp_file.flush
temp_file
end
|
#diff ⇒ Object
216
217
218
219
220
221
|
# File 'lib/deprecation_tracker.rb', line 216
def diff
temp_file = create_temp_file
`git diff --no-index #{shitlist_path} #{temp_file.path}`
ensure
temp_file.delete
end
|
#normalized_deprecation_messages ⇒ Object
Normalize deprecation messages to reduce noise from file output and test files to be tracked with separate test runs
247
248
249
250
251
252
253
254
255
256
257
258
259
260
|
# File 'lib/deprecation_tracker.rb', line 247
def normalized_deprecation_messages
@normalized_deprecation_messages ||= begin
normalized = read_json(target_path).merge(deprecation_messages).each_with_object({}) do |(bucket, messages), hash|
hash[bucket] = messages.sort
end
{}.tap do |h|
normalized.reject {|_key, value| value.empty? }.sort_by {|key, _value| key }.each do |k ,v|
h[k] = v
end
end
end
end
|
#parallel? ⇒ Boolean
150
151
152
|
# File 'lib/deprecation_tracker.rb', line 150
def parallel?
!@node_index.nil?
end
|
#read_json(path) ⇒ Object
262
263
264
265
266
267
|
# File 'lib/deprecation_tracker.rb', line 262
def read_json(path)
return {} unless File.exist?(path)
JSON.parse(File.read(path))
rescue JSON::ParserError => e
raise "#{path} is not valid JSON: #{e.message}"
end
|
#save ⇒ Object
223
224
225
226
227
228
229
|
# File 'lib/deprecation_tracker.rb', line 223
def save
temp_file = create_temp_file
create_if_path_does_not_exist(target_path)
FileUtils.cp(temp_file.path, target_path)
ensure
temp_file.delete if temp_file
end
|
#shard_path ⇒ Object
154
155
156
157
|
# File 'lib/deprecation_tracker.rb', line 154
def shard_path
ext = File.extname(shitlist_path)
"#{shitlist_path.chomp(ext)}.node-#{node_index}#{ext}"
end
|
#target_path ⇒ Object
159
160
161
|
# File 'lib/deprecation_tracker.rb', line 159
def target_path
parallel? ? shard_path : shitlist_path
end
|