Skip to content

Commit 8b006a9

Browse files
committed
Add code lens for running migrations
Adds code lens to run migrations to specific versions in the terminal. This is convenient because it allows developers to quickly rollback or fast-forward to specific schema versions with a click.
1 parent 5704d93 commit 8b006a9

File tree

2 files changed

+58
-8
lines changed

2 files changed

+58
-8
lines changed

lib/ruby_lsp/ruby_lsp_rails/code_lens.rb

Lines changed: 41 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ module Rails
1010
# - Run tests in the VS Terminal
1111
# - Run tests in the VS Code Test Explorer
1212
# - Debug tests
13+
# - Run migrations in the VS Terminal
1314
#
1415
# The
1516
# [code lens](https://microsoft.github.io/language-server-protocol/specification#textDocument_codeLens)
@@ -34,6 +35,14 @@ module Rails
3435
# end
3536
# ````
3637
#
38+
# # Example:
39+
# ```ruby
40+
# Run
41+
# class AddFirstNameToUsers < ActiveRecord::Migration[7.1]
42+
# # ...
43+
# end
44+
# ````
45+
#
3746
# The code lenses will be displayed above the class and above each test method.
3847
#
3948
# Note: When using the Test Explorer view, if your code contains a statement to pause execution (e.g. `debugger`) it
@@ -74,6 +83,7 @@ def on_call_node_enter(node)
7483
sig { params(node: Prism::DefNode).void }
7584
def on_def_node_enter(node)
7685
method_name = node.name.to_s
86+
7787
if method_name.start_with?("test_")
7888
line_number = node.location.start_line
7989
command = "#{test_command} #{@path}:#{line_number}"
@@ -84,12 +94,19 @@ def on_def_node_enter(node)
8494
sig { params(node: Prism::ClassNode).void }
8595
def on_class_node_enter(node)
8696
class_name = node.constant_path.slice
97+
superclass_name = node.superclass&.slice
98+
8799
if class_name.end_with?("Test")
88100
command = "#{test_command} #{@path}"
89101
add_test_code_lens(node, name: class_name, command: command, kind: :group)
90102
@group_id_stack.push(@group_id)
91103
@group_id += 1
92104
end
105+
106+
if superclass_name&.start_with?("ActiveRecord::Migration")
107+
command = "#{migrate_command} VERSION=#{migration_version}"
108+
add_migrate_code_lens(node, name: class_name, command: command)
109+
end
93110
end
94111

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

105122
sig { returns(String) }
106123
def test_command
107-
if Gem.win_platform?
108-
"ruby bin/rails test"
109-
else
110-
"bin/rails test"
111-
end
124+
"#{RbConfig.ruby} bin/rails test"
125+
end
126+
127+
sig { returns(String) }
128+
def migrate_command
129+
"#{RbConfig.ruby} bin/rails db:migrate"
130+
end
131+
132+
sig { returns(T.nilable(String)) }
133+
def migration_version
134+
File.basename(T.must(@path)).split("_").first
135+
end
136+
137+
sig { params(node: Prism::Node, name: String, command: String).void }
138+
def add_migrate_code_lens(node, name:, command:)
139+
return unless @path
140+
141+
@response_builder << create_code_lens(
142+
node,
143+
title: "Run",
144+
command_name: "rubyLsp.runTask",
145+
arguments: [command],
146+
data: { type: "migrate" },
147+
)
112148
end
113149

114150
sig { params(node: Prism::Node, name: String, command: String, kind: Symbol).void }

test/ruby_lsp_rails/code_lens_test.rb

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -270,13 +270,27 @@ class Test < ActiveSupport::TestCase
270270
end
271271
RUBY
272272

273-
assert_equal("ruby bin/rails test /fake.rb", response[0].command.arguments[2])
273+
assert_match("ruby bin/rails test /fake.rb", response[0].command.arguments[2])
274+
end
275+
276+
test "recognizes migrations" do
277+
response = generate_code_lens_for_source(<<~RUBY, file: "file://db/migrate/123456_add_first_name_to_users.rb")
278+
class AddFirstNameToUsers < ActiveRecord::Migration[7.1]
279+
def change
280+
add_column(:users, :first_name, :string)
281+
end
282+
end
283+
RUBY
284+
285+
assert_equal(1, response.size)
286+
assert_match("Run", response[0].command.title)
287+
assert_match("ruby bin/rails db:migrate VERSION=123456", response[0].command.arguments[0])
274288
end
275289

276290
private
277291

278-
def generate_code_lens_for_source(source)
279-
with_server(source) do |server, uri|
292+
def generate_code_lens_for_source(source, file: "/fake.rb")
293+
with_server(source, URI(file)) do |server, uri|
280294
server.process_message(
281295
id: 1,
282296
method: "textDocument/codeLens",

0 commit comments

Comments
 (0)