ten_years_rails 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +11 -0
- data/.rspec +3 -0
- data/.travis.yml +5 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +87 -0
- data/LICENSE.txt +21 -0
- data/README.md +96 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/deprecation_tracker.md +120 -0
- data/exe/bundle_report +264 -0
- data/exe/deprecations +110 -0
- data/exe/gem-next-diff +46 -0
- data/exe/next +4 -0
- data/exe/next.sh +36 -0
- data/lib/deprecation_tracker.rb +147 -0
- data/lib/ten_years_rails.rb +6 -0
- data/lib/ten_years_rails/version.rb +3 -0
- data/ten_years_rails.gemspec +30 -0
- metadata +167 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: cb75bc7f573b543ca6491b72f0289b4f107b93b8
|
4
|
+
data.tar.gz: ede4f3a2877aee2dbb3d0034b6b99d3b570b0cc4
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 0d98fba5b66b37ad5ba174f234ae2670c5908687c97db16339a61364a8b3ab343dfb698d90b25c9d75a8e5faec2d7eeab1fcea9045ee716b6b85c24ff9ca9625
|
7
|
+
data.tar.gz: 1c230f4d09bd81f2fb89e346f32304b05c26be4a4c715a8d93e5d7b83135156ef3ec5cfce648805fc6c1bab91409d4eb91ae5b8b95bca8a0b1ce5c9c0ac41f6c
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,87 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
ten_years_rails (0.1.0)
|
5
|
+
actionview
|
6
|
+
activesupport
|
7
|
+
colorize (>= 0.8.1)
|
8
|
+
rest-client (>= 2.0.2)
|
9
|
+
|
10
|
+
GEM
|
11
|
+
remote: https://rubygems.org/
|
12
|
+
specs:
|
13
|
+
actionview (5.2.0)
|
14
|
+
activesupport (= 5.2.0)
|
15
|
+
builder (~> 3.1)
|
16
|
+
erubi (~> 1.4)
|
17
|
+
rails-dom-testing (~> 2.0)
|
18
|
+
rails-html-sanitizer (~> 1.0, >= 1.0.3)
|
19
|
+
activesupport (5.2.0)
|
20
|
+
concurrent-ruby (~> 1.0, >= 1.0.2)
|
21
|
+
i18n (>= 0.7, < 2)
|
22
|
+
minitest (~> 5.1)
|
23
|
+
tzinfo (~> 1.1)
|
24
|
+
builder (3.2.3)
|
25
|
+
colorize (0.8.1)
|
26
|
+
concurrent-ruby (1.0.5)
|
27
|
+
crass (1.0.4)
|
28
|
+
diff-lcs (1.3)
|
29
|
+
domain_name (0.5.20180417)
|
30
|
+
unf (>= 0.0.5, < 1.0.0)
|
31
|
+
erubi (1.7.1)
|
32
|
+
http-cookie (1.0.3)
|
33
|
+
domain_name (~> 0.5)
|
34
|
+
i18n (1.0.1)
|
35
|
+
concurrent-ruby (~> 1.0)
|
36
|
+
loofah (2.2.2)
|
37
|
+
crass (~> 1.0.2)
|
38
|
+
nokogiri (>= 1.5.9)
|
39
|
+
mime-types (3.1)
|
40
|
+
mime-types-data (~> 3.2015)
|
41
|
+
mime-types-data (3.2016.0521)
|
42
|
+
mini_portile2 (2.3.0)
|
43
|
+
minitest (5.11.3)
|
44
|
+
netrc (0.11.0)
|
45
|
+
nokogiri (1.8.2)
|
46
|
+
mini_portile2 (~> 2.3.0)
|
47
|
+
rails-dom-testing (2.0.3)
|
48
|
+
activesupport (>= 4.2.0)
|
49
|
+
nokogiri (>= 1.6)
|
50
|
+
rails-html-sanitizer (1.0.4)
|
51
|
+
loofah (~> 2.2, >= 2.2.2)
|
52
|
+
rake (10.4.2)
|
53
|
+
rest-client (2.0.2)
|
54
|
+
http-cookie (>= 1.0.2, < 2.0)
|
55
|
+
mime-types (>= 1.16, < 4.0)
|
56
|
+
netrc (~> 0.8)
|
57
|
+
rspec (3.7.0)
|
58
|
+
rspec-core (~> 3.7.0)
|
59
|
+
rspec-expectations (~> 3.7.0)
|
60
|
+
rspec-mocks (~> 3.7.0)
|
61
|
+
rspec-core (3.7.1)
|
62
|
+
rspec-support (~> 3.7.0)
|
63
|
+
rspec-expectations (3.7.0)
|
64
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
65
|
+
rspec-support (~> 3.7.0)
|
66
|
+
rspec-mocks (3.7.0)
|
67
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
68
|
+
rspec-support (~> 3.7.0)
|
69
|
+
rspec-support (3.7.1)
|
70
|
+
thread_safe (0.3.6)
|
71
|
+
tzinfo (1.2.5)
|
72
|
+
thread_safe (~> 0.1)
|
73
|
+
unf (0.1.4)
|
74
|
+
unf_ext
|
75
|
+
unf_ext (0.0.7.5)
|
76
|
+
|
77
|
+
PLATFORMS
|
78
|
+
ruby
|
79
|
+
|
80
|
+
DEPENDENCIES
|
81
|
+
bundler (~> 1.16)
|
82
|
+
rake (~> 10.0)
|
83
|
+
rspec (~> 3.0)
|
84
|
+
ten_years_rails!
|
85
|
+
|
86
|
+
BUNDLED WITH
|
87
|
+
1.16.1
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2018 Jordan Raine
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,96 @@
|
|
1
|
+
# Ten Years of Rails Upgrades
|
2
|
+
|
3
|
+
This is a companion to the "Ten Years of Rails Upgrades" conference talk. You'll find various utilities that we use at Clio to help us prepare for and complete Rails upgrades.
|
4
|
+
|
5
|
+
These scripts are still early days and may not work in every environment or app.
|
6
|
+
|
7
|
+
I wouldn't recommend adding this to your Gemfile long-term. Rather, try out the scripts and use them as a point of reference. Feel free to tweak them to better fit your environment.
|
8
|
+
|
9
|
+
## Usage
|
10
|
+
|
11
|
+
### `bundle_report`
|
12
|
+
|
13
|
+
Learn about your Gemfile and see what needs updating.
|
14
|
+
|
15
|
+
```bash
|
16
|
+
# Show all out-of-date gems
|
17
|
+
bundle_report outdated
|
18
|
+
# Show five oldest, out-of-date gems
|
19
|
+
bundle_report outdated | head -n 5
|
20
|
+
# Show gems that don't work with Rails 5.2.0
|
21
|
+
bundle_report compatibility --rails-version=5.2.0
|
22
|
+
bundle_report --help
|
23
|
+
```
|
24
|
+
|
25
|
+
### Deprecation tracking
|
26
|
+
|
27
|
+
If you're using RSpec, add this snippet to `rails_helper.rb` or `spec_helper.rb` (whichever loads Rails).
|
28
|
+
|
29
|
+
```ruby
|
30
|
+
RSpec.configure do |config|
|
31
|
+
# Tracker deprecation messages in each file
|
32
|
+
if ENV["DEPRECATION_TRACKER"]
|
33
|
+
DeprecationTracker.track_rspec(
|
34
|
+
config,
|
35
|
+
shitlist_path: "spec/support/deprecation_warning.shitlist.json",
|
36
|
+
mode: ENV["DEPRECATION_TRACKER"],
|
37
|
+
transform_message: -> (message) { message.gsub("#{Rails.root}/", "") }
|
38
|
+
)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
```
|
42
|
+
|
43
|
+
We don't use MiniTest, so there isn't a prebuilt config for it but I suspect it's pretty similar to `DeprecationTracker.track_rspec`.
|
44
|
+
|
45
|
+
Once you have that, you can start using deprecation tracking in your tests:
|
46
|
+
|
47
|
+
```bash
|
48
|
+
# Run your tests and save the deprecations to the shitlist
|
49
|
+
DEPRECATION_TRACKER=save rspec
|
50
|
+
# Run your tests and raise an error when the deprecations change
|
51
|
+
DEPRECATION_TRACKER=compare rspec
|
52
|
+
```
|
53
|
+
|
54
|
+
#### `deprecations` command
|
55
|
+
|
56
|
+
Once you have stored your deprecations, you can use `deprecations` to display common warnings, run specs, or update the shitlist file.
|
57
|
+
|
58
|
+
```bash
|
59
|
+
deprecations info
|
60
|
+
deprecations info --pattern "ActiveRecord::Base"
|
61
|
+
deprecations run
|
62
|
+
deprecations --help # For more options and examples
|
63
|
+
```
|
64
|
+
|
65
|
+
Right now, the path to the shitlist is hardcoded so make sure you store yours at `spec/support/deprecations.shitlist.json`.
|
66
|
+
|
67
|
+
### Dual-boot Rails next
|
68
|
+
|
69
|
+
This command helps you dual-boot your application.
|
70
|
+
|
71
|
+
```bash
|
72
|
+
next --init # Create Gemfile.next
|
73
|
+
vim Gemfile # Tweak your dependencies conditionally using `next?`
|
74
|
+
next bundle install # Install new gems
|
75
|
+
next rails s # Start server using Gemfile.next
|
76
|
+
```
|
77
|
+
|
78
|
+
## Installation
|
79
|
+
|
80
|
+
Add this line to your application's Gemfile:
|
81
|
+
|
82
|
+
```ruby
|
83
|
+
gem 'ten_years_rails'
|
84
|
+
```
|
85
|
+
|
86
|
+
And then execute:
|
87
|
+
|
88
|
+
$ bundle
|
89
|
+
|
90
|
+
Or install it yourself as:
|
91
|
+
|
92
|
+
$ gem install ten_years_rails
|
93
|
+
|
94
|
+
## License
|
95
|
+
|
96
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "ten_years_rails"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start(__FILE__)
|
data/bin/setup
ADDED
@@ -0,0 +1,120 @@
|
|
1
|
+
# Deprecation Tracker
|
2
|
+
|
3
|
+
In order to control the deprecation warnings that occur during a test run, we create a shitlist of deprecation warnings that we expect to see for each spec file. If code run by a spec file changes how often or what deprecation warning occurs, an error is raised after the RSpec run is complete.
|
4
|
+
|
5
|
+
It looks something like this:
|
6
|
+
|
7
|
+
```
|
8
|
+
An error occurred in an `after(:suite)` hook.
|
9
|
+
Failure/Error: raise UnexpectedDeprecations, message
|
10
|
+
|
11
|
+
DeprecationTracker::UnexpectedDeprecations:
|
12
|
+
⚠️ Deprecation warnings have changed!
|
13
|
+
|
14
|
+
Code called by the following spec files is now generating different deprecation warnings:
|
15
|
+
|
16
|
+
./spec/deprecation_spec.rb
|
17
|
+
|
18
|
+
Here is a diff between what is expected and what was generated by this process:
|
19
|
+
|
20
|
+
diff --git a/spec/support/deprecation_tracker.json b/var/folders/mv/x81dlrp92w5053_m9bgqbkmm0000gp/T/test-deprecations20180328-33449-xgor20
|
21
|
+
index 76d2118f9f2..257be30d46c 100644
|
22
|
+
--- a/spec/support/deprecation_tracker.json
|
23
|
+
+++ b/var/folders/mv/x81dlrp92w5053_m9bgqbkmm0000gp/T/test-deprecations20180328-33449-xgor20
|
24
|
+
@@ -1,7 +1,8 @@
|
25
|
+
{
|
26
|
+
"./spec/deprecation_spec.rb": [
|
27
|
+
"DEPRECATION WARNING: `ActiveRecord::Base.symbolized_base_class` is deprecated and will be removed without replacement. (called from block (2 levels) in <top (required)> at /Users/Jordan/projects/themis3/spec/deprecation_spec.rb:5)",
|
28
|
+
- "DEPRECATION WARNING: `ActiveRecord::Base.symbolized_base_class` is deprecated and will be removed without replacement. (called from block (2 levels) in <top (required)> at /Users/Jordan/projects/themis3/spec/deprecation_spec.rb:6)"
|
29
|
+
+ "DEPRECATION WARNING: `ActiveRecord::Base.symbolized_base_class` is deprecated and will be removed without replacement. (called from block (2 levels) in <top (required)> at /Users/Jordan/projects/themis3/spec/deprecation_spec.rb:6)",
|
30
|
+
+ "DEPRECATION WARNING: `ActiveRecord::Base.symbolized_base_class` is deprecated and will be removed without replacement. (called from block (2 levels) in <top (required)> at /Users/Jordan/projects/themis3/spec/deprecation_spec.rb:7)"
|
31
|
+
],
|
32
|
+
"./spec/models/refund_spec.rb": [
|
33
|
+
|
34
|
+
# ./spec/support/deprecation_tracker.rb:65:in `compare'
|
35
|
+
# ./spec/support/deprecation_tracker.rb:29:in `block in track_rspec'
|
36
|
+
# /Users/Jordan/.rbenv/versions/2.4.3/bin/rspec:23:in `load'
|
37
|
+
# /Users/Jordan/.rbenv/versions/2.4.3/bin/rspec:23:in `<top (required)>'
|
38
|
+
# /Users/Jordan/.rbenv/versions/2.4.3/bin/bundle:23:in `load'
|
39
|
+
# /Users/Jordan/.rbenv/versions/2.4.3/bin/bundle:23:in `<main>'
|
40
|
+
|
41
|
+
Finished in 1.83 seconds (files took 9.09 seconds to load)
|
42
|
+
1 example, 0 failures, 1 error occurred outside of examples
|
43
|
+
```
|
44
|
+
|
45
|
+
When the diff shows a line was removed, it means we expected to see that deprecation message but didn't.
|
46
|
+
When the diff shows a line was added, it means didn't expect to see that deprecation message.
|
47
|
+
|
48
|
+
> **Protip**: If you find the diff difficult to read in your terminal, copy/paste it into your text editor and set syntax highlighting to "diff" for a colorized view.
|
49
|
+
|
50
|
+
Keeping a list of all deprecation warnings has two primary benefits:
|
51
|
+
|
52
|
+
- We can fail CI when new deprecation warnings are added (i.e., "stop the bleeding")
|
53
|
+
- We can more easily find and eliminate deprecation warnings
|
54
|
+
|
55
|
+
## Modes
|
56
|
+
|
57
|
+
The deprecation tracker has three mode: `compare`, `save`, and off.
|
58
|
+
|
59
|
+
- `DEPRECATION_TRACKER=compare rspec foo_spec.rb`: in `compare` mode, changes to the deprecation warnings output by a test file will trigger an error.
|
60
|
+
- `DEPRECATION_TRACKER=save rspec foo_spec.rb`: in `save` mode, changes to the deprecation warnings output by a test file will update the shitlist.
|
61
|
+
- `rspec foo_spec.rb`: when turned off, changes to the deprecation warnings output by a test file won't trigger a warning or update the shitlist.
|
62
|
+
|
63
|
+
|
64
|
+
## What does it track?
|
65
|
+
|
66
|
+
This tracks deprecations from Rails and `Kernel#warn`, the latter often used by gems that don't use ActiveSupport.
|
67
|
+
|
68
|
+
It only tracks deprecation warnings that occur during a test and not before or after. This means that some deprecations, for example the ones you might see while the app boots, won't be tracked.
|
69
|
+
|
70
|
+
It also doesn't track constant deprecations (`warning: constant Foo is deprecated`) because those [happen in C code](http://ruby-doc.org/core-2.3.0/Module.html#method-i-deprecate_constant). (If you can think of a way to capture these, do it!)
|
71
|
+
|
72
|
+
## How do I get my pull request green on CI?
|
73
|
+
|
74
|
+
### There are _added_ deprecation warnings
|
75
|
+
|
76
|
+
If the diff shows added deprecation warnings, you'll need to go back and change code until those messages don't happen. Under normal circumstances, we shouldn't increase the number of deprecation warnings.
|
77
|
+
|
78
|
+
You can check if your test file has changed deprecation warnings by running this command:
|
79
|
+
|
80
|
+
```bash
|
81
|
+
DEPRECATION_TRACKER=compare bundle exec rspec spec/foo_spec.rb
|
82
|
+
```
|
83
|
+
|
84
|
+
In this case, an error will be raised if `spec/foo_spec.rb` triggers deprecation warnings that are different than we expect.
|
85
|
+
|
86
|
+
> An example of when it would be OK to increase the number of deprecation warnings is during a Rails upgrade. We're not introducing code that adds deprecation warnings but rather change libraries so what used to be safe to call is now deprecated.
|
87
|
+
|
88
|
+
### There are _removed_ deprecation warnings
|
89
|
+
|
90
|
+
If the diff shows removed deprecation warnings, congratulations! Pat yourself on the back and then run this command:
|
91
|
+
|
92
|
+
```ruby
|
93
|
+
DEPRECATION_TRACKER=save bundle exec rspec <spec files mentioned in the error>
|
94
|
+
```
|
95
|
+
|
96
|
+
This will rerun the tests that reduces the number of deprecation warnings and save that to the log.
|
97
|
+
|
98
|
+
Be sure to commit your changes, then push and wait for CI to go ✅.
|
99
|
+
|
100
|
+
### The deprecation warnings are _different_
|
101
|
+
|
102
|
+
If the diff shows added and removed lines, the deprecation messages we expected to see may have changed. Most deprecation warnings contain the file and line of app code that caused it. If the line number changes, the deprecation warning message will also change. In this case, you can follow the same steps as you would if you removed deprecation warnings to update the stale deprecation messages:
|
103
|
+
|
104
|
+
```ruby
|
105
|
+
DEPRECATION_TRACKER=save bundle exec rspec <spec files mentioned in the error>
|
106
|
+
```
|
107
|
+
|
108
|
+
This will update the deprecation warning shitlist. Be sure to commit your changes, then push and wait for CI to go ✅.
|
109
|
+
|
110
|
+
## Where is the shitlist stored?
|
111
|
+
|
112
|
+
```
|
113
|
+
spec/support/deprecation_warnings.shitlist.json
|
114
|
+
```
|
115
|
+
|
116
|
+
## How does it work?
|
117
|
+
|
118
|
+
While running tests, we keep track of what test file is being run and record each deprecation warning as it happens. After the test run is complete, we compare the deprecation messages we saw with the deprecation messages we expected to see and raise an error if the two differ.
|
119
|
+
|
120
|
+
See `spec/support/deprecation_tracker.rb` for implementation details.
|
data/exe/bundle_report
ADDED
@@ -0,0 +1,264 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# Print a report on our Gemfile
|
4
|
+
# Why not just use `bundle outdated`? It doesn't give us the information we care about (and it fails).
|
5
|
+
#
|
6
|
+
at_exit do
|
7
|
+
require "optparse"
|
8
|
+
|
9
|
+
options = {}
|
10
|
+
option_parser = OptionParser.new do |opts|
|
11
|
+
opts.banner = <<~EOS
|
12
|
+
Usage: #{$0} [report-type] [options]
|
13
|
+
|
14
|
+
report-type There are two report types available: `outdated` and `compatibility`
|
15
|
+
|
16
|
+
Examples:
|
17
|
+
#{$0} compatibility --rails-version 5.0
|
18
|
+
#{$0} outdated
|
19
|
+
EOS
|
20
|
+
|
21
|
+
opts.separator ""
|
22
|
+
opts.separator "Options:"
|
23
|
+
|
24
|
+
opts.on("--rails-version [STRING]", "Rails version to check compatibility against (defaults to 5.0)") do |rails_version|
|
25
|
+
options[:rails_version] = rails_version
|
26
|
+
end
|
27
|
+
|
28
|
+
opts.on("--include-rails-gems", "Include Rails gems in compatibility report (defaults to false)") do
|
29
|
+
options[:include_rails_gems] = true
|
30
|
+
end
|
31
|
+
|
32
|
+
opts.on_tail("-h", "--help", "Show this message") do
|
33
|
+
puts opts
|
34
|
+
exit
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
begin
|
39
|
+
option_parser.parse!
|
40
|
+
rescue OptionParser::ParseError => e
|
41
|
+
STDERR.puts e.message.red
|
42
|
+
puts option_parser
|
43
|
+
exit 1
|
44
|
+
end
|
45
|
+
|
46
|
+
report_type = ARGV.first
|
47
|
+
|
48
|
+
case report_type
|
49
|
+
when "outdated" then BundleReport.outdated
|
50
|
+
else
|
51
|
+
BundleReport.compatibility(rails_version: options.fetch(:rails_version, "5.0"), include_rails_gems: options.fetch(:include_rails_gems, false))
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
# Needs to happen first
|
56
|
+
require "bundler/setup"
|
57
|
+
|
58
|
+
require "action_view"
|
59
|
+
require "active_support/core_ext/object/acts_like"
|
60
|
+
require "colorize"
|
61
|
+
require "cgi"
|
62
|
+
require "erb"
|
63
|
+
require "json"
|
64
|
+
require "rest-client"
|
65
|
+
|
66
|
+
class BundleReport
|
67
|
+
def self.compatibility(rails_version:, include_rails_gems:)
|
68
|
+
incompatible_gems = BundleReport::GemInfo.all.reject do |gem|
|
69
|
+
gem.compatible_with_rails?(rails_version: rails_version) || (!include_rails_gems && gem.from_rails?)
|
70
|
+
end.sort_by do |gem|
|
71
|
+
[
|
72
|
+
gem.latest_version.compatible_with_rails?(rails_version: rails_version) ? 0 : 1,
|
73
|
+
gem.name
|
74
|
+
].join("-")
|
75
|
+
end
|
76
|
+
|
77
|
+
incompatible_gems_by_state = incompatible_gems.group_by { |gem| gem.state(rails_version) }
|
78
|
+
|
79
|
+
template = <<~ERB
|
80
|
+
<% if incompatible_gems_by_state[:latest_compatible] -%>
|
81
|
+
<%= "=> Incompatible with Rails #{rails_version} (with new versions that are compatible):".white.bold %>
|
82
|
+
<%= "These gems will need to be upgraded before upgrading to Rails #{rails_version}.".italic %>
|
83
|
+
|
84
|
+
<% incompatible_gems_by_state[:latest_compatible].each do |gem| -%>
|
85
|
+
<%= gem_header(gem) %> - upgrade to <%= gem.latest_version.version %>
|
86
|
+
<% end -%>
|
87
|
+
|
88
|
+
<% end -%>
|
89
|
+
<% if incompatible_gems_by_state[:incompatible] -%>
|
90
|
+
<%= "=> Incompatible with Rails #{rails_version} (with no new compatible versions):".white.bold %>
|
91
|
+
<%= "These gems will need to be removed or replaced before upgrading to Rails #{rails_version}.".italic %>
|
92
|
+
|
93
|
+
<% incompatible_gems_by_state[:incompatible].each do |gem| -%>
|
94
|
+
<%= gem_header(gem) %> - new version, <%= gem.latest_version.version %>, is not compatible with Rails #{rails_version}
|
95
|
+
<% end -%>
|
96
|
+
|
97
|
+
<% end -%>
|
98
|
+
<% if incompatible_gems_by_state[:no_new_version] -%>
|
99
|
+
<%= "=> Incompatible with Rails #{rails_version} (with no new versions):".white.bold %>
|
100
|
+
<%= "These gems will need to be upgraded by us or removed before upgrading to Rails #{rails_version}.".italic %>
|
101
|
+
<%= "This list is likely to contain internal gems, like Cuddlefish.".italic %>
|
102
|
+
|
103
|
+
<% incompatible_gems_by_state[:no_new_version].each do |gem| -%>
|
104
|
+
<%= gem_header(gem) %> - new version not found
|
105
|
+
<% end -%>
|
106
|
+
|
107
|
+
<% end -%>
|
108
|
+
<%= incompatible_gems.length.to_s.red %> gems incompatible with Rails <%= rails_version %>
|
109
|
+
ERB
|
110
|
+
|
111
|
+
puts ERB.new(template, nil, "-").result(binding)
|
112
|
+
end
|
113
|
+
|
114
|
+
def self.gem_header(_gem)
|
115
|
+
header = "#{_gem.name} #{_gem.version}".bold
|
116
|
+
header << " (loaded from git)".magenta if _gem.sourced_from_git?
|
117
|
+
header
|
118
|
+
end
|
119
|
+
|
120
|
+
def self.outdated
|
121
|
+
gems = BundleReport::GemInfo.all
|
122
|
+
out_of_date_gems = gems.reject(&:up_to_date?).sort_by(&:created_at)
|
123
|
+
percentage_out_of_date = ((out_of_date_gems.count / gems.count.to_f) * 100).round
|
124
|
+
sourced_from_git = gems.select(&:sourced_from_git?)
|
125
|
+
|
126
|
+
out_of_date_gems.each do |_gem|
|
127
|
+
header = "#{_gem.name} #{_gem.version}"
|
128
|
+
|
129
|
+
puts <<~MESSAGE
|
130
|
+
#{header.bold.white}: released #{_gem.age} (latest version, #{_gem.latest_version.version}, released #{_gem.latest_version.age})
|
131
|
+
MESSAGE
|
132
|
+
end
|
133
|
+
|
134
|
+
puts ""
|
135
|
+
puts <<~MESSAGE
|
136
|
+
#{"#{sourced_from_git.count}".yellow} gems are sourced from git
|
137
|
+
#{"#{out_of_date_gems.length}".red} of the #{gems.count} gems are out-of-date (#{percentage_out_of_date}%)
|
138
|
+
MESSAGE
|
139
|
+
end
|
140
|
+
|
141
|
+
class GemInfo
|
142
|
+
include ActionView::Helpers::DateHelper
|
143
|
+
|
144
|
+
class NullGemInfo < GemInfo
|
145
|
+
def initialize; end
|
146
|
+
|
147
|
+
def age
|
148
|
+
"-"
|
149
|
+
end
|
150
|
+
|
151
|
+
def time_to_latest_version
|
152
|
+
"-"
|
153
|
+
end
|
154
|
+
|
155
|
+
def created_at
|
156
|
+
Time.now
|
157
|
+
end
|
158
|
+
|
159
|
+
def up_to_date?
|
160
|
+
false
|
161
|
+
end
|
162
|
+
|
163
|
+
def version
|
164
|
+
"NOT FOUND"
|
165
|
+
end
|
166
|
+
|
167
|
+
def unsatisfied_rails_dependencies(*)
|
168
|
+
["unknown"]
|
169
|
+
end
|
170
|
+
|
171
|
+
def state(_)
|
172
|
+
:null
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
def self.all
|
177
|
+
Gem::Specification.each.map do |gem_specification|
|
178
|
+
new(gem_specification)
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
attr_reader :gem_specification, :version, :name
|
183
|
+
def initialize(gem_specification)
|
184
|
+
@gem_specification = gem_specification
|
185
|
+
@version = gem_specification.version
|
186
|
+
@name = gem_specification.name
|
187
|
+
end
|
188
|
+
|
189
|
+
def age
|
190
|
+
"#{time_ago_in_words(created_at)} ago"
|
191
|
+
end
|
192
|
+
|
193
|
+
def sourced_from_git?
|
194
|
+
!!gem_specification.git_version
|
195
|
+
end
|
196
|
+
|
197
|
+
def time_to_latest_version
|
198
|
+
distance_of_time_in_words(created_at, latest_version.created_at)
|
199
|
+
end
|
200
|
+
|
201
|
+
def created_at
|
202
|
+
@created_at ||= gem_specification.date
|
203
|
+
end
|
204
|
+
|
205
|
+
def up_to_date?
|
206
|
+
version == latest_version.version
|
207
|
+
end
|
208
|
+
|
209
|
+
def state(rails_version)
|
210
|
+
if compatible_with_rails?(rails_version: rails_version)
|
211
|
+
:compatible
|
212
|
+
elsif latest_version.compatible_with_rails?(rails_version: rails_version)
|
213
|
+
:latest_compatible
|
214
|
+
elsif latest_version.version == "NOT FOUND"
|
215
|
+
:no_new_version
|
216
|
+
else
|
217
|
+
:incompatible
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
def latest_version
|
222
|
+
@latest_version ||= begin
|
223
|
+
latest_gem_specification = Gem.latest_spec_for(name)
|
224
|
+
if latest_gem_specification
|
225
|
+
GemInfo.new(latest_gem_specification)
|
226
|
+
else
|
227
|
+
NullGemInfo.new
|
228
|
+
end
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
def compatible_with_rails?(rails_version: Gem::Version.new("5.0"))
|
233
|
+
unsatisfied_rails_dependencies(rails_version: rails_version).empty?
|
234
|
+
end
|
235
|
+
|
236
|
+
def unsatisfied_rails_dependencies(rails_version:)
|
237
|
+
rails_dependencies = gem_specification.runtime_dependencies.select {|dependency| rails_gems.include?(dependency.name) }
|
238
|
+
|
239
|
+
rails_dependencies.reject do |rails_dependency|
|
240
|
+
rails_dependency.requirement.satisfied_by?(Gem::Version.new(rails_version))
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
244
|
+
def from_rails?
|
245
|
+
rails_gems.include?(name)
|
246
|
+
end
|
247
|
+
|
248
|
+
private def rails_gems
|
249
|
+
[
|
250
|
+
"rails",
|
251
|
+
"activemodel",
|
252
|
+
"activerecord",
|
253
|
+
"actionmailer",
|
254
|
+
"actioncable",
|
255
|
+
"actionpack",
|
256
|
+
"actionview",
|
257
|
+
"activejob",
|
258
|
+
"activestorage",
|
259
|
+
"activesupport",
|
260
|
+
"railties",
|
261
|
+
]
|
262
|
+
end
|
263
|
+
end
|
264
|
+
end
|
data/exe/deprecations
ADDED
@@ -0,0 +1,110 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require "json"
|
3
|
+
require "colorize"
|
4
|
+
require "optparse"
|
5
|
+
require "set"
|
6
|
+
|
7
|
+
def run_tests(deprecation_warnings, tracker_mode:, next_mode:)
|
8
|
+
rspec_command = if next_mode
|
9
|
+
"bin/next rspec"
|
10
|
+
else
|
11
|
+
"bundle exec rspec"
|
12
|
+
end
|
13
|
+
|
14
|
+
command = "DEPRECATION_TRACKER=#{tracker_mode} #{rspec_command} #{deprecation_warnings.keys.join(" ")}"
|
15
|
+
puts command
|
16
|
+
exec command
|
17
|
+
end
|
18
|
+
|
19
|
+
def print_info(deprecation_warnings, verbose: false)
|
20
|
+
frequency_by_message = deprecation_warnings.each_with_object({}) do |(test_file, messages), hash|
|
21
|
+
messages.each do |message|
|
22
|
+
hash[message] ||= { test_files: Set.new, occurrences: 0 }
|
23
|
+
hash[message][:test_files] << test_file
|
24
|
+
hash[message][:occurrences] += 1
|
25
|
+
end
|
26
|
+
end.sort_by {|message, data| data[:occurrences] }.reverse.to_h
|
27
|
+
|
28
|
+
puts "Ten most common deprecation warnings:".underline
|
29
|
+
frequency_by_message.take(10).each do |message, data|
|
30
|
+
puts "Occurrences: #{data.fetch(:occurrences)}".bold
|
31
|
+
puts "Test files: #{data.fetch(:test_files).to_a.join(" ")}" if verbose
|
32
|
+
puts message.red
|
33
|
+
puts "----------"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
options = {}
|
38
|
+
option_parser = OptionParser.new do |opts|
|
39
|
+
opts.banner = <<~MESSAGE
|
40
|
+
Usage: #{__FILE__.to_s} [options] [mode]
|
41
|
+
|
42
|
+
Parses the deprecation warning shitlist and show info or run tests.
|
43
|
+
|
44
|
+
Examples:
|
45
|
+
bin/deprecations info # Show top ten deprecations
|
46
|
+
bin/deprecations --next info # Show top ten deprecations for Rails 5
|
47
|
+
bin/deprecations --pattern "ActiveRecord::Base" --verbose info # Show full details on deprecations matching pattern
|
48
|
+
bin/deprecations --tracker-mode save --pattern "pass" run # Run tests that output deprecations matching pattern and update shitlist
|
49
|
+
|
50
|
+
Modes:
|
51
|
+
info
|
52
|
+
Show information on the ten most frequent deprceation warnings.
|
53
|
+
|
54
|
+
run
|
55
|
+
Run tests that are known to cause deprecation warnings. Use --pattern to filter what tests are run.
|
56
|
+
|
57
|
+
Options:
|
58
|
+
MESSAGE
|
59
|
+
|
60
|
+
opts.on("--next", "Run against the next shitlist") do |next_mode|
|
61
|
+
options[:next] = next_mode
|
62
|
+
end
|
63
|
+
|
64
|
+
opts.on("--tracker-mode MODE", "Set DEPRECATION_TRACKER in test mode. Options: save or compare") do |tracker_mode|
|
65
|
+
options[:tracker_mode] = tracker_mode
|
66
|
+
end
|
67
|
+
|
68
|
+
opts.on("--pattern RUBY_REGEX", "Filter deprecation warnings with a pattern.") do |pattern|
|
69
|
+
options[:pattern] = pattern
|
70
|
+
end
|
71
|
+
|
72
|
+
opts.on("--verbose", "show more information") do
|
73
|
+
options[:verbose] = true
|
74
|
+
end
|
75
|
+
|
76
|
+
opts.on_tail("-h", "--help", "Prints this help") do
|
77
|
+
puts opts
|
78
|
+
exit
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
option_parser.parse!
|
83
|
+
|
84
|
+
options[:mode] = ARGV.last
|
85
|
+
path = options[:next] ? "spec/support/deprecation_warning.next.shitlist.json" : "spec/support/deprecation_warning.shitlist.json"
|
86
|
+
|
87
|
+
pattern_string = options.fetch(:pattern, ".+")
|
88
|
+
pattern = /#{pattern_string}/
|
89
|
+
|
90
|
+
deprecation_warnings = JSON.parse(File.read(path)).each_with_object({}) do |(test_file, messages), hash|
|
91
|
+
filtered_messages = messages.select {|message| message.match(pattern) }
|
92
|
+
hash[test_file] = filtered_messages if !filtered_messages.empty?
|
93
|
+
end
|
94
|
+
|
95
|
+
if deprecation_warnings.empty?
|
96
|
+
abort "No test files with deprecations matching #{pattern.inspect}."
|
97
|
+
exit 2
|
98
|
+
end
|
99
|
+
|
100
|
+
case options.fetch(:mode, "info")
|
101
|
+
when "run" then run_tests(deprecation_warnings, next_mode: options[:next], tracker_mode: options[:tracker_mode])
|
102
|
+
when "info" then print_info(deprecation_warnings, verbose: options[:verbose])
|
103
|
+
when nil
|
104
|
+
STDERR.puts "Must pass a mode: run or info".red
|
105
|
+
puts option_parser
|
106
|
+
exit 1
|
107
|
+
else
|
108
|
+
STDERR.puts "Unknown mode: #{options[:mode]}".red
|
109
|
+
exit 1
|
110
|
+
end
|
data/exe/gem-next-diff
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# Output a markdown table containing the version differences between the Gemfile and Gemfile.next.
|
4
|
+
# This can be used as a TODO list to bring the two Gemfiles as close to parity as possible,
|
5
|
+
# either by upgrading gems within `Gemfile` or downgrading gems within `Gemfile.next`.
|
6
|
+
#
|
7
|
+
|
8
|
+
def parse_gem_versions(&block)
|
9
|
+
bundler_output = block.call
|
10
|
+
bundler_output.split("\n").each_with_object({}) do |line, hash|
|
11
|
+
next unless line.start_with?("Using")
|
12
|
+
|
13
|
+
gem_name, version = line.split(/\s+/)[1..2]
|
14
|
+
hash[gem_name] = version
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
rails_gems = [
|
19
|
+
"rails",
|
20
|
+
"activemodel",
|
21
|
+
"activerecord",
|
22
|
+
"actionmailer",
|
23
|
+
"actioncable",
|
24
|
+
"actionpack",
|
25
|
+
"actionview",
|
26
|
+
"activejob",
|
27
|
+
"activestorage",
|
28
|
+
"activesupport",
|
29
|
+
"railties",
|
30
|
+
]
|
31
|
+
|
32
|
+
gems = parse_gem_versions { `BUNDLE_CACHE_PATH=vendor/cache BUNDLE_GEMFILE=Gemfile bundle install` }
|
33
|
+
gems_next = parse_gem_versions { `BUNDLE_CACHE_PATH=vendor/cache.next BUNDLE_GEMFILE=Gemfile.next bundle install` }
|
34
|
+
all_gem_names = (gems.keys + gems_next.keys).uniq.sort
|
35
|
+
|
36
|
+
puts "| Gem | `Gemfile` version | `Gemfile.next` version | Rails internals |"
|
37
|
+
puts "|-----|-------------------|------------------------|-----------------| "
|
38
|
+
all_gem_names.each do |gem_name|
|
39
|
+
gem_version = gems[gem_name] || "-"
|
40
|
+
gem_next_version = gems_next[gem_name] || "-"
|
41
|
+
rails_internal = rails_gems.include?(gem_name) ? "✅" : ""
|
42
|
+
|
43
|
+
if gem_version != gem_next_version
|
44
|
+
puts "| **#{gem_name}** | #{gem_version} | #{gem_next_version} | #{rails_internal} |"
|
45
|
+
end
|
46
|
+
end
|
data/exe/next
ADDED
data/exe/next.sh
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
#!/bin/bash
|
2
|
+
if [[ "${@}" == "--init" ]]; then
|
3
|
+
echo "doing a thing"
|
4
|
+
# Add next? top of Gemfile
|
5
|
+
cat <<-STRING > Gemfile.tmp
|
6
|
+
def next?
|
7
|
+
File.basename(__FILE__) == "Gemfile.next"
|
8
|
+
end
|
9
|
+
STRING
|
10
|
+
cat Gemfile >> Gemfile.tmp
|
11
|
+
mv Gemfile.tmp Gemfile
|
12
|
+
|
13
|
+
ln -s Gemfile Gemfile.next
|
14
|
+
exit $?
|
15
|
+
fi
|
16
|
+
|
17
|
+
if [[ "${@}" =~ ^bundle ]]; then
|
18
|
+
BUNDLE_GEMFILE=Gemfile.next BUNDLE_CACHE_PATH=vendor/cache.next $@
|
19
|
+
else
|
20
|
+
BUNDLE_GEMFILE=Gemfile.next BUNDLE_CACHE_PATH=vendor/cache.next bundle exec $@
|
21
|
+
fi
|
22
|
+
|
23
|
+
COMMAND_EXIT=$?
|
24
|
+
|
25
|
+
GEM_NOT_FOUND=7 # https://github.com/bundler/bundler/blob/master/lib/bundler/errors.rb#L35
|
26
|
+
EXECUTABLE_NOT_FOUND=127 # https://github.com/bundler/bundler/blob/master/lib/bundler/cli/exec.rb#L62
|
27
|
+
if [[ $COMMAND_EXIT -eq $GEM_NOT_FOUND || $COMMAND_EXIT -eq $EXECUTABLE_NOT_FOUND ]]; then
|
28
|
+
BLUE='\033[0;34m'
|
29
|
+
UNDERLINE_WHITE='\033[37m'
|
30
|
+
NO_COLOR='\033[0m'
|
31
|
+
|
32
|
+
echo -e "${BLUE}Having trouble running commands with ${UNDERLINE_WHITE}bin/next${BLUE}?"
|
33
|
+
echo -e "Try running ${UNDERLINE_WHITE}bin/next bundle install${BLUE}, then try your command again.${NO_COLOR}"
|
34
|
+
fi
|
35
|
+
|
36
|
+
exit $COMMAND_EXIT
|
@@ -0,0 +1,147 @@
|
|
1
|
+
require "json"
|
2
|
+
|
3
|
+
# A shitlist for deprecation warnings during test runs. It has two modes: "save" and "compare"
|
4
|
+
#
|
5
|
+
# DEPRECATION_TRACKER=save
|
6
|
+
# Record deprecation warnings, grouped by spec file. After the test run, save to a file.
|
7
|
+
#
|
8
|
+
# DEPRECATION_TRACKER=compare
|
9
|
+
# Tracks deprecation warnings, grouped by spec file. After the test run, compare against shitlist of expected
|
10
|
+
# deprecation warnings. If anything is added or removed, raise an error with a diff of the changes.
|
11
|
+
#
|
12
|
+
class DeprecationTracker
|
13
|
+
UnexpectedDeprecations = Class.new(StandardError)
|
14
|
+
|
15
|
+
module KernelWarnTracker
|
16
|
+
def self.callbacks
|
17
|
+
@callbacks ||= []
|
18
|
+
end
|
19
|
+
|
20
|
+
def warn(*messages)
|
21
|
+
KernelWarnTracker.callbacks.each do |callback|
|
22
|
+
messages.each { |message| callback.(message) }
|
23
|
+
end
|
24
|
+
|
25
|
+
super
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
# There are two forms of the `warn` method: one for class Kernel and one for instances of Kernel (i.e., every Object)
|
30
|
+
Object.prepend(KernelWarnTracker)
|
31
|
+
Kernel.singleton_class.prepend(KernelWarnTracker)
|
32
|
+
|
33
|
+
def self.track_rspec(rspec_config, shitlist_path:, mode:, transform_message: nil)
|
34
|
+
deprecation_tracker = DeprecationTracker.new(shitlist_path, transform_message)
|
35
|
+
ActiveSupport::Deprecation.behavior << -> (message, _callstack) { deprecation_tracker.add(message) }
|
36
|
+
KernelWarnTracker.callbacks << -> (message) { deprecation_tracker.add(message) }
|
37
|
+
|
38
|
+
rspec_config.around do |example|
|
39
|
+
deprecation_tracker.bucket = example.metadata.fetch(:rerun_file_path)
|
40
|
+
|
41
|
+
begin
|
42
|
+
example.run
|
43
|
+
ensure
|
44
|
+
deprecation_tracker.bucket = nil
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
rspec_config.after(:suite) do
|
49
|
+
if mode == "save"
|
50
|
+
deprecation_tracker.save
|
51
|
+
elsif mode == "compare"
|
52
|
+
deprecation_tracker.compare
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
attr_reader :deprecation_messages, :shitlist_path, :transform_message
|
58
|
+
attr_reader :bucket
|
59
|
+
|
60
|
+
def initialize(shitlist_path, transform_message = nil)
|
61
|
+
@shitlist_path = shitlist_path
|
62
|
+
@transform_message = transform_message || -> (message) { message }
|
63
|
+
@deprecation_messages = {}
|
64
|
+
end
|
65
|
+
|
66
|
+
def add(message)
|
67
|
+
return if bucket.nil?
|
68
|
+
|
69
|
+
@deprecation_messages[bucket] << transform_message.(message)
|
70
|
+
end
|
71
|
+
|
72
|
+
def bucket=(value)
|
73
|
+
@bucket = value
|
74
|
+
@deprecation_messages[value] ||= [] unless value.nil?
|
75
|
+
end
|
76
|
+
|
77
|
+
def compare
|
78
|
+
shitlist = read_shitlist
|
79
|
+
|
80
|
+
changed_buckets = []
|
81
|
+
normalized_deprecation_messages.each do |bucket, messages|
|
82
|
+
if shitlist[bucket] != messages
|
83
|
+
changed_buckets << bucket
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
if changed_buckets.length > 0
|
88
|
+
message = <<~MESSAGE.red
|
89
|
+
⚠️ Deprecation warnings have changed!
|
90
|
+
|
91
|
+
Code called by the following spec files is now generating different deprecation warnings:
|
92
|
+
|
93
|
+
#{changed_buckets.join("\n")}
|
94
|
+
|
95
|
+
To check your failures locally, you can run:
|
96
|
+
|
97
|
+
DEPRECATION_TRACKER=compare bundle exec rspec #{changed_buckets.join(" ")}
|
98
|
+
|
99
|
+
Here is a diff between what is expected and what was generated by this process:
|
100
|
+
|
101
|
+
#{diff}
|
102
|
+
|
103
|
+
See \e[4;37mdev-docs/testing/deprecation_tracker.md\e[0;31m for more information.
|
104
|
+
MESSAGE
|
105
|
+
|
106
|
+
raise UnexpectedDeprecations, message
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def diff
|
111
|
+
new_shitlist = create_temp_shitlist
|
112
|
+
`git diff --no-index #{shitlist_path} #{new_shitlist.path}`
|
113
|
+
ensure
|
114
|
+
new_shitlist.delete
|
115
|
+
end
|
116
|
+
|
117
|
+
def save
|
118
|
+
new_shitlist = create_temp_shitlist
|
119
|
+
FileUtils.cp(new_shitlist.path, shitlist_path)
|
120
|
+
ensure
|
121
|
+
new_shitlist&.delete
|
122
|
+
end
|
123
|
+
|
124
|
+
def create_temp_shitlist
|
125
|
+
temp_file = Tempfile.new("temp-deprecation-tracker-shitlist")
|
126
|
+
temp_file.write(JSON.pretty_generate(normalized_deprecation_messages))
|
127
|
+
temp_file.flush
|
128
|
+
|
129
|
+
temp_file
|
130
|
+
end
|
131
|
+
|
132
|
+
# Normalize deprecation messages to reduce noise from file output and test files to be tracked with separate test runs
|
133
|
+
def normalized_deprecation_messages
|
134
|
+
normalized = read_shitlist.merge(deprecation_messages).each_with_object({}) do |(bucket, messages), hash|
|
135
|
+
hash[bucket] = messages.sort
|
136
|
+
end
|
137
|
+
|
138
|
+
normalized.reject {|_key, value| value.empty? }.sort_by {|key, _value| key }.to_h
|
139
|
+
end
|
140
|
+
|
141
|
+
def read_shitlist
|
142
|
+
return {} unless File.exist?(shitlist_path)
|
143
|
+
JSON.parse(File.read(shitlist_path))
|
144
|
+
rescue JSON::ParserError => e
|
145
|
+
raise "#{shitlist_path} is not valid JSON: #{e.message}"
|
146
|
+
end
|
147
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
|
2
|
+
lib = File.expand_path("../lib", __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require "ten_years_rails/version"
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "ten_years_rails"
|
8
|
+
spec.version = TenYearsRails::VERSION
|
9
|
+
spec.authors = ["Jordan Raine"]
|
10
|
+
spec.email = ["jnraine@gmail.com"]
|
11
|
+
|
12
|
+
spec.summary = %q{Companion code to Ten Years of Rails Upgrades}
|
13
|
+
spec.homepage = "https://github.com/clio/ten_years_rails"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
17
|
+
f.match(%r{^(test|spec|features)/})
|
18
|
+
end
|
19
|
+
spec.bindir = "exe"
|
20
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
21
|
+
spec.require_paths = ["lib"]
|
22
|
+
|
23
|
+
spec.add_dependency "actionview"
|
24
|
+
spec.add_dependency "activesupport"
|
25
|
+
spec.add_dependency "colorize", ">= 0.8.1"
|
26
|
+
spec.add_dependency "rest-client", ">= 2.0.2"
|
27
|
+
spec.add_development_dependency "bundler", "~> 1.16"
|
28
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
29
|
+
spec.add_development_dependency "rspec", "~> 3.0"
|
30
|
+
end
|
metadata
ADDED
@@ -0,0 +1,167 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ten_years_rails
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.2.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Jordan Raine
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2018-10-21 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: actionview
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: activesupport
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: colorize
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 0.8.1
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 0.8.1
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rest-client
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 2.0.2
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 2.0.2
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: bundler
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '1.16'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '1.16'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rake
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '10.0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '10.0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: rspec
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '3.0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '3.0'
|
111
|
+
description:
|
112
|
+
email:
|
113
|
+
- jnraine@gmail.com
|
114
|
+
executables:
|
115
|
+
- bundle_report
|
116
|
+
- deprecations
|
117
|
+
- gem-next-diff
|
118
|
+
- next
|
119
|
+
- next.sh
|
120
|
+
extensions: []
|
121
|
+
extra_rdoc_files: []
|
122
|
+
files:
|
123
|
+
- ".gitignore"
|
124
|
+
- ".rspec"
|
125
|
+
- ".travis.yml"
|
126
|
+
- Gemfile
|
127
|
+
- Gemfile.lock
|
128
|
+
- LICENSE.txt
|
129
|
+
- README.md
|
130
|
+
- Rakefile
|
131
|
+
- bin/console
|
132
|
+
- bin/setup
|
133
|
+
- deprecation_tracker.md
|
134
|
+
- exe/bundle_report
|
135
|
+
- exe/deprecations
|
136
|
+
- exe/gem-next-diff
|
137
|
+
- exe/next
|
138
|
+
- exe/next.sh
|
139
|
+
- lib/deprecation_tracker.rb
|
140
|
+
- lib/ten_years_rails.rb
|
141
|
+
- lib/ten_years_rails/version.rb
|
142
|
+
- ten_years_rails.gemspec
|
143
|
+
homepage: https://github.com/clio/ten_years_rails
|
144
|
+
licenses:
|
145
|
+
- MIT
|
146
|
+
metadata: {}
|
147
|
+
post_install_message:
|
148
|
+
rdoc_options: []
|
149
|
+
require_paths:
|
150
|
+
- lib
|
151
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
152
|
+
requirements:
|
153
|
+
- - ">="
|
154
|
+
- !ruby/object:Gem::Version
|
155
|
+
version: '0'
|
156
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
157
|
+
requirements:
|
158
|
+
- - ">="
|
159
|
+
- !ruby/object:Gem::Version
|
160
|
+
version: '0'
|
161
|
+
requirements: []
|
162
|
+
rubyforge_project:
|
163
|
+
rubygems_version: 2.6.14
|
164
|
+
signing_key:
|
165
|
+
specification_version: 4
|
166
|
+
summary: Companion code to Ten Years of Rails Upgrades
|
167
|
+
test_files: []
|