summaryrefslogtreecommitdiff
path: root/rubocop/cop/migration/versioned_migration_class.rb
diff options
context:
space:
mode:
Diffstat (limited to 'rubocop/cop/migration/versioned_migration_class.rb')
-rw-r--r--rubocop/cop/migration/versioned_migration_class.rb56
1 files changed, 56 insertions, 0 deletions
diff --git a/rubocop/cop/migration/versioned_migration_class.rb b/rubocop/cop/migration/versioned_migration_class.rb
new file mode 100644
index 00000000000..f2e4550c691
--- /dev/null
+++ b/rubocop/cop/migration/versioned_migration_class.rb
@@ -0,0 +1,56 @@
+# frozen_string_literal: true
+
+require_relative '../../migration_helpers'
+
+module RuboCop
+ module Cop
+ module Migration
+ class VersionedMigrationClass < RuboCop::Cop::Cop
+ include MigrationHelpers
+
+ ENFORCED_SINCE = 2021_09_02_00_00_00
+
+ MSG_INHERIT = 'Don\'t inherit from ActiveRecord::Migration but use Gitlab::Database::Migration[1.0] instead. See https://docs.gitlab.com/ee/development/migration_style_guide.html#migration-helpers-and-versioning.'
+ MSG_INCLUDE = 'Don\'t include migration helper modules directly. Inherit from Gitlab::Database::Migration[1.0] instead. See https://docs.gitlab.com/ee/development/migration_style_guide.html#migration-helpers-and-versioning.'
+
+ ACTIVERECORD_MIGRATION_CLASS = 'ActiveRecord::Migration'
+
+ def_node_search :includes_helpers?, <<~PATTERN
+ (send nil? :include
+ (const
+ (const
+ (const nil? :Gitlab) :Database) :MigrationHelpers))
+ PATTERN
+
+ def on_class(node)
+ return unless relevant_migration?(node)
+ return unless activerecord_migration_class?(node)
+
+ add_offense(node, location: :expression, message: MSG_INHERIT)
+ end
+
+ def on_send(node)
+ return unless relevant_migration?(node)
+
+ add_offense(node, location: :expression, message: MSG_INCLUDE) if includes_helpers?(node)
+ end
+
+ private
+
+ def relevant_migration?(node)
+ in_migration?(node) && version(node) >= ENFORCED_SINCE
+ end
+
+ def activerecord_migration_class?(node)
+ superclass(node) == ACTIVERECORD_MIGRATION_CLASS
+ end
+
+ def superclass(class_node)
+ _, *others = class_node.descendants
+
+ others.find { |node| node.const_type? && node&.const_name != 'Types' }&.const_name
+ end
+ end
+ end
+ end
+end