Last active
April 16, 2024 23:04
-
-
Save anujbiyani/25f3d3096fe76f91fe271b2a722b4cc0 to your computer and use it in GitHub Desktop.
A script to make sure new Rails migrations cleanly migrate forwards and backwards.
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 "pathname" | |
common_ancestor_sha = `git merge-base HEAD origin/master`.strip | |
commit_messages = `git log --pretty=format:"%B" #{common_ancestor_sha}..HEAD` | |
if commit_messages.include?("[skip schema checks]") | |
puts "Found [skip schema checks] tag, skipping db migration check." | |
exit | |
end | |
changed_files = `git diff --name-only HEAD #{common_ancestor_sha}`.split("\n") | |
migration_files = changed_files.select { |path| File.dirname(path) == "db/migrate" } | |
schema_file = changed_files.detect { |path| path.include?("db/schema.rb") } | |
if schema_file && migration_files.none? | |
puts "DB schema file changed, but no migration files are present. All changes to the schema should be driven by a migration file." | |
puts "If you really mean to change the schema without a migration, e.g. you are fixing a bad schema, then please disable this check in this PR and re-enable it after this PR is merged." | |
puts "Failing." | |
exit 1 | |
end | |
unless migration_files.any? | |
puts "Did not find any migration files in the list of files changed. Exiting." | |
exit | |
end | |
versions = migration_files.map { |path| Pathname.new(path).basename.to_s.split("_").first }.sort | |
human_formatted_versions = versions.join(", ") | |
puts "Testing migrations <#{human_formatted_versions}>" | |
puts "First step: rolling back each migration and checking the DB schema file." | |
versions.reverse_each do |version| | |
success = system("bundle exec rake db:migrate:down VERSION=#{version}") | |
unless success | |
puts "When rolling back the migration <#{version}>, the command failed." | |
exit 1 | |
end | |
end | |
diff = `git diff #{common_ancestor_sha} -- db/schema.rb` | |
if diff.empty? | |
puts "Rolling back migrations resulted in the same DB schema file as master." | |
else | |
raise <<~MSG | |
When rolling back the migrations <#{human_formatted_versions}>, the DB schema file did not match master. We observed the following differences: | |
#{diff} | |
Please ensure reversing your migrations results in the same db/schema.rb file as master. | |
MSG | |
end | |
puts "Last step: running each migration forwards, and checking the DB schema file and missing annotations." | |
versions.each do |version| | |
success = system("bundle exec rake MISC_TEST=true db:migrate:up VERSION=#{version}") | |
unless success | |
puts "When running migration <#{version}> forward, the command failed." | |
exit 1 | |
end | |
end | |
if `git status --porcelain`.empty? | |
puts "Running migrations forwards resulted in no changes, so your DB schema file is stable and annotations have been checked-in." | |
else | |
raise <<~MSG | |
Running migrations forwards resulted in the following changes: | |
#{`git diff`} | |
Either your DB schema file is not stable (aka if you were to merge this branch to master and another dev pulled your changes and ran migrations, their schema file would differ) or you have not checked in annotations. | |
MSG | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment