as_deprecation_tracker 1.0.0
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/LICENSE +20 -0
- data/README.md +108 -0
- data/Rakefile +14 -0
- data/config.ru +8 -0
- data/lib/as_deprecation_tracker/configuration.rb +15 -0
- data/lib/as_deprecation_tracker/railtie.rb +15 -0
- data/lib/as_deprecation_tracker/receiver.rb +34 -0
- data/lib/as_deprecation_tracker/version.rb +4 -0
- data/lib/as_deprecation_tracker/whitelist.rb +30 -0
- data/lib/as_deprecation_tracker/whitelist_entry.rb +63 -0
- data/lib/as_deprecation_tracker/writer.rb +31 -0
- data/lib/as_deprecation_tracker.rb +20 -0
- data/test/as_deprecation_tracker_test.rb +32 -0
- data/test/configuration_test.rb +46 -0
- data/test/internal/config/as_deprecation_whitelist.yaml +1 -0
- data/test/internal/config/routes.rb +4 -0
- data/test/internal/log/.gitignore +1 -0
- data/test/internal/public/favicon.ico +0 -0
- data/test/railtie_test.rb +8 -0
- data/test/receiver_test.rb +50 -0
- data/test/test_helper.rb +13 -0
- data/test/whitelist_entry_test.rb +108 -0
- data/test/whitelist_test.rb +46 -0
- data/test/writer_test.rb +54 -0
- metadata +96 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: b25a9c470b3310b7a3112d290e0655811ea93c3d
|
4
|
+
data.tar.gz: 78857eba82e956ad61ad8e6276128fe4a73d6056
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 83efcef8a382e9c9cace6a2e942f7d96032d587b76b1ab36707cf3f7c37c82a1e6a8a241c1bdd8da5de298fe6e5ec2b2f705414f8c47208d3581059087629e0e
|
7
|
+
data.tar.gz: c6558bacefd24acba76e6aa3e6bb23beff1e26cf1ec502cc010f6172f7cdd07f86affaf919509eef9b58015fb2ab7d3e761b129b16800765684a422b9aa7b94d
|
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2016 Dominic Cleal
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
17
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
18
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
19
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
20
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,108 @@
|
|
1
|
+
# as_deprecation_tracker
|
2
|
+
|
3
|
+
Tracks known ActiveSupport (Rails) deprecation warnings and catches new issues
|
4
|
+
when an unknown warning is seen.
|
5
|
+
|
6
|
+
This allows for easier upgrades of Rails and other AS-based apps because as
|
7
|
+
each deprecation warning is fixed, it's removed from the whitelist and any
|
8
|
+
attempt to reintroduce the deprecated call will fail. It's also useful when the
|
9
|
+
app runs on multiple versions of Rails and newer deprecation warnings can't be
|
10
|
+
fixed yet without breaking the older version.
|
11
|
+
|
12
|
+
The library maintains the whitelist in a configuration file that's usually
|
13
|
+
initially written by running the app test suite with an environment variable
|
14
|
+
set. When the tests are run normally, deprecation warnings triggered that
|
15
|
+
aren't in the config file will raise an exception. The call can then be fixed
|
16
|
+
or added to the whitelist with the provided instructions.
|
17
|
+
|
18
|
+
If you'd prefer just to fix all deprecation warnings at once then this gem is
|
19
|
+
unnecessary! Just use:
|
20
|
+
|
21
|
+
```ruby
|
22
|
+
ActiveSupport::Deprecation.behavior = :raise
|
23
|
+
```
|
24
|
+
|
25
|
+
in your test environment config.
|
26
|
+
|
27
|
+
## Installation
|
28
|
+
|
29
|
+
$ gem install as_deprecation_tracker
|
30
|
+
|
31
|
+
or in your Gemfile:
|
32
|
+
|
33
|
+
gem 'as_deprecation_tracker', '~> 1.0', group: 'test'
|
34
|
+
|
35
|
+
This gem and its API is versioned according to semver.
|
36
|
+
|
37
|
+
It's recommended to only add the gem to the test Bundler group as raising
|
38
|
+
errors in production and development isn't desirable.
|
39
|
+
|
40
|
+
## Usage
|
41
|
+
|
42
|
+
### Automatic whitelisting
|
43
|
+
|
44
|
+
To set up an initial whitelist, run:
|
45
|
+
|
46
|
+
AS_DEPRECATION_RECORD=yes bin/rake test
|
47
|
+
|
48
|
+
This will generate `config/as_deprecation_whitelist.yaml` with a list of
|
49
|
+
specific instances of deprecated calls which can be committed. Subsequent `rake
|
50
|
+
test` runs will then automatically raise errors for new occurrences.
|
51
|
+
|
52
|
+
Re-run tests with `AS_DEPRECATION_RECORD=yes` to append new instances to the
|
53
|
+
existing configuration file, if you wish to whitelist rather than fix them.
|
54
|
+
|
55
|
+
### Whitelist configuration
|
56
|
+
|
57
|
+
The whitelist may be broad, permitting any call causing a particular
|
58
|
+
deprecation message or be precise, only permitting known calls identified by
|
59
|
+
their backtrace. With broad whitelists, more instances of the same deprecated
|
60
|
+
call may be added, but precise whitelists require more maintenance if code is
|
61
|
+
moved and the backtrace changes.
|
62
|
+
|
63
|
+
The whitelist is stored in the Rails root at
|
64
|
+
`config/as_deprecation_whitelist.yaml` and is a YAML file containing a single
|
65
|
+
array of hashes:
|
66
|
+
|
67
|
+
```yaml
|
68
|
+
---
|
69
|
+
- message: "Deprecated call to X, use Y instead"
|
70
|
+
- message: "Deprecated call to Z"
|
71
|
+
callstack: "app/models/foo.rb:23:in `example_method'"
|
72
|
+
```
|
73
|
+
|
74
|
+
Accepted keys are `message`, matching the exact deprecation message and
|
75
|
+
`callstack`, a string or an array forming the backtrace of the deprecation.
|
76
|
+
If an array is given for the callstack, all entries must match the caller.
|
77
|
+
|
78
|
+
The callstack will match on as much data as is provided - if only a file is
|
79
|
+
given, any matching deprecation within the file will be whitelisted. The line
|
80
|
+
number and method specification may be given for more specificity. The line
|
81
|
+
number may vary by up to ten lines from the recorded number by default (see
|
82
|
+
`line_tolerance` to tune). Usually the filename and method name are sufficient
|
83
|
+
to match the caller without needing line numbers.
|
84
|
+
|
85
|
+
### Configuration
|
86
|
+
|
87
|
+
Use an initializer to change ASDT's behaviour at startup:
|
88
|
+
|
89
|
+
```ruby
|
90
|
+
ASDeprecationTracker.config.envs = %w(test development)
|
91
|
+
```
|
92
|
+
|
93
|
+
Supported options:
|
94
|
+
|
95
|
+
* `envs` is an array of string Rails environment names that ASDT will monitor
|
96
|
+
and raise errors for unpermitted deprecation warnings (defaults to
|
97
|
+
`['test']`)
|
98
|
+
* `line_tolerance` is the number of lines that callstack line numbers may
|
99
|
+
differ from the deprecated call (defaults to 10)
|
100
|
+
* `register_behavior` controls whether to change the AS::Deprecation behavior
|
101
|
+
to ASDeprecationTracker::Receiver at startup, may be disabled to use multiple
|
102
|
+
behaviors (defaults to true)
|
103
|
+
* `whitelist_file` to customise the location of the whitelist YAML file
|
104
|
+
(defaults to `config/as_deprecation_whitelist.yaml` beneath the Rails root)
|
105
|
+
|
106
|
+
## License
|
107
|
+
|
108
|
+
Copyright (c) 2016 Dominic Cleal. Distributed under the MIT license.
|
data/Rakefile
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'bundler/gem_tasks'
|
3
|
+
require 'rake/testtask'
|
4
|
+
require 'rubocop/rake_task'
|
5
|
+
|
6
|
+
Rake::TestTask.new do |t|
|
7
|
+
t.libs << 'test'
|
8
|
+
t.test_files = FileList['test/*_test.rb']
|
9
|
+
t.verbose = true
|
10
|
+
end
|
11
|
+
|
12
|
+
RuboCop::RakeTask.new
|
13
|
+
|
14
|
+
task default: %w(rubocop test)
|
data/config.ru
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module ASDeprecationTracker
|
3
|
+
# Maintains configuration for one instance (usually global)
|
4
|
+
class Configuration
|
5
|
+
attr_accessor :envs, :line_tolerance, :register_behavior, :whitelist_file
|
6
|
+
alias register_behavior? register_behavior
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
@envs = %w(test)
|
10
|
+
@line_tolerance = 10
|
11
|
+
@register_behavior = true
|
12
|
+
@whitelist_file = File.join(Rails.root, 'config', 'as_deprecation_whitelist.yaml')
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'as_deprecation_tracker/receiver'
|
3
|
+
|
4
|
+
module ASDeprecationTracker
|
5
|
+
# Railtie to register for deprecation notifications
|
6
|
+
class Railtie < ::Rails::Railtie
|
7
|
+
initializer 'as_deprecation_tracker.deprecation_notifications', after: :load_environment_config, if: -> { ASDeprecationTracker.active? } do
|
8
|
+
Receiver.attach_to :rails
|
9
|
+
ActiveSupport::Deprecation.behavior = :notify if ASDeprecationTracker.config.register_behavior?
|
10
|
+
|
11
|
+
whitelist = ASDeprecationTracker.config.whitelist_file
|
12
|
+
ASDeprecationTracker.whitelist.load_file(whitelist) if File.exist?(whitelist)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'active_support/subscriber'
|
3
|
+
require 'as_deprecation_tracker/writer'
|
4
|
+
|
5
|
+
module ASDeprecationTracker
|
6
|
+
# Receives deprecation.rails events via ActiveSupport::Notifications
|
7
|
+
class Receiver < ::ActiveSupport::Subscriber
|
8
|
+
def deprecation(event)
|
9
|
+
return if ASDeprecationTracker.whitelist.matches?(event.payload)
|
10
|
+
|
11
|
+
message = event.payload[:message]
|
12
|
+
callstack = event.payload[:callstack].map(&:to_s)
|
13
|
+
if ENV['AS_DEPRECATION_RECORD'].present?
|
14
|
+
write_deprecation(message, callstack)
|
15
|
+
else
|
16
|
+
raise_deprecation(message, callstack)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def write_deprecation(message, callstack)
|
23
|
+
writer = ASDeprecationTracker::Writer.new(ASDeprecationTracker.config.whitelist_file)
|
24
|
+
writer.add(message, callstack)
|
25
|
+
writer.write_file
|
26
|
+
end
|
27
|
+
|
28
|
+
def raise_deprecation(message, callstack)
|
29
|
+
e = ActiveSupport::DeprecationException.new(message)
|
30
|
+
e.set_backtrace(callstack)
|
31
|
+
raise e
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'as_deprecation_tracker/whitelist_entry'
|
3
|
+
|
4
|
+
module ASDeprecationTracker
|
5
|
+
# Stores a list of known and ignored deprecation warnings, and provides a
|
6
|
+
# query interface to check if a warning matches the list
|
7
|
+
class Whitelist
|
8
|
+
attr_reader :list
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
@list = []
|
12
|
+
end
|
13
|
+
|
14
|
+
def add_to_list(entries)
|
15
|
+
entries.each { |entry| @list << WhitelistEntry.new(entry) }
|
16
|
+
end
|
17
|
+
|
18
|
+
def clear
|
19
|
+
@list.clear
|
20
|
+
end
|
21
|
+
|
22
|
+
def load_file(path)
|
23
|
+
add_to_list(YAML.load(File.read(path)))
|
24
|
+
end
|
25
|
+
|
26
|
+
def matches?(deprecation)
|
27
|
+
@list.any? { |entry| entry.matches?(deprecation) }
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module ASDeprecationTracker
|
3
|
+
# Configuration of a whitelisted (known) deprecation warning matched by data
|
4
|
+
# such as a message and/or callstack
|
5
|
+
class WhitelistEntry
|
6
|
+
MESSAGE_CLEANUP_RE = Regexp.new('\ADEPRECATION WARNING: (.+) \(called from.*')
|
7
|
+
CALLSTACK_FILE_RE = Regexp.new('\A(.*?)(?::(\d+))?(?::in `(.+)\')?\z')
|
8
|
+
|
9
|
+
def initialize(entry)
|
10
|
+
entry = entry.with_indifferent_access
|
11
|
+
raise('Missing `message` or `callstack` from whitelist entry') unless entry.key?(:message) || entry.key?(:callstack)
|
12
|
+
@message = entry[:message]
|
13
|
+
@callstack = callstack_to_files_lines(Array.wrap(entry[:callstack]))
|
14
|
+
end
|
15
|
+
|
16
|
+
def matches?(deprecation)
|
17
|
+
return false if @message.present? && !message_matches?(deprecation[:message])
|
18
|
+
return false if @callstack.present? && !callstack_matches?(deprecation[:callstack])
|
19
|
+
true
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def message_matches?(message)
|
25
|
+
cleanup_match = MESSAGE_CLEANUP_RE.match(message)
|
26
|
+
message = cleanup_match[1] if cleanup_match
|
27
|
+
message == @message
|
28
|
+
end
|
29
|
+
|
30
|
+
def callstack_to_files_lines(callstack)
|
31
|
+
callstack.map do |entry|
|
32
|
+
file_match = CALLSTACK_FILE_RE.match(entry)
|
33
|
+
[file_match[1], file_match[2].nil? ? nil : file_match[2].to_i, file_match[3]]
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def callstack_matches?(callstack)
|
38
|
+
callstack = callstack_to_files_lines(callstack)
|
39
|
+
|
40
|
+
@callstack.all? do |whitelist_entry|
|
41
|
+
callstack_entry_matches?(whitelist_entry, callstack)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def callstack_entry_matches?(whitelist_entry, callstack)
|
46
|
+
callstack.any? do |callstack_entry|
|
47
|
+
callstack_entry[0] == whitelist_entry[0] &&
|
48
|
+
line_number_within_tolerance(callstack_entry[1], whitelist_entry[1]) &&
|
49
|
+
method_name_matches(callstack_entry[2], whitelist_entry[2])
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def line_number_within_tolerance(line1, line2)
|
54
|
+
return true if line1.nil? || line2.nil?
|
55
|
+
(line1 - line2).abs <= ASDeprecationTracker.config.line_tolerance
|
56
|
+
end
|
57
|
+
|
58
|
+
def method_name_matches(method1, method2)
|
59
|
+
return true if method1.nil? || method2.nil?
|
60
|
+
method1 == method2
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'as_deprecation_tracker/whitelist_entry'
|
3
|
+
require 'rails/backtrace_cleaner'
|
4
|
+
|
5
|
+
module ASDeprecationTracker
|
6
|
+
# Rewrites the whitelist configuration file to append new observed entries
|
7
|
+
class Writer
|
8
|
+
def initialize(filename)
|
9
|
+
@filename = filename
|
10
|
+
@contents = []
|
11
|
+
@contents = YAML.load(File.read(filename)) || [] if File.exist?(filename)
|
12
|
+
end
|
13
|
+
|
14
|
+
def add(message, callstack)
|
15
|
+
cleanup_match = WhitelistEntry::MESSAGE_CLEANUP_RE.match(message)
|
16
|
+
message = cleanup_match[1] if cleanup_match
|
17
|
+
|
18
|
+
callstack = Rails::BacktraceCleaner.new.clean(callstack, :silent)
|
19
|
+
|
20
|
+
@contents << { 'message' => message, 'callstack' => callstack.first }
|
21
|
+
end
|
22
|
+
|
23
|
+
def contents
|
24
|
+
@contents.sort_by { |e| e.values_at('message', 'callstack') }.to_yaml
|
25
|
+
end
|
26
|
+
|
27
|
+
def write_file
|
28
|
+
File.write(@filename, contents)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# Entry point, provides constant with access to global configuration only
|
3
|
+
module ASDeprecationTracker
|
4
|
+
require 'as_deprecation_tracker/configuration'
|
5
|
+
require 'as_deprecation_tracker/railtie'
|
6
|
+
require 'as_deprecation_tracker/version'
|
7
|
+
require 'as_deprecation_tracker/whitelist'
|
8
|
+
|
9
|
+
def self.active?
|
10
|
+
config.envs.include?(Rails.env)
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.config
|
14
|
+
@config ||= Configuration.new
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.whitelist
|
18
|
+
@whitelist ||= Whitelist.new
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'test_helper'
|
3
|
+
|
4
|
+
class ASDeprecationTrackerTest < ASDeprecationTracker::TestCase
|
5
|
+
def test_active?
|
6
|
+
assert ASDeprecationTracker.active?
|
7
|
+
end
|
8
|
+
|
9
|
+
def test_active_in_other_env
|
10
|
+
ASDeprecationTracker.expects(:config).twice.returns(ASDeprecationTracker::Configuration.new)
|
11
|
+
ASDeprecationTracker.config.envs = ['development']
|
12
|
+
refute ASDeprecationTracker.active?
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_config
|
16
|
+
assert_kind_of ASDeprecationTracker::Configuration, ASDeprecationTracker.config
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_config_returns_same_configuration
|
20
|
+
config = ASDeprecationTracker.config
|
21
|
+
assert_equal config, ASDeprecationTracker.config
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_whitelist
|
25
|
+
assert_kind_of ASDeprecationTracker::Whitelist, ASDeprecationTracker.whitelist
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_whitelist_returns_same_whitelist
|
29
|
+
whitelist = ASDeprecationTracker.whitelist
|
30
|
+
assert_equal whitelist, ASDeprecationTracker.whitelist
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'test_helper'
|
3
|
+
|
4
|
+
class ConfigurationTest < ASDeprecationTracker::TestCase
|
5
|
+
def setup
|
6
|
+
@config = ASDeprecationTracker::Configuration.new
|
7
|
+
super
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_envs
|
11
|
+
assert_equal ['test'], @config.envs
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_envs=
|
15
|
+
@config.envs = ['development']
|
16
|
+
assert_equal ['development'], @config.envs
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_line_tolerance
|
20
|
+
assert_equal 10, @config.line_tolerance
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_line_tolerance=
|
24
|
+
@config.line_tolerance = 42
|
25
|
+
assert_equal 42, @config.line_tolerance
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_register_behavior?
|
29
|
+
assert_equal true, @config.register_behavior?
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_register_behavior=
|
33
|
+
@config.register_behavior = false
|
34
|
+
assert_equal false, @config.register_behavior?
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_whitelist_file
|
38
|
+
assert_kind_of String, @config.whitelist_file
|
39
|
+
assert File.exist?(@config.whitelist_file)
|
40
|
+
end
|
41
|
+
|
42
|
+
def test_whitelist_file=
|
43
|
+
@config.whitelist_file = 'another_file.yaml'
|
44
|
+
assert_equal 'another_file.yaml', @config.whitelist_file
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
--- []
|
@@ -0,0 +1 @@
|
|
1
|
+
*.log
|
File without changes
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'test_helper'
|
3
|
+
|
4
|
+
class ReceiverTest < ASDeprecationTracker::TestCase
|
5
|
+
def test_deprecation_whitelisted
|
6
|
+
whitelist = ASDeprecationTracker::Whitelist.new
|
7
|
+
ASDeprecationTracker.expects(:whitelist).returns(whitelist)
|
8
|
+
stack = caller
|
9
|
+
whitelist.expects(:matches?).with(message: 'deprecated call', callstack: stack).returns(true)
|
10
|
+
ASDeprecationTracker::Receiver.new.deprecation(event(message: 'deprecated call', callstack: stack))
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_deprecation_unknown
|
14
|
+
whitelist = ASDeprecationTracker::Whitelist.new
|
15
|
+
ASDeprecationTracker.expects(:whitelist).returns(whitelist)
|
16
|
+
stack = caller
|
17
|
+
whitelist.expects(:matches?).with(message: 'deprecated call', callstack: stack).returns(false)
|
18
|
+
e = assert_raises(ActiveSupport::DeprecationException) do
|
19
|
+
ASDeprecationTracker::Receiver.new.deprecation(event(message: 'deprecated call', callstack: stack))
|
20
|
+
end
|
21
|
+
assert_equal 'deprecated call', e.message
|
22
|
+
assert_equal stack, e.backtrace
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_deprecation_unknown_record
|
26
|
+
whitelist = ASDeprecationTracker::Whitelist.new
|
27
|
+
ASDeprecationTracker.expects(:whitelist).returns(whitelist)
|
28
|
+
stack = caller
|
29
|
+
whitelist.expects(:matches?).with(message: 'deprecated call', callstack: stack).returns(false)
|
30
|
+
ASDeprecationTracker::Writer.any_instance.expects(:add).with('deprecated call', stack)
|
31
|
+
ASDeprecationTracker::Writer.any_instance.expects(:write_file)
|
32
|
+
ENV['AS_DEPRECATION_RECORD'] = 'true'
|
33
|
+
ASDeprecationTracker::Receiver.new.deprecation(event(message: 'deprecated call', callstack: stack))
|
34
|
+
ensure
|
35
|
+
ENV.delete('AS_DEPRECATION_RECORD')
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_subscription
|
39
|
+
ASDeprecationTracker::Receiver.any_instance.expects(:deprecation)
|
40
|
+
ActiveSupport::Notifications.instrument('deprecation.rails', message: 'test')
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def event(payload)
|
46
|
+
mock('event').tap do |event|
|
47
|
+
event.stubs(:payload).returns(payload)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'minitest/autorun'
|
3
|
+
require 'mocha/mini_test'
|
4
|
+
require 'combustion'
|
5
|
+
|
6
|
+
require 'as_deprecation_tracker'
|
7
|
+
|
8
|
+
Combustion.path = 'test/internal'
|
9
|
+
Combustion.initialize!
|
10
|
+
|
11
|
+
module ASDeprecationTracker
|
12
|
+
class TestCase < ::Minitest::Test; end
|
13
|
+
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'test_helper'
|
3
|
+
|
4
|
+
class WhitelistEntryTest < ASDeprecationTracker::TestCase
|
5
|
+
def test_initialize_with_strings
|
6
|
+
ASDeprecationTracker::WhitelistEntry.new('message' => 'test')
|
7
|
+
end
|
8
|
+
|
9
|
+
def test_initialize_with_symbols
|
10
|
+
ASDeprecationTracker::WhitelistEntry.new(message: 'test')
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_matches_message_and_callstack
|
14
|
+
assert entry.matches?(deprecation)
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_matches_message_with_surrounding_content
|
18
|
+
assert entry.matches?(deprecation(message: 'DEPRECATION WARNING: uniq is deprecated and will be removed (called from block in <class:Foo> at app/models/foo.rb:23)'))
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_matches_message_only
|
22
|
+
assert entry(callstack: nil).matches?(deprecation(callstack: caller))
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_matches_callstack_only
|
26
|
+
assert entry(message: nil).matches?(deprecation)
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_matches_partial_callstack_top
|
30
|
+
assert entry(callstack: ['/home/user/app/models/foo.rb:23']).matches?(deprecation)
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_matches_partial_callstack_bottom
|
34
|
+
assert entry(callstack: ['/home/user/app/controllers/foos_controller.rb:42']).matches?(deprecation)
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_matches_partial_callstack_multiple
|
38
|
+
assert entry(callstack: [
|
39
|
+
'/home/user/app/models/foo.rb:23',
|
40
|
+
'/home/user/app/controllers/foos_controller.rb:42'
|
41
|
+
]).matches?(deprecation)
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_matches_partial_callstack_within_tolerance
|
45
|
+
assert entry(callstack: ['/home/user/app/models/foo.rb:25']).matches?(deprecation)
|
46
|
+
end
|
47
|
+
|
48
|
+
def test_matches_partial_callstack_outside_tolerance
|
49
|
+
refute entry(callstack: ['/home/user/app/models/foo.rb:34']).matches?(deprecation)
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_matches_partial_callstack_same_method
|
53
|
+
assert entry(callstack: ['/home/user/app/models/foo.rb:in `example_method\'']).matches?(deprecation)
|
54
|
+
end
|
55
|
+
|
56
|
+
def test_matches_partial_callstack_different_method
|
57
|
+
refute entry(callstack: ['/home/user/app/models/foo.rb:23:in `another_method\'']).matches?(deprecation)
|
58
|
+
end
|
59
|
+
|
60
|
+
def test_matches_partial_callstack_different_method_no_line
|
61
|
+
refute entry(callstack: ['/home/user/app/models/foo.rb:in `another_method\'']).matches?(deprecation)
|
62
|
+
end
|
63
|
+
|
64
|
+
def test_matches_partial_callstack_within_tolerance_same_method
|
65
|
+
assert entry(callstack: ['/home/user/app/models/foo.rb:25:in `example_method\'']).matches?(deprecation)
|
66
|
+
end
|
67
|
+
|
68
|
+
def test_matches_partial_callstack_outside_tolerance_same_method
|
69
|
+
refute entry(callstack: ['/home/user/app/models/foo.rb:34:in `example_method\'']).matches?(deprecation)
|
70
|
+
end
|
71
|
+
|
72
|
+
def test_matches_partial_callstack_string
|
73
|
+
assert entry(callstack: '/home/user/app/models/foo.rb:23').matches?(deprecation)
|
74
|
+
end
|
75
|
+
|
76
|
+
def test_matches_partial_callstack_file
|
77
|
+
assert entry(callstack: ['/home/user/app/models/foo.rb']).matches?(deprecation)
|
78
|
+
end
|
79
|
+
|
80
|
+
def test_matches_different_message_same_callstack
|
81
|
+
refute entry.matches?(deprecation(message: 'a different method is deprecated'))
|
82
|
+
end
|
83
|
+
|
84
|
+
def test_matches_same_message_different_callstack
|
85
|
+
refute entry.matches?(deprecation(callstack: caller))
|
86
|
+
end
|
87
|
+
|
88
|
+
def test_matches_different_message_different_callstack
|
89
|
+
refute entry.matches?(deprecation(message: 'a different method is deprecated', callstack: caller))
|
90
|
+
end
|
91
|
+
|
92
|
+
private
|
93
|
+
|
94
|
+
def deprecation(overrides = {})
|
95
|
+
{
|
96
|
+
message: 'uniq is deprecated and will be removed',
|
97
|
+
callstack: [
|
98
|
+
'/home/user/app/models/foo.rb:23:in `example_method\'',
|
99
|
+
'/home/user/app/controllers/foos_controller.rb:42:in `update\'',
|
100
|
+
'/home/user/test/controllers/foos_controller_test.rb:18:in `block in <class:FoosControllerTest>\''
|
101
|
+
]
|
102
|
+
}.merge(overrides).compact
|
103
|
+
end
|
104
|
+
|
105
|
+
def entry(overrides = {})
|
106
|
+
ASDeprecationTracker::WhitelistEntry.new(deprecation(overrides))
|
107
|
+
end
|
108
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'test_helper'
|
3
|
+
|
4
|
+
class WhitelistTest < ASDeprecationTracker::TestCase
|
5
|
+
def setup
|
6
|
+
@whitelist = ASDeprecationTracker::Whitelist.new
|
7
|
+
super
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_add_to_list
|
11
|
+
@whitelist.add_to_list([entry])
|
12
|
+
assert_equal 1, @whitelist.list.count
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_clear
|
16
|
+
@whitelist.add_to_list([entry])
|
17
|
+
@whitelist.clear
|
18
|
+
assert @whitelist.list.empty?
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_load_file
|
22
|
+
File.expects(:read).with('root/config/as_deprecation_whitelist.yaml').returns("---\n- :message: test\n")
|
23
|
+
@whitelist.load_file('root/config/as_deprecation_whitelist.yaml')
|
24
|
+
assert_equal 1, @whitelist.list.count
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_matches_failure
|
28
|
+
@whitelist.add_to_list([entry])
|
29
|
+
deprecation = mock('deprecation')
|
30
|
+
@whitelist.list.first.expects(:matches?).with(deprecation).returns(false)
|
31
|
+
refute @whitelist.matches?(deprecation)
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_matches_success
|
35
|
+
@whitelist.add_to_list([entry])
|
36
|
+
deprecation = mock('deprecation')
|
37
|
+
@whitelist.list.first.expects(:matches?).with(deprecation).returns(true)
|
38
|
+
assert @whitelist.matches?(deprecation)
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def entry
|
44
|
+
{ message: 'deprecated call', callstack: caller }
|
45
|
+
end
|
46
|
+
end
|
data/test/writer_test.rb
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'test_helper'
|
3
|
+
|
4
|
+
class WriterTest < ASDeprecationTracker::TestCase
|
5
|
+
def test_add
|
6
|
+
writer = new_writer
|
7
|
+
writer.add('deprecated call', ['app/models/a.rb:23', 'app/models/b.rb:42'])
|
8
|
+
assert_equal [{ 'message' => 'deprecated call', 'callstack' => 'app/models/a.rb:23' }], YAML.load(writer.contents)
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_add_strips_surrounding
|
12
|
+
writer = new_writer
|
13
|
+
writer.add('DEPRECATION WARNING: deprecated call (called from app/models/a.rb:23)', ['app/models/a.rb:23', 'app/models/b.rb:42'])
|
14
|
+
assert_equal [{ 'message' => 'deprecated call', 'callstack' => 'app/models/a.rb:23' }], YAML.load(writer.contents)
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_add_cleans_callstack
|
18
|
+
writer = new_writer
|
19
|
+
Gem.expects(:path).returns(['/home/user/.rvm/gems/ruby-2.3.0'])
|
20
|
+
writer.add('deprecated call', ['/home/user/.rvm/gems/ruby-2.3.0/gems/activerecord-4.2.7.1/lib/active_record/relation/finder_methods.rb:280:in `exists?\'', 'app/models/a.rb:23', 'app/models/b.rb:42'])
|
21
|
+
assert_equal [{ 'message' => 'deprecated call', 'callstack' => 'app/models/a.rb:23' }], YAML.load(writer.contents)
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_contents_new_file_is_array
|
25
|
+
assert_equal [], YAML.load(new_writer('').contents)
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_contents_sorting
|
29
|
+
writer = new_writer
|
30
|
+
writer.add('deprecated call 1', ['app/models/a.rb:42', 'app/models/b.rb:42'])
|
31
|
+
writer.add('deprecated call 2', ['app/models/a.rb:23', 'app/models/b.rb:42'])
|
32
|
+
writer.add('deprecated call 1', ['app/models/a.rb:23', 'app/models/b.rb:42'])
|
33
|
+
assert_equal [
|
34
|
+
{ 'message' => 'deprecated call 1', 'callstack' => 'app/models/a.rb:23' },
|
35
|
+
{ 'message' => 'deprecated call 1', 'callstack' => 'app/models/a.rb:42' },
|
36
|
+
{ 'message' => 'deprecated call 2', 'callstack' => 'app/models/a.rb:23' }
|
37
|
+
], YAML.load(writer.contents)
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_write_file
|
41
|
+
writer = new_writer
|
42
|
+
writer.expects(:contents).returns('--- []')
|
43
|
+
File.expects(:write).with('root/config/as_deprecation_whitelist.yaml', '--- []')
|
44
|
+
writer.write_file
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def new_writer(input = '')
|
50
|
+
File.expects(:exist?).with('root/config/as_deprecation_whitelist.yaml').returns(true)
|
51
|
+
File.expects(:read).with('root/config/as_deprecation_whitelist.yaml').returns(input)
|
52
|
+
ASDeprecationTracker::Writer.new('root/config/as_deprecation_whitelist.yaml')
|
53
|
+
end
|
54
|
+
end
|
metadata
ADDED
@@ -0,0 +1,96 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: as_deprecation_tracker
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Dominic Cleal
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-11-02 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: activesupport
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '4.2'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '4.2'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: railties
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '4.2'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '4.2'
|
41
|
+
description: Tracks known ActiveSupport (Rails) deprecation warnings and catches new
|
42
|
+
issues when an unknown warning is seen.
|
43
|
+
email: dominic@cleal.org
|
44
|
+
executables: []
|
45
|
+
extensions: []
|
46
|
+
extra_rdoc_files: []
|
47
|
+
files:
|
48
|
+
- LICENSE
|
49
|
+
- README.md
|
50
|
+
- Rakefile
|
51
|
+
- config.ru
|
52
|
+
- lib/as_deprecation_tracker.rb
|
53
|
+
- lib/as_deprecation_tracker/configuration.rb
|
54
|
+
- lib/as_deprecation_tracker/railtie.rb
|
55
|
+
- lib/as_deprecation_tracker/receiver.rb
|
56
|
+
- lib/as_deprecation_tracker/version.rb
|
57
|
+
- lib/as_deprecation_tracker/whitelist.rb
|
58
|
+
- lib/as_deprecation_tracker/whitelist_entry.rb
|
59
|
+
- lib/as_deprecation_tracker/writer.rb
|
60
|
+
- test/as_deprecation_tracker_test.rb
|
61
|
+
- test/configuration_test.rb
|
62
|
+
- test/internal/config/as_deprecation_whitelist.yaml
|
63
|
+
- test/internal/config/routes.rb
|
64
|
+
- test/internal/log/.gitignore
|
65
|
+
- test/internal/public/favicon.ico
|
66
|
+
- test/railtie_test.rb
|
67
|
+
- test/receiver_test.rb
|
68
|
+
- test/test_helper.rb
|
69
|
+
- test/whitelist_entry_test.rb
|
70
|
+
- test/whitelist_test.rb
|
71
|
+
- test/writer_test.rb
|
72
|
+
homepage: https://github.com/domcleal/as_deprecation_tracker
|
73
|
+
licenses:
|
74
|
+
- MIT
|
75
|
+
metadata: {}
|
76
|
+
post_install_message:
|
77
|
+
rdoc_options: []
|
78
|
+
require_paths:
|
79
|
+
- lib
|
80
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
81
|
+
requirements:
|
82
|
+
- - ">="
|
83
|
+
- !ruby/object:Gem::Version
|
84
|
+
version: 2.0.0
|
85
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
requirements: []
|
91
|
+
rubyforge_project:
|
92
|
+
rubygems_version: 2.6.8
|
93
|
+
signing_key:
|
94
|
+
specification_version: 4
|
95
|
+
summary: Track known ActiveSupport deprecation warnings
|
96
|
+
test_files: []
|