Skip to content

Commit 2c357f0

Browse files
authored
Merge pull request #1383 from koic/intro_migrated_schema_version
Introduce `AllCops: MigratedSchemaVersion` config
2 parents 2671fb4 + 86b7a55 commit 2c357f0

22 files changed

+224
-54
lines changed

README.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,22 @@ gems.locked file to find the version of Rails that has been bound to the
8383
application. If neither of those files exist, RuboCop will use Rails 5.0
8484
as the default.
8585

86+
### `AllCops: MigratedSchemaVersion`
87+
88+
By specifying the `MigratedSchemaVersion` option, migration files that have already been run can be ignored.
89+
When `MigratedSchemaVersion: '20241225000000'` is set, migration files lower than or equal to '20241225000000' will be ignored.
90+
For example, to ignore db/migrate/20241225000000_create_articles.rb and earlier migrations you would configure it the following way:
91+
92+
```yaml
93+
AllCops
94+
MigratedSchemaVersion: '20241225000000'
95+
```
96+
97+
This prevents inspecting schema settings for already applied migration files.
98+
Changing already applied migrations should be avoided because it can lead to the schema getting out of sync
99+
between your local copy and what it actually is in production, depending on when `bin/rails db:migrate` was executed.
100+
If you want to modify your schema to comply with the cops, you should instead create new migrations.
101+
86102
## Rails configuration tip
87103

88104
In Rails 6.1+, add the following `config.generators.after_generate` setting to
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
* [#1383](https://github.com/rubocop/rubocop-rails/pull/1383): Introduce `AllCops: MigratedSchemaVersion` config. ([@koic][])

config/default.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@ AllCops:
2525
# application. If neither of those files exist, RuboCop will use Rails 5.0
2626
# as the default.
2727
TargetRailsVersion: ~
28+
# By specifying `MigratedSchemaVersion` option, migration files that have been migrated can be ignored.
29+
# When `MigratedSchemaVersion: '20241231000000'` is set. Migration files lower than or equal to '20250101000000' will be ignored.
30+
# For example, this is the timestamp in db/migrate/20250101000000_create_articles.rb.
31+
MigratedSchemaVersion: ~
2832

2933
Lint/NumberConversion:
3034
# Add Rails' duration methods to the ignore list for `Lint/NumberConversion`

docs/modules/ROOT/pages/usage.adoc

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,23 @@ gems.locked file to find the version of Rails that has been bound to the
5252
application. If neither of those files exist, RuboCop will use Rails 5.0
5353
as the default.
5454

55+
=== `AllCops: MigratedSchemaVersion`
56+
57+
By specifying the `MigratedSchemaVersion` option, migration files that have already been run can be ignored.
58+
When `MigratedSchemaVersion: '20241225000000'` is set, migration files lower than or equal to '20241225000000' will be ignored.
59+
For example, to ignore db/migrate/20241225000000_create_articles.rb and earlier migrations you would configure it the following way:
60+
61+
[source,yaml]
62+
----
63+
AllCops
64+
MigratedSchemaVersion: '20241225000000'
65+
----
66+
67+
This prevents inspecting schema settings for already applied migration files.
68+
Changing already applied migrations should be avoided because it can lead to the schema getting out of sync
69+
between your local copy and what it actually is in production, depending on when `bin/rails db:migrate` was executed.
70+
If you want to modify your schema to comply with the cops, you should instead create new migrations.
71+
5572
== Rails configuration tip
5673

5774
In Rails 6.1+, add the following `config.generators.after_generate` setting to

lib/rubocop/cop/mixin/migrations_helper.rb

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,35 @@ def in_migration?(node)
2121
migration_class?(class_node)
2222
end
2323
end
24+
25+
# rubocop:disable Style/DocumentDynamicEvalDefinition
26+
%i[on_send on_csend on_block on_numblock on_class].each do |method|
27+
class_eval(<<~RUBY, __FILE__, __LINE__ + 1)
28+
def #{method}(node)
29+
return if already_migrated_file?
30+
31+
super if method(__method__).super_method
32+
end
33+
RUBY
34+
end
35+
# rubocop:enable Style/DocumentDynamicEvalDefinition
36+
37+
private
38+
39+
def already_migrated_file?
40+
return false unless migrated_schema_version
41+
42+
match_data = File.basename(processed_source.file_path).match(/(?<timestamp>\d{14})/)
43+
schema_version = match_data['timestamp'] if match_data
44+
45+
return false unless schema_version
46+
47+
schema_version <= migrated_schema_version.to_s # Ignore applied migration files.
48+
end
49+
50+
def migrated_schema_version
51+
config.for_all_cops.fetch('MigratedSchemaVersion', nil)
52+
end
2453
end
2554
end
2655
end

lib/rubocop/cop/rails/add_column_index.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ module Rails
1919
class AddColumnIndex < Base
2020
extend AutoCorrector
2121
include RangeHelp
22+
prepend MigrationsHelper
2223

2324
MSG = '`add_column` does not accept an `index` key, use `add_index` instead.'
2425
RESTRICT_ON_SEND = %i[add_column].freeze

lib/rubocop/cop/rails/bulk_change_table.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ module Rails
6565
# end
6666
class BulkChangeTable < Base
6767
include DatabaseTypeResolvable
68+
prepend MigrationsHelper
6869

6970
MSG_FOR_CHANGE_TABLE = <<~MSG.chomp
7071
You can combine alter queries using `bulk: true` options.

lib/rubocop/cop/rails/dangerous_column_names.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ module Rails
1414
# # good
1515
# add_column :users, :saved
1616
class DangerousColumnNames < Base # rubocop:disable Metrics/ClassLength
17+
prepend MigrationsHelper
18+
1719
COLUMN_TYPE_METHOD_NAMES = %i[
1820
bigint
1921
binary

lib/rubocop/cop/rails/migration_class_name.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ module Rails
2020
#
2121
class MigrationClassName < Base
2222
extend AutoCorrector
23-
include MigrationsHelper
23+
prepend MigrationsHelper
2424

2525
MSG = 'Replace with `%<camelized_basename>s` that matches the file name.'
2626

lib/rubocop/cop/rails/not_null_column.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ module Rails
4141
# change_column_null :products, :category_id, false
4242
class NotNullColumn < Base
4343
include DatabaseTypeResolvable
44+
prepend MigrationsHelper
4445

4546
MSG = 'Do not add a NOT NULL column without a default value.'
4647
RESTRICT_ON_SEND = %i[add_column add_reference].freeze

0 commit comments

Comments
 (0)