Skip to content

Commit 2def04b

Browse files
justin808claude
andauthored
Fix CI failure by skipping version validation during generator runtime (#1918)
* Fix CI failure by skipping version validation during generator runtime The strict version validation added in #1881 runs during Rails initialization via an after_initialize hook. However, when running `rails generate react_on_rails:install`, the npm packages haven't been installed yet, causing the validation to fail with: "No React on Rails npm package is installed." This fix adds a check to skip validation when running Rails generators (detected by checking if ARGV.first is "generate" or "g"). The generator will install packages during its execution, so validation at initialization time is not appropriate. This allows CI to successfully run example generation tasks without errors. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * Address code review feedback: improve validation skip logic Improvements based on code review: 1. **Nil-safe ARGV check**: Use safe navigation operator and check for empty ARGV - Prevents errors when ARGV is empty or nil - More defensive against edge cases 2. **Refactored to extract methods**: Created testable class methods - skip_version_validation?() - main entry point - running_generator?() - checks if running Rails generator - package_json_missing?() - checks if package.json exists - Improves testability and code clarity 3. **Added debug logging**: Log when validation is skipped - "Skipping validation - package.json not found" - "Skipping validation during generator runtime" - Helps debugging and understanding behavior 4. **Optimized check order**: Check package.json existence first - File existence check is cheaper than ARGV inspection - Handles more cases (initial setup, generators, etc.) 5. **Comprehensive test coverage**: Added 15 test cases - Tests for package.json missing scenarios - Tests for generator detection (both "generate" and "g") - Tests for edge cases (empty ARGV, other commands) - Tests for each helper method All tests passing, RuboCop clean. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * Fix NoMethodError: call Engine.skip_version_validation? as class method The initializer block context doesn't have direct access to class methods. Changed from `skip_version_validation?` to `Engine.skip_version_validation?` to properly call the class method. Fixes error: NoMethodError: undefined method `skip_version_validation?' for #<ReactOnRails::Engine> 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent 777bee2 commit 2def04b

File tree

2 files changed

+192
-4
lines changed

2 files changed

+192
-4
lines changed

lib/react_on_rails/engine.rb

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,47 @@ module ReactOnRails
66
class Engine < ::Rails::Engine
77
# Validate package versions and compatibility on Rails startup
88
# This ensures the application fails fast if versions don't match or packages are misconfigured
9-
# Skip validation during installation tasks (e.g., shakapacker:install)
9+
# Skip validation during installation tasks (e.g., shakapacker:install) or generator runtime
1010
initializer "react_on_rails.validate_version_and_package_compatibility" do
1111
config.after_initialize do
12-
# Skip validation if package.json doesn't exist yet (during initial setup)
13-
package_json = VersionChecker::NodePackageVersion.package_json_path
14-
next unless File.exist?(package_json)
12+
next if Engine.skip_version_validation?
1513

1614
Rails.logger.info "[React on Rails] Validating package version and compatibility..."
1715
VersionChecker.build.validate_version_and_package_compatibility!
1816
Rails.logger.info "[React on Rails] Package validation successful"
1917
end
2018
end
2119

20+
# Determine if version validation should be skipped
21+
# @return [Boolean] true if validation should be skipped
22+
def self.skip_version_validation?
23+
# Check package.json first as it's cheaper and handles more cases
24+
if package_json_missing?
25+
Rails.logger.debug "[React on Rails] Skipping validation - package.json not found"
26+
return true
27+
end
28+
29+
# Skip during generator runtime since packages are installed during execution
30+
if running_generator?
31+
Rails.logger.debug "[React on Rails] Skipping validation during generator runtime"
32+
return true
33+
end
34+
35+
false
36+
end
37+
38+
# Check if we're running a Rails generator
39+
# @return [Boolean] true if running a generator
40+
def self.running_generator?
41+
!ARGV.empty? && ARGV.first&.in?(%w[generate g])
42+
end
43+
44+
# Check if package.json doesn't exist yet
45+
# @return [Boolean] true if package.json is missing
46+
def self.package_json_missing?
47+
!File.exist?(VersionChecker::NodePackageVersion.package_json_path)
48+
end
49+
2250
config.to_prepare do
2351
ReactOnRails::ServerRenderingPool.reset_pool
2452
end

spec/react_on_rails/engine_spec.rb

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
# frozen_string_literal: true
2+
3+
require_relative "spec_helper"
4+
5+
module ReactOnRails
6+
RSpec.describe Engine do
7+
describe ".skip_version_validation?" do
8+
let(:package_json_path) { "/fake/path/package.json" }
9+
10+
before do
11+
allow(VersionChecker::NodePackageVersion).to receive(:package_json_path)
12+
.and_return(package_json_path)
13+
allow(Rails.logger).to receive(:debug)
14+
end
15+
16+
context "when package.json doesn't exist" do
17+
before do
18+
allow(File).to receive(:exist?).with(package_json_path).and_return(false)
19+
end
20+
21+
it "returns true" do
22+
expect(described_class.skip_version_validation?).to be true
23+
end
24+
25+
it "logs debug message about missing package.json" do
26+
described_class.skip_version_validation?
27+
expect(Rails.logger).to have_received(:debug)
28+
.with("[React on Rails] Skipping validation - package.json not found")
29+
end
30+
end
31+
32+
context "when package.json exists" do
33+
before do
34+
allow(File).to receive(:exist?).with(package_json_path).and_return(true)
35+
end
36+
37+
context "when running a generator" do
38+
before do
39+
stub_const("ARGV", ["generate", "react_on_rails:install"])
40+
end
41+
42+
it "returns true" do
43+
expect(described_class.skip_version_validation?).to be true
44+
end
45+
46+
it "logs debug message about generator runtime" do
47+
described_class.skip_version_validation?
48+
expect(Rails.logger).to have_received(:debug)
49+
.with("[React on Rails] Skipping validation during generator runtime")
50+
end
51+
end
52+
53+
context "when running a generator with short form" do
54+
before do
55+
stub_const("ARGV", ["g", "react_on_rails:install"])
56+
end
57+
58+
it "returns true" do
59+
expect(described_class.skip_version_validation?).to be true
60+
end
61+
end
62+
63+
context "when ARGV is empty" do
64+
before do
65+
stub_const("ARGV", [])
66+
end
67+
68+
it "returns false" do
69+
expect(described_class.skip_version_validation?).to be false
70+
end
71+
end
72+
73+
context "when running other commands" do
74+
%w[server console runner].each do |command|
75+
context "when running '#{command}'" do
76+
before do
77+
stub_const("ARGV", [command])
78+
end
79+
80+
it "returns false" do
81+
expect(described_class.skip_version_validation?).to be false
82+
end
83+
end
84+
end
85+
end
86+
end
87+
end
88+
89+
describe ".running_generator?" do
90+
context "when ARGV is empty" do
91+
before do
92+
stub_const("ARGV", [])
93+
end
94+
95+
it "returns false" do
96+
expect(described_class.running_generator?).to be false
97+
end
98+
end
99+
100+
context "when ARGV.first is 'generate'" do
101+
before do
102+
stub_const("ARGV", %w[generate model User])
103+
end
104+
105+
it "returns true" do
106+
expect(described_class.running_generator?).to be true
107+
end
108+
end
109+
110+
context "when ARGV.first is 'g'" do
111+
before do
112+
stub_const("ARGV", %w[g controller Users])
113+
end
114+
115+
it "returns true" do
116+
expect(described_class.running_generator?).to be true
117+
end
118+
end
119+
120+
context "when ARGV.first is another command" do
121+
before do
122+
stub_const("ARGV", ["server"])
123+
end
124+
125+
it "returns false" do
126+
expect(described_class.running_generator?).to be false
127+
end
128+
end
129+
end
130+
131+
describe ".package_json_missing?" do
132+
let(:package_json_path) { "/fake/path/package.json" }
133+
134+
before do
135+
allow(VersionChecker::NodePackageVersion).to receive(:package_json_path)
136+
.and_return(package_json_path)
137+
end
138+
139+
context "when package.json exists" do
140+
before do
141+
allow(File).to receive(:exist?).with(package_json_path).and_return(true)
142+
end
143+
144+
it "returns false" do
145+
expect(described_class.package_json_missing?).to be false
146+
end
147+
end
148+
149+
context "when package.json doesn't exist" do
150+
before do
151+
allow(File).to receive(:exist?).with(package_json_path).and_return(false)
152+
end
153+
154+
it "returns true" do
155+
expect(described_class.package_json_missing?).to be true
156+
end
157+
end
158+
end
159+
end
160+
end

0 commit comments

Comments
 (0)