Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Tapioca Addon] Support gem RBI generation #2081

Open
wants to merge 13 commits into
base: main
Choose a base branch
from

Conversation

alexcrocha
Copy link
Contributor

@alexcrocha alexcrocha commented Nov 20, 2024

Motivation

To support gem RBI generation, we needed a way to detect changes in Gemfile.lock. Currently, changes to this file cause the Ruby LSP to restart, resulting in loss of access to any previous state information. This limitation prevents monitoring and processing of gem changes.

Implementation

We've implemented a solution that uses git diff to track Gemfile.lock changes:

  1. Change Detection

    • Added git_repo? check to ensure we're in a git repository
    • Use git diff HEAD Gemfile.lock to detect uncommitted changes
    • Parse the diff output to identify gem removals, additions or modifications
  2. Gem Change Analysis

    • Created LockfileDiffParser class to analyze diff output
    • Identifies:
      • Removed gems (completely deleted)
      • Added or modified gems (new or version changes)
  3. Gem RBI Processing

    • Remove RBI files for deleted gems
    • Triggers gem rbis generation command for added or modified gems

Key Components

  • Addon: Monitors Gemfile.lock changes and handles RBI file operations when changes are detected
  • LockfileDiffParser: Analyzes git diff output to identify added, modified, and removed gems

This approach specifically targets manual bundle updates while avoiding unnecessary RBI regeneration during normal git operations like branch switches.

Tests

@alexcrocha alexcrocha added the enhancement New feature or request label Nov 20, 2024
lib/ruby_lsp/tapioca/addon.rb Outdated Show resolved Hide resolved
lib/ruby_lsp/tapioca/server_addon.rb Outdated Show resolved Hide resolved
lib/ruby_lsp/tapioca/addon.rb Outdated Show resolved Hide resolved
current_lockfile = File.read("Gemfile.lock")
snapshot_lockfile = File.read(GEMFILE_LOCK_SNAPSHOT) if File.exist?(GEMFILE_LOCK_SNAPSHOT)

unless snapshot_lockfile
Copy link
Contributor

Choose a reason for hiding this comment

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

Have we compared the snapshot approach to git diff? I can think of one scenario where you update the lockfile before snapshot is created so upon the consequent restart there are changes in git status however, snapshot doesn't exist yet so we don't generate. It's not a common scenario so not important. But feels like running git diff instead is a viable solution. Curious about the reasoning here. Does it have downsides for changing branches?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thank you for mentioning git diff again. I looked into it with more attention and I do agree it is a much nicer solution.

I have pushed a refactor to take advantage of git diff. Let me know what you think.

def handle_gemfile_changes
return unless File.exist?(".git")

gemfile_status = %x(git status --porcelain Gemfile.lock).strip
Copy link
Contributor

Choose a reason for hiding this comment

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

With shelling out and the file parsing I'm curious how long this adds to the boot time. Could you add some simple timings to the PR description, before and after this change for core?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is now an older implementation, but I do agree some timings would be nice to have. I'll take a look on Monday.

@vinistock vinistock force-pushed the tapioca-addon-feature-branch branch from cc19ba0 to 3ce0a60 Compare November 22, 2024 14:23
@alexcrocha alexcrocha force-pushed the ar/gem-regeneration-git-status branch from 351a2fb to f387c8d Compare November 22, 2024 19:10
attr_reader :removed_gems

def initialize(diff_content)
@diff_content = diff_content
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
@diff_content = diff_content
@diff_content = diff_content.lines

If the only thing we do is call .lines on it we could do it here and do it only once instead of 2 calls below.

# typed: true
# frozen_string_literal: true

module RubyLsp
Copy link
Contributor

Choose a reason for hiding this comment

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

Nice work on this!

@alexcrocha alexcrocha force-pushed the ar/gem-regeneration-git-status branch from 7f173a8 to 5f3dc43 Compare November 26, 2024 02:27
@alexcrocha alexcrocha changed the title WIP: [Tapioca Addon] Support gem RBI generation on dirty lockfile [Tapioca Addon] Support gem RBI generation Nov 26, 2024
@andyw8
Copy link
Contributor

