Skip to content

Commit b3b230c

Browse files
authored
Merge pull request rails#50231 from rails/revert-50205-ac-validate-migration-timestamps
Revert "Add config for validating migration timestamps"
2 parents d6197c5 + 5a09d32 commit b3b230c

File tree

11 files changed

+63
-192
lines changed

11 files changed

+63
-192
lines changed

activerecord/CHANGELOG.md

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,3 @@
1-
* Add `active_record.config.validate_migration_timestamps` option for validating migration timestamps.
2-
3-
When set, validates that the timestamp prefix for a migration is in the form YYYYMMDDHHMMSS.
4-
This is designed to prevent migration timestamps from being modified by hand.
5-
6-
*Adrianna Chang*
7-
81
* When using a `DATABASE_URL`, allow for a configuration to map the protocol in the URL to a specific database
92
adapter. This allows decoupling the adapter the application chooses to use from the database connection details
103
set in the deployment environment.

activerecord/lib/active_record.rb

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -370,14 +370,6 @@ def self.global_executor_concurrency # :nodoc:
370370
singleton_class.attr_accessor :timestamped_migrations
371371
self.timestamped_migrations = true
372372

373-
##
374-
# :singleton-method:
375-
# Specify whether or not to validate migration timestamps. When set, an error
376-
# will be raised if a timestamp is not a valid timestamp in the form
377-
# YYYYMMDDHHMMSS. +timestamped_migrations+ must be set to true.
378-
singleton_class.attr_accessor :validate_migration_timestamps
379-
self.validate_migration_timestamps = false
380-
381373
##
382374
# :singleton-method:
383375
# Specify strategy to use for executing migrations.

activerecord/lib/active_record/migration.rb

Lines changed: 1 addition & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -131,16 +131,6 @@ def initialize(name = nil)
131131
end
132132
end
133133

134-
class InvalidMigrationTimestampError < MigrationError # :nodoc:
135-
def initialize(version = nil, name = nil)
136-
if version && name
137-
super("Invalid timestamp #{version} for migration file: #{name}.\nTimestamp should be in form YYYYMMDDHHMMSS.")
138-
else
139-
super("Invalid timestamp for migration. Timestamp should be in form YYYYMMDDHHMMSS.")
140-
end
141-
end
142-
end
143-
144134
class PendingMigrationError < MigrationError # :nodoc:
145135
include ActiveSupport::ActionableError
146136

@@ -503,11 +493,7 @@ def initialize
503493
#
504494
# 20080717013526_your_migration_name.rb
505495
#
506-
# The prefix is a generation timestamp (in UTC). Timestamps should not be
507-
# modified manually. To validate that migration timestamps adhere to the
508-
# format Active Record expects, you can use the following configuration option:
509-
#
510-
# config.active_record.validate_migration_timestamps = true
496+
# The prefix is a generation timestamp (in UTC).
511497
#
512498
# If you'd prefer to use numeric prefixes, you can turn timestamped migrations
513499
# off by setting:
@@ -1330,9 +1316,6 @@ def migrations # :nodoc:
13301316
migrations = migration_files.map do |file|
13311317
version, name, scope = parse_migration_filename(file)
13321318
raise IllegalMigrationNameError.new(file) unless version
1333-
if validate_timestamp? && !valid_migration_timestamp?(version)
1334-
raise InvalidMigrationTimestampError.new(version, name)
1335-
end
13361319
version = version.to_i
13371320
name = name.camelize
13381321

@@ -1348,9 +1331,6 @@ def migrations_status # :nodoc:
13481331
file_list = migration_files.filter_map do |file|
13491332
version, name, scope = parse_migration_filename(file)
13501333
raise IllegalMigrationNameError.new(file) unless version
1351-
if validate_timestamp? && !valid_migration_timestamp?(version)
1352-
raise InvalidMigrationTimestampError.new(version, name)
1353-
end
13541334
version = schema_migration.normalize_migration_number(version)
13551335
status = db_list.delete(version) ? "up" : "down"
13561336
[status, version, (name + scope).humanize]
@@ -1395,22 +1375,6 @@ def parse_migration_filename(filename)
13951375
File.basename(filename).scan(Migration::MigrationFilenameRegexp).first
13961376
end
13971377

