diff --git a/lib/ruby_lsp/ruby_lsp_rails/addon.rb b/lib/ruby_lsp/ruby_lsp_rails/addon.rb index e10e9e91..0d650683 100644 --- a/lib/ruby_lsp/ruby_lsp_rails/addon.rb +++ b/lib/ruby_lsp/ruby_lsp_rails/addon.rb @@ -138,8 +138,12 @@ def workspace_did_change_watched_files(changes) @rails_runner_client.trigger_reload end + # It may be too agressive to ask a user to run a migration which has just been created. + # But we do want to offer it for situations such as switching branches or pulling from a remote. + # As a middle-ground, we only offer to run migrations if the # migration was created more than a minute ago. if changes.any? do |c| - %r{db/migrate/.*\.rb}.match?(c[:uri]) && c[:type] != Constant::FileChangeType::CHANGED + %r{db/migrate/.*\.rb}.match?(c[:uri]) && + c[:type] == Constant::FileChangeType::CREATED && !changed_in_last_minute?(c[:uri]) end offer_to_run_pending_migrations @@ -178,6 +182,12 @@ def handle_window_show_message_response(title) private + sig { params(uri: String).returns(T::Boolean) } + def changed_in_last_minute?(uri) + path = URI(uri).to_standardized_path + File.stat(path).mtime > (Time.now - 60) + end + sig { params(id: String, title: String, percentage: T.nilable(Integer), message: T.nilable(String)).void } def begin_progress(id, title, percentage: nil, message: nil) return unless @global_state&.client_capabilities&.supports_progress && @outgoing_queue diff --git a/test/ruby_lsp_rails/addon_test.rb b/test/ruby_lsp_rails/addon_test.rb index 63213552..390fb2ff 100644 --- a/test/ruby_lsp_rails/addon_test.rb +++ b/test/ruby_lsp_rails/addon_test.rb @@ -92,6 +92,64 @@ class AddonTest < ActiveSupport::TestCase ensure T.must(outgoing_queue).close end + + test "offers to run migrations created more than 60 seconds ago" do + path = "#{dummy_root}/db/migrate/20210101000000_create_foos.rb" + begin + mtime = 1.minute.ago.to_time + FileUtils.touch(path, mtime: mtime) + changes = [ + { + uri: "file://#{path}", + type: RubyLsp::Constant::FileChangeType::CREATED, + }, + ] + + addon = Addon.new + addon.expects(:offer_to_run_pending_migrations).once + addon.workspace_did_change_watched_files(changes) + ensure + FileUtils.rm(path) + end + end + + test "does not offer to run migrations created less than 60 seconds ago" do + path = "#{dummy_root}/db/migrate/20210101000000_create_foos.rb" + begin + mtime = 30.seconds.ago.to_time + FileUtils.touch(path, mtime: mtime) + changes = [ + { + uri: "file://#{path}", + type: RubyLsp::Constant::FileChangeType::CREATED, + }, + ] + + addon = Addon.new + addon.expects(:offer_to_run_pending_migrations).never + addon.workspace_did_change_watched_files(changes) + ensure + FileUtils.rm(path) + end + end + + test "doesn't offers to run migrations if deleted" do + path = "#{dummy_root}/db/migrate/20210101000000_create_foos.rb" + changes = [ + { + uri: "file://#{path}", + type: Constant::FileChangeType::DELETED, + }, + { + uri: "file://#{path}", + type: RubyLsp::Constant::FileChangeType::CHANGED, + }, + ] + + addon = Addon.new + addon.expects(:offer_to_run_pending_migrations).never + addon.workspace_did_change_watched_files(changes) + end end end end