adjust migration to proxy call to ActiveRecord

By adding proxy method the call to ActiveRecord::Migrator.migrations_paths
is decoupled from the migration task allowing more flexibility for the
underlying migration set selection to change in future Rails versions.
This commit is contained in:
Jeffrey Martin 2020-07-08 12:21:23 -05:00
parent ffee2a5a43
commit 0b65266ac1
No known key found for this signature in database
GPG Key ID: 0CD9BBC2AF15F171
2 changed files with 30 additions and 27 deletions

View File

@ -1,8 +1,8 @@
# -*- coding: binary -*-
module Msf::DBManager::Migration
# Loads Metasploit Data Models and adds its migrations to migrations paths.
# Loads Metasploit Data Models and adds gathers migration paths.
#
# @return [void]
# @return Array[String]
def add_rails_engine_migration_paths
unless defined? ActiveRecord
fail "Bundle installed '--without #{Bundler.settings.without.join(' ')}'. To clear the without option do " \
@ -10,20 +10,7 @@ module Msf::DBManager::Migration
"the .bundle/config manually and then `bundle install`"
end
::Rails::Engine.subclasses.map(&:instance).each.each do |engine|
migrations_paths = engine.paths['db/migrate'].existent_directories
migrations_paths.each do |migrations_path|
# Since ActiveRecord::Migrator.migrations_paths can persist between
# instances of Msf::DBManager, such as in specs,
# migrations_path may already be part of
# migrations_paths, in which case it should not be added or multiple
# migrations with the same version number errors will occur.
unless ActiveRecord::Migrator.migrations_paths.include? migrations_path
ActiveRecord::Migrator.migrations_paths << migrations_path
end
end
end
gather_engine_migration_paths
end
# Migrate database to latest schema version.
@ -47,8 +34,7 @@ module Msf::DBManager::Migration
ActiveRecord::Migration.verbose = verbose
ActiveRecord::Base.connection_pool.with_connection do
begin
# When framework reached Rails 6 the path set here may be better suited a simple Array[]
context = ActiveRecord::MigrationContext.new(ActiveRecord::Migrator.migrations_paths)
context = ActiveRecord::MigrationContext.new(gather_engine_migration_paths)
if context.needs_migration?
ran = context.migrate
end
@ -81,6 +67,29 @@ module Msf::DBManager::Migration
private
# Loads gathers migration paths from all loaded Rails engines.
#
# @return Array[String]
def gather_engine_migration_paths
paths = ActiveRecord::Migrator.migrations_paths
::Rails::Engine.subclasses.map(&:instance).each.each do |engine|
migrations_paths = engine.paths['db/migrate'].existent_directories
migrations_paths.each do |migrations_path|
# Since ActiveRecord::Migrator.migrations_paths can persist between
# instances of Msf::DBManager, such as in specs,
# migrations_path may already be part of
# migrations_paths, in which case it should not be added or multiple
# migrations with the same version number errors will occur.
unless paths.include? migrations_path
paths << migrations_path
end
end
end
paths
end
# Resets the column information for all descendants of ApplicationRecord
# since some of the migrations may have cached column information that
# has been updated by later migrations.

View File

@ -12,16 +12,10 @@ RSpec.shared_examples_for 'Msf::DBManager::Migration' do
db_manager.add_rails_engine_migration_paths
end
it 'should not add duplicate paths to ActiveRecord::Migrator.migrations_paths' do
add_rails_engine_migration_paths
it 'should not add duplicate paths to gather_engine_migration_paths' do
paths = add_rails_engine_migration_paths
expect {
add_rails_engine_migration_paths
}.to_not change {
ActiveRecord::Migrator.migrations_paths.length
}
expect(ActiveRecord::Migrator.migrations_paths.uniq).to eq ActiveRecord::Migrator.migrations_paths
expect(add_rails_engine_migration_paths.uniq).to eq paths
end
end