summaryrefslogtreecommitdiff
path: root/rubocop
diff options
context:
space:
mode:
Diffstat (limited to 'rubocop')
-rw-r--r--rubocop/cop/database/multiple_databases.rb3
-rw-r--r--rubocop/cop/gitlab/avoid_feature_get.rb4
-rw-r--r--rubocop/cop/gitlab/mark_used_feature_flags.rb14
-rw-r--r--rubocop/cop/gitlab/namespaced_class.rb59
-rw-r--r--rubocop/cop/migration/background_migration_base_class.rb33
-rw-r--r--rubocop/cop/migration/background_migration_record.rb41
-rw-r--r--rubocop/cop/migration/hash_index.rb53
-rw-r--r--rubocop/cop/migration/migration_record.rb37
-rw-r--r--rubocop/migration_helpers.rb11
9 files changed, 176 insertions, 79 deletions
diff --git a/rubocop/cop/database/multiple_databases.rb b/rubocop/cop/database/multiple_databases.rb
index f20348d9d1f..1ac9bb4473b 100644
--- a/rubocop/cop/database/multiple_databases.rb
+++ b/rubocop/cop/database/multiple_databases.rb
@@ -19,10 +19,11 @@ module RuboCop
ALLOWED_METHODS = %i[
no_touching
+ configurations
].freeze
def_node_matcher :active_record_base_method_is_used?, <<~PATTERN
- (send (const (const nil? :ActiveRecord) :Base) $_)
+ (send (const (const _ :ActiveRecord) :Base) $_)
PATTERN
def on_send(node)
diff --git a/rubocop/cop/gitlab/avoid_feature_get.rb b/rubocop/cop/gitlab/avoid_feature_get.rb
index e36e0b020c0..1bce89268d9 100644
--- a/rubocop/cop/gitlab/avoid_feature_get.rb
+++ b/rubocop/cop/gitlab/avoid_feature_get.rb
@@ -5,8 +5,8 @@ module RuboCop
module Gitlab
# Cop that blacklists the use of `Feature.get`.
class AvoidFeatureGet < RuboCop::Cop::Cop
- MSG = 'Use `Feature.enable/disable` methods instead of `Feature.get`. ' \
- 'See doc/development/testing_guide/best_practices.md#feature-flags-in-tests for more information.'
+ MSG = 'Use `stub_feature_flags` method instead of `Feature.get`. ' \
+ 'See doc/development/feature_flags/index.md#feature-flags-in-tests for more information.'
def_node_matcher :feature_get?, <<~PATTERN
(send (const nil? :Feature) :get ...)
diff --git a/rubocop/cop/gitlab/mark_used_feature_flags.rb b/rubocop/cop/gitlab/mark_used_feature_flags.rb
index 290e62436e2..0bebd7901f3 100644
--- a/rubocop/cop/gitlab/mark_used_feature_flags.rb
+++ b/rubocop/cop/gitlab/mark_used_feature_flags.rb
@@ -43,13 +43,6 @@ module RuboCop
File.expand_path("../../../lib/gitlab/usage_data_counters/known_events/*.yml", __dir__)
].freeze
- DYNAMIC_FEATURE_FLAGS = [
- :usage_data_static_site_editor_commits, # https://gitlab.com/gitlab-org/gitlab/-/issues/284082
- :usage_data_static_site_editor_merge_requests, # https://gitlab.com/gitlab-org/gitlab/-/issues/284083
- :usage_data_users_clicking_license_testing_visiting_external_website, # https://gitlab.com/gitlab-org/gitlab/-/merge_requests/77866
- :usage_data_users_visiting_testing_license_compliance_full_report # https://gitlab.com/gitlab-org/gitlab/-/merge_requests/77866
- ].freeze
-
class << self
# We track feature flags in `on_new_investigation` only once per
# rubocop whole run instead once per file.
@@ -65,7 +58,6 @@ module RuboCop
self.class.feature_flags_already_tracked = true
- track_dynamic_feature_flags!
track_usage_data_counters_known_events!
end
@@ -231,12 +223,6 @@ module RuboCop
# Marking all event's feature flags as used as Gitlab::UsageDataCounters::HLLRedisCounter.track_event{,context}
# is mostly used with dynamic event name.
- def track_dynamic_feature_flags!
- DYNAMIC_FEATURE_FLAGS.each(&method(:save_used_feature_flag))
- end
-
- # Marking all event's feature flags as used as Gitlab::UsageDataCounters::HLLRedisCounter.track_event{,context}
- # is mostly used with dynamic event name.
def track_usage_data_counters_known_events!
usage_data_counters_known_event_feature_flags.each(&method(:save_used_feature_flag))
end
diff --git a/rubocop/cop/gitlab/namespaced_class.rb b/rubocop/cop/gitlab/namespaced_class.rb
index 1f1fd280922..914cc8720b9 100644
--- a/rubocop/cop/gitlab/namespaced_class.rb
+++ b/rubocop/cop/gitlab/namespaced_class.rb
@@ -5,33 +5,76 @@ module RuboCop
module Gitlab
# Cop that enforces use of namespaced classes in order to better identify
# high level domains within the codebase.
-
+ #
# @example
# # bad
# class MyClass
# end
#
+ # module Gitlab
+ # class MyClass
+ # end
+ # end
+ #
+ # class Gitlab::MyClass
+ # end
+ #
# # good
# module MyDomain
# class MyClass
# end
# end
-
+ #
+ # module Gitlab
+ # module MyDomain
+ # class MyClass
+ # end
+ # end
+ # end
+ #
+ # class Gitlab::MyDomain::MyClass
+ # end
class NamespacedClass < RuboCop::Cop::Cop
MSG = 'Classes must be declared inside a module indicating a product domain namespace. For more info: https://gitlab.com/gitlab-org/gitlab/-/issues/212156'
- def_node_matcher :compact_namespaced_class?, <<~PATTERN
- (class (const (const ...) ...) ...)
- PATTERN
+ # These namespaces are considered top-level semantically.
+ # Note: Nested namespace like Foo::Bar are also supported.
+ PSEUDO_TOPLEVEL = %w[Gitlab]
+ .map { _1.split('::') }.freeze
def on_module(node)
- @namespaced = true
+ add_potential_domain_namespace(node)
end
def on_class(node)
- return if @namespaced
+ # Add potential namespaces from compact definitions like `class Foo::Bar`.
+ # Remove class name because it's not a domain namespace.
+ add_potential_domain_namespace(node) { _1.pop }
+
+ add_offense(node) if domain_namespaces.none?
+ end
+
+ private
+
+ def domain_namespaces
+ @domain_namespaces ||= []
+ end
+
+ def add_potential_domain_namespace(node)
+ return if domain_namespaces.any?
+
+ identifiers = identifiers_for(node)
+ yield(identifiers) if block_given?
+
+ PSEUDO_TOPLEVEL.each do |namespaces|
+ identifiers.shift(namespaces.size) if namespaces == identifiers.first(namespaces.size)
+ end
+
+ domain_namespaces.concat(identifiers)
+ end
- add_offense(node) unless compact_namespaced_class?(node)
+ def identifiers_for(node)
+ node.identifier.source.sub(/^::/, '').split('::')
end
end
end
diff --git a/rubocop/cop/migration/background_migration_base_class.rb b/rubocop/cop/migration/background_migration_base_class.rb
new file mode 100644
index 00000000000..50cbe3a69c3
--- /dev/null
+++ b/rubocop/cop/migration/background_migration_base_class.rb
@@ -0,0 +1,33 @@
+# frozen_string_literal: true
+
+module RuboCop
+ module Cop
+ module Migration
+ class BackgroundMigrationBaseClass < RuboCop::Cop::Cop
+ MSG = 'Batched background migration jobs should inherit from Gitlab::BackgroundMigration::BatchedMigrationJob'
+
+ def_node_search :top_level_module?, <<~PATTERN
+ (module (const nil? :Gitlab) (module (const nil? :BackgroundMigration) ...))
+ PATTERN
+
+ def_node_matcher :matching_parent_namespace?, <<~PATTERN
+ {nil? (const (const {cbase nil?} :Gitlab) :BackgroundMigration)}
+ PATTERN
+
+ def_node_search :inherits_batched_migration_job?, <<~PATTERN
+ (class _ (const #matching_parent_namespace? :BatchedMigrationJob) ...)
+ PATTERN
+
+ def on_module(module_node)
+ return unless top_level_module?(module_node)
+
+ top_level_class_node = module_node.each_descendant(:class).first
+
+ return if top_level_class_node.nil? || inherits_batched_migration_job?(top_level_class_node)
+
+ add_offense(top_level_class_node, location: :expression)
+ end
+ end
+ end
+ end
+end
diff --git a/rubocop/cop/migration/background_migration_record.rb b/rubocop/cop/migration/background_migration_record.rb
new file mode 100644
index 00000000000..2ee6b9f7b42
--- /dev/null
+++ b/rubocop/cop/migration/background_migration_record.rb
@@ -0,0 +1,41 @@
+# frozen_string_literal: true
+
+require_relative '../../migration_helpers'
+
+module RuboCop
+ module Cop
+ module Migration
+ class BackgroundMigrationRecord < RuboCop::Cop::Cop
+ include MigrationHelpers
+
+ MSG = <<~MSG
+ Don't use or inherit from ActiveRecord::Base.
+ Use ::ApplicationRecord or ::Ci::ApplicationRecord to ensure the correct database is used.
+ See https://docs.gitlab.com/ee/development/database/batched_background_migrations.html#accessing-data-for-multiple-databases.
+ MSG
+
+ def_node_matcher :inherits_from_active_record_base?, <<~PATTERN
+ (class _ (const (const _ :ActiveRecord) :Base) _)
+ PATTERN
+
+ def_node_search :class_new_active_record_base?, <<~PATTERN
+ (send (const _ :Class) :new (const (const _ :ActiveRecord) :Base) ...)
+ PATTERN
+
+ def on_class(node)
+ return unless in_background_migration?(node)
+ return unless inherits_from_active_record_base?(node)
+
+ add_offense(node, location: :expression)
+ end
+
+ def on_send(node)
+ return unless in_background_migration?(node)
+ return unless class_new_active_record_base?(node)
+
+ add_offense(node, location: :expression)
+ end
+ end
+ end
+ end
+end
diff --git a/rubocop/cop/migration/hash_index.rb b/rubocop/cop/migration/hash_index.rb
deleted file mode 100644
index 8becef891af..00000000000
--- a/rubocop/cop/migration/hash_index.rb
+++ /dev/null
@@ -1,53 +0,0 @@
-# frozen_string_literal: true
-
-require 'set'
-require_relative '../../migration_helpers'
-
-module RuboCop
- module Cop
- module Migration
- # Cop that prevents the use of hash indexes in database migrations
- class HashIndex < RuboCop::Cop::Cop
- include MigrationHelpers
-
- MSG = 'hash indexes should be avoided at all costs since they are not ' \
- 'recorded in the PostgreSQL WAL, you should use a btree index instead'
-
- NAMES = Set.new([:add_index, :index, :add_concurrent_index]).freeze
-
- def on_send(node)
- return unless in_migration?(node)
-
- name = node.children[1]
-
- return unless NAMES.include?(name)
-
- opts = node.children.last
-
- return unless opts && opts.type == :hash
-
- opts.each_node(:pair) do |pair|
- next unless hash_key_type(pair) == :sym &&
- hash_key_name(pair) == :using
-
- if hash_key_value(pair).to_s == 'hash'
- add_offense(pair, location: :expression)
- end
- end
- end
-
- def hash_key_type(pair)
- pair.children[0].type
- end
-
- def hash_key_name(pair)
- pair.children[0].children[0]
- end
-
- def hash_key_value(pair)
- pair.children[1].children[0]
- end
- end
- end
- end
-end
diff --git a/rubocop/cop/migration/migration_record.rb b/rubocop/cop/migration/migration_record.rb
new file mode 100644
index 00000000000..bb81b3cbaf1
--- /dev/null
+++ b/rubocop/cop/migration/migration_record.rb
@@ -0,0 +1,37 @@
+# frozen_string_literal: true
+
+require_relative '../../migration_helpers'
+
+module RuboCop
+ module Cop
+ module Migration
+ class MigrationRecord < RuboCop::Cop::Cop
+ include MigrationHelpers
+
+ ENFORCED_SINCE = 2022_04_26_00_00_00
+
+ MSG = <<~MSG
+ Don't inherit from ActiveRecord::Base but use MigrationRecord instead.
+ See https://docs.gitlab.com/ee/development/database/migrations_for_multiple_databases.html#example-usage-of-activerecord-classes.
+ MSG
+
+ def_node_search :inherits_from_active_record_base?, <<~PATTERN
+ (class _ (const (const _ :ActiveRecord) :Base) _)
+ PATTERN
+
+ def on_class(node)
+ return unless relevant_migration?(node)
+ return unless inherits_from_active_record_base?(node)
+
+ add_offense(node, location: :expression)
+ end
+
+ private
+
+ def relevant_migration?(node)
+ in_migration?(node) && version(node) >= ENFORCED_SINCE
+ end
+ end
+ end
+ end
+end
diff --git a/rubocop/migration_helpers.rb b/rubocop/migration_helpers.rb
index 63b3766e126..f14f4d33709 100644
--- a/rubocop/migration_helpers.rb
+++ b/rubocop/migration_helpers.rb
@@ -32,6 +32,11 @@ module RuboCop
in_deployment_migration?(node) || in_post_deployment_migration?(node)
end
+ def in_background_migration?(node)
+ filepath(node).include?('/lib/gitlab/background_migration/') ||
+ filepath(node).include?('/ee/lib/ee/gitlab/background_migration/')
+ end
+
def in_deployment_migration?(node)
dirname(node).end_with?('db/migrate', 'db/geo/migrate')
end
@@ -56,8 +61,12 @@ module RuboCop
private
+ def filepath(node)
+ node.location.expression.source_buffer.name
+ end
+
def dirname(node)
- File.dirname(node.location.expression.source_buffer.name)
+ File.dirname(filepath(node))
end
def rubocop_migrations_config