From 49f39434c48c6f05ab2037f0f31c9da521401cfb Mon Sep 17 00:00:00 2001 From: David Taylor Date: Wed, 23 Jun 2021 13:31:58 +0100 Subject: [PATCH] DEV: Introduce script/promote_migrations tool Post-deploy migrations exist to allow for seamless Discourse upgrades. By design, they cause migrations to run out of numerical order. This has the potential to cause some unexpected edge cases. To reduce the likelihood of these edge cases, we will promote historical post_deploy migrations to regular migrations after a full Discourse stable release cycle. This script is intended to be run at least during every Discourse release cycle. This means that truly seamless upgrades will not be possible between non-consecutive Discourse versions. (Upgrades will still work, but may cause some server errors for users during the upgrade) --- script/promote_migrations | 97 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100755 script/promote_migrations diff --git a/script/promote_migrations b/script/promote_migrations new file mode 100755 index 00000000000..a76e751bea4 --- /dev/null +++ b/script/promote_migrations @@ -0,0 +1,97 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +# This script will promote post_migrate files +# which have existed for more than one Discourse +# stable version cycle. +# +# Renames will be staged in git, but not committed +# +# Usage: +# script/promote_migrations [--dry-run] [--plugins] + +require 'open3' +require 'fileutils' + +VERSION_REGEX = %r{\/(\d+)_} +DRY_RUN = ARGV.include? '--dry-run' +PLUGINS = ARGV.include? '--plugins' + +def run(*args, capture: true) + out, s = Open3.capture2(*args) + if s.exitstatus != 0 + STDERR.puts "Command failed: '#{args.join(' ')}'" + exit 1 + end + out.strip +end + +current_version = run 'git describe --abbrev=0 --match "v*"' +puts "Current version is #{current_version}" + +run 'git fetch' +current_stable_version = + run 'git describe --abbrev=0 --match "v*" origin/stable' +puts "Current stable version is #{current_stable_version}" + +minor = current_stable_version[/^(v\d+\.\d+)\./, 1] + +previous_stable_version = + run "git describe --abbrev=0 --match 'v*' --exclude '#{minor}*' origin/stable" +puts "Previous stable version is #{previous_stable_version}" + +stable_post_migrate_filenames = + run( + 'git', + 'ls-tree', + '--name-only', + '-r', + previous_stable_version, + 'db/post_migrate' + ).split("\n") + +stable_post_migrate_filenames.sort! +latest_stable_post_migration = stable_post_migrate_filenames.last + +puts "The latest core post_migrate file in #{previous_stable_version} is #{latest_stable_post_migration}" +puts 'Promoting this, and all earlier post_migrates, to regular migrations' + +promote_threshold = latest_stable_post_migration[VERSION_REGEX, 1].to_i +current_post_migrations = + if PLUGINS + puts 'Looking in plugins...' + Dir.glob('plugins/*/db/post_migrate/*') + else + Dir.glob('db/post_migrate/*') + end + +if current_post_migrations.length == 0 + puts 'No post_migrate files found. All done' +end + +current_post_migrations.each do |path| + version = path[VERSION_REGEX, 1].to_i + file = File.basename(path) + dir = File.dirname(path) + + if version <= promote_threshold + print "Promoting #{path}..." + if DRY_RUN + puts ' (dry run)' + else + run 'mkdir', '-p', "#{dir}/../migrate" + run 'git', '-C', dir, 'mv', file, "../migrate/#{file}" + puts ' (done)' + end + end +end + +puts 'Done! File moves are staged and ready for commit.' +puts 'Suggested commit message:' +puts '-' * 20 +puts <<~MESSAGE +DEV: Promote historic post_deploy migrations + +This commit promotes all post_deploy migrations which existed in Discourse #{previous_stable_version} (timestamp <= #{promote_threshold}) +MESSAGE +puts '-' * 20