next_rails 1.6.0 → 1.7.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7ef709432bba364ea112d6d8774d0c51b8bf1959b48ede86437b7ae801c7ea3b
4
- data.tar.gz: f568512b09f8d16199ec4fb1800964f6a8067a3fb3d36eeaf48a335e117d56c5
3
+ metadata.gz: 683bb3cbd05a568e913cdbecabc84aa9046f534ebfee134eae53b5ae98d3690f
4
+ data.tar.gz: 83e65946157ab5de2ee05b9d73f735e6d638df7c14bda1ddaff6bd489dec1bd6
5
5
  SHA512:
6
- metadata.gz: a2b296e5306c8ab34b7f5b38801785ecfb3a6039a6a48310533ffc02033634a9d67ca2c03f6531c0dc05725a44cffe06d9dc65071f947bc6ec5c6bdd2892a6f9
7
- data.tar.gz: cba5e3a34b3127fdcb2bfa28775250b5d7b2f8e0bdb5fb453976c6304f34ca1e272c4b6abee61eb12fe01c0e0cb4c22ea838d7d94164c40f57d7e039ecd7db51
6
+ metadata.gz: 38021c508b777bbef26be6b897b43f60150ad1658b06d07795b370173c4e1b0f75307e78d95cc147737313d9f263966e0cf7b94370dbd998ba50ed94b31fcd72
7
+ data.tar.gz: 751730c5320f1fa4dcbdba5b26cd1d2deac911fa5de9abd42ced0224ebc9f811827b3dd4de9f2c63181187c32a6beb3a6956ca0b176f655b1a2ad6a382d125ec
data/CHANGELOG.md CHANGED
@@ -1,9 +1,18 @@
1
- # main [(unreleased)](https://github.com/fastruby/next_rails/compare/v1.6.0...main)
1
+ # main [(unreleased)](https://github.com/fastruby/next_rails/compare/v1.7.0...main)
2
2
 
3
3
  - [BUGFIX: example](https://github.com/fastruby/next_rails/pull/<number>)
4
4
 
5
5
  * Your changes/patches go here.
6
6
 
7
+ # v1.7.0 / 2026-08-05 [(commits)](https://github.com/fastruby/next_rails/compare/v1.6.0...v1.7.0)
8
+
9
+ - [FEATURE: Add support for SimpleCov 1.0](https://github.com/fastruby/next_rails/pull/196)
10
+ - [FEATURE: Validate the DeprecationTracker mode at initialization, treating a blank mode as the default `save`](https://github.com/fastruby/next_rails/pull/186)
11
+ - [BUGFIX: `bundle_report outdated` no longer confuses a locally-sourced (`path:`) gem with a same-named public gem on rubygems; local gems are excluded from the out-of-date check and counted separately](https://github.com/fastruby/next_rails/pull/189)
12
+ - [BUGFIX: The `deprecations` executable no longer requires the undeclared `rainbow` gem, which made it fail to load on a clean install](https://github.com/fastruby/next_rails/pull/197)
13
+ - [BUGFIX: `deprecations run` no longer raises `NoMethodError` before doing any work](https://github.com/fastruby/next_rails/pull/198)
14
+ - [DOC: Explain `BUNDLE_GEMFILE` usage for the next Gemfile](https://github.com/fastruby/next_rails/pull/187)
15
+
7
16
  # v1.6.0 / 2026-05-07 [(commits)](https://github.com/fastruby/next_rails/compare/v1.5.0...v1.6.0)
8
17
 
9
18
  - [CHORE: Drop `rainbow` gem dependency in favor of a native `NextRails::Tint` ANSI wrapper](https://github.com/fastruby/next_rails/pull/183)
data/README.md CHANGED
@@ -51,9 +51,49 @@ vim Gemfile
51
51
  next bundle install
52
52
 
53
53
  # Start your server using the next Gemfile
54
- next rails s
54
+ next rails server
55
55
  ```
56
56
 
57
+ ### How `next` works (and using `BUNDLE_GEMFILE` directly)
58
+
59
+ The `next` command is a thin wrapper. It runs your command with `BUNDLE_GEMFILE`
60
+ set so Bundler reads the next dependency set instead of the default one. So these
61
+ two are equivalent:
62
+
63
+ ```bash
64
+ next rails server
65
+
66
+ BUNDLE_GEMFILE=Gemfile.next rails server
67
+ ```
68
+
69
+ Set `BUNDLE_GEMFILE=Gemfile.next` directly when you can't use the `next` wrapper,
70
+ for example in CI jobs, IDE run configurations, Docker, or other tooling that
71
+ calls Bundler on its own:
72
+
73
+ ```bash
74
+ # Run the test suite against the next Gemfile in CI
75
+ BUNDLE_GEMFILE=Gemfile.next bundle exec rspec
76
+
77
+ # Export it for a whole shell session
78
+ export BUNDLE_GEMFILE=Gemfile.next
79
+ bundle install
80
+ rails server
81
+ ```
82
+
83
+ When updating `Gemfile.next.lock`, prefer a conservative update so you only bump
84
+ what you intend to and keep the diff small:
85
+
86
+ ```bash
87
+ # Update a single gem against the next Gemfile, leaving everything else pinned
88
+ BUNDLE_GEMFILE=Gemfile.next bundle update rails --conservative
89
+ ```
90
+
91
+ > [!IMPORTANT]
92
+ > Whenever you update `Gemfile.lock`, update `Gemfile.next.lock` at the same time
93
+ > (run the equivalent command with `BUNDLE_GEMFILE=Gemfile.next`). Keeping the two
94
+ > lockfiles in sync avoids surprising differences between the current and next
95
+ > dependency sets.
96
+
57
97
  ### Conditional code
58
98
 
59
99
  When your Gemfile targets two versions, you may need to branch application code as well:
data/exe/deprecations CHANGED
@@ -1,12 +1,16 @@
1
1
  #!/usr/bin/env ruby
2
2
  require "json"
3
- require "rainbow"
4
3
  require "optparse"
5
4
  require "set"
5
+ require_relative "../lib/next_rails/tint"
6
+ require_relative "../lib/deprecation_tracker/valid_modes"
6
7
  require_relative "../lib/deprecation_tracker/shard_merger"
7
8
 
8
9
  def run_tests(deprecation_warnings, opts = {})
9
- tracker_mode = opts[:tracker_mode]
10
+ tracker_mode = DeprecationTracker.sanitize_mode(opts[:tracker_mode])
11
+ if tracker_mode && !DeprecationTracker.valid_mode?(tracker_mode)
12
+ abort "Invalid --tracker-mode #{tracker_mode.inspect}. Must be one of: #{DeprecationTracker.valid_modes_display}."
13
+ end
10
14
  next_mode = opts[:next_mode]
11
15
  rspec_command = if next_mode
12
16
  "bin/next rspec"
@@ -29,11 +33,11 @@ def print_info(deprecation_warnings, opts = {})
29
33
  end
30
34
  end.sort_by {|message, data| data[:occurrences] }.reverse.to_h
31
35
 
32
- puts Rainbow("Ten most common deprecation warnings:").underline
36
+ puts NextRails::Tint("Ten most common deprecation warnings:").underline
33
37
  frequency_by_message.take(10).each do |message, data|
34
- puts Rainbow("Occurrences: #{data.fetch(:occurrences)}").bold
38
+ puts NextRails::Tint("Occurrences: #{data.fetch(:occurrences)}").bold
35
39
  puts "Test files: #{data.fetch(:test_files).to_a.join(" ")}" if verbose
36
- puts Rainbow(message).red
40
+ puts NextRails::Tint(message).red
37
41
  puts "----------"
38
42
  end
39
43
  end
@@ -69,7 +73,7 @@ option_parser = OptionParser.new do |opts|
69
73
  options[:next] = next_mode
70
74
  end
71
75
 
72
- opts.on("--tracker-mode MODE", "Set DEPRECATION_TRACKER in test mode. Options: save or compare") do |tracker_mode|
76
+ opts.on("--tracker-mode MODE", "Set DEPRECATION_TRACKER in test mode. Options: #{DeprecationTracker.valid_modes_display}") do |tracker_mode|
73
77
  options[:tracker_mode] = tracker_mode
74
78
  end
75
79
 
@@ -123,10 +127,10 @@ when "run", "info"
123
127
  print_info(deprecation_warnings, verbose: options[:verbose])
124
128
  end
125
129
  when nil
126
- STDERR.puts Rainbow("Must pass a mode: run, info, or merge").red
130
+ STDERR.puts NextRails::Tint("Must pass a mode: run, info, or merge").red
127
131
  puts option_parser
128
132
  exit 1
129
133
  else
130
- STDERR.puts Rainbow("Unknown mode: #{options[:mode]}").red
134
+ STDERR.puts NextRails::Tint("Unknown mode: #{options[:mode]}").red
131
135
  exit 1
132
136
  end
@@ -0,0 +1,22 @@
1
+ class DeprecationTracker
2
+ VALID_MODES = %i[save compare].freeze
3
+
4
+ # Human-readable list of valid modes for error messages and CLI help text.
5
+ def self.valid_modes_display
6
+ @valid_modes_display ||= VALID_MODES.map(&:to_s).join(", ")
7
+ end
8
+
9
+ def self.valid_mode?(mode)
10
+ mode && VALID_MODES.include?(mode.to_sym)
11
+ end
12
+
13
+ # Returns the mode as-is, or nil when it is blank. A blank DEPRECATION_TRACKER
14
+ # (e.g. `DEPRECATION_TRACKER= rspec`) is truthy in Ruby, so callers can use this
15
+ # to treat an empty value as unset and fall back to the default mode.
16
+ def self.sanitize_mode(mode)
17
+ return if mode.nil?
18
+
19
+ stripped = mode.to_s.strip
20
+ stripped.empty? ? nil : stripped
21
+ end
22
+ end
@@ -1,4 +1,4 @@
1
- require "next_rails/tint"
1
+ require_relative "next_rails/tint"
2
2
  require "json"
3
3
 
4
4
  # A shitlist for deprecation warnings during test runs. It has two modes: "save" and "compare"
@@ -10,6 +10,8 @@ require "json"
10
10
  # Tracks deprecation warnings, grouped by spec file. After the test run, compare against shitlist of expected
11
11
  # deprecation warnings. If anything is added or removed, raise an error with a diff of the changes.
12
12
  #
13
+ require_relative "deprecation_tracker/valid_modes"
14
+
13
15
  class DeprecationTracker
14
16
  UnexpectedDeprecations = Class.new(StandardError)
15
17
 
@@ -77,7 +79,7 @@ class DeprecationTracker
77
79
 
78
80
  def self.init_tracker(opts = {})
79
81
  shitlist_path = opts[:shitlist_path] || DEFAULT_PATH
80
- mode = opts[:mode] || ENV["DEPRECATION_TRACKER"] || :save
82
+ mode = sanitize_mode(opts[:mode] || ENV["DEPRECATION_TRACKER"]) || :save
81
83
  transform_message = opts[:transform_message]
82
84
  node_index = opts[:node_index]
83
85
  deprecation_tracker = DeprecationTracker.new(shitlist_path, transform_message, mode, node_index: node_index)
@@ -141,6 +143,9 @@ class DeprecationTracker
141
143
  @transform_message = transform_message || -> (message) { message }
142
144
  @deprecation_messages = {}
143
145
  @mode = mode ? mode.to_sym : :save
146
+ unless self.class.valid_mode?(@mode)
147
+ raise ArgumentError, "mode must be one of: #{self.class.valid_modes_display}. Got: #{mode.inspect}"
148
+ end
144
149
  if @mode == :compare && node_index
145
150
  raise ArgumentError, "node_index cannot be used with compare mode"
146
151
  end
@@ -63,22 +63,27 @@ module NextRails
63
63
 
64
64
  def outdated(format = nil)
65
65
  gems = NextRails::GemInfo.all
66
- out_of_date_gems = gems.reject(&:up_to_date?).sort_by(&:created_at)
66
+ sourced_locally = gems.select(&:sourced_locally?)
67
67
  sourced_from_git = gems.select(&:sourced_from_git?)
68
68
 
69
+ # Locally-sourced gems (e.g. `path:` engines) are excluded from the
70
+ # out-of-date check: looking them up by name on rubygems can match an
71
+ # unrelated public gem with the same name and report a bogus upgrade.
72
+ out_of_date_gems = (gems - sourced_locally).reject(&:up_to_date?).sort_by(&:created_at)
73
+
69
74
  if format == 'json'
70
- output_to_json(out_of_date_gems, gems.count, sourced_from_git.count)
75
+ output_to_json(out_of_date_gems, gems.count, sourced_from_git.count, sourced_locally.count)
71
76
  else
72
- output_to_stdout(out_of_date_gems, gems.count, sourced_from_git.count)
77
+ output_to_stdout(out_of_date_gems, gems.count, sourced_from_git.count, sourced_locally.count)
73
78
  end
74
79
  end
75
80
 
76
- def output_to_json(out_of_date_gems, total_gem_count, sourced_from_git_count)
77
- obj = build_json(out_of_date_gems, total_gem_count, sourced_from_git_count)
81
+ def output_to_json(out_of_date_gems, total_gem_count, sourced_from_git_count, sourced_locally_count)
82
+ obj = build_json(out_of_date_gems, total_gem_count, sourced_from_git_count, sourced_locally_count)
78
83
  puts JSON.pretty_generate(obj)
79
84
  end
80
85
 
81
- def build_json(out_of_date_gems, total_gem_count, sourced_from_git_count)
86
+ def build_json(out_of_date_gems, total_gem_count, sourced_from_git_count, sourced_locally_count)
82
87
  output = Hash.new { [] }
83
88
  out_of_date_gems.each do |gem|
84
89
  output[:outdated_gems] += [
@@ -95,12 +100,13 @@ module NextRails
95
100
  output.merge(
96
101
  {
97
102
  sourced_from_git_count: sourced_from_git_count,
103
+ sourced_locally_count: sourced_locally_count,
98
104
  total_gem_count: total_gem_count
99
105
  }
100
106
  )
101
107
  end
102
108
 
103
- def output_to_stdout(out_of_date_gems, total_gem_count, sourced_from_git_count)
109
+ def output_to_stdout(out_of_date_gems, total_gem_count, sourced_from_git_count, sourced_locally_count)
104
110
  out_of_date_gems.each do |gem|
105
111
  header = "#{gem.name} #{gem.version}"
106
112
 
@@ -112,6 +118,7 @@ module NextRails
112
118
  percentage_out_of_date = ((out_of_date_gems.count / total_gem_count.to_f) * 100).round
113
119
  footer = <<-MESSAGE
114
120
  #{NextRails::Tint(sourced_from_git_count.to_s).yellow} gems are sourced from git
121
+ #{NextRails::Tint(sourced_locally_count.to_s).yellow} gems are sourced from a local path
115
122
  #{NextRails::Tint(out_of_date_gems.count.to_s).red} of the #{total_gem_count} gems are out-of-date (#{percentage_out_of_date}%)
116
123
  MESSAGE
117
124
 
@@ -66,6 +66,17 @@ module NextRails
66
66
  !!gem_specification.git_version
67
67
  end
68
68
 
69
+ def sourced_locally?
70
+ # Bundler defines Source::Path and patches Gem::Specification#source to return the
71
+ # gem's real source. Without Bundler loaded, #source is RubyGems' own and returns a
72
+ # Gem::Source::Installed, so no path source can exist; treat the gem as not local.
73
+ return false unless defined?(Bundler::Source::Path)
74
+
75
+ source = gem_specification.source
76
+ # Git sources subclass Path, so exclude them; they are reported via #sourced_from_git?.
77
+ source.is_a?(Bundler::Source::Path) && !source.is_a?(Bundler::Source::Git)
78
+ end
79
+
69
80
  def created_at
70
81
  @created_at ||= gem_specification.date
71
82
  end
@@ -13,6 +13,7 @@ module NextRails
13
13
  CODES = {
14
14
  bold: 1,
15
15
  italic: 3,
16
+ underline: 4,
16
17
  red: 31,
17
18
  green: 32,
18
19
  yellow: 33,
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module NextRails
4
- VERSION = "1.6.0"
4
+ VERSION = "1.7.0"
5
5
  end
data/next_rails.gemspec CHANGED
@@ -25,7 +25,7 @@ Gem::Specification.new do |spec|
25
25
  spec.add_development_dependency "bundler", ">= 1.16"
26
26
  spec.add_development_dependency "rake"
27
27
  spec.add_development_dependency "rspec", "~> 3.0"
28
- spec.add_development_dependency "simplecov", "~> 0.17.1"
28
+ spec.add_development_dependency "simplecov", ">= 0.17.1"
29
29
  spec.add_development_dependency "timecop", "~> 0.9.1"
30
30
  spec.add_development_dependency "byebug"
31
31
  spec.add_development_dependency "rexml", "3.2.5" # limited on purpose, new versions don't work with old rubies
metadata CHANGED
@@ -1,15 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: next_rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.6.0
4
+ version: 1.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ernesto Tagwerker
8
8
  - Luis Sagastume
9
- autorequire:
10
9
  bindir: exe
11
10
  cert_chain: []
12
- date: 2026-05-07 00:00:00.000000000 Z
11
+ date: 2026-08-06 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: bundler
@@ -57,14 +56,14 @@ dependencies:
57
56
  name: simplecov
58
57
  requirement: !ruby/object:Gem::Requirement
59
58
  requirements:
60
- - - "~>"
59
+ - - ">="
61
60
  - !ruby/object:Gem::Version
62
61
  version: 0.17.1
63
62
  type: :development
64
63
  prerelease: false
65
64
  version_requirements: !ruby/object:Gem::Requirement
66
65
  requirements:
67
- - - "~>"
66
+ - - ">="
68
67
  - !ruby/object:Gem::Version
69
68
  version: 0.17.1
70
69
  - !ruby/object:Gem::Dependency
@@ -176,6 +175,7 @@ files:
176
175
  - exe/next_rails
177
176
  - lib/deprecation_tracker.rb
178
177
  - lib/deprecation_tracker/shard_merger.rb
178
+ - lib/deprecation_tracker/valid_modes.rb
179
179
  - lib/next_rails.rb
180
180
  - lib/next_rails/bundle_report.rb
181
181
  - lib/next_rails/bundle_report/cli.rb
@@ -191,7 +191,6 @@ homepage: https://github.com/fastruby/next_rails
191
191
  licenses:
192
192
  - MIT
193
193
  metadata: {}
194
- post_install_message:
195
194
  rdoc_options: []
196
195
  require_paths:
197
196
  - lib
@@ -206,8 +205,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
206
205
  - !ruby/object:Gem::Version
207
206
  version: '0'
208
207
  requirements: []
209
- rubygems_version: 3.4.19
210
- signing_key:
208
+ rubygems_version: 3.6.2
211
209
  specification_version: 4
212
210
  summary: A toolkit to upgrade your next Rails application
213
211
  test_files: []