Skip to content

Failure to recognize custom Gemfile during initial bundler setup #4043

@cbossy

Description

@cbossy

Description

Ruby LSP Information

VS Code Version

1.105.1

Ruby LSP Extension Version

0.10.2

Ruby LSP Server Version

0.26.9

Ruby LSP Add-ons

  • Standard Ruby (unknown)
  • Ruby LSP Rails (0.4.8)

Ruby Version

3.3.10

Ruby Version Manager

rbenv

Installed Extensions

Click to expand
  • catppuccin-vsc (3.18.1)
  • catppuccin-vsc-icons (1.26.0)
  • ruby-lsp (0.10.2)
  • scala (0.5.9)
  • terraform (2.39.2)
  • theme-dracula (2.25.1)
  • vscode-kubernetes-tools (1.3.26)
  • vscode-yaml (1.21.0)

Ruby LSP Settings

Click to expand
Workspace
{
  "rubyVersionManager": {
    "identifier": "rbenv",
    "rbenvExecutablePath": "/opt/homebrew/bin/rbenv"
  }
}
User
{
  "enabledFeatures": {
    "codeActions": true,
    "diagnostics": true,
    "documentHighlights": true,
    "documentLink": true,
    "documentSymbols": true,
    "foldingRanges": true,
    "formatting": true,
    "hover": true,
    "inlayHint": true,
    "onTypeFormatting": true,
    "selectionRanges": true,
    "semanticHighlighting": true,
    "completion": true,
    "codeLens": false,
    "definition": true,
    "workspaceSymbol": true,
    "signatureHelp": true,
    "typeHierarchy": true
  },
  "featuresConfiguration": {},
  "addonSettings": {},
  "rubyVersionManager": {
    "identifier": "rbenv",
    "rbenvExecutablePath": "/opt/homebrew/bin/rbenv"
  },
  "customRubyCommand": "",
  "formatter": "auto",
  "linters": null,
  "bundleGemfile": "",
  "testTimeout": 30,
  "pullDiagnosticsOn": "both",
  "useBundlerCompose": false,
  "bypassTypechecker": false,
  "rubyExecutablePath": "",
  "indexing": {},
  "erbSupport": true,
  "featureFlags": {},
  "sigOpacityLevel": "1"
}

Background

I'm working in a legacy enterprise Ruby on Rails application with a fairly unusual Bunder setup that requires us to use a custom BUNDLE_GEMFILE, and this is causing some trouble when first bootstrapping the Ruby LSP plugin in my editor. This is my first time diving into this plugin so will certainly consider the possibility of user error here, so wanted to start with an issue to discuss!

Basically, our repository has a Gemfile/Gemfile.lock, but they are not used for Ruby/Rails development (they are relics for some old scripts). Instead of those, we have a different set of explicitly named Gemfiles like:

  • Gemfile.ruby33.rails42 / Gemfile.ruby33.rails42.lock
  • Gemfile.ruby4.rails5 / Gemfile.ruby4.rails5.lock

For local development, in the project's .bundle/config, we set a gemfile override depending on which versions we want to use, eg:

# .bundle/config
BUNDLE_GEMFILE: "Gemfile.ruby4.rails5"

When the Ruby LSP gem starts for the first time, it runs without bundler or a BUNDLE_GEMFILE env variable set. As such, this code in lib/ruby_lsp/setup_bundler.rb does not account for special configuration set in the .bundle/config and will always use Gemfile/Gemfile.lock:

# Regular bundle paths
@gemfile = begin
  Bundler.default_gemfile
rescue Bundler::GemfileNotFound
  nil
end #: Pathname?
@lockfile = @gemfile ? Bundler.default_lockfile : nil #: Pathname?

So, for our codebase, things fall apart and the incorrect configuration is used during initial setup.

Potential solution

I was able to address this issue for myself with this patch, but I didn't want to immediately jump to a PR since I'm not sure I've thought through this well enough yet:

diff --git a/lib/ruby_lsp/setup_bundler.rb b/lib/ruby_lsp/setup_bundler.rb
--- a/lib/ruby_lsp/setup_bundler.rb
+++ b/lib/ruby_lsp/setup_bundler.rb
@@
     def initialize(project_path, **options)
       @project_path = project_path
       @launcher = options[:launcher] #: bool?
       @beta = options[:beta] #: bool?
       force_output_to_stderr! if @launcher

-      # Regular bundle paths
-      @gemfile = begin
-        Bundler.default_gemfile
-      rescue Bundler::GemfileNotFound
-        nil
-      end #: Pathname?
-      @lockfile = @gemfile ? Bundler.default_lockfile : nil #: Pathname?
+      gemfile, lockfile = project_gemfile_names
+      @gemfile = gemfile #: Pathname?
+      @lockfile = lockfile #: Pathname?

       @gemfile_hash = @gemfile ? Digest::SHA256.hexdigest(@gemfile.read) : nil #: String?
       @lockfile_hash = @lockfile&.exist? ? Digest::SHA256.hexdigest(@lockfile.read) : nil #: String?

@@
     private

+    #: -> [String, String]
+    def project_gemfile_names
+      configured_gemfile = bundler_settings_as_env["BUNDLE_GEMFILE"]
+      original_bundle_gemfile = ENV["BUNDLE_GEMFILE"]
+
+      if configured_gemfile && !configured_gemfile.empty?
+        ENV["BUNDLE_GEMFILE"] = File.expand_path(configured_gemfile, @project_path)
+      end
+
+      begin
+        [Bundler.default_gemfile, Bundler.default_lockfile]
+      rescue Bundler::GemfileNotFound
+        [nil, nil]
+      end
+    ensure
+      ENV["BUNDLE_GEMFILE"] = original_bundle_gemfile
+    end
+
     #: -> Hash[String, untyped]
     def composed_bundle_dependencies
       @composed_bundle_dependencies ||= begin
         original_bundle_gemfile = ENV["BUNDLE_GEMFILE"]

Reproduction steps

  1. Start the Ruby LSP in Cursor
  2. Bundler setup falls back to Gemfile and Gemfile.lock in spite of BUNDLE_GEMFILE override specifying a different Gemfile
  3. bundle install etc attempt to run based on the incorrect Gemfile and it fails

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions