Skip to content

Commit 97cb29c

Browse files
authored
Run bundle update only on the composed bundle (#3819)
1 parent f226e90 commit 97cb29c

File tree

3 files changed

+95
-2
lines changed

3 files changed

+95
-2
lines changed

lib/ruby_lsp/setup_bundler.rb

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -270,12 +270,21 @@ def run_bundle_install(bundle_gemfile = @gemfile)
270270
#: (Hash[String, String] env, ?force_install: bool) -> Hash[String, String]
271271
def run_bundle_install_directly(env, force_install: false)
272272
RubyVM::YJIT.enable if defined?(RubyVM::YJIT.enable)
273+
274+
# The should_bundle_update? check needs to run on the original Bundler environment, but everything else (like
275+
# updating or running install) requires the modified environment. Here we compute the check ahead of time and
276+
# merge the environment to ensure correct results.
277+
#
278+
# The symptoms of having these operations in the wrong order is seeing unwanted modifications in the application's
279+
# main lockfile because we accidentally run update on the main bundle instead of the composed one.
280+
needs_update = should_bundle_update?
281+
ENV.merge!(env)
282+
273283
return update(env) if @needs_update_path.exist?
274284

275285
# The ENV can only be merged after checking if an update is required because we depend on the original value of
276286
# ENV["BUNDLE_GEMFILE"], which gets overridden after the merge
277-
FileUtils.touch(@needs_update_path) if should_bundle_update?
278-
ENV.merge!(env)
287+
FileUtils.touch(@needs_update_path) if needs_update
279288

280289
$stderr.puts("Ruby LSP> Checking if the composed bundle is satisfied...")
281290
missing_gems = bundle_check

project-words

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,9 @@ testresult
109109
testrunner
110110
testrunnermediator
111111
truffleruby
112+
tsort
112113
unaliased
114+
ucrt
113115
unindexed
114116
unparser
115117
unresolve

test/integration_test.rb

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,88 @@ def test_launch_mode_with_bundle_package
289289
end
290290
end
291291

292+
def test_launch_mode_update_does_not_modify_main_lockfile
293+
in_temp_dir do |dir|
294+
File.write(File.join(dir, "Gemfile"), <<~RUBY)
295+
source "https://rubygems.org"
296+
gem "ruby-lsp-rails"
297+
gem "debug"
298+
RUBY
299+
300+
platforms = [
301+
"arm64-darwin-23",
302+
"ruby",
303+
]
304+
platforms << "x64-mingw-ucrt" if Gem.win_platform?
305+
306+
lockfile_contents = <<~LOCKFILE
307+
GEM
308+
remote: https://rubygems.org/
309+
specs:
310+
date (3.5.0)
311+
debug (1.11.0)
312+
irb (~> 1.10)
313+
reline (>= 0.3.8)
314+
erb (5.1.3)
315+
io-console (0.8.1)
316+
irb (1.15.3)
317+
pp (>= 0.6.0)
318+
rdoc (>= 4.0.0)
319+
reline (>= 0.4.2)
320+
language_server-protocol (3.17.0.5)
321+
logger (1.7.0)
322+
pp (0.6.3)
323+
prettyprint
324+
prettyprint (0.2.0)
325+
prism (1.6.0)
326+
psych (5.2.6)
327+
date
328+
stringio
329+
rbs (3.9.5)
330+
logger
331+
rdoc (6.15.1)
332+
erb
333+
psych (>= 4.0.0)
334+
tsort
335+
reline (0.6.3)
336+
io-console (~> 0.5)
337+
ruby-lsp (0.26.1)
338+
language_server-protocol (~> 3.17.0)
339+
prism (>= 1.2, < 2.0)
340+
rbs (>= 3, < 5)
341+
ruby-lsp-rails (0.4.8)
342+
ruby-lsp (>= 0.26.0, < 0.27.0)
343+
stringio (3.1.8)
344+
tsort (0.2.0)
345+
346+
PLATFORMS
347+
#{platforms.join("\n ")}
348+
349+
DEPENDENCIES
350+
debug
351+
ruby-lsp-rails
352+
353+
BUNDLED WITH
354+
2.7.1
355+
LOCKFILE
356+
File.write(File.join(dir, "Gemfile.lock"), lockfile_contents)
357+
358+
Bundler.with_unbundled_env do
359+
capture_subprocess_io do
360+
system("bundle", "install")
361+
end
362+
363+
# First launch creates the composed bundle
364+
launch(dir)
365+
366+
# Second launch updates
367+
FileUtils.touch(File.join(dir, ".ruby-lsp", "needs_update"))
368+
launch(dir)
369+
assert_equal(lockfile_contents, File.read(File.join(dir, "Gemfile.lock")))
370+
end
371+
end
372+
end
373+
292374
def test_launch_mode_retries_if_setup_failed_after_successful_install
293375
# RubyGems asks for confirmation when uninstalling a gem, so we need to be able to write the `y` to stdin
294376
uninstall_rails = ->() {

0 commit comments

Comments
 (0)