Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ After a release, please make sure to run `bundle exec rake update_changelog`. Th

Changes since the last non-beta release.

#### Fixed

- Fixed invalid warnings about non-exact versions when using a pre-release version of React on Rails, as well as missing warnings when using different pre-release versions of the gem and the Node package. [PR 1742](https://github.com/shakacode/react_on_rails/pull/1742) by [alexeyr-ci2](https://github.com/alexeyr-ci2).

### [15.0.0-rc.1] - 2025-06-18

#### Improved
Expand Down
4 changes: 1 addition & 3 deletions lib/react_on_rails/packer_utils.rb
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,7 @@ def self.shakapacker_version
end

def self.shakapacker_version_as_array
match = shakapacker_version.match(ReactOnRails::VersionChecker::MAJOR_MINOR_PATCH_VERSION_REGEX)

@shakapacker_version_as_array = [match[1].to_i, match[2].to_i, match[3].to_i]
Gem::Version.new(shakapacker_version).segments
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why don’t we use the VERSION_PARTS_REGEX to extract the parts instead? Gem::Version#segments can return different results from the regex parts in certain cases.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, please check the semver_to_string function at lib/react_on_rails/packer_utils.rb and check if it needs updating.

end

def self.shakapacker_version_requirement_met?(required_version)
Expand Down
34 changes: 14 additions & 20 deletions lib/react_on_rails/version_checker.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ module ReactOnRails
class VersionChecker
attr_reader :node_package_version

MAJOR_MINOR_PATCH_VERSION_REGEX = /(\d+)\.(\d+)\.(\d+)/
# Semver uses - to separate pre-release, but RubyGems use .
VERSION_PARTS_REGEX = /(\d+)\.(\d+)\.(\d+)(?:[-.]([0-9A-Za-z.-]+))?/

def self.build
new(NodePackageVersion.build)
Expand All @@ -23,13 +24,7 @@ def log_if_gem_and_node_package_versions_differ
return if node_package_version.raw.nil? || node_package_version.local_path_or_url?
return log_node_semver_version_warning if node_package_version.semver_wildcard?

node_major_minor_patch = node_package_version.major_minor_patch
gem_major_minor_patch = gem_major_minor_patch_version
versions_match = node_major_minor_patch[0] == gem_major_minor_patch[0] &&
node_major_minor_patch[1] == gem_major_minor_patch[1] &&
node_major_minor_patch[2] == gem_major_minor_patch[2]

log_differing_versions_warning unless versions_match
log_differing_versions_warning unless node_package_version.parts == gem_version_parts
end

private
Expand All @@ -39,30 +34,29 @@ def common_error_msg
Detected: #{node_package_version.raw}
gem: #{gem_version}
Ensure the installed version of the gem is the same as the version of
your installed node package. Do not use >= or ~> in your Gemfile for react_on_rails.
Do not use ^ or ~ in your package.json for react-on-rails.
your installed Node package. Do not use >= or ~> in your Gemfile for react_on_rails.
Do not use ^, ~, or other non-exact versions in your package.json for react-on-rails.
Run `yarn add react-on-rails --exact` in the directory containing folder node_modules.
MSG
end

def log_differing_versions_warning
msg = "**WARNING** ReactOnRails: ReactOnRails gem and node package versions do not match\n#{common_error_msg}"
msg = "**WARNING** ReactOnRails: ReactOnRails gem and Node package versions do not match\n#{common_error_msg}"
Rails.logger.warn(msg)
end

def log_node_semver_version_warning
msg = "**WARNING** ReactOnRails: Your node package version for react-on-rails contains a " \
"^ or ~\n#{common_error_msg}"
msg = "**WARNING** ReactOnRails: Your Node package version for react-on-rails is not an exact version\n" \
"#{common_error_msg}"
Rails.logger.warn(msg)
end

def gem_version
ReactOnRails::VERSION
end

def gem_major_minor_patch_version
match = gem_version.match(MAJOR_MINOR_PATCH_VERSION_REGEX)
[match[1], match[2], match[3]]
def gem_version_parts
gem_version.match(VERSION_PARTS_REGEX)&.captures&.compact
end

class NodePackageVersion
Expand Down Expand Up @@ -100,7 +94,7 @@ def semver_wildcard?
# See https://docs.npmjs.com/cli/v10/configuring-npm/package-json#dependencies
# We want to disallow all expressions other than exact versions
# and the ones allowed by local_path_or_url?
raw.blank? || raw.match(/[~^><|*-]/).present?
raw.blank? || raw.start_with?(/[~^><*]/) || raw.include?(" - ") || raw.include?(" || ")
end

def local_path_or_url?
Expand All @@ -110,15 +104,15 @@ def local_path_or_url?
!raw.nil? && raw.include?("/") && !raw.start_with?("npm:")
end

def major_minor_patch
def parts
return if local_path_or_url?

match = raw.match(MAJOR_MINOR_PATCH_VERSION_REGEX)
match = raw.match(VERSION_PARTS_REGEX)
unless match
raise ReactOnRails::Error, "Cannot parse version number '#{raw}' (only exact versions are supported)"
end

[match[1], match[2], match[3]]
match.captures.compact
end

private
Expand Down
48 changes: 24 additions & 24 deletions spec/react_on_rails/version_checker_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ module ReactOnRails # rubocop:disable Metrics/ModuleLength

context "when gem and node package major and minor versions are equal" do
let(:node_package_version) do
double_package_version(raw: "2.2.5-beta.2", major_minor_patch: %w[2 2 5])
double_package_version(raw: "2.2.5-beta.2", parts: %w[2 2 5 beta.2])
end

before { stub_gem_version("2.2.5.beta.2") }
Expand All @@ -32,67 +32,67 @@ module ReactOnRails # rubocop:disable Metrics/ModuleLength

context "when major and minor versions are equal BUT node uses semver wildcard" do
let(:node_package_version) do
double_package_version(raw: "^2.2.5", semver_wildcard: true, major_minor_patch: %w[2 2 5])
double_package_version(raw: "^2.2.5", semver_wildcard: true, parts: %w[2 2 5])
end

before { stub_gem_version("2.2.5") }

it "logs" do
allow(Rails.logger).to receive(:warn)
message = /ReactOnRails: Your node package version for react-on-rails contains a \^ or ~/
message = /ReactOnRails: Your Node package version for react-on-rails is not an exact version/
check_version_and_log(node_package_version)
expect(Rails.logger).to have_received(:warn).with(message)
end
end

context "when gem and node package major versions differ" do
let(:node_package_version) do
double_package_version(raw: "13.0.0.beta-2", major_minor_patch: %w[13 0 0])
double_package_version(raw: "13.0.0.beta-2", parts: %w[13 0 0 beta-2])
end

before { stub_gem_version("12.0.0.beta.1") }

it "logs" do
allow(Rails.logger).to receive(:warn)
message = /ReactOnRails: ReactOnRails gem and node package versions do not match/
message = /ReactOnRails: ReactOnRails gem and Node package versions do not match/
check_version_and_log(node_package_version)
expect(Rails.logger).to have_received(:warn).with(message)
end
end

context "when gem and node package major versions match and minor differs" do
let(:node_package_version) do
double_package_version(raw: "13.0.0.beta-2", major_minor_patch: %w[13 0 0])
double_package_version(raw: "13.0.0.beta-2", parts: %w[13 0 0 beta-2])
end

before { stub_gem_version("13.1.0") }

it "logs" do
allow(Rails.logger).to receive(:warn)
message = /ReactOnRails: ReactOnRails gem and node package versions do not match/
message = /ReactOnRails: ReactOnRails gem and Node package versions do not match/
check_version_and_log(node_package_version)
expect(Rails.logger).to have_received(:warn).with(message)
end
end

context "when gem and node package major, minor versions match and patch differs" do
let(:node_package_version) do
double_package_version(raw: "13.0.1", major_minor_patch: %w[13 0 1])
double_package_version(raw: "13.0.1", parts: %w[13 0 1])
end

before { stub_gem_version("13.0.0") }

it "logs" do
allow(Rails.logger).to receive(:warn)
message = /ReactOnRails: ReactOnRails gem and node package versions do not match/
message = /ReactOnRails: ReactOnRails gem and Node package versions do not match/
check_version_and_log(node_package_version)
expect(Rails.logger).to have_received(:warn).with(message)
end
end

context "when package json uses a relative path with dots" do
let(:node_package_version) do
double_package_version(raw: "../../..", major_minor_patch: "", local_path_or_url: true)
double_package_version(raw: "../../..", parts: nil, local_path_or_url: true)
end

before { stub_gem_version("2.0.0.beta.1") }
Expand All @@ -116,11 +116,11 @@ module ReactOnRails # rubocop:disable Metrics/ModuleLength
end

def double_package_version(raw: nil, semver_wildcard: false,
major_minor_patch: nil, local_path_or_url: false)
parts: nil, local_path_or_url: false)
instance_double(VersionChecker::NodePackageVersion,
raw: raw,
semver_wildcard?: semver_wildcard,
major_minor_patch: major_minor_patch,
parts: parts,
local_path_or_url?: local_path_or_url)
end