andyw8 commented Nov 26, 2024

Some feedback from testing. It's possible some won't need addressed:

  • I noticed the output from Tapioca is double-spaced (vertically) in the logs. It's likely that Ruby LSP itself is adding extra newlines unnecessarily.
  • Once the add-on succesfully creates/update some RBIs, it will so again on every restart and report them as identical, until committed/staged. We could be smart and check the new/changed RBIs files on disk but this may add unwanted complexity.

@andyw8
Copy link
Contributor

andyw8 commented Nov 26, 2024

(Continued)

  • After running, we show a message in the logs "Please review changes and commit them." but users would not normally be reading that. We may want to consider showing an alert instead.
  • It would be nice if we could eliminate the FILE_HEADER_OPTION_DESC warnings in Tapioca to prevent them showing on startup.
  • I added a gem to the Gemfile and the add-on generated the RBI. Without committing, then removed the new entry from the Gemfile. The 'orphaned' RBI remained on disk.

@alexcrocha alexcrocha marked this pull request as ready for review November 27, 2024 20:15
@alexcrocha alexcrocha requested a review from a team as a code owner November 27, 2024 20:15
@alexcrocha alexcrocha requested review from KaanOzkan, andyw8 and vinistock and removed request for a team November 27, 2024 20:15
@alexcrocha alexcrocha force-pushed the ar/gem-regeneration-git-status branch from 1098d0d to 21df7e6 Compare November 27, 2024 23:09
@alexcrocha alexcrocha changed the base branch from tapioca-addon-feature-branch to main November 27, 2024 23:09
@alexcrocha alexcrocha force-pushed the ar/gem-regeneration-git-status branch from 21df7e6 to ebfb33d Compare November 28, 2024 01:34
spec/tapioca/ruby_lsp/tapioca/lockfile_diff_parser_spec.rb Outdated Show resolved Hide resolved
lib/ruby_lsp/tapioca/server_addon.rb Outdated Show resolved Hide resolved
lib/ruby_lsp/tapioca/addon.rb Outdated Show resolved Hide resolved
@alexcrocha alexcrocha force-pushed the ar/gem-regeneration-git-status branch from ebfb33d to e19934f Compare November 30, 2024 00:40
@alexcrocha alexcrocha force-pushed the ar/gem-regeneration-git-status branch 2 times, most recently from e2697ce to b28ebb0 Compare December 18, 2024 19:21
@alexcrocha alexcrocha force-pushed the ar/gem-regeneration-git-status branch 2 times, most recently from c2bdc3e to bc29ae7 Compare January 8, 2025 00:01
lib/ruby_lsp/tapioca/lockfile_diff_parser.rb Outdated Show resolved Hide resolved
lib/ruby_lsp/tapioca/lockfile_diff_parser.rb Outdated Show resolved Hide resolved
@alexcrocha alexcrocha force-pushed the ar/gem-regeneration-git-status branch 4 times, most recently from 17d6c89 to 2be1ab2 Compare January 10, 2025 18:57
alexcrocha and others added 10 commits January 10, 2025 13:37
To support gem RBI generation, we needed a way to detect changes in
Gemfile.lock. Currently, changes to this file cause the Ruby LSP to
restart, resulting in loss of access to any previous state information.

By running git diff on Gemfile.lock, we can detect changes to the file,
and trigger the gem RBI generation process.

Then we can parse the diff output to determine which gems have been
removed, added or modified, and either remove the corresponding RBI
files or trigger the RBI generation process for the gems.
@alexcrocha alexcrocha force-pushed the ar/gem-regeneration-git-status branch 8 times, most recently from 5529801 to 290c482 Compare January 14, 2025 00:32
@alexcrocha alexcrocha force-pushed the ar/gem-regeneration-git-status branch from 290c482 to 2db5af3 Compare January 14, 2025 01:09
@alexcrocha alexcrocha force-pushed the ar/gem-regeneration-git-status branch from e3d4abf to 1129df9 Compare January 14, 2025 01:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants