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

Add code lens for running migrations #239

Merged
merged 1 commit into from
Jul 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
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
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ Ruby LSP Rails is a [Ruby LSP](https://github.com/Shopify/ruby-lsp) addon for ex
* Navigate to associations, validations, callbacks and test cases using your editor's "Go to Symbol" feature, or outline view.
* Jump to the definition of callbacks using your editor's "Go to Definition" feature.
* Jump to the declaration of a route.
* Code Lens allowing fast-forwarding or rewinding of migrations.

## Installation

Expand Down
46 changes: 41 additions & 5 deletions lib/ruby_lsp/ruby_lsp_rails/code_lens.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ module Rails
# - Run tests in the VS Terminal
# - Run tests in the VS Code Test Explorer
# - Debug tests
# - Run migrations in the VS Terminal
#
# The
# [code lens](https://microsoft.github.io/language-server-protocol/specification#textDocument_codeLens)
Expand All @@ -34,6 +35,14 @@ module Rails
# end
# ````
#
# # Example:
# ```ruby
# Run
# class AddFirstNameToUsers < ActiveRecord::Migration[7.1]
# # ...
# end
# ````
#
# The code lenses will be displayed above the class and above each test method.
#
# Note: When using the Test Explorer view, if your code contains a statement to pause execution (e.g. `debugger`) it
Expand Down Expand Up @@ -74,6 +83,7 @@ def on_call_node_enter(node)
sig { params(node: Prism::DefNode).void }
def on_def_node_enter(node)
method_name = node.name.to_s

if method_name.start_with?("test_")
line_number = node.location.start_line
command = "#{test_command} #{@path}:#{line_number}"
Expand All @@ -84,12 +94,19 @@ def on_def_node_enter(node)
sig { params(node: Prism::ClassNode).void }
def on_class_node_enter(node)
class_name = node.constant_path.slice
superclass_name = node.superclass&.slice

if class_name.end_with?("Test")
command = "#{test_command} #{@path}"
add_test_code_lens(node, name: class_name, command: command, kind: :group)
@group_id_stack.push(@group_id)
@group_id += 1
end

if superclass_name&.start_with?("ActiveRecord::Migration")
command = "#{migrate_command} VERSION=#{migration_version}"
add_migrate_code_lens(node, name: class_name, command: command)
end
end

sig { params(node: Prism::ClassNode).void }
Expand All @@ -104,11 +121,30 @@ def on_class_node_leave(node)

sig { returns(String) }
def test_command
if Gem.win_platform?
"ruby bin/rails test"
else
"bin/rails test"
end
"#{RbConfig.ruby} bin/rails test"
end

sig { returns(String) }
def migrate_command
"#{RbConfig.ruby} bin/rails db:migrate"
end

sig { returns(T.nilable(String)) }
def migration_version
File.basename(T.must(@path)).split("_").first
end

sig { params(node: Prism::Node, name: String, command: String).void }
def add_migrate_code_lens(node, name:, command:)
return unless @path

@response_builder << create_code_lens(
node,
title: "Run",
command_name: "rubyLsp.runTask",
arguments: [command],
data: { type: "migrate" },
)
end

sig { params(node: Prism::Node, name: String, command: String, kind: Symbol).void }
Expand Down
23 changes: 20 additions & 3 deletions test/ruby_lsp_rails/code_lens_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ module Rails
class CodeLensTest < ActiveSupport::TestCase
setup do
GlobalState.any_instance.stubs(:test_library).returns("rails")
@ruby = Gem.win_platform? ? "ruby.exe" : "ruby"
end

test "does not create code lenses if rails is not the test library" do
Expand Down Expand Up @@ -270,13 +271,29 @@ class Test < ActiveSupport::TestCase
end
RUBY

assert_equal("ruby bin/rails test /fake.rb", response[0].command.arguments[2])
assert_match("#{ruby} bin/rails test /fake.rb", response[0].command.arguments[2])
end

test "recognizes migrations" do
response = generate_code_lens_for_source(<<~RUBY, file: "file://db/migrate/123456_add_first_name_to_users.rb")
class AddFirstNameToUsers < ActiveRecord::Migration[7.1]
def change
add_column(:users, :first_name, :string)
end
end
RUBY

assert_equal(1, response.size)
assert_match("Run", response[0].command.title)
assert_match("#{ruby} bin/rails db:migrate VERSION=123456", response[0].command.arguments[0])
end

private

def generate_code_lens_for_source(source)
with_server(source) do |server, uri|
attr_reader :ruby

def generate_code_lens_for_source(source, file: "/fake.rb")
with_server(source, URI(file)) do |server, uri|
server.process_message(
id: 1,
method: "textDocument/codeLens",
Expand Down
Loading