Skip to content

Instantly share code, notes, and snippets.

@jimryan
Last active Apr 12, 2016
Embed
What would you like to do?
Save and restore the state of your Rails development and test databases as you work on different branches
#!/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