Last active
April 12, 2016 17:11
-
-
Save jimryan/8853110 to your computer and use it in GitHub Desktop.
Save and restore the state of your Rails development and test databases as you work on different branches
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env ruby | |
require 'yaml' | |
# If this was a branch checkout | |
if ARGV[2] == '1' | |
def dump(database_name, branch_name) | |
print "Saving state of #{database_name} on '#{branch_name}' branch..." | |
if system(%[pg_dump -c -f "#{@dump_folder}/#{database_name}-#{branch_name}" #{database_name}]) | |
print "done!\n" | |
true | |
else | |
print "failed!\n" | |
false | |
end | |
end | |
def restore(database_name, path) | |
system(%[psql #{database_name} < #{path} > /dev/null 2>&1]) | |
end | |
def branches_from_refhead(ref) | |
`git show-ref --heads | grep #{ref} | awk '{print $2}'`.split("\n").map{ |b| b.sub(/^refs\/heads\//, '') } | |
end | |
# Get the current (destination) branch | |
@destination_branch = `git rev-parse --abbrev-ref HEAD`.strip | |
# Since we're just given a commit ID referencing the branch head we're coming from, | |
# it could be at the head of multiple branches. We can assume the source isn't the same as the | |
# destination branch, so we can remove that immediately. | |
@source_branches = branches_from_refhead(ARGV[0]).reject{ |b| b == @destination_branch } | |
@project_root = %x[git rev-parse --show-toplevel].strip | |
@dump_folder = "#{@project_root}/.db_branch_dumps" | |
# Load Rails DB config and grab database name | |
rails_db_config = YAML.load_file("#{@project_root}/config/database.yml") | |
dev_database_name = rails_db_config['development']['database'] | |
test_database_name = rails_db_config['test']['database'] | |
# Ensure dump directory exists | |
unless Dir.exists?(@dump_folder) | |
Dir.mkdir @dump_folder | |
end | |
# Don't do anything if the source and destination branches are the same or nonexistent | |
unless @source_branches.include?(@destination_branch) || @source_branches.empty? || (@source_branches | [@destination_branch]).any?{ |b| b == '' } | |
# Dump database for source branches | |
if @source_branches.all? { |branch| dump(dev_database_name, branch) } | |
# Restore dump from this branch, if it exists | |
dump_path = "#{@dump_folder}/#{dev_database_name}-#{@destination_branch}" | |
if File.exists?(dump_path) | |
print "Restoring #{dev_database_name} to its previous state on this branch..." | |
if restore(dev_database_name, dump_path) | |
print "done!\n" | |
# If we have a structure.sql file, restore that to the test database, | |
# otherwise fall back to rake | |
structure_sql = File.join(@project_root, 'db', 'structure.sql') | |
if File.exists?(structure_sql) | |
print "Restoring test database from structure.sql..." | |
print restore(test_database_name, structure_sql) ? "done!\n" : "failed!\n" | |
else | |
print "Preparing test database..." | |
system %[rake db:test:prepare] | |
print "done!\n" | |
end | |
else | |
print "failed!\n" | |
end | |
else | |
print "No DB dump for #{dev_database_name} on the '#{@destination_branch}' branch was found!\n" | |
print "The state of your database has been saved for when you return to the '#{@source_branches.join('\' or \'')}' branch, but its current state has been left unchanged. You are now free to make changes to it that are specific to this branch, and they will be saved when you checkout a different branch, then restored when you checkout this one again.\n" | |
end | |
else | |
print "Failed to dump database. Halting.\n" | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment