Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2023-07-19 17:16:28 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2023-07-19 17:16:28 +0300
commite4384360a16dd9a19d4d2d25d0ef1f2b862ed2a6 (patch)
tree2fcdfa7dcdb9db8f5208b2562f4b4e803d671243 /rubocop
parentffda4e7bcac36987f936b4ba515995a6698698f0 (diff)
Add latest changes from gitlab-org/gitlab@16-2-stable-eev16.2.0-rc42
Diffstat (limited to 'rubocop')
-rw-r--r--rubocop/cop/active_record_association_reload.rb2
-rw-r--r--rubocop/cop/avoid_becomes.rb2
-rw-r--r--rubocop/cop/avoid_keyword_arguments_in_sidekiq_workers.rb2
-rw-r--r--rubocop/cop/avoid_return_from_blocks.rb8
-rw-r--r--rubocop/cop/background_migration/avoid_silent_rescue_exceptions.rb84
-rw-r--r--rubocop/cop/background_migration/feature_category.rb2
-rw-r--r--rubocop/cop/default_scope.rb2
-rw-r--r--rubocop/cop/destroy_all.rb2
-rw-r--r--rubocop/cop/gitlab/doc_url.rb2
-rw-r--r--rubocop/cop/gitlab/finder_with_find_by.rb2
-rw-r--r--rubocop/cop/gitlab/strong_memoize_attr.rb15
-rw-r--r--rubocop/cop/graphql/gid_expected_type.rb21
-rw-r--r--rubocop/cop/graphql/id_type.rb4
-rw-r--r--rubocop/cop/group_public_or_visible_to_user.rb2
-rw-r--r--rubocop/cop/ignored_columns.rb4
-rw-r--r--rubocop/cop/inject_enterprise_edition_module.rb6
-rw-r--r--rubocop/cop/migration/add_columns_to_wide_tables.rb4
-rw-r--r--rubocop/cop/migration/avoid_finalize_background_migration.rb23
-rw-r--r--rubocop/cop/project_path_helper.rb4
-rw-r--r--rubocop/cop/qa/selector_usage.rb4
-rw-r--r--rubocop/cop/rake/require.rb10
-rw-r--r--rubocop/cop/rspec/before_all_role_assignment.rb77
-rw-r--r--rubocop/cop/rspec/factory_bot/strategy_in_callback.rb2
-rw-r--r--rubocop/cop/search/avoid_checking_finished_on_deprecated_migrations.rb38
-rw-r--r--rubocop/cop/usage_data/distinct_count_by_large_foreign_key.rb6
-rw-r--r--rubocop/cop/usage_data/histogram_with_large_table.rb6
-rw-r--r--rubocop/cop/usage_data/instrumentation_superclass.rb8
-rw-r--r--rubocop/cop/usage_data/large_table.rb6
-rw-r--r--rubocop/cop_todo.rb4
-rw-r--r--rubocop/formatter/todo_formatter.rb19
-rw-r--r--rubocop/rubocop-code_reuse.yml1
-rw-r--r--rubocop/rubocop-usage-data.yml12
-rw-r--r--rubocop/usage_data_helpers.rb19
33 files changed, 335 insertions, 68 deletions
diff --git a/rubocop/cop/active_record_association_reload.rb b/rubocop/cop/active_record_association_reload.rb
index 9a1e9674904..758d5de348c 100644
--- a/rubocop/cop/active_record_association_reload.rb
+++ b/rubocop/cop/active_record_association_reload.rb
@@ -2,7 +2,7 @@
module RuboCop
module Cop
- # Cop that blacklists the use of `reload`.
+ # Cop that denylists the use of `reload`.
class ActiveRecordAssociationReload < RuboCop::Cop::Base
MSG = 'Use reset instead of reload. ' \
'For more details check the https://gitlab.com/gitlab-org/gitlab-foss/issues/60218.'
diff --git a/rubocop/cop/avoid_becomes.rb b/rubocop/cop/avoid_becomes.rb
index 20df394c32c..9ef623e6360 100644
--- a/rubocop/cop/avoid_becomes.rb
+++ b/rubocop/cop/avoid_becomes.rb
@@ -2,7 +2,7 @@
module RuboCop
module Cop
- # Cop that blacklists the use of ".becomes(SomeConstant)".
+ # Cop that denylists the use of ".becomes(SomeConstant)".
#
# The use of becomes() will result in a new object being created, throwing
# away any eager loaded assocations. This in turn can cause N+1 query
diff --git a/rubocop/cop/avoid_keyword_arguments_in_sidekiq_workers.rb b/rubocop/cop/avoid_keyword_arguments_in_sidekiq_workers.rb
index ea7cdd5bf9d..78e405cf0cc 100644
--- a/rubocop/cop/avoid_keyword_arguments_in_sidekiq_workers.rb
+++ b/rubocop/cop/avoid_keyword_arguments_in_sidekiq_workers.rb
@@ -2,7 +2,7 @@
module RuboCop
module Cop
- # Cop that blacklists keyword arguments usage in Sidekiq workers
+ # Cop that denylists keyword arguments usage in Sidekiq workers
class AvoidKeywordArgumentsInSidekiqWorkers < RuboCop::Cop::Base
MSG = "Do not use keyword arguments in Sidekiq workers. " \
"For details, check https://github.com/mperham/sidekiq/issues/2372"
diff --git a/rubocop/cop/avoid_return_from_blocks.rb b/rubocop/cop/avoid_return_from_blocks.rb
index c6a7a87c548..bc10410af1d 100644
--- a/rubocop/cop/avoid_return_from_blocks.rb
+++ b/rubocop/cop/avoid_return_from_blocks.rb
@@ -23,7 +23,7 @@ module RuboCop
class AvoidReturnFromBlocks < RuboCop::Cop::Base
MSG = 'Do not return from a block, use next or break instead.'
DEF_METHODS = %i[define_method lambda].freeze
- WHITELISTED_METHODS = %i[each each_filename times loop].freeze
+ ALLOWLISTED_METHODS = %i[each each_filename times loop].freeze
def on_block(node)
block_body = node.body
@@ -32,7 +32,7 @@ module RuboCop
return unless top_block?(node)
block_body.each_node(:return) do |return_node|
- next if parent_blocks(node, return_node).all? { |block_node| whitelisted?(block_node) }
+ next if parent_blocks(node, return_node).all? { |block_node| allowlisted?(block_node) }
add_offense(return_node)
end
@@ -69,8 +69,8 @@ module RuboCop
(node.type == :block && DEF_METHODS.include?(node.method_name))
end
- def whitelisted?(block_node)
- WHITELISTED_METHODS.include?(block_node.method_name)
+ def allowlisted?(block_node)
+ ALLOWLISTED_METHODS.include?(block_node.method_name)
end
end
end
diff --git a/rubocop/cop/background_migration/avoid_silent_rescue_exceptions.rb b/rubocop/cop/background_migration/avoid_silent_rescue_exceptions.rb
new file mode 100644
index 00000000000..0bd5c587205
--- /dev/null
+++ b/rubocop/cop/background_migration/avoid_silent_rescue_exceptions.rb
@@ -0,0 +1,84 @@
+# frozen_string_literal: true
+
+module RuboCop
+ module Cop
+ module BackgroundMigration
+ # Checks for rescuing errors inside Batched Background Migration Job Classes.
+ #
+ # @example
+ #
+ # # bad
+ # def perform
+ # do_something
+ # rescue StandardError => error
+ # logger.error(error.message)
+ # end
+ #
+ # # bad
+ # def perform
+ # do_something
+ # rescue JSON::ParserError, ActiveRecord::StatementTimeout => error
+ # logger.error(error.message)
+ # end
+ #
+ # # good
+ # def perform
+ # do_something
+ # rescue StandardError => error
+ # logger.error(error.message)
+ #
+ # raise
+ # end
+ #
+ # # good
+ # def perform
+ # do_something
+ # rescue JSON::ParserError, ActiveRecord::StatementTimeout => error
+ # logger.error(error.message)
+ #
+ # raise MyCustomException
+ # end
+ class AvoidSilentRescueExceptions < RuboCop::Cop::Base
+ MSG = 'Avoid rescuing exceptions inside job classes. See ' \
+ 'https://docs.gitlab.com/ee/development/database/batched_background_migrations.html#best-practices'
+
+ def_node_matcher :batched_migration_job_class?, <<~PATTERN
+ (class
+ const
+ (const {nil? cbase const} :BatchedMigrationJob)
+ ...
+ )
+ PATTERN
+
+ # Matches rescued exceptions that were not re-raised
+ #
+ # @example
+ # rescue => error
+ # rescue Exception => error
+ # rescue JSON::ParserError => e
+ # rescue ActiveRecord::StatementTimeout => error
+ # rescue ActiveRecord::StatementTimeout, ActiveRecord::QueryCanceled => error
+ def_node_matcher :rescue_timeout_error, <<~PATTERN
+ (resbody $_ _ (... !(send nil? :raise ...)))
+ PATTERN
+
+ def on_class(node)
+ @batched_migration_job_class ||= batched_migration_job_class?(node)
+ end
+
+ def on_resbody(node)
+ return unless batched_migration_job_class
+
+ rescue_timeout_error(node) do |error|
+ range = error ? node.loc.keyword.join(error.loc.expression) : node.loc.keyword
+ add_offense(range)
+ end
+ end
+
+ private
+
+ attr_reader :batched_migration_job_class
+ end
+ end
+ end
+end
diff --git a/rubocop/cop/background_migration/feature_category.rb b/rubocop/cop/background_migration/feature_category.rb
index c6611a65e49..f6b68e03736 100644
--- a/rubocop/cop/background_migration/feature_category.rb
+++ b/rubocop/cop/background_migration/feature_category.rb
@@ -10,7 +10,7 @@ module RuboCop
class FeatureCategory < RuboCop::Cop::Base
include MigrationHelpers
- FEATURE_CATEGORIES_FILE_PATH = "config/feature_categories.yml"
+ FEATURE_CATEGORIES_FILE_PATH = File.expand_path("../../../config/feature_categories.yml", __dir__)
MSG = "'feature_category' should be defined to better assign the ownership for batched migration jobs. " \
"For more details refer: " \
diff --git a/rubocop/cop/default_scope.rb b/rubocop/cop/default_scope.rb
index 930a69be881..1656c0b1569 100644
--- a/rubocop/cop/default_scope.rb
+++ b/rubocop/cop/default_scope.rb
@@ -2,7 +2,7 @@
module RuboCop
module Cop
- # Cop that blacklists the use of `default_scope`.
+ # Cop that denylists the use of `default_scope`.
class DefaultScope < RuboCop::Cop::Base
MSG = <<~EOF
Do not use `default_scope`, as it does not follow the principle of
diff --git a/rubocop/cop/destroy_all.rb b/rubocop/cop/destroy_all.rb
index 78e5d0f25f3..55c0bc93d43 100644
--- a/rubocop/cop/destroy_all.rb
+++ b/rubocop/cop/destroy_all.rb
@@ -2,7 +2,7 @@
module RuboCop
module Cop
- # Cop that blacklists the use of `destroy_all`.
+ # Cop that denylists the use of `destroy_all`.
class DestroyAll < RuboCop::Cop::Base
MSG = 'Use `delete_all` instead of `destroy_all`. ' \
'`destroy_all` will load the rows into memory, then execute a ' \
diff --git a/rubocop/cop/gitlab/doc_url.rb b/rubocop/cop/gitlab/doc_url.rb
index cbfbdf7eb57..41a1c2f8b36 100644
--- a/rubocop/cop/gitlab/doc_url.rb
+++ b/rubocop/cop/gitlab/doc_url.rb
@@ -21,7 +21,7 @@ module RuboCop
MSG = 'Use `#help_page_url` instead of directly including link. ' \
'See https://docs.gitlab.com/ee/development/documentation/#linking-to-help-in-ruby.'
- DOCS_URL_REGEXP = %r{https://docs.gitlab.com/ee/[\w#%./-]+}.freeze
+ DOCS_URL_REGEXP = %r{https://docs.gitlab.com/ee/[\w#%./-]+}
def on_str(node)
match = DOCS_URL_REGEXP.match(node.source)
diff --git a/rubocop/cop/gitlab/finder_with_find_by.rb b/rubocop/cop/gitlab/finder_with_find_by.rb
index ac454398f9c..e6d190e4476 100644
--- a/rubocop/cop/gitlab/finder_with_find_by.rb
+++ b/rubocop/cop/gitlab/finder_with_find_by.rb
@@ -6,7 +6,7 @@ module RuboCop
class FinderWithFindBy < RuboCop::Cop::Base
extend RuboCop::Cop::AutoCorrector
- FIND_PATTERN = /\Afind(_by!?)?\z/.freeze
+ FIND_PATTERN = /\Afind(_by!?)?\z/
ALLOWED_MODULES = ['FinderMethods'].freeze
def message(used_method)
diff --git a/rubocop/cop/gitlab/strong_memoize_attr.rb b/rubocop/cop/gitlab/strong_memoize_attr.rb
index 0b3de9d7863..0de581f8ccd 100644
--- a/rubocop/cop/gitlab/strong_memoize_attr.rb
+++ b/rubocop/cop/gitlab/strong_memoize_attr.rb
@@ -34,11 +34,13 @@ module RuboCop
class StrongMemoizeAttr < RuboCop::Cop::Base
extend RuboCop::Cop::AutoCorrector
- MSG = 'Use `strong_memoize_attr`, instead of using `strong_memoize` directly.'
+ STRONG_MEMOIZE_MSG = 'Use `strong_memoize_attr`, instead of using `strong_memoize` directly.'
+ STRONG_MEMOIZE_WITH_MSG =
+ 'Use `strong_memoize_attr`, instead of using `strong_memoize_with` without parameters.'
def_node_matcher :strong_memoize?, <<~PATTERN
(block
- $(send nil? :strong_memoize
+ $(send nil? {:strong_memoize | :strong_memoize_with}
(sym _)
)
(args)
@@ -58,7 +60,14 @@ module RuboCop
corrector = autocorrect_pure_definitions(node.parent, body) if node.parent.def_type?
- add_offense(send_node, &corrector)
+ message = case send_node.method_name
+ when :strong_memoize
+ STRONG_MEMOIZE_MSG
+ when :strong_memoize_with
+ STRONG_MEMOIZE_WITH_MSG
+ end
+
+ add_offense(send_node, message: message, &corrector)
end
private
diff --git a/rubocop/cop/graphql/gid_expected_type.rb b/rubocop/cop/graphql/gid_expected_type.rb
deleted file mode 100644
index 7e802e6d2db..00000000000
--- a/rubocop/cop/graphql/gid_expected_type.rb
+++ /dev/null
@@ -1,21 +0,0 @@
-# frozen_string_literal: true
-
-module RuboCop
- module Cop
- module Graphql
- class GIDExpectedType < RuboCop::Cop::Base
- MSG = 'Add an expected_type parameter to #object_from_id calls if possible.'
-
- def_node_search :id_from_object?, <<~PATTERN
- (send ... :object_from_id (...))
- PATTERN
-
- def on_send(node)
- return unless id_from_object?(node)
-
- add_offense(node)
- end
- end
- end
- end
-end
diff --git a/rubocop/cop/graphql/id_type.rb b/rubocop/cop/graphql/id_type.rb
index c9d9b4ea6eb..53d79751fa8 100644
--- a/rubocop/cop/graphql/id_type.rb
+++ b/rubocop/cop/graphql/id_type.rb
@@ -6,7 +6,7 @@ module RuboCop
class IDType < RuboCop::Cop::Base
MSG = 'Do not use GraphQL::Types::ID, use a specific GlobalIDType instead'
- WHITELISTED_ARGUMENTS = %i[iid full_path project_path group_path target_project_path namespace_path].freeze
+ ALLOWLISTED_ARGUMENTS = %i[iid full_path project_path group_path target_project_path namespace_path].freeze
def_node_search :graphql_id_type?, <<~PATTERN
(send nil? :argument (_ #does_not_match?) (const (const (const nil? :GraphQL) :Types) :ID) ...)
@@ -21,7 +21,7 @@ module RuboCop
private
def does_not_match?(arg)
- !WHITELISTED_ARGUMENTS.include?(arg) # rubocop:disable Rails/NegateInclude
+ !ALLOWLISTED_ARGUMENTS.include?(arg) # rubocop:disable Rails/NegateInclude
end
end
end
diff --git a/rubocop/cop/group_public_or_visible_to_user.rb b/rubocop/cop/group_public_or_visible_to_user.rb
index d3aa230680b..2038bd6f4f6 100644
--- a/rubocop/cop/group_public_or_visible_to_user.rb
+++ b/rubocop/cop/group_public_or_visible_to_user.rb
@@ -2,7 +2,7 @@
#
module RuboCop
module Cop
- # Cop that blacklists the usage of Group.public_or_visible_to_user
+ # Cop that denylists the usage of Group.public_or_visible_to_user
class GroupPublicOrVisibleToUser < RuboCop::Cop::Base
MSG = '`Group.public_or_visible_to_user` should be used with extreme care. ' \
'Please ensure that you are not using it on its own and that the amount ' \
diff --git a/rubocop/cop/ignored_columns.rb b/rubocop/cop/ignored_columns.rb
index 8b17447c46b..86ab8df6927 100644
--- a/rubocop/cop/ignored_columns.rb
+++ b/rubocop/cop/ignored_columns.rb
@@ -19,8 +19,8 @@ module RuboCop
# ignore_column :full_name, remove_after: '2023-05-22', remove_with: '16.0'
# end
class IgnoredColumns < RuboCop::Cop::Base
- USE_CONCERN_ADD_MSG = 'Use `IgnoredColumns` concern instead of adding to `self.ignored_columns`.'
- USE_CONCERN_SET_MSG = 'Use `IgnoredColumns` concern instead of setting `self.ignored_columns`.'
+ USE_CONCERN_ADD_MSG = 'Use `IgnorableColumns` concern instead of adding to `self.ignored_columns`.'
+ USE_CONCERN_SET_MSG = 'Use `IgnorableColumns` concern instead of setting `self.ignored_columns`.'
WRONG_MODEL_MSG = <<~MSG
If the model exists in CE and EE, the column has to be ignored
in the CE model. If the model only exists in EE, then it has to be added there.
diff --git a/rubocop/cop/inject_enterprise_edition_module.rb b/rubocop/cop/inject_enterprise_edition_module.rb
index 7e3c44cc5fd..24b679e092d 100644
--- a/rubocop/cop/inject_enterprise_edition_module.rb
+++ b/rubocop/cop/inject_enterprise_edition_module.rb
@@ -2,7 +2,7 @@
module RuboCop
module Cop
- # Cop that blacklists the injecting of extension specific modules before any lines which are not already injecting another module.
+ # Cop that denylists the injecting of extension specific modules before any lines which are not already injecting another module.
# It allows multiple module injections as long as they're all at the end.
class InjectEnterpriseEditionModule < RuboCop::Cop::Base
extend RuboCop::Cop::AutoCorrector
@@ -20,7 +20,7 @@ module RuboCop
DISALLOW_METHODS = Set.new(%i[include extend prepend]).freeze
- COMMENT_OR_EMPTY_LINE = /^\s*(#.*|$)/.freeze
+ COMMENT_OR_EMPTY_LINE = /^\s*(#.*|$)/
CHECK_LINE_METHODS_REGEXP = Regexp.union((CHECK_LINE_METHODS + DISALLOW_METHODS).map(&:to_s) + [COMMENT_OR_EMPTY_LINE]).freeze
@@ -80,7 +80,7 @@ module RuboCop
# Automatically correcting these offenses is not always possible, as
# sometimes code needs to be refactored to make this work. As such, we
- # only allow developers to easily blacklist existing offenses.
+ # only allow developers to easily denylist existing offenses.
def corrector(node)
lambda do |corrector|
corrector.insert_after(
diff --git a/rubocop/cop/migration/add_columns_to_wide_tables.rb b/rubocop/cop/migration/add_columns_to_wide_tables.rb
index 98dd605faef..ba53177b5d5 100644
--- a/rubocop/cop/migration/add_columns_to_wide_tables.rb
+++ b/rubocop/cop/migration/add_columns_to_wide_tables.rb
@@ -12,7 +12,7 @@ module RuboCop
MSG = '`%s` is a wide table with several columns, adding more should be avoided unless absolutely necessary.' \
' Consider storing the column in a different table or creating a new one.'
- BLACKLISTED_METHODS = %i[
+ DENYLISTED_METHODS = %i[
add_column
add_reference
add_timestamps_with_timezone
@@ -33,7 +33,7 @@ module RuboCop
def offense?(method_name, table_name)
wide_table?(table_name) &&
- BLACKLISTED_METHODS.include?(method_name)
+ DENYLISTED_METHODS.include?(method_name)
end
def wide_table?(table_name)
diff --git a/rubocop/cop/migration/avoid_finalize_background_migration.rb b/rubocop/cop/migration/avoid_finalize_background_migration.rb
new file mode 100644
index 00000000000..42e6e72a330
--- /dev/null
+++ b/rubocop/cop/migration/avoid_finalize_background_migration.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+require_relative '../../migration_helpers'
+
+module RuboCop
+ module Cop
+ module Migration
+ class AvoidFinalizeBackgroundMigration < RuboCop::Cop::Base
+ include MigrationHelpers
+
+ RESTRICT_ON_SEND = [:finalize_background_migration].freeze
+
+ MSG = 'Prefer `ensure_batched_background_migration_is_finished` over ' \
+ '`finalize_background_migration` in Batched Background Migrations. ' \
+ 'See https://docs.gitlab.com/ee/development/database/batched_background_migrations.html'
+
+ def on_send(node)
+ add_offense(node)
+ end
+ end
+ end
+ end
+end
diff --git a/rubocop/cop/project_path_helper.rb b/rubocop/cop/project_path_helper.rb
index 104a352949f..fdf452ccbae 100644
--- a/rubocop/cop/project_path_helper.rb
+++ b/rubocop/cop/project_path_helper.rb
@@ -9,10 +9,10 @@ module RuboCop
'`foo_project_bar_path(project, bar)` instead of ' \
'`foo_namespace_project_bar_path(project.namespace, project, bar)`.'
- METHOD_NAME_PATTERN = /\A([a-z_]+_)?namespace_project(?:_[a-z_]+)?_(?:url|path)\z/.freeze
+ METHOD_NAME_PATTERN = /\A([a-z_]+_)?namespace_project(?:_[a-z_]+)?_(?:url|path)\z/
def on_send(node)
- return unless method_name(node).to_s =~ METHOD_NAME_PATTERN
+ return unless METHOD_NAME_PATTERN.match?(method_name(node).to_s)
namespace_expr, project_expr = arguments(node)
return unless namespace_expr && project_expr
diff --git a/rubocop/cop/qa/selector_usage.rb b/rubocop/cop/qa/selector_usage.rb
index d615bd2926c..331c2c8a18b 100644
--- a/rubocop/cop/qa/selector_usage.rb
+++ b/rubocop/cop/qa/selector_usage.rb
@@ -20,14 +20,14 @@ module RuboCop
include QAHelpers
include CodeReuseHelpers
- SELECTORS = /\.qa-\w+|data-qa-\w+/.freeze
+ SELECTORS = /\.qa-\w+|data-qa-\w+/
MESSAGE = %(Do not use `%s` as this is reserved for the end-to-end specs. Use a different selector or a data-testid instead.)
def on_str(node)
return if in_qa_file?(node)
return unless in_spec?(node)
- add_offense(node, message: MESSAGE % node.value) if SELECTORS =~ node.value
+ add_offense(node, message: MESSAGE % node.value) if SELECTORS.match?(node.value)
rescue StandardError
# catch all errors and ignore them.
# without this catch-all rescue, rubocop will fail
diff --git a/rubocop/cop/rake/require.rb b/rubocop/cop/rake/require.rb
index e3e1696943d..eff0d45fe19 100644
--- a/rubocop/cop/rake/require.rb
+++ b/rubocop/cop/rake/require.rb
@@ -59,6 +59,8 @@ module RuboCop
PATTERN
def on_send(node)
+ return unless in_rake_file?(node)
+
method, file = require_method(node)
return unless method
@@ -70,6 +72,14 @@ module RuboCop
private
+ def in_rake_file?(node)
+ File.extname(filepath(node)) == '.rake'
+ end
+
+ def filepath(node)
+ node.location.expression.source_buffer.name
+ end
+
# Allow `require "foo/rake_task"`
def requires_task?(file)
file.source.include?('task')
diff --git a/rubocop/cop/rspec/before_all_role_assignment.rb b/rubocop/cop/rspec/before_all_role_assignment.rb
new file mode 100644
index 00000000000..fc7fdf4208a
--- /dev/null
+++ b/rubocop/cop/rspec/before_all_role_assignment.rb
@@ -0,0 +1,77 @@
+# frozen_string_literal: true
+
+require 'rubocop-rspec'
+
+module Rubocop
+ module Cop
+ module RSpec
+ # Checks for let_it_be with before instead of before_all when using `add_*` methods
+ #
+ # @example
+ #
+ # # bad
+ # let_it_be(:project) { create(:project) }
+ # let_it_be(:guest) { create(:user) }
+ #
+ # before do
+ # project.add_guest(guest)
+ # end
+ #
+ # # good
+ # let_it_be(:project) { create(:project) }
+ # let_it_be(:guest) { create(:user) }
+ #
+ # before_all do
+ # project.add_guest(guest)
+ # end
+ class BeforeAllRoleAssignment < RuboCop::Cop::RSpec::Base
+ MSG = "Use `before_all` when used with `%{let_it_be}`."
+
+ ROLE_METHODS = %i[add_guest add_reporter add_developer add_maintainer add_owner add_role].to_set.freeze
+
+ RESTRICT_ON_SEND = ROLE_METHODS
+
+ # @!method matching_let_it_be(node)
+ def_node_matcher :matching_let_it_be, <<~PATTERN
+ (block (send nil? $/^let_it_be/ (sym %name)) ...)
+ PATTERN
+
+ # @!method before_block?(node)
+ def_node_matcher :before_block?, <<~PATTERN
+ (block (send nil? :before ...) ...)
+ PATTERN
+
+ def_node_matcher :object_calling_add_role_method, <<~PATTERN
+ (send (send nil? $_) %ROLE_METHODS ...)
+ PATTERN
+
+ def on_send(node)
+ object_calling_add_role = object_calling_add_role_method(node)
+ return unless object_calling_add_role
+
+ before_block = before_block_ancestor(node)
+ return unless before_block
+
+ each_block_node_in_ancestor(node) do |child_node|
+ matching_let_it_be(child_node, name: object_calling_add_role) do |let_it_be|
+ message = format(MSG, let_it_be: let_it_be)
+ add_offense(node, message: message)
+ end
+ end
+ end
+
+ private
+
+ def before_block_ancestor(node)
+ node.each_ancestor(:block).find { |block_node| before_block?(block_node) }
+ end
+
+ def each_block_node_in_ancestor(node, &block)
+ node.each_ancestor do |parent_node|
+ parent_node.each_child_node(:block, &block)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/rubocop/cop/rspec/factory_bot/strategy_in_callback.rb b/rubocop/cop/rspec/factory_bot/strategy_in_callback.rb
index 3153d54887e..534a145b13a 100644
--- a/rubocop/cop/rspec/factory_bot/strategy_in_callback.rb
+++ b/rubocop/cop/rspec/factory_bot/strategy_in_callback.rb
@@ -7,7 +7,7 @@ module RuboCop
module RSpec
module FactoryBot
class StrategyInCallback < RuboCop::Cop::Base
- include RuboCop::RSpec::FactoryBot::Language
+ include RuboCop::FactoryBot::Language
MSG = 'Prefer inline `association` over `%{type}`. ' \
'See https://docs.gitlab.com/ee/development/testing_guide/best_practices.html#factories'
diff --git a/rubocop/cop/search/avoid_checking_finished_on_deprecated_migrations.rb b/rubocop/cop/search/avoid_checking_finished_on_deprecated_migrations.rb
new file mode 100644
index 00000000000..0a6813d4bba
--- /dev/null
+++ b/rubocop/cop/search/avoid_checking_finished_on_deprecated_migrations.rb
@@ -0,0 +1,38 @@
+# frozen_string_literal: true
+
+module RuboCop
+ module Cop
+ module Search
+ # Cop that prevents checking migration_has_finished? on deprecated migrations
+ #
+ # @example
+ #
+ # # bad
+ # def disable_project_joins_for_blob?
+ # Elastic::DataMigrationService
+ # .migration_has_finished?(:backfill_project_permissions_in_blobs_using_permutations)
+ # end
+ #
+ # # good
+ # def disable_project_joins_for_blob?
+ # Elastic::DataMigrationService.migration_has_finished?(:backfill_project_permissions_in_blobs)
+ # end
+
+ class AvoidCheckingFinishedOnDeprecatedMigrations < RuboCop::Cop::Base
+ MSG = 'Migration is deprecated and can not be used with `migration_has_finished?`.'
+
+ def_node_matcher :deprecated_migration?, <<~PATTERN
+ (send
+ (const (const {nil? cbase} :Elastic) :DataMigrationService) :migration_has_finished?
+ (sym :backfill_project_permissions_in_blobs_using_permutations))
+ PATTERN
+
+ RESTRICT_ON_SEND = %i[migration_has_finished?].freeze
+
+ def on_send(node)
+ add_offense(node) if deprecated_migration?(node)
+ end
+ end
+ end
+ end
+end
diff --git a/rubocop/cop/usage_data/distinct_count_by_large_foreign_key.rb b/rubocop/cop/usage_data/distinct_count_by_large_foreign_key.rb
index a083318288b..19f6e393e1f 100644
--- a/rubocop/cop/usage_data/distinct_count_by_large_foreign_key.rb
+++ b/rubocop/cop/usage_data/distinct_count_by_large_foreign_key.rb
@@ -1,5 +1,7 @@
# frozen_string_literal: true
+require_relative '../../usage_data_helpers'
+
module RuboCop
module Cop
module UsageData
@@ -13,6 +15,8 @@ module RuboCop
# distinct_count(Ci::Build, :commit_id)
#
class DistinctCountByLargeForeignKey < RuboCop::Cop::Base
+ include UsageDataHelpers
+
MSG = 'Avoid doing `%s` on foreign keys for large tables having above 100 million rows.'
def_node_matcher :distinct_count?, <<-PATTERN
@@ -20,6 +24,8 @@ module RuboCop
PATTERN
def on_send(node)
+ return unless in_usage_data_file?(node)
+
distinct_count?(node) do |method_name, method_arguments|
next unless method_arguments && method_arguments.length >= 2
next if batch_set_to_false?(method_arguments[2])
diff --git a/rubocop/cop/usage_data/histogram_with_large_table.rb b/rubocop/cop/usage_data/histogram_with_large_table.rb
index 35ec568792c..0ff3b0b3c81 100644
--- a/rubocop/cop/usage_data/histogram_with_large_table.rb
+++ b/rubocop/cop/usage_data/histogram_with_large_table.rb
@@ -1,5 +1,7 @@
# frozen_string_literal: true
+require_relative '../../usage_data_helpers'
+
module RuboCop
module Cop
module UsageData
@@ -12,6 +14,8 @@ module RuboCop
# histogram(Issue, buckets: 1..100)
# histogram(User.active, buckets: 1..100)
class HistogramWithLargeTable < RuboCop::Cop::Base
+ include UsageDataHelpers
+
MSG = 'Avoid histogram method on %{model_name}'
# Match one level const as Issue, Gitlab
@@ -31,6 +35,8 @@ module RuboCop
PATTERN
def on_send(node)
+ return unless in_usage_data_file?(node)
+
one_level_matches = one_level_node(node)
two_level_matches = two_level_node(node)
diff --git a/rubocop/cop/usage_data/instrumentation_superclass.rb b/rubocop/cop/usage_data/instrumentation_superclass.rb
index 601f2340582..80eed19dafa 100644
--- a/rubocop/cop/usage_data/instrumentation_superclass.rb
+++ b/rubocop/cop/usage_data/instrumentation_superclass.rb
@@ -1,5 +1,7 @@
# frozen_string_literal: true
+require_relative '../../usage_data_helpers'
+
module RuboCop
module Cop
module UsageData
@@ -17,6 +19,8 @@ module RuboCop
# # ...
# end
class InstrumentationSuperclass < RuboCop::Cop::Base
+ include UsageDataHelpers
+
MSG = "Instrumentation classes should subclass one of the following: %{allowed_classes}."
BASE_PATTERN = "(const nil? !#allowed_class?)"
@@ -32,12 +36,16 @@ module RuboCop
PATTERN
def on_class(node)
+ return unless in_instrumentation_file?(node)
+
class_definition(node) do
register_offense(node.children[1])
end
end
def on_send(node)
+ return unless in_instrumentation_file?(node)
+
class_new_definition(node) do
register_offense(node.children.last)
end
diff --git a/rubocop/cop/usage_data/large_table.rb b/rubocop/cop/usage_data/large_table.rb
index 7d50eebaa83..414c89209ed 100644
--- a/rubocop/cop/usage_data/large_table.rb
+++ b/rubocop/cop/usage_data/large_table.rb
@@ -1,9 +1,13 @@
# frozen_string_literal: true
+require_relative '../../usage_data_helpers'
+
module RuboCop
module Cop
module UsageData
class LargeTable < RuboCop::Cop::Base
+ include UsageDataHelpers
+
# This cop checks that batch count and distinct_count are used in usage_data.rb files in metrics based on ActiveRecord models.
#
# @example
@@ -38,6 +42,8 @@ module RuboCop
PATTERN
def on_send(node)
+ return unless in_usage_data_file?(node)
+
one_level_matches = one_level_node(node)
two_level_matches = two_level_node(node)
diff --git a/rubocop/cop_todo.rb b/rubocop/cop_todo.rb
index 943f3375461..cd1c6669ae2 100644
--- a/rubocop/cop_todo.rb
+++ b/rubocop/cop_todo.rb
@@ -22,6 +22,10 @@ module RuboCop
@offense_count += offense_count
end
+ def add_files(files)
+ @files.merge(files)
+ end
+
def autocorrectable?
@cop_class&.support_autocorrect?
end
diff --git a/rubocop/formatter/todo_formatter.rb b/rubocop/formatter/todo_formatter.rb
index 5e49e2dc082..9e20a95ba85 100644
--- a/rubocop/formatter/todo_formatter.rb
+++ b/rubocop/formatter/todo_formatter.rb
@@ -18,6 +18,14 @@ module RuboCop
class TodoFormatter < BaseFormatter
DEFAULT_BASE_DIRECTORY = File.expand_path('../../.rubocop_todo', __dir__)
+ # Make sure that HAML exclusions are retained.
+ # This allows enabling cop rules in haml-lint and only exclude HAML files
+ # with offenses.
+ #
+ # See https://gitlab.com/gitlab-org/gitlab/-/issues/415330#caveats
+ # on why the entry must end with `.haml.rb`.
+ RETAIN_EXCLUSIONS = %r{\.haml\.rb$}
+
class << self
attr_accessor :base_directory
end
@@ -31,7 +39,7 @@ module RuboCop
@config_inspect_todo_dir = load_config_inspect_todo_dir
@config_old_todo_yml = load_config_old_todo_yml
check_multiple_configurations!
- create_empty_todos(@config_inspect_todo_dir)
+ create_todos_retaining_exclusions(@config_inspect_todo_dir)
super
end
@@ -81,11 +89,10 @@ module RuboCop
raise "Multiple configurations found for cops:\n#{list}\n"
end
- # For each inspected cop TODO config create a TODO object to make sure
- # the cop TODO config will be written even without any offenses.
- def create_empty_todos(inspected_cop_config)
- inspected_cop_config.each_key do |cop_name|
- @todos[cop_name]
+ def create_todos_retaining_exclusions(inspected_cop_config)
+ inspected_cop_config.each do |cop_name, config|
+ todo = @todos[cop_name]
+ todo.add_files(config.fetch('Exclude', []).grep(RETAIN_EXCLUSIONS))
end
end
diff --git a/rubocop/rubocop-code_reuse.yml b/rubocop/rubocop-code_reuse.yml
index c1babff4b12..f96de5caf99 100644
--- a/rubocop/rubocop-code_reuse.yml
+++ b/rubocop/rubocop-code_reuse.yml
@@ -42,3 +42,4 @@ CodeReuse/ActiveRecord:
- ee/lib/tasks/**/*.rake
- ee/lib/ee/gitlab/background_migration/**/*.rb
- ee/lib/gitlab/llm/open_ai/response_modifiers/tanuki_bot.rb
+ - ee/lib/gitlab/usage/metrics/instrumentations/**/*.rb
diff --git a/rubocop/rubocop-usage-data.yml b/rubocop/rubocop-usage-data.yml
index 129dbc75acf..5ec383010f5 100644
--- a/rubocop/rubocop-usage-data.yml
+++ b/rubocop/rubocop-usage-data.yml
@@ -1,8 +1,5 @@
UsageData/LargeTable:
Enabled: true
- Include:
- - 'lib/gitlab/usage_data.rb'
- - 'ee/lib/ee/gitlab/usage_data.rb'
NonRelatedClasses:
- :ActionMailer::Base
- :Date
@@ -41,9 +38,6 @@ UsageData/LargeTable:
- :maximum
UsageData/HistogramWithLargeTable:
Enabled: true
- Include:
- - 'lib/gitlab/usage_data.rb'
- - 'ee/lib/ee/gitlab/usage_data.rb'
HighTrafficModels: &high_traffic_models # models for all high traffic tables in Migration/UpdateLargeTable
- 'AuditEvent'
- 'CommitStatus'
@@ -98,9 +92,6 @@ UsageData/HistogramWithLargeTable:
- 'WebHookLog'
UsageData/DistinctCountByLargeForeignKey:
Enabled: true
- Include:
- - 'lib/gitlab/usage_data.rb'
- - 'ee/lib/ee/gitlab/usage_data.rb'
AllowedForeignKeys:
- 'agent_id'
- 'author_id'
@@ -116,8 +107,6 @@ UsageData/DistinctCountByLargeForeignKey:
- 'requirement_id'
UsageData/InstrumentationSuperclass:
Enabled: true
- Include:
- - 'lib/gitlab/usage/metrics/instrumentations/**/*.rb'
AllowedClasses:
- :DatabaseMetric
- :GenericMetric
@@ -125,3 +114,4 @@ UsageData/InstrumentationSuperclass:
- :RedisMetric
- :NumbersMetric
- :AggregatedMetric
+ - :PrometheusMetric
diff --git a/rubocop/usage_data_helpers.rb b/rubocop/usage_data_helpers.rb
new file mode 100644
index 00000000000..a6252594778
--- /dev/null
+++ b/rubocop/usage_data_helpers.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+module RuboCop
+ module UsageDataHelpers
+ def in_usage_data_file?(node)
+ filepath(node).end_with?('gitlab/usage_data.rb')
+ end
+
+ def in_instrumentation_file?(node)
+ filepath(node).start_with?('lib/gitlab/usage/metrics/instrumentations') && File.extname(filepath(node)) == '.rb'
+ end
+
+ private
+
+ def filepath(node)
+ node.location.expression.source_buffer.name
+ end
+ end
+end