Skip to content

Instantly share code, notes, and snippets.

@bf4
Forked from matthewd/db-switch.rb
Created August 30, 2021 18:21
Show Gist options
  • Select an option

  • Save bf4/b2ac2f77b2bf7144e84775c6151258e3 to your computer and use it in GitHub Desktop.

Select an option

Save bf4/b2ac2f77b2bf7144e84775c6151258e3 to your computer and use it in GitHub Desktop.

Revisions

  1. @matthewd matthewd created this gist Apr 1, 2021.
    90 changes: 90 additions & 0 deletions db-switch.rb
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,90 @@
    #!/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