heroku_san
heroku_san copied to clipboard
For Rails apps, only run migrations and restart after deploy if migrations pending
This only works for postgresql setups. Fixes https://github.com/fastestforward/heroku_san/issues/5.
I should add, the reason I implemented this as a memoized function on the Stage class is so that it can easily be used in the before_deploy and after_deploy hooks. We need this on a Heroku project where we enable maintenance mode and do a couple other things in the before_deploy if there are pending migrations. Then in the after_deploy we clean up (disable maintenance mode) if there were pending migrations.
This is an awesome feature and one I would find really useful too! I'm not sure why but the psql command in your pull request didn't work for me. This worked for me (basically just copied what the heroku toolbelt was doing):
def remote_migrations
database_uri = URI.parse(long_config['DATABASE_URL'])
begin
ENV['PGPASSWORD'] = database_uri.password
ENV['PGSSLMODE'] = 'require'
psql_cmd = "psql -U #{database_uri.user} -h #{database_uri.host} " \
"-p #{database_uri.port || 5432} #{database_uri.path[1..-1]}"
`#{psql_cmd} -Atc "SELECT * FROM schema_migrations;"`.split.map(&:to_i)
ensure
ENV.delete('PGPASSWORD')
ENV.delete('PGSSLMODE')
end
end
This approach has the added benefit of being slightly more secure since the database password isn't included in the psql command line.
Another thing I found useful was basing the state of required migrations on the migration source code rather than the state of my local database (which can occasionally get out of sync when switching between branches). With the approach the change looks more like this (leaving out your checking for Rails and Postgres for brevity):
# Returns true if the remote DB has pending migrations and false if not.
def has_pending_migrations
@has_pending_migrations ||= (local_migrations - remote_migrations).present?
end
private
# returns an array of schema migration versions in the local source directory
def local_migrations
ActiveRecord::Migrator.migrations(ActiveRecord::Migrator.migrations_paths).map(&:version)
end
I'm curious to hear your thoughts on this approach.
Sorry for taking long to respond. I like your changes. I'll work on making those changes now.