1398-
def validate_timestamp?
1399-
ActiveRecord.timestamped_migrations && ActiveRecord.validate_migration_timestamps
1400-
end
1401-
1402-
def valid_migration_timestamp?(version)
1403-
timestamp = "#{version} UTC"
1404-
timestamp_format = "%Y%m%d%H%M%S %Z"
1405-
time = Time.strptime(timestamp, timestamp_format)
1406-
1407-
# Time.strptime will wrap if a day between 1-31 is specified, even if the day doesn't exist
1408-
# for the given month. Comparing against the original timestamp guards against this.
1409-
time.strftime(timestamp_format) == timestamp
1410-
rescue ArgumentError
1411-
false
1412-
end
1413-
14141378
def move(direction, steps)
14151379
migrator = Migrator.new(direction, migrations, schema_migration, internal_metadata)
14161380

activerecord/test/cases/migration_test.rb

Lines changed: 57 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -1801,103 +1801,75 @@ def test_check_pending_with_stdlib_logger
18011801
def test_unknown_migration_version_should_raise_an_argument_error
18021802
assert_raise(ArgumentError) { ActiveRecord::Migration[1.0] }
18031803
end
1804-
end
1805-
1806-
class MigrationValidationTest < ActiveRecord::TestCase
1807-
def setup
1808-
@verbose_was, ActiveRecord::Migration.verbose = ActiveRecord::Migration.verbose, false
1809-
@schema_migration = ActiveRecord::Base.connection.schema_migration
1810-
@internal_metadata = ActiveRecord::Base.connection.internal_metadata
1811-
@active_record_validate_timestamps_was = ActiveRecord.validate_migration_timestamps
1812-
ActiveRecord.validate_migration_timestamps = true
1813-
ActiveRecord::Base.connection.schema_cache.clear!
1814-
1815-
@migrations_path = MIGRATIONS_ROOT + "/temp"
1816-
@migrator = ActiveRecord::MigrationContext.new(@migrations_path, @schema_migration, @internal_metadata)
1817-
end
18181804

1819-
def teardown
1820-
@schema_migration.create_table
1821-
@schema_migration.delete_all_versions
1822-
ActiveRecord.validate_migration_timestamps = @active_record_validate_timestamps_was
1823-
ActiveRecord::Migration.verbose = @verbose_was
1824-
end
1805+
class MigrationValidationTest < ActiveRecord::TestCase
1806+
def setup
1807+
@verbose_was, ActiveRecord::Migration.verbose = ActiveRecord::Migration.verbose, false
1808+
@schema_migration = ActiveRecord::Base.connection.schema_migration
1809+
@internal_metadata = ActiveRecord::Base.connection.internal_metadata
1810+
ActiveRecord::Base.connection.schema_cache.clear!
18251811

1826-
def test_migration_raises_if_timestamp_not_14_digits
1827-
with_temp_migration_file(@migrations_path, "201801010101010000_test_migration.rb") do
1828-
error = assert_raises(ActiveRecord::InvalidMigrationTimestampError) do
1829-
@migrator.up(201801010101010000)
1830-
end
1831-
assert_match(/Invalid timestamp 201801010101010000 for migration file: test_migration/, error.message)
1812+
@migrations_path = MIGRATIONS_ROOT + "/temp"
1813+
@migrator = ActiveRecord::MigrationContext.new(@migrations_path, @schema_migration, @internal_metadata)
18321814
end
18331815

1834-
with_temp_migration_file(@migrations_path, "201801010_test_migration.rb") do
1835-
error = assert_raises(ActiveRecord::InvalidMigrationTimestampError) do
1836-
@migrator.up(201801010)
1837-
end
1838-
assert_match(/Invalid timestamp 201801010 for migration file: test_migration/, error.message)
1816+
def teardown
1817+
@schema_migration.create_table
1818+
@schema_migration.delete_all_versions
1819+
ActiveRecord::Migration.verbose = @verbose_was
18391820
end
1840-
end
18411821

