Skip to content

Instantly share code, notes, and snippets.

@ghiculescu
Created May 8, 2020 21:51
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save ghiculescu/234da1a8aada56d543e6b876a17859ff to your computer and use it in GitHub Desktop.
Save ghiculescu/234da1a8aada56d543e6b876a17859ff to your computer and use it in GitHub Desktop.
# typed: false
require "English"
namespace :db do
task :prevent_disparate_pg_dump_versions => :environment do
allowed_pg_dump_version = "x.x.x".freeze
`pg_dump --version`
pg_dump_exit_status = $CHILD_STATUS.exitstatus
locally_installed_version = begin
`pg_dump --version`.chomp[/(\d.*)/, 1]
rescue StandardError
nil
end
if locally_installed_version != allowed_pg_dump_version
puts(<<~OUTPUT_BLOCK)
Required pg_dump version: #{allowed_pg_dump_version}
Your version: #{locally_installed_version}
OUTPUT_BLOCK
if Gem::Version.new(locally_installed_version) > Gem::Version.new(allowed_pg_dump_version)
puts(<<~OUTPUT_BLOCK)
---
Your local version of postgresql is ahead of the pinned version in:
`lib/tasks/migrate_enhancements.rake`.
Please update `allowed_pg_dump_version` in `lib/tasks/migrate_enhancements.rake`
to match your version (as listed above).
---
OUTPUT_BLOCK
raise("You must update `lib/tasks/migrate_enhancements.rake` if you wish to proceed with migrating")
else
puts(<<~OUTPUT_BLOCK)
---
Linux upgrade command: `sudo apt-get update && sudo apt-get upgrade`
OS X upgrade command: `brew upgrade postgresql@9.6`
You may also need to tell OS X how to use your Homebrew version of postgres.
To do this, run `brew info postgresql@9.6`. There will be a command output that tells you
how to add it to your path. Follow those instructions.
---
OUTPUT_BLOCK
raise("You must update your postgresql-client if you wish to proceed with migrating")
end
elsif pg_dump_exit_status == 127
puts(<<~OUTPUT_BLOCK)
System postgres client not installed - it is needed for the db:migrate task.
---
Linux install command:
`sudo add-apt-repository "deb http://apt.postgresql.org/pub/repos/apt/ $(lsb_release -sc)-pgdg main"`
`wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add -`
`sudo apt-get update && sudo apt-get install postgresql-9.6`
OS X install command: `brew install postgresql@9.6`
---
OUTPUT_BLOCK
raise("You must install postgresql-client if you wish to proceed with migrating")
end
end
# keep structure.sql in sync with the actual files in the db/migrate folder
# this minimises the chance of merge conflicts if different branches add migrations
# since, ideally, migrations will not make it to master in this file unless the corresponding
# migration actaully exists
# also removes duplicates!
task :make_structure_sql_match_db_migrate_folder do
path = Rails.root.join("db", "structure.sql")
structure_sql_lines = File.read(path).lines
migration_insert_index = structure_sql_lines.index { |l| l == "INSERT INTO \"schema_migrations\" (version) VALUES\n" }
migration_lines = structure_sql_lines[migration_insert_index + 1..-1]
migrations_in_repo = Set.new(Dir.glob("db/migrate/*.rb").map { |p| p.match(/[0-9]+/).try { |m| m[0] } })
seen_migration_lines = Set.new
correct_structure_sql_lines = migration_lines.select do |line|
match = line.match(/\('(\d+)'\)/)
should_include = !match || (migrations_in_repo.include?(match[1]) && !seen_migration_lines.include?(match[1]))
seen_migration_lines << match[1] if should_include && match
should_include
end.flatten
index_of_last_populated_line = -correct_structure_sql_lines.reverse.index(&:present?) - 1
if correct_structure_sql_lines[index_of_last_populated_line].end_with?(",\n")
correct_structure_sql_lines[index_of_last_populated_line] = "#{correct_structure_sql_lines[index_of_last_populated_line][0...-2]};"
end
File.write(path, (structure_sql_lines[0..migration_insert_index] + correct_structure_sql_lines).join)
end
end
if Rails.env.development?
# see http://edgar.tumblr.com/post/52300664342/how-to-extend-an-existing-rake-task
# if you call #enhance with an array it sets it as a prereq (runs before)
# if you give #enhance a block it adds a behaviour (runs after)
# see https://github.com/ruby/rake/blob/v10.5.0/lib/rake/task.rb#L100 if you don't believe an API this odd could exist
Rake::Task["db:migrate"].enhance(["db:prevent_disparate_pg_dump_versions"])
Rake::Task["db:migrate"].enhance do
Rake::Task["db:make_structure_sql_match_db_migrate_folder"].invoke
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment