Fix `bin/rails db:migrate` with specified `VERSION` #30714
Conversation
r? @eileencodes (@rails-bot has picked a reviewer for you, use r? to override) |
result = execute_migration_in_transaction(migration, @direction) | ||
if invalid_target? | ||
raise UnknownMigrationVersionError.new(@target_version) | ||
end |
eileencodes
Sep 29, 2017
•
Member
What does the error message say for the UnknownMigrationVersionError? I'm wondering if it's user friendly enough like "0.1.1" is an unknown migration number please run with VERSION=123
. I'm concerned about inexperienced users not realizing their VERSION env var is set elsewhere and how to set it for the Rails migrations.
What does the error message say for the UnknownMigrationVersionError? I'm wondering if it's user friendly enough like "0.1.1" is an unknown migration number please run with VERSION=123
. I'm concerned about inexperienced users not realizing their VERSION env var is set elsewhere and how to set it for the Rails migrations.
I think this is fine as a bandaid fix, but I'm not sure whether this is a good long term solution. Think about this usecase:
I worry that this PR instead will completely block migrations without a clear path forward causing a lot of friction in the migration process. |
Thanks, @eileencodes. This PR doesn't fix the issue #30707 (but related to this issue), it just fix our current implementation that we have. Currently, if run Example: $ rails db:migrate:status
Status Migration ID Migration Name
--------------------------------------------------
up 20171005143525 One
up 20171005143538 Two
up 20171005143556 Three
$ rails db:migrate VERSION=1
rails aborted!
ActiveRecord::UnknownMigrationVersionError:
No migration with version number 1.
# There is bug
$ rails db:migrate VERSION=-1
ubuntu@ubuntu-xenial:/active_projects/zz$ rails db:migrate VERSION=-1
== 20171005143556 Three: reverting ============================================
== 20171005143556 Three: reverted (0.4047s) ===================================
== 20171005143538 Two: reverting ==============================================
== 20171005143538 Two: reverted (0.0000s) =====================================
== 20171005143525 One: reverting ==============================================
== 20171005143525 One: reverted (0.0000s) ===================================== After: $ rails db:migrate:status
Status Migration ID Migration Name
--------------------------------------------------
up 20171005143525 One
up 20171005143538 Two
up 20171005143556 Three
$ rails db:migrate VERSION=1
rails aborted!
ActiveRecord::UnknownMigrationVersionError:
No migration with version number 1.
# Fixed
$ rails db:migrate VERSION=-1
rails aborted! About the case:
I think the main reason of the problem in common name of environment variable that we use What do you think about deprecation of using |
Can we validate the supplied version before we call Renaming the variable is not appropriate: unlike the others you mentioned, it's intended to be set on the rake command line; the others are intended to suitable for setting more globally across a session. (And I believe that's the stronger convention in general: the more broadly a variable is visible, the more specifically it should be named.) Naming such a redundant variable on a It would also be an unnecessary stopgap: the ability to pass proper arguments to commands, instead of using ugly env vars, is a large motivation for our ongoing effort to convert rake-based commands to thor. Once we've done We've been using |
If someone does have I haven't checked, but I assume they can run the command with |
@matthewd I think I got your point. I just added the changes that check VERSION. This PR shouldn't break our current implementation that we have and AIUI we can apply new strict behavior(See #30714 (comment)). Could you please review and provide feedback about behavior that this PR provides? If this behavior doesn't fit, I'll try to find another implementation Thank you for the response! |
scope.blank? || scope == migration.scope | ||
end | ||
ActiveRecord::Base.clear_cache! | ||
ensure | ||
Migration.verbose = verbose_was | ||
end | ||
|
||
def check_target_version | ||
if ENV["VERSION"] && ENV["VERSION"].empty? | ||
raise "Empty VERSION provided" |
matthewd
Oct 6, 2017
Member
As I mentioned, I think an empty VERSION should be treated just the same as when it's not set at all, so people can easily override a more widely-set variable. Before we kill it though, can you see any history on why we added the existing emptiness check?
As I mentioned, I think an empty VERSION should be treated just the same as when it's not set at all, so people can easily override a more widely-set variable. Before we kill it though, can you see any history on why we added the existing emptiness check?
bogdanvlviv
Oct 8, 2017
Author
Contributor
Checking for empties of VERSION
is added by #28485 because db:migrate:redo
, db:migrate:up
, db:migrate:down
require VERSION
,
but db:migrate
doesn't require VERSION
, so I think it db:migrate
with empty VERSION
should behave as without VERSION
.
Checking for empties of VERSION
is added by #28485 because db:migrate:redo
, db:migrate:up
, db:migrate:down
require VERSION
,
but db:migrate
doesn't require VERSION
, so I think it db:migrate
with empty VERSION
should behave as without VERSION
.
raise "Empty VERSION provided" | ||
end | ||
|
||
if target_version == 0 && ENV["VERSION"].strip.length != 1 |
matthewd
Oct 6, 2017
Member
This sounds like an overly-special case. 1.2.3
should raise too, even if there's a migration number 1.
This sounds like an overly-special case. 1.2.3
should raise too, even if there's a migration number 1.
|
||
if target_version == 0 && ENV["VERSION"].strip.length != 1 | ||
raise( | ||
"Invalid format of target version: \n\n `VERSION=#{ENV['VERSION']}`" |
matthewd
Oct 6, 2017
Member
I don't think we need the fancy spacing here
I don't think we need the fancy spacing here
@@ -206,6 +278,46 @@ class AMigration < ActiveRecord::Migration::Current | |||
end | |||
end | |||
|
|||
test "raise error on any move when target migration does not exist" do | |||
app_file "db/migrate/01_one_migration.rb", <<-MIGRATION |
matthewd
Oct 6, 2017
Member
I'd like to see a test somewhere (assuming we don't already have one, though I haven't checked) to ensure that VERSION=01_one_migration.rb
will work, even after we make VERSION=1.2
fail.
I'd like to see a test somewhere (assuming we don't already have one, though I haven't checked) to ensure that VERSION=01_one_migration.rb
will work, even after we make VERSION=1.2
fail.
bogdanvlviv
Oct 8, 2017
Author
Contributor
I'd like to see a test somewhere (assuming we don't already have one, though I haven't checked) to ensure that VERSION=01_one_migration.rb will work, even after we make VERSION=1.2 fail.
I just implemented this behavior and added test cases.
I'd like to see a test somewhere (assuming we don't already have one, though I haven't checked) to ensure that VERSION=01_one_migration.rb will work, even after we make VERSION=1.2 fail.
I just implemented this behavior and added test cases.
@matthewd What do you think about current behavior that is implemented by this PR? |
scope.blank? || scope == migration.scope | ||
end | ||
ActiveRecord::Base.clear_cache! | ||
ensure | ||
Migration.verbose = verbose_was | ||
end | ||
|
||
def check_target_version | ||
if target_version && !(Migration::MigrationFilenameRegexp.match?(ENV["VERSION"]) || /\A\d+\z/.match?(ENV["VERSION"])) |
let me know if there is something i should to do. |
Could you please provide any feedback about this PR? |
end | ||
|
||
def target_version | ||
return ENV["VERSION"].to_i if ENV["VERSION"] && !ENV["VERSION"].empty? |
rafaelfranca
Nov 6, 2017
Member
✂️ the return
return
bogdanvlviv
Nov 6, 2017
Author
Contributor
fixed
fixed
Ensure that `bin/rails db:migrate` with specified `VERSION` reverts all migrations only if `VERSION` is `0`. Raise error if target migration doesn't exist.
Fix
bin/rails db:migrate
with specifiedVERSION
.bin/rails db:migrate
with empty VERSION behaves as withoutVERSION
.Check a format of
VERSION
: Allow a migration version numberor name of a migration file. Raise error if format of
VERSION
is invalid.Raise error if target migration doesn't exist.
Related to #30707
/cc @matthewd