namespace :forkcms do namespace :migrations do desc 'Prepare the server for running Fork CMS migrations' task :prepare do on roles(:web) do create_migrations_file end end desc 'Execute pending migrations' task :execute do on roles(:web) do # Prepare for migrations if it's not done already Rake::Task["forkcms:migrations:prepare"].invoke() # Abort if no migrations are found migration_folders = get_migration_folders next if migration_folders.length == 0 migrations_to_execute = get_migrations_to_execute # Abort if no new migrations are found next if migrations_to_execute.length == 0 # As migrations can take a while we show a maintenance page Rake::Task["forkcms:maintenance:enable"].invoke() # Back up the database, just in case Rake::Task["forkcms:database:backup"].invoke() # Execute all migrations migrations_to_execute.each do |dirname| migration_path = "#{release_path}/migrations/#{dirname}" migration_files = capture("ls -1 #{migration_path}").split(/\r?\n/) migration_files.each do |filename| # Execute a MySQL file if filename.index('update.sql') != nil Rake::Task["forkcms:database:execute"].invoke("#{migration_path}/#{filename}") next end # Update the locale through the console command if filename.index('locale.xml') != nil execute :php, "#{release_path}/bin/console forkcms:locale:import -f #{migration_path}/#{filename} --env=prod" next end end end # All migrations were executed successfully and we didn't roll back so put them in the executed_migrations file migrations_to_execute.each do |dirname| execute :echo , "#{dirname} | tee -a #{shared_path}/executed_migrations" end # Disable maintenance mode, everything is done Rake::Task["forkcms:maintenance:disable"].invoke() end end desc 'Rollback the migrations' task :rollback do # Restore the database backup so we undo any executed migrations Rake::Task["forkcms:database:restore"].invoke() # Disable the maintenance page so the site is accessible again Rake::Task["forkcms:maintenance:disable"].invoke() end private # Creates a migration file to hold our executed migrations def create_migrations_file # Stop if the migrations file exists return if test "[[ -f #{shared_path}/executed_migrations ]]" # Create an empty executed_migrations file upload! StringIO.new(''), "#{shared_path}/executed_migrations" # If we just created the executed_migrations file, add all existing migrations execute_initial_migration end # Put all items in the migrations folder in the executed_migrations file def execute_initial_migration migration_folders = get_migration_folders migration_folders.each do |dirname| run "echo #{dirname} | tee -a #{shared_path}/executed_migrations" end end # Gets the new migrations to execute def get_migrations_to_execute executed_migrations = capture("cat #{shared_path}/executed_migrations").chomp.split(/\r?\n/) migrations_to_execute = Array.new migration_folders = get_migration_folders # Fetch all migration directories that aren't executed yet migration_folders.each do |dirname| if executed_migrations.index(dirname) == nil migrations_to_execute.push(dirname) end end return migrations_to_execute end def get_migration_folders return capture("if [ -e #{release_path}/migrations ]; then ls -1 #{release_path}/migrations; fi").split(/\r?\n/) end end end