Skip to content

Commit d1e9779

Browse files
justin808claude
andcommitted
Fix minimum version CI failures for React 18 compatibility
Two fixes: 1. Skip uncommitted changes check in CI environments - CI often makes temporary modifications (e.g., script/convert for minimum version testing) before running generators - Add CI=true check alongside existing COVERAGE=true check in git_utils.rb - Add test coverage for CI environment skip behavior 2. Use react-helmet-async for React 18 minimum version testing - @dr.pogodin/react-helmet only supports React 19+ - react-helmet-async supports React 16-18 and has the same HelmetProvider API - script/convert now swaps the package and updates imports for minimum testing 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
1 parent e5051df commit d1e9779

File tree

3 files changed

+60
-1
lines changed

3 files changed

+60
-1
lines changed

react_on_rails/lib/react_on_rails/git_utils.rb

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@
55
module ReactOnRails
66
module GitUtils
77
def self.uncommitted_changes?(message_handler, git_installed: true)
8-
return false if ENV["COVERAGE"] == "true"
8+
# Skip check in CI environments - CI often makes temporary modifications
9+
# (e.g., script/convert for minimum version testing) before running generators
10+
return false if ENV["CI"] == "true" || ENV["COVERAGE"] == "true"
911

1012
status = `git status --porcelain`
1113
return false if git_installed && status&.empty?

react_on_rails/spec/react_on_rails/git_utils_spec.rb

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,14 @@ module ReactOnRails
88
context "with uncommitted git changes" do
99
let(:message_handler) { instance_double("MessageHandler") } # rubocop:disable RSpec/VerifiedDoubleReference
1010

11+
around do |example|
12+
# Temporarily unset CI env var to test actual uncommitted changes behavior
13+
original_ci = ENV.fetch("CI", nil)
14+
ENV.delete("CI")
15+
example.run
16+
ENV["CI"] = original_ci if original_ci
17+
end
18+
1119
it "returns true" do
1220
allow(described_class).to receive(:`).with("git status --porcelain").and_return("M file/path")
1321
expect(message_handler).to receive(:add_error)
@@ -22,9 +30,37 @@ module ReactOnRails
2230
end
2331
end
2432

33+
context "when CI environment variable is set" do
34+
let(:message_handler) { instance_double("MessageHandler") } # rubocop:disable RSpec/VerifiedDoubleReference
35+
36+
around do |example|
37+
original_ci = ENV.fetch("CI", nil)
38+
ENV["CI"] = "true"
39+
example.run
40+
ENV["CI"] = original_ci
41+
ENV.delete("CI") unless original_ci
42+
end
43+
44+
it "returns false without checking git status" do
45+
# Should not call git status at all
46+
expect(described_class).not_to receive(:`)
47+
expect(message_handler).not_to receive(:add_error)
48+
49+
expect(described_class.uncommitted_changes?(message_handler, git_installed: true)).to be(false)
50+
end
51+
end
52+
2553
context "with clean git status" do
2654
let(:message_handler) { instance_double("MessageHandler") } # rubocop:disable RSpec/VerifiedDoubleReference
2755

56+
around do |example|
57+
# Temporarily unset CI env var to test actual clean git behavior
58+
original_ci = ENV.fetch("CI", nil)
59+
ENV.delete("CI")
60+
example.run
61+
ENV["CI"] = original_ci if original_ci
62+
end
63+
2864
it "returns false" do
2965
allow(described_class).to receive(:`).with("git status --porcelain").and_return("")
3066
expect(message_handler).not_to receive(:add_error)
@@ -36,6 +72,14 @@ module ReactOnRails
3672
context "with git not installed" do
3773
let(:message_handler) { instance_double("MessageHandler") } # rubocop:disable RSpec/VerifiedDoubleReference
3874

75+
around do |example|
76+
# Temporarily unset CI env var to test actual git not installed behavior
77+
original_ci = ENV.fetch("CI", nil)
78+
ENV.delete("CI")
79+
example.run
80+
ENV["CI"] = original_ci if original_ci
81+
end
82+
3983
it "returns true" do
4084
allow(described_class).to receive(:`).with("git status --porcelain").and_return(nil)
4185
expect(message_handler).to receive(:add_error)

script/convert

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,19 @@ gsub_file_content("../package.json", /"react": "[^"]*",/, '"react": "18.0.0",')
4747
gsub_file_content("../package.json", /"react-dom": "[^"]*",/, '"react-dom": "18.0.0",')
4848
gsub_file_content("../react_on_rails/spec/dummy/package.json", /"react": "[^"]*",/, '"react": "18.0.0",')
4949
gsub_file_content("../react_on_rails/spec/dummy/package.json", /"react-dom": "[^"]*",/, '"react-dom": "18.0.0",')
50+
51+
# Switch from @dr.pogodin/react-helmet (React 19+) to react-helmet-async (React 18 compatible)
52+
# Both have the same HelmetProvider API, but different package names
53+
gsub_file_content("../react_on_rails/spec/dummy/package.json", /"@dr\.pogodin\/react-helmet": "[^"]*",/, '"react-helmet-async": "^1.3.0",')
54+
# Update import statements in all client files
55+
Dir.glob(File.expand_path("../react_on_rails/spec/dummy/client/**/*.{js,jsx,ts,tsx}", __dir__)).each do |file|
56+
content = File.binread(file)
57+
if content.include?("@dr.pogodin/react-helmet")
58+
content.gsub!(%r{from ['"]@dr\.pogodin/react-helmet['"]}, 'from "react-helmet-async"')
59+
content.gsub!(%r{['"]@dr\.pogodin/react-helmet['"]}, '"react-helmet-async"')
60+
File.binwrite(file, content)
61+
end
62+
end
5063
gsub_file_content(
5164
"../packages/react-on-rails-pro/package.json",
5265
/"test:non-rsc": "(?:\\"|[^"])*",/,

0 commit comments

Comments
 (0)