1842-
def test_migration_raises_if_timestamp_is_invalid_date
1843-
# 2023-15-26 is an invalid date
1844-
with_temp_migration_file(@migrations_path, "20231526101010_test_migration.rb") do
1845-
error = assert_raises(ActiveRecord::InvalidMigrationTimestampError) do
1846-
@migrator.up(20231526101010)
1847-
end
1848-
assert_match(/Invalid timestamp 20231526101010 for migration file: test_migration/, error.message)
1849-
end
1850-
end
1822+
def test_copied_migrations_at_timestamp_boundary_are_valid
1823+
migrations_path_source = MIGRATIONS_ROOT + "/temp_source"
1824+
migrations_path_dest = MIGRATIONS_ROOT + "/temp_dest"
1825+
migrations = ["20180101010101_test_migration.rb", "20180101010102_test_migration_two.rb", "20180101010103_test_migration_three.rb"]
1826+
1827+
with_temp_migration_files(migrations_path_source, migrations) do
1828+
travel_to(Time.utc(2023, 12, 1, 10, 10, 59)) do
1829+
ActiveRecord::Migration.copy(migrations_path_dest, temp: migrations_path_source)
1830+
1831+
assert File.exist?(migrations_path_dest + "/20231201101059_test_migration.temp.rb")
1832+
assert File.exist?(migrations_path_dest + "/20231201101060_test_migration_two.temp.rb")
1833+
assert File.exist?(migrations_path_dest + "/20231201101061_test_migration_three.temp.rb")
1834+
1835+
migrator = ActiveRecord::MigrationContext.new(migrations_path_dest, @schema_migration, @internal_metadata)
1836+
migrator.up(20231201101059)
1837+
migrator.up(20231201101060)
1838+
migrator.up(20231201101061)
18511839

1852-
def test_migration_raises_if_timestamp_is_invalid_day_month_combo
1853-
# 2023-02-31 is an invalid date; 02 and 31 are valid month / days individually,
1854-
# but February 31 does not exist.
1855-
with_temp_migration_file(@migrations_path, "20230231101010_test_migration.rb") do
1856-
error = assert_raises(ActiveRecord::InvalidMigrationTimestampError) do
1857-
@migrator.up(20230231101010)
1840+
assert_equal 20231201101061, migrator.current_version
1841+
assert_not migrator.needs_migration?
1842+
end
18581843
end
1859-
assert_match(/Invalid timestamp 20230231101010 for migration file: test_migration/, error.message)
1844+
ensure
1845+
File.delete(*Dir[migrations_path_dest + "/*.rb"])
1846+
Dir.rmdir(migrations_path_dest) if Dir.exist?(migrations_path_dest)
18601847
end
1861-
end
18621848

1863-
def test_migration_succeeds_despite_invalid_timestamp_if_validate_timestamps_is_false
1864-
validate_migration_timestamps_was = ActiveRecord.validate_migration_timestamps
1865-
ActiveRecord.validate_migration_timestamps = false
1866-
with_temp_migration_file(@migrations_path, "201801010_test_migration.rb") do
1867-
@migrator.up(201801010)
1868-
assert_equal 201801010, @migrator.current_version
1869-
end
1870-
ensure
1871-
ActiveRecord.validate_migration_timestamps = validate_migration_timestamps_was
1872-
end
1849+
private
1850+
def with_temp_migration_files(migrations_dir, filenames)
1851+
Dir.mkdir(migrations_dir) unless Dir.exist?(migrations_dir)
18731852

1874-
def test_migration_succeeds_despite_invalid_timestamp_if_timestamped_migrations_is_false
1875-
timestamped_migrations_was = ActiveRecord.timestamped_migrations
1876-
ActiveRecord.timestamped_migrations = false
1877-
with_temp_migration_file(@migrations_path, "201801010_test_migration.rb") do
1878-
@migrator.up(201801010)
1879-
assert_equal 201801010, @migrator.current_version
1880-
end
1881-
ensure
1882-
ActiveRecord.timestamped_migrations = timestamped_migrations_was
1883-
end
1853+
paths = []
1854+
filenames.each do |filename|
1855+
path = File.join(migrations_dir, filename)
1856+
paths << path
18841857