Expand Down Expand Up @@ -187,8 +187,8 @@ def check_version_and_log(node_package_version)
specify { expect(node_package_version.local_path_or_url?).to be false }
end

describe "#major" do
specify { expect(node_package_version.major_minor_patch).to eq(%w[0 0 2]) }
describe "#parts" do
specify { expect(node_package_version.parts).to eq(%w[0 0 2]) }
end
end

Expand All @@ -203,8 +203,8 @@ def check_version_and_log(node_package_version)
specify { expect(node_package_version.local_path_or_url?).to be false }
end

describe "#major_minor_patch" do
specify { expect(node_package_version.major_minor_patch).to eq(%w[14 0 0]) }
describe "#parts" do
specify { expect(node_package_version.parts).to eq(%w[14 0 0 beta-2]) }
end
end

Expand All @@ -219,8 +219,8 @@ def check_version_and_log(node_package_version)
specify { expect(node_package_version.local_path_or_url?).to be true }
end

describe "#major" do
specify { expect(node_package_version.major_minor_patch).to be_nil }
describe "#parts" do
specify { expect(node_package_version.parts).to be_nil }
end
end

Expand All @@ -235,8 +235,8 @@ def check_version_and_log(node_package_version)
specify { expect(node_package_version.local_path_or_url?).to be true }
end

describe "#major" do
specify { expect(node_package_version.major_minor_patch).to be_nil }
describe "#parts" do
specify { expect(node_package_version.parts).to be_nil }
end
end

Expand All @@ -251,8 +251,8 @@ def check_version_and_log(node_package_version)
specify { expect(node_package_version.local_path_or_url?).to be true }
end

describe "#major" do
specify { expect(node_package_version.major_minor_patch).to be_nil }
describe "#parts" do
specify { expect(node_package_version.parts).to be_nil }
end
end

Expand All @@ -267,8 +267,8 @@ def check_version_and_log(node_package_version)
specify { expect(node_package_version.local_path_or_url?).to be true }
end

describe "#major" do
specify { expect(node_package_version.major_minor_patch).to be_nil }
describe "#parts" do
specify { expect(node_package_version.parts).to be_nil }
end
end

Expand Down
Loading