#!/usr/bin/env ruby require(Dir.pwd + "/config/environment") ActiveRecord::Base.configurations.configs_for(env_name: ActiveRecord::Tasks::DatabaseTasks.env).each do |db_config| ActiveRecord::Base.establish_connection(db_config.config) context = ActiveRecord::Base.connection.migration_context missing_migrations = [] context.migrations_status.each do |status, version, name| # We're only interested in migrations that are currently applied next unless status == "up" # We're only interested in migrations being displayed as "***** NO FILE *****" next unless name.start_with?("*") raise "Unexpected version format: #{version.inspect} is not numeric" unless version =~ /\A[0-9]+\z/ missing_migrations << version end next if missing_migrations.empty? puts puts "Missing migrations in #{db_config.spec_name}:" puts missing_migrations.map { |s| " #{s}" } puts migration_sha = {} missing_migrations.each do |version| migration_sha[version] = nil end puts "% git rev-list --walk-reflogs HEAD" IO.popen("git rev-list --walk-reflogs HEAD") do |sha_list| until migration_sha.values.all? sha = sha_list.gets.chomp newly_found = [] paths = Shellwords.join([*context.migrations_paths].map { |path| "#{path}/" }) puts %(% git ls-tree --name-only #{sha} -- #{paths}) migrate_files = %x(git ls-tree --name-only #{sha} -- #{paths}).lines.map(&:chomp) migrate_files.each do |filename| version = File.basename(filename).split("_", 2).first if migration_sha.key?(version) && migration_sha[version].nil? migration_sha[version] = [sha, filename] newly_found << version end end puts " found #{newly_found.sort.join(", ")}" unless newly_found.empty? end end migration_files = [] missing_migrations.each do |version| next unless migration_sha[version] sha, filename = migration_sha[version] puts %(% git cat-file blob #{sha}:#{Shellwords.escape filename}) migration_script = %x(git cat-file blob #{sha}:#{Shellwords.escape filename}) eval migration_script, nil, filename, 1 $LOADED_FEATURES << File.expand_path(filename) migration_files << filename end puts dummy_context = ActiveRecord::MigrationContext.new(nil, ActiveRecord::Base.connection.migration_context.schema_migration) class << dummy_context attr_accessor :migration_files end dummy_context.migration_files = migration_files dummy_context.down if ActiveRecord::Base.dump_schema_after_migration ActiveRecord::Tasks::DatabaseTasks.dump_schema(db_config) end end