diff --git a/CHANGELOG.md b/CHANGELOG.md index 23bad782..b83e664c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,9 @@ Changes since the last non-beta release. ### Changed - Changed internal `require`s to `require_relative` to make code less dependent on the load path. [PR 516](https://github.com/shakacode/shakapacker/pull/516) by [tagliala](https://github.com/tagliala). +### Fixed +- Fix error when rails environment is required from outside the rails root directory [PR 520](https://github.com/shakacode/shakapacker/pull/520) + ## [v8.0.2] - August 28, 2024 ### Fixed diff --git a/lib/shakapacker/utils/manager.rb b/lib/shakapacker/utils/manager.rb index 417d4a68..2d2e038e 100644 --- a/lib/shakapacker/utils/manager.rb +++ b/lib/shakapacker/utils/manager.rb @@ -16,7 +16,7 @@ class Error < StandardError; end # Emits a warning if it's not obvious what package manager to use def self.error_unless_package_manager_is_obvious! - return unless PackageJson.read.fetch("packageManager", nil).nil? + return unless PackageJson.read(rails_root).fetch("packageManager", nil).nil? guessed_binary = guess_binary @@ -35,7 +35,7 @@ def self.error_unless_package_manager_is_obvious! # # @return [String] def self.guess_binary - MANAGER_LOCKS.find { |_, lock| File.exist?(lock) }&.first || "npm" + MANAGER_LOCKS.find { |_, lock| File.exist?(rails_root.join(lock)) }&.first || "npm" end # Guesses the version of the package manager to use by calling ` --version` @@ -53,6 +53,17 @@ def self.guess_version stdout.chomp end + + private + def self.rails_root + if defined?(APP_ROOT) + Pathname.new(APP_ROOT) + elsif defined?(Rails) + Rails.root + else + raise "can only be called from a rails environment or with APP_ROOT defined" + end + end end end end diff --git a/spec/shakapacker/utils_manager_spec.rb b/spec/shakapacker/utils_manager_spec.rb index f8768f8e..c29d4de2 100644 --- a/spec/shakapacker/utils_manager_spec.rb +++ b/spec/shakapacker/utils_manager_spec.rb @@ -48,6 +48,7 @@ def exitstatus context "when there is a #{lock}" do before do allow(Open3).to receive(:capture3).and_return(["1.2.3\n", "", Struct::Status.new(0)]) + allow(Rails).to receive(:root).and_return(Pathname.new(".")) end it "raises an error about setting 'packageManager' for #{manager}" do @@ -63,10 +64,35 @@ def exitstatus MSG end end + + context "when lockfile is in Rails.root, but pwd is different" do + before do + allow(Open3).to receive(:capture3).and_return(["1.2.3\n", "", Struct::Status.new(0)]) + end + + it "raises an error about setting 'packageManager' for #{manager}" do + rails_root = Pathname.new("rails_root_#{lock}") + FileUtils.mkdir_p(rails_root) + allow(Rails).to receive(:root).and_return(rails_root) + + File.write(rails_root.join("package.json"), {}.to_json) + FileUtils.touch(rails_root.join(lock)) + + expect { Shakapacker::Utils::Manager.error_unless_package_manager_is_obvious! }.to raise_error(Shakapacker::Utils::Manager::Error, <<~MSG) + You don't have "packageManager" set in your package.json + meaning that Shakapacker will use npm but you've got a #{lock} + file meaning you probably want to be using #{manager} instead. + + To make this happen, set "packageManager" in your package.json to #{manager}@1.2.3 + MSG + end + end end end describe "~guess_binary" do + before { allow(Rails).to receive(:root).and_return(Pathname.new(".")) } + Shakapacker::Utils::Manager::MANAGER_LOCKS.each do |manager, lock| context "when a #{lock} exists" do before { FileUtils.touch(lock) } @@ -75,6 +101,19 @@ def exitstatus expect(Shakapacker::Utils::Manager.guess_binary).to eq manager end end + + context "when lockfile is in Rails.root, but pwd is different" do + before do + rails_root = Pathname.new("rails_root_#{lock}") + FileUtils.mkdir_p(rails_root) + FileUtils.touch(rails_root.join(lock)) + allow(Rails).to receive(:root).and_return(rails_root) + end + + it "guesses #{manager}" do + expect(Shakapacker::Utils::Manager.guess_binary).to eq manager + end + end end context "when there is no lockfile" do @@ -91,7 +130,25 @@ def exitstatus Shakapacker::Utils::Manager::MANAGER_LOCKS.each do |manager, lock| context "when a #{lock} exists" do - before { FileUtils.touch(lock) } + before do + FileUtils.touch(lock) + allow(Rails).to receive(:root).and_return(Pathname.new(".")) + end + + it "calls #{manager} with --version" do + Shakapacker::Utils::Manager.guess_version + + expect(Open3).to have_received(:capture3).with("#{manager} --version") + end + end + + context "when lockfile is in Rails.root, but pwd is different" do + before do + rails_root = Pathname.new("rails_root_#{lock}") + FileUtils.mkdir_p(rails_root) + FileUtils.touch(rails_root.join(lock)) + allow(Rails).to receive(:root).and_return(rails_root) + end it "calls #{manager} with --version" do Shakapacker::Utils::Manager.guess_version @@ -110,6 +167,7 @@ def exitstatus context "when the command errors" do before do allow(Open3).to receive(:capture3).and_return(["", "oh noes!", Struct::Status.new(1)]) + allow(Rails).to receive(:root).and_return(Pathname.new(".")) end it "raises an error" do