1885-
private
1886-
def with_temp_migration_file(migrations_dir, filename)
1887-
Dir.mkdir(migrations_dir) unless Dir.exist?(migrations_dir)
1888-
path = File.join(migrations_dir, filename)
1858+
migration_class = filename.match(ActiveRecord::Migration::MigrationFilenameRegexp)[2].camelize
18891859

1890-
File.open(path, "w+") do |file|
1891-
file << <<-MIGRATION
1892-
class TestMigration < ActiveRecord::Migration::Current
1893-
def change; end
1894-
end
1895-
MIGRATION
1896-
end
1860+
File.open(path, "w+") do |file|
1861+
file << <<~MIGRATION
1862+
class #{migration_class} < ActiveRecord::Migration::Current
1863+
def change; end
1864+
end
1865+
MIGRATION
1866+
end
1867+
end
18971868

1898-
yield
1899-
ensure
1900-
File.delete(path) if File.exist?(path)
1901-
Dir.rmdir(migrations_dir) if Dir.exist?(migrations_dir)
1902-
end
1869+
yield
1870+
ensure
1871+
paths.each { |path| File.delete(path) if File.exist?(path) }
1872+
Dir.rmdir(migrations_dir) if Dir.exist?(migrations_dir)
1873+
end
1874+
end
19031875
end

guides/source/configuring.md

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -58,10 +58,6 @@ NOTE: If you need to apply configuration directly to a class, use a [lazy load h
5858

5959
Below are the default values associated with each target version. In cases of conflicting values, newer versions take precedence over older versions.
6060

61-
#### Default Values for Target Version 7.2
62-
63-
- [`config.active_record.validate_migration_timestamps`](#config-active-record-validate-migration-timestamps): `true`
64-
6561
#### Default Values for Target Version 7.1
6662

6763
- [`config.action_dispatch.debug_exception_log_level`](#config-action-dispatch-debug-exception-log-level): `:error`
@@ -1051,17 +1047,6 @@ Specifies if an error should be raised if the order of a query is ignored during
10511047
10521048
Controls whether migrations are numbered with serial integers or with timestamps. The default is `true`, to use timestamps, which are preferred if there are multiple developers working on the same application.
10531049
1054-
#### `config.active_record.validate_migration_timestamps`
1055-
1056-
Controls whether to validate migration timestamps. When set, an error will be raised if a timestamp is not a valid timestamp in the form YYYYMMDDHHMMSS. `config.active_record.timestamped_migrations` must be set to `true`.
1057-
1058-
The default value depends on the `config.load_defaults` target version:
1059-
1060-
| Starting with version | The default value is |
1061-
| --------------------- | -------------------- |
1062-
| (original) | `false` |
1063-
| 7.2 | `true` |
1064-
10651050
#### `config.active_record.db_warnings_action`
10661051
10671052
Controls the action to be taken when a SQL query produces a warning. The following options are available:

railties/lib/rails/application/configuration.rb

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -323,10 +323,6 @@ def load_defaults(target_version)
323323
end
324324
when "7.2"
325325
load_defaults "7.1"
326-
327-
if respond_to?(:active_record)
328-
active_record.validate_migration_timestamps = true
329-
end
330326
else
331327
raise "Unknown version #{target_version.to_s.inspect}"
332328
end

railties/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults_7_2.rb.tt

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,3 @@
88
#
99
# Read the Guide for Upgrading Ruby on Rails for more info on each option.
1010
# https://guides.rubyonrails.org/upgrading_ruby_on_rails.html
11-
12-
###
13-
# Enable validation of migration timestamps. Migration timestamps must be
14-
# in the form YYYYMMDDHHMMSS, or an ActiveRecord::InvalidMigrationTimestampError
15-
# will be raised.
16-
#
17-
# Applications with existing timestamped migrations that do not adhere to the
18-
# expected format can disable validation by setting this config to `false`.
19-
#++
20-
# Rails.application.config.active_record.validate_migration_timestamps = true

railties/test/application/loading_test.rb

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -319,7 +319,6 @@ class User
319319
test "columns migrations also trigger reloading" do
320320
add_to_config <<-RUBY
321321
config.enable_reloading = true
322-
config.active_record.timestamped_migrations = false
323322
RUBY
324323

325324
app_file "config/routes.rb", <<-RUBY

0 commit comments

Comments
 (0)