next_rails 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: c7d45da029e83bc0af55e23c79339edd199a1ed5971ab4d065c5a48fabf35f62
4
+ data.tar.gz: 2115c4363736ad020d7231908d075f8626cd5ba1ea7c2a82c50534aff1f46ebc
5
+ SHA512:
6
+ metadata.gz: 44e54e44a58b1f09b50f9ec8d5f4547af3d9f50b1f9a6eac103bf17857a2bfb3619fd33676285352a6d88d83c860e44fe152a2939e54b3d3902485445b8e0c77
7
+ data.tar.gz: a626d36676fe0217d0a3e868336fcdf43ea208eaf5ed03bb15d9967063b9c9e3db5f63bfd8ae9feb0776416a9f5d2b79b30bca69254f5f93cb9641c3f8cd4f9e
@@ -0,0 +1,15 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+
10
+ .byebug_history
11
+
12
+ # rspec failure tracking
13
+ .rspec_status
14
+
15
+ .ruby-version
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
@@ -0,0 +1,6 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.2.10
5
+ - 2.3.3
6
+ before_install: gem install bundler -v 1.16.1
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source "https://rubygems.org"
2
+
3
+ git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
4
+
5
+ # Specify your gem's dependencies in next_rails.gemspec
6
+ gemspec
@@ -0,0 +1,72 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ next_rails (0.2.0)
5
+ actionview
6
+ colorize (>= 0.8.1)
7
+
8
+ GEM
9
+ remote: https://rubygems.org/
10
+ specs:
11
+ actionview (5.2.3)
12
+ activesupport (= 5.2.3)
13
+ builder (~> 3.1)
14
+ erubi (~> 1.4)
15
+ rails-dom-testing (~> 2.0)
16
+ rails-html-sanitizer (~> 1.0, >= 1.0.3)
17
+ activesupport (5.2.3)
18
+ concurrent-ruby (~> 1.0, >= 1.0.2)
19
+ i18n (>= 0.7, < 2)
20
+ minitest (~> 5.1)
21
+ tzinfo (~> 1.1)
22
+ builder (3.2.3)
23
+ colorize (0.8.1)
24
+ concurrent-ruby (1.1.5)
25
+ crass (1.0.4)
26
+ diff-lcs (1.3)
27
+ erubi (1.8.0)
28
+ i18n (1.6.0)
29
+ concurrent-ruby (~> 1.0)
30
+ loofah (2.2.3)
31
+ crass (~> 1.0.2)
32
+ nokogiri (>= 1.5.9)
33
+ mini_portile2 (2.4.0)
34
+ minitest (5.11.3)
35
+ nokogiri (1.10.3)
36
+ mini_portile2 (~> 2.4.0)
37
+ rails-dom-testing (2.0.3)
38
+ activesupport (>= 4.2.0)
39
+ nokogiri (>= 1.6)
40
+ rails-html-sanitizer (1.0.4)
41
+ loofah (~> 2.2, >= 2.2.2)
42
+ rake (10.5.0)
43
+ rspec (3.8.0)
44
+ rspec-core (~> 3.8.0)
45
+ rspec-expectations (~> 3.8.0)
46
+ rspec-mocks (~> 3.8.0)
47
+ rspec-core (3.8.2)
48
+ rspec-support (~> 3.8.0)
49
+ rspec-expectations (3.8.4)
50
+ diff-lcs (>= 1.2.0, < 2.0)
51
+ rspec-support (~> 3.8.0)
52
+ rspec-mocks (3.8.1)
53
+ diff-lcs (>= 1.2.0, < 2.0)
54
+ rspec-support (~> 3.8.0)
55
+ rspec-support (3.8.2)
56
+ thread_safe (0.3.6)
57
+ timecop (0.9.1)
58
+ tzinfo (1.2.5)
59
+ thread_safe (~> 0.1)
60
+
61
+ PLATFORMS
62
+ ruby
63
+
64
+ DEPENDENCIES
65
+ bundler (~> 1.16)
66
+ next_rails!
67
+ rake (~> 10.0)
68
+ rspec (~> 3.0)
69
+ timecop (~> 0.9.1)
70
+
71
+ BUNDLED WITH
72
+ 1.17.2
@@ -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.
@@ -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 'next_rails'
84
+ ```
85
+
86
+ And then execute:
87
+
88
+ $ bundle
89
+
90
+ Or install it yourself as:
91
+
92
+ $ gem install next_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).
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "next_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__)
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -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.
@@ -0,0 +1,60 @@
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
+ require "next_rails"
9
+
10
+ options = {}
11
+ option_parser = OptionParser.new do |opts|
12
+ opts.banner = <<-EOS
13
+ Usage: #{$0} [report-type] [options]
14
+
15
+ report-type There are two report types available: `outdated` and `compatibility`
16
+
17
+ Examples:
18
+ #{$0} compatibility --rails-version 5.0
19
+ #{$0} outdated
20
+ EOS
21
+
22
+ opts.separator ""
23
+ opts.separator "Options:"
24
+
25
+ opts.on("--rails-version [STRING]", "Rails version to check compatibility against (defaults to 5.0)") do |rails_version|
26
+ options[:rails_version] = rails_version
27
+ end
28
+
29
+ opts.on("--include-rails-gems", "Include Rails gems in compatibility report (defaults to false)") do
30
+ options[:include_rails_gems] = true
31
+ end
32
+
33
+ opts.on_tail("-h", "--help", "Show this message") do
34
+ puts opts
35
+ exit
36
+ end
37
+ end
38
+
39
+ begin
40
+ option_parser.parse!
41
+ rescue OptionParser::ParseError => e
42
+ STDERR.puts e.message.red
43
+ puts option_parser
44
+ exit 1
45
+ end
46
+
47
+ report_type = ARGV.first
48
+
49
+ case report_type
50
+ when "outdated" then BundleReport.outdated
51
+ else
52
+ TenYearsRails::BundleReport.compatibility(rails_version: options.fetch(:rails_version, "5.0"), include_rails_gems: options.fetch(:include_rails_gems, false))
53
+ end
54
+ end
55
+
56
+ # Needs to happen first
57
+ require "bundler/setup"
58
+
59
+ require "action_view"
60
+ require "active_support/core_ext/object/acts_like"
@@ -0,0 +1,113 @@
1
+ #!/usr/bin/env ruby
2
+ require "json"
3
+ require "colorize"
4
+ require "optparse"
5
+ require "set"
6
+
7
+ def run_tests(deprecation_warnings, opts = {})
8
+ tracker_mode = opts[:tracker_mode]
9
+ next_mode = opts[:next_mode]
10
+ rspec_command = if next_mode
11
+ "bin/next rspec"
12
+ else
13
+ "bundle exec rspec"
14
+ end
15
+
16
+ command = "DEPRECATION_TRACKER=#{tracker_mode} #{rspec_command} #{deprecation_warnings.keys.join(" ")}"
17
+ puts command
18
+ exec command
19
+ end
20
+
21
+ def print_info(deprecation_warnings, opts = {})
22
+ verbose = !!opts[:verbose]
23
+ frequency_by_message = deprecation_warnings.each_with_object({}) do |(test_file, messages), hash|
24
+ messages.each do |message|
25
+ hash[message] ||= { test_files: Set.new, occurrences: 0 }
26
+ hash[message][:test_files] << test_file
27
+ hash[message][:occurrences] += 1
28
+ end
29
+ end.sort_by {|message, data| data[:occurrences] }.reverse.to_h
30
+
31
+ puts "Ten most common deprecation warnings:".underline
32
+ frequency_by_message.take(10).each do |message, data|
33
+ puts "Occurrences: #{data.fetch(:occurrences)}".bold
34
+ puts "Test files: #{data.fetch(:test_files).to_a.join(" ")}" if verbose
35
+ puts message.red
36
+ puts "----------"
37
+ end
38
+ end
39
+
40
+ options = {}
41
+ option_parser = OptionParser.new do |opts|
42
+ opts.banner = <<-MESSAGE
43
+ Usage: #{__FILE__.to_s} [options] [mode]
44
+
45
+ Parses the deprecation warning shitlist and show info or run tests.
46
+
47
+ Examples:
48
+ bin/deprecations info # Show top ten deprecations
49
+ bin/deprecations --next info # Show top ten deprecations for Rails 5
50
+ bin/deprecations --pattern "ActiveRecord::Base" --verbose info # Show full details on deprecations matching pattern
51
+ bin/deprecations --tracker-mode save --pattern "pass" run # Run tests that output deprecations matching pattern and update shitlist
52
+
53
+ Modes:
54
+ info
55
+ Show information on the ten most frequent deprceation warnings.
56
+
57
+ run
58
+ Run tests that are known to cause deprecation warnings. Use --pattern to filter what tests are run.
59
+
60
+ Options:
61
+ MESSAGE
62
+
63
+ opts.on("--next", "Run against the next shitlist") do |next_mode|
64
+ options[:next] = next_mode
65
+ end
66
+
67
+ opts.on("--tracker-mode MODE", "Set DEPRECATION_TRACKER in test mode. Options: save or compare") do |tracker_mode|
68
+ options[:tracker_mode] = tracker_mode
69
+ end
70
+
71
+ opts.on("--pattern RUBY_REGEX", "Filter deprecation warnings with a pattern.") do |pattern|
72
+ options[:pattern] = pattern
73
+ end
74
+
75
+ opts.on("--verbose", "show more information") do
76
+ options[:verbose] = true
77
+ end
78
+
79
+ opts.on_tail("-h", "--help", "Prints this help") do
80
+ puts opts
81
+ exit
82
+ end
83
+ end
84
+
85
+ option_parser.parse!
86
+
87
+ options[:mode] = ARGV.last
88
+ path = options[:next] ? "spec/support/deprecation_warning.next.shitlist.json" : "spec/support/deprecation_warning.shitlist.json"
89
+
90
+ pattern_string = options.fetch(:pattern, ".+")
91
+ pattern = /#{pattern_string}/
92
+
93
+ deprecation_warnings = JSON.parse(File.read(path)).each_with_object({}) do |(test_file, messages), hash|
94
+ filtered_messages = messages.select {|message| message.match(pattern) }
95
+ hash[test_file] = filtered_messages if !filtered_messages.empty?
96
+ end
97
+
98
+ if deprecation_warnings.empty?
99
+ abort "No test files with deprecations matching #{pattern.inspect}."
100
+ exit 2
101
+ end
102
+
103
+ case options.fetch(:mode, "info")
104
+ when "run" then run_tests(deprecation_warnings, next_mode: options[:next], tracker_mode: options[:tracker_mode])
105
+ when "info" then print_info(deprecation_warnings, verbose: options[:verbose])
106
+ when nil
107
+ STDERR.puts "Must pass a mode: run or info".red
108
+ puts option_parser
109
+ exit 1
110
+ else
111
+ STDERR.puts "Unknown mode: #{options[:mode]}".red
112
+ exit 1
113
+ end
@@ -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
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+ # Ruby wrapper around next.sh so it works with Rubygems
3
+ exe_dir = File.expand_path(File.dirname(__FILE__))
4
+ exec(File.join(exe_dir, 'next.sh'), *ARGV)
@@ -0,0 +1,48 @@
1
+ #!/bin/bash
2
+ if [[ "${@}" == "--init" ]]; then
3
+ # Add next? top of Gemfile
4
+ cat <<-STRING > Gemfile.tmp
5
+ def next?
6
+ File.basename(__FILE__) == "Gemfile.next"
7
+ end
8
+ STRING
9
+ cat Gemfile >> Gemfile.tmp
10
+ mv Gemfile.tmp Gemfile
11
+
12
+ ln -s Gemfile Gemfile.next
13
+ echo <<-MESSAGE
14
+ Created Gemfile.next (a symlink to your Gemfile). Your Gemfile has been modified to support dual-booting!
15
+
16
+ There's just one more step: modify your Gemfile to use a newer version of Rails using the \`next?\` helper method.
17
+
18
+ For example, here's how to go from 5.2.3 to 6.0:
19
+
20
+ if next?
21
+ gem "rails", "6.0.0"
22
+ else
23
+ gem "rails", "5.2.3"
24
+ end
25
+ MESSAGE
26
+ exit $?
27
+ fi
28
+
29
+ if [[ "${@}" =~ ^bundle ]]; then
30
+ BUNDLE_GEMFILE=Gemfile.next BUNDLE_CACHE_PATH=vendor/cache.next $@
31
+ else
32
+ BUNDLE_GEMFILE=Gemfile.next BUNDLE_CACHE_PATH=vendor/cache.next bundle exec $@
33
+ fi
34
+
35
+ COMMAND_EXIT=$?
36
+
37
+ GEM_NOT_FOUND=7 # https://github.com/bundler/bundler/blob/master/lib/bundler/errors.rb#L35
38
+ EXECUTABLE_NOT_FOUND=127 # https://github.com/bundler/bundler/blob/master/lib/bundler/cli/exec.rb#L62
39
+ if [[ $COMMAND_EXIT -eq $GEM_NOT_FOUND || $COMMAND_EXIT -eq $EXECUTABLE_NOT_FOUND ]]; then
40
+ BLUE='\033[0;34m'
41
+ UNDERLINE_WHITE='\033[37m'
42
+ NO_COLOR='\033[0m'
43
+
44
+ echo -e "${BLUE}Having trouble running commands with ${UNDERLINE_WHITE}bin/next${BLUE}?"
45
+ echo -e "Try running ${UNDERLINE_WHITE}bin/next bundle install${BLUE}, then try your command again.${NO_COLOR}"
46
+ fi
47
+
48
+ exit $COMMAND_EXIT
@@ -0,0 +1,161 @@
1
+ require "colorize"
2
+ require "json"
3
+
4
+ # A shitlist for deprecation warnings during test runs. It has two modes: "save" and "compare"
5
+ #
6
+ # DEPRECATION_TRACKER=save
7
+ # Record deprecation warnings, grouped by spec file. After the test run, save to a file.
8
+ #
9
+ # DEPRECATION_TRACKER=compare
10
+ # Tracks deprecation warnings, grouped by spec file. After the test run, compare against shitlist of expected
11
+ # deprecation warnings. If anything is added or removed, raise an error with a diff of the changes.
12
+ #
13
+ class DeprecationTracker
14
+ UnexpectedDeprecations = Class.new(StandardError)
15
+
16
+ module KernelWarnTracker
17
+ def self.callbacks
18
+ @callbacks ||= []
19
+ end
20
+
21
+ def warn(*messages)
22
+ KernelWarnTracker.callbacks.each do |callback|
23
+ messages.each { |message| callback.(message) }
24
+ end
25
+
26
+ super
27
+ end
28
+ end
29
+
30
+ # There are two forms of the `warn` method: one for class Kernel and one for instances of Kernel (i.e., every Object)
31
+ Object.prepend(KernelWarnTracker)
32
+
33
+ # Ruby 2.2 and lower doesn't appear to allow overriding of Kernel.warn using `singleton_class.prepend`.
34
+ if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("2.3.0")
35
+ Kernel.singleton_class.prepend(KernelWarnTracker)
36
+ else
37
+ def Kernel.warn(*args, &block)
38
+ Object.warn(*args, &block)
39
+ end
40
+ end
41
+
42
+ def self.track_rspec(rspec_config, opts = {})
43
+ shitlist_path = opts[:shitlist_path]
44
+ mode = opts[:mode]
45
+ transform_message = opts[:transform_message]
46
+ deprecation_tracker = DeprecationTracker.new(shitlist_path, transform_message)
47
+ if defined?(ActiveSupport)
48
+ ActiveSupport::Deprecation.behavior << -> (message, _callstack, _deprecation_horizon, _gem_name) { deprecation_tracker.add(message) }
49
+ end
50
+ KernelWarnTracker.callbacks << -> (message) { deprecation_tracker.add(message) }
51
+
52
+ rspec_config.around do |example|
53
+ deprecation_tracker.bucket = example.metadata.fetch(:rerun_file_path)
54
+
55
+ begin
56
+ example.run
57
+ ensure
58
+ deprecation_tracker.bucket = nil
59
+ end
60
+ end
61
+
62
+ rspec_config.after(:suite) do
63
+ if mode == "save"
64
+ deprecation_tracker.save
65
+ elsif mode == "compare"
66
+ deprecation_tracker.compare
67
+ end
68
+ end
69
+ end
70
+
71
+ attr_reader :deprecation_messages, :shitlist_path, :transform_message
72
+ attr_reader :bucket
73
+
74
+ def initialize(shitlist_path, transform_message = nil)
75
+ @shitlist_path = shitlist_path
76
+ @transform_message = transform_message || -> (message) { message }
77
+ @deprecation_messages = {}
78
+ end
79
+
80
+ def add(message)
81
+ return if bucket.nil?
82
+
83
+ @deprecation_messages[bucket] << transform_message.(message)
84
+ end
85
+
86
+ def bucket=(value)
87
+ @bucket = value
88
+ @deprecation_messages[value] ||= [] unless value.nil?
89
+ end
90
+
91
+ def compare
92
+ shitlist = read_shitlist
93
+
94
+ changed_buckets = []
95
+ normalized_deprecation_messages.each do |bucket, messages|
96
+ if shitlist[bucket] != messages
97
+ changed_buckets << bucket
98
+ end
99
+ end
100
+
101
+ if changed_buckets.length > 0
102
+ message = <<-MESSAGE.red
103
+ ⚠️ Deprecation warnings have changed!
104
+
105
+ Code called by the following spec files is now generating different deprecation warnings:
106
+
107
+ #{changed_buckets.join("\n")}
108
+
109
+ To check your failures locally, you can run:
110
+
111
+ DEPRECATION_TRACKER=compare bundle exec rspec #{changed_buckets.join(" ")}
112
+
113
+ Here is a diff between what is expected and what was generated by this process:
114
+
115
+ #{diff}
116
+
117
+ See \e[4;37mdev-docs/testing/deprecation_tracker.md\e[0;31m for more information.
118
+ MESSAGE
119
+
120
+ raise UnexpectedDeprecations, message
121
+ end
122
+ end
123
+
124
+ def diff
125
+ new_shitlist = create_temp_shitlist
126
+ `git diff --no-index #{shitlist_path} #{new_shitlist.path}`
127
+ ensure
128
+ new_shitlist.delete
129
+ end
130
+
131
+ def save
132
+ new_shitlist = create_temp_shitlist
133
+ FileUtils.cp(new_shitlist.path, shitlist_path)
134
+ ensure
135
+ new_shitlist.delete if new_shitlist
136
+ end
137
+
138
+ def create_temp_shitlist
139
+ temp_file = Tempfile.new("temp-deprecation-tracker-shitlist")
140
+ temp_file.write(JSON.pretty_generate(normalized_deprecation_messages))
141
+ temp_file.flush
142
+
143
+ temp_file
144
+ end
145
+
146
+ # Normalize deprecation messages to reduce noise from file output and test files to be tracked with separate test runs
147
+ def normalized_deprecation_messages
148
+ normalized = read_shitlist.merge(deprecation_messages).each_with_object({}) do |(bucket, messages), hash|
149
+ hash[bucket] = messages.sort
150
+ end
151
+
152
+ normalized.reject {|_key, value| value.empty? }.sort_by {|key, _value| key }.to_h
153
+ end
154
+
155
+ def read_shitlist
156
+ return {} unless File.exist?(shitlist_path)
157
+ JSON.parse(File.read(shitlist_path))
158
+ rescue JSON::ParserError => e
159
+ raise "#{shitlist_path} is not valid JSON: #{e.message}"
160
+ end
161
+ end
@@ -0,0 +1,8 @@
1
+ require "next_rails/gem_info"
2
+ require "next_rails/version"
3
+ require "next_rails/bundle_report"
4
+ require "deprecation_tracker"
5
+
6
+ module TenYearsRails
7
+ # Your code goes here...
8
+ end
@@ -0,0 +1,82 @@
1
+ require "colorize"
2
+ require "cgi"
3
+ require "erb"
4
+ require "json"
5
+
6
+ module TenYearsRails
7
+ class BundleReport
8
+ def self.compatibility(rails_version:, include_rails_gems:)
9
+ incompatible_gems = TenYearsRails::GemInfo.all.reject do |gem|
10
+ gem.compatible_with_rails?(rails_version: rails_version) || (!include_rails_gems && gem.from_rails?)
11
+ end.sort_by do |gem|
12
+ [
13
+ gem.latest_version.compatible_with_rails?(rails_version: rails_version) ? 0 : 1,
14
+ gem.name
15
+ ].join("-")
16
+ end
17
+
18
+ incompatible_gems_by_state = incompatible_gems.group_by { |gem| gem.state(rails_version) }
19
+
20
+ template = <<~ERB
21
+ <% if incompatible_gems_by_state[:latest_compatible] -%>
22
+ <%= "=> Incompatible with Rails #{rails_version} (with new versions that are compatible):".white.bold %>
23
+ <%= "These gems will need to be upgraded before upgrading to Rails #{rails_version}.".italic %>
24
+
25
+ <% incompatible_gems_by_state[:latest_compatible].each do |gem| -%>
26
+ <%= gem_header(gem) %> - upgrade to <%= gem.latest_version.version %>
27
+ <% end -%>
28
+
29
+ <% end -%>
30
+ <% if incompatible_gems_by_state[:incompatible] -%>
31
+ <%= "=> Incompatible with Rails #{rails_version} (with no new compatible versions):".white.bold %>
32
+ <%= "These gems will need to be removed or replaced before upgrading to Rails #{rails_version}.".italic %>
33
+
34
+ <% incompatible_gems_by_state[:incompatible].each do |gem| -%>
35
+ <%= gem_header(gem) %> - new version, <%= gem.latest_version.version %>, is not compatible with Rails #{rails_version}
36
+ <% end -%>
37
+
38
+ <% end -%>
39
+ <% if incompatible_gems_by_state[:no_new_version] -%>
40
+ <%= "=> Incompatible with Rails #{rails_version} (with no new versions):".white.bold %>
41
+ <%= "These gems will need to be upgraded by us or removed before upgrading to Rails #{rails_version}.".italic %>
42
+ <%= "This list is likely to contain internal gems, like Cuddlefish.".italic %>
43
+
44
+ <% incompatible_gems_by_state[:no_new_version].each do |gem| -%>
45
+ <%= gem_header(gem) %> - new version not found
46
+ <% end -%>
47
+
48
+ <% end -%>
49
+ <%= incompatible_gems.length.to_s.red %> gems incompatible with Rails <%= rails_version %>
50
+ ERB
51
+
52
+ puts ERB.new(template, nil, "-").result(binding)
53
+ end
54
+
55
+ def self.gem_header(_gem)
56
+ header = "#{_gem.name} #{_gem.version}".bold
57
+ header << " (loaded from git)".magenta if _gem.sourced_from_git?
58
+ header
59
+ end
60
+
61
+ def self.outdated
62
+ gems = TenYearsRails::GemInfo.all
63
+ out_of_date_gems = gems.reject(&:up_to_date?).sort_by(&:created_at)
64
+ percentage_out_of_date = ((out_of_date_gems.count / gems.count.to_f) * 100).round
65
+ sourced_from_git = gems.select(&:sourced_from_git?)
66
+
67
+ out_of_date_gems.each do |_gem|
68
+ header = "#{_gem.name} #{_gem.version}"
69
+
70
+ puts <<~MESSAGE
71
+ #{header.bold.white}: released #{_gem.age} (latest version, #{_gem.latest_version.version}, released #{_gem.latest_version.age})
72
+ MESSAGE
73
+ end
74
+
75
+ puts ""
76
+ puts <<~MESSAGE
77
+ #{"#{sourced_from_git.count}".yellow} gems are sourced from git
78
+ #{"#{out_of_date_gems.length}".red} of the #{gems.count} gems are out-of-date (#{percentage_out_of_date}%)
79
+ MESSAGE
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,129 @@
1
+ begin
2
+ require "action_view"
3
+ rescue LoadError
4
+ puts "ActionView not available"
5
+ end
6
+
7
+ module TenYearsRails
8
+ class GemInfo
9
+ if defined?(ActionView)
10
+ include ActionView::Helpers::DateHelper
11
+ end
12
+
13
+ class NullGemInfo < GemInfo
14
+ def initialize; end
15
+
16
+ def age
17
+ "-"
18
+ end
19
+
20
+ def created_at
21
+ Time.now
22
+ end
23
+
24
+ def up_to_date?
25
+ false
26
+ end
27
+
28
+ def version
29
+ "NOT FOUND"
30
+ end
31
+
32
+ def unsatisfied_rails_dependencies(*)
33
+ ["unknown"]
34
+ end
35
+
36
+ def state(_)
37
+ :null
38
+ end
39
+ end
40
+
41
+ def self.all
42
+ Gem::Specification.each.map do |gem_specification|
43
+ new(gem_specification)
44
+ end
45
+ end
46
+
47
+ attr_reader :gem_specification, :version, :name
48
+ def initialize(gem_specification)
49
+ @gem_specification = gem_specification
50
+ @version = gem_specification.version
51
+ @name = gem_specification.name
52
+ end
53
+
54
+ def age
55
+ if respond_to?(:time_ago_in_words)
56
+ "#{time_ago_in_words(created_at)} ago"
57
+ else
58
+ created_at.strftime("%b %e, %Y")
59
+ end
60
+ end
61
+
62
+ def sourced_from_git?
63
+ !!gem_specification.git_version
64
+ end
65
+
66
+ def created_at
67
+ @created_at ||= gem_specification.date
68
+ end
69
+
70
+ def up_to_date?
71
+ version == latest_version.version
72
+ end
73
+
74
+ def state(rails_version)
75
+ if compatible_with_rails?(rails_version: rails_version)
76
+ :compatible
77
+ elsif latest_version.compatible_with_rails?(rails_version: rails_version)
78
+ :latest_compatible
79
+ elsif latest_version.version == "NOT FOUND"
80
+ :no_new_version
81
+ else
82
+ :incompatible
83
+ end
84
+ end
85
+
86
+ def latest_version
87
+ @latest_version ||= begin
88
+ latest_gem_specification = Gem.latest_spec_for(name)
89
+ if latest_gem_specification
90
+ GemInfo.new(latest_gem_specification)
91
+ else
92
+ NullGemInfo.new
93
+ end
94
+ end
95
+ end
96
+
97
+ def compatible_with_rails?(rails_version: Gem::Version.new("5.0"))
98
+ unsatisfied_rails_dependencies(rails_version: rails_version).empty?
99
+ end
100
+
101
+ def unsatisfied_rails_dependencies(rails_version:)
102
+ rails_dependencies = gem_specification.runtime_dependencies.select {|dependency| rails_gems.include?(dependency.name) }
103
+
104
+ rails_dependencies.reject do |rails_dependency|
105
+ rails_dependency.requirement.satisfied_by?(Gem::Version.new(rails_version))
106
+ end
107
+ end
108
+
109
+ def from_rails?
110
+ rails_gems.include?(name)
111
+ end
112
+
113
+ private def rails_gems
114
+ [
115
+ "rails",
116
+ "activemodel",
117
+ "activerecord",
118
+ "actionmailer",
119
+ "actioncable",
120
+ "actionpack",
121
+ "actionview",
122
+ "activejob",
123
+ "activestorage",
124
+ "activesupport",
125
+ "railties",
126
+ ]
127
+ end
128
+ end
129
+ end
@@ -0,0 +1,3 @@
1
+ module TenYearsRails
2
+ VERSION = "1.0.0"
3
+ end
@@ -0,0 +1,32 @@
1
+
2
+ lib = File.expand_path("../lib", __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require "next_rails/version"
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "next_rails"
8
+ spec.version = TenYearsRails::VERSION
9
+ spec.authors = ["Jordan Raine", "Ernesto Tagwerker"]
10
+ spec.email = ["jnraine@gmail.com", "ernesto@ombulabs.com"]
11
+
12
+ spec.summary = %q{Companion code to Ten Years of Rails Upgrades}
13
+ spec.description = %q{A set of handy tools to upgrade your Rails application and keep it up to date}
14
+ spec.homepage = "https://github.com/fastruby/ten_years_rails"
15
+ spec.license = "MIT"
16
+
17
+ spec.required_ruby_version = ">= 2.3.0"
18
+
19
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
20
+ f.match(%r{^(test|spec|features)/})
21
+ end
22
+ spec.bindir = "exe"
23
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
24
+ spec.require_paths = ["lib"]
25
+
26
+ spec.add_dependency "colorize", ">= 0.8.1"
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
+ spec.add_development_dependency "timecop", "~> 0.9.1"
31
+ spec.add_runtime_dependency "actionview"
32
+ end
metadata ADDED
@@ -0,0 +1,157 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: next_rails
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Jordan Raine
8
+ - Ernesto Tagwerker
9
+ autorequire:
10
+ bindir: exe
11
+ cert_chain: []
12
+ date: 2019-07-24 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: colorize
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - ">="
19
+ - !ruby/object:Gem::Version
20
+ version: 0.8.1
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ version: 0.8.1
28
+ - !ruby/object:Gem::Dependency
29
+ name: bundler
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - "~>"
33
+ - !ruby/object:Gem::Version
34
+ version: '1.16'
35
+ type: :development
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - "~>"
40
+ - !ruby/object:Gem::Version
41
+ version: '1.16'
42
+ - !ruby/object:Gem::Dependency
43
+ name: rake
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - "~>"
47
+ - !ruby/object:Gem::Version
48
+ version: '10.0'
49
+ type: :development
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - "~>"
54
+ - !ruby/object:Gem::Version
55
+ version: '10.0'
56
+ - !ruby/object:Gem::Dependency
57
+ name: rspec
58
+ requirement: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - "~>"
61
+ - !ruby/object:Gem::Version
62
+ version: '3.0'
63
+ type: :development
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - "~>"
68
+ - !ruby/object:Gem::Version
69
+ version: '3.0'
70
+ - !ruby/object:Gem::Dependency
71
+ name: timecop
72
+ requirement: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - "~>"
75
+ - !ruby/object:Gem::Version
76
+ version: 0.9.1
77
+ type: :development
78
+ prerelease: false
79
+ version_requirements: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - "~>"
82
+ - !ruby/object:Gem::Version
83
+ version: 0.9.1
84
+ - !ruby/object:Gem::Dependency
85
+ name: actionview
86
+ requirement: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ version: '0'
91
+ type: :runtime
92
+ prerelease: false
93
+ version_requirements: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - ">="
96
+ - !ruby/object:Gem::Version
97
+ version: '0'
98
+ description: A set of handy tools to upgrade your Rails application and keep it up
99
+ to date
100
+ email:
101
+ - jnraine@gmail.com
102
+ - ernesto@ombulabs.com
103
+ executables:
104
+ - bundle_report
105
+ - deprecations
106
+ - gem-next-diff
107
+ - next
108
+ - next.sh
109
+ extensions: []
110
+ extra_rdoc_files: []
111
+ files:
112
+ - ".gitignore"
113
+ - ".rspec"
114
+ - ".travis.yml"
115
+ - Gemfile
116
+ - Gemfile.lock
117
+ - LICENSE.txt
118
+ - README.md
119
+ - Rakefile
120
+ - bin/console
121
+ - bin/setup
122
+ - deprecation_tracker.md
123
+ - exe/bundle_report
124
+ - exe/deprecations
125
+ - exe/gem-next-diff
126
+ - exe/next
127
+ - exe/next.sh
128
+ - lib/deprecation_tracker.rb
129
+ - lib/next_rails.rb
130
+ - lib/next_rails/bundle_report.rb
131
+ - lib/next_rails/gem_info.rb
132
+ - lib/next_rails/version.rb
133
+ - next_rails.gemspec
134
+ homepage: https://github.com/fastruby/ten_years_rails
135
+ licenses:
136
+ - MIT
137
+ metadata: {}
138
+ post_install_message:
139
+ rdoc_options: []
140
+ require_paths:
141
+ - lib
142
+ required_ruby_version: !ruby/object:Gem::Requirement
143
+ requirements:
144
+ - - ">="
145
+ - !ruby/object:Gem::Version
146
+ version: 2.3.0
147
+ required_rubygems_version: !ruby/object:Gem::Requirement
148
+ requirements:
149
+ - - ">="
150
+ - !ruby/object:Gem::Version
151
+ version: '0'
152
+ requirements: []
153
+ rubygems_version: 3.0.3
154
+ signing_key:
155
+ specification_version: 4
156
+ summary: Companion code to Ten Years of Rails Upgrades
157
+ test_files: []