summaryrefslogtreecommitdiff
path: root/rubocop
diff options
context:
space:
mode:
Diffstat (limited to 'rubocop')
-rw-r--r--rubocop/code_reuse_helpers.rb156
-rw-r--r--rubocop/cop/avoid_route_redirect_leading_slash.rb52
-rw-r--r--rubocop/cop/code_reuse/active_record.rb170
-rw-r--r--rubocop/cop/code_reuse/finder.rb39
-rw-r--r--rubocop/cop/code_reuse/presenter.rb41
-rw-r--r--rubocop/cop/code_reuse/serializer.rb41
-rw-r--r--rubocop/cop/code_reuse/service_class.rb39
-rw-r--r--rubocop/cop/code_reuse/worker.rb56
-rw-r--r--rubocop/cop/gitlab/union.rb27
-rw-r--r--rubocop/cop/group_public_or_visible_to_user.rb22
-rw-r--r--rubocop/cop/line_break_around_conditional_block.rb7
-rw-r--r--rubocop/cop/ruby_interpolation_in_translation.rb1
-rw-r--r--rubocop/rubocop.rb9
13 files changed, 658 insertions, 2 deletions
diff --git a/rubocop/code_reuse_helpers.rb b/rubocop/code_reuse_helpers.rb
new file mode 100644
index 00000000000..0929a55d901
--- /dev/null
+++ b/rubocop/code_reuse_helpers.rb
@@ -0,0 +1,156 @@
+# frozen_string_literal: true
+
+module RuboCop
+ module CodeReuseHelpers
+ # Returns true for a `(send const ...)` node.
+ def send_to_constant?(node)
+ node.type == :send && node.children&.first&.type == :const
+ end
+
+ # Returns `true` if the name of the receiving constant ends with a given
+ # `String`.
+ def send_receiver_name_ends_with?(node, suffix)
+ return false unless send_to_constant?(node)
+
+ receiver_name = name_of_receiver(node)
+
+ receiver_name != suffix &&
+ receiver_name.end_with?(suffix)
+ end
+
+ # Returns the file path (as a `String`) for an AST node.
+ def file_path_for_node(node)
+ node.location.expression.source_buffer.name
+ end
+
+ # Returns the name of a constant node.
+ #
+ # Given the AST node `(const nil :Foo)`, this method will return `:Foo`.
+ def name_of_constant(node)
+ node.children[1]
+ end
+
+ # Returns true if the given node resides in app/finders or ee/app/finders.
+ def in_finder?(node)
+ in_directory?(node, 'finders')
+ end
+
+ # Returns true if the given node resides in app/models or ee/app/models.
+ def in_model?(node)
+ in_directory?(node, 'models')
+ end
+
+ # Returns true if the given node resides in app/services or ee/app/services.
+ def in_service_class?(node)
+ in_directory?(node, 'services')
+ end
+
+ # Returns true if the given node resides in app/presenters or
+ # ee/app/presenters.
+ def in_presenter?(node)
+ in_directory?(node, 'presenters')
+ end
+
+ # Returns true if the given node resides in app/serializers or
+ # ee/app/serializers.
+ def in_serializer?(node)
+ in_directory?(node, 'serializers')
+ end
+
+ # Returns true if the given node resides in app/workers or ee/app/workers.
+ def in_worker?(node)
+ in_directory?(node, 'workers')
+ end
+
+ # Returns true if the given node resides in app/controllers or
+ # ee/app/controllers.
+ def in_controller?(node)
+ in_directory?(node, 'controllers')
+ end
+
+ # Returns true if the given node resides in lib/api or ee/lib/api.
+ def in_api?(node)
+ file_path_for_node(node).start_with?(
+ File.join(ce_lib_directory, 'api'),
+ File.join(ee_lib_directory, 'api')
+ )
+ end
+
+ # Returns `true` if the given AST node resides in the given directory,
+ # relative to app and/or ee/app.
+ def in_directory?(node, directory)
+ file_path_for_node(node).start_with?(
+ File.join(ce_app_directory, directory),
+ File.join(ee_app_directory, directory)
+ )
+ end
+
+ # Returns the receiver name of a send node.
+ #
+ # For the AST node `(send (const nil :Foo) ...)` this would return
+ # `'Foo'`.
+ def name_of_receiver(node)
+ name_of_constant(node.children.first).to_s
+ end
+
+ # Yields every defined class method in the given AST node.
+ def each_class_method(node)
+ return to_enum(__method__, node) unless block_given?
+
+ # class << self
+ # def foo
+ # end
+ # end
+ node.each_descendant(:sclass) do |sclass|
+ sclass.each_descendant(:def) do |def_node|
+ yield def_node
+ end
+ end
+
+ # def self.foo
+ # end
+ node.each_descendant(:defs) do |defs_node|
+ yield defs_node
+ end
+ end
+
+ # Yields every send node found in the given AST node.
+ def each_send_node(node, &block)
+ node.each_descendant(:send, &block)
+ end
+
+ # Registers a RuboCop offense for a `(send)` node with a receiver that ends
+ # with a given suffix.
+ #
+ # node - The AST node to check.
+ # suffix - The suffix of the receiver name, such as "Finder".
+ # message - The message to use for the offense.
+ def disallow_send_to(node, suffix, message)
+ each_send_node(node) do |send_node|
+ next unless send_receiver_name_ends_with?(send_node, suffix)
+
+ add_offense(send_node, location: :expression, message: message)
+ end
+ end
+
+ def ce_app_directory
+ File.join(rails_root, 'app')
+ end
+
+ def ee_app_directory
+ File.join(rails_root, 'ee', 'app')
+ end
+
+ def ce_lib_directory
+ File.join(rails_root, 'lib')
+ end
+
+ def ee_lib_directory
+ File.join(rails_root, 'ee', 'lib')
+ end
+
+ def rails_root
+ File.expand_path('..', __dir__)
+ end
+ end
+end
diff --git a/rubocop/cop/avoid_route_redirect_leading_slash.rb b/rubocop/cop/avoid_route_redirect_leading_slash.rb
new file mode 100644
index 00000000000..7ac1c881269
--- /dev/null
+++ b/rubocop/cop/avoid_route_redirect_leading_slash.rb
@@ -0,0 +1,52 @@
+# frozen_string_literal: true
+
+module RuboCop
+ module Cop
+ # Checks for a leading '/' in route redirects
+ # For more information see: https://gitlab.com/gitlab-org/gitlab-ce/issues/50645
+ #
+ # @example
+ # # bad
+ # root to: redirect('/-/instance/statistics/conversational_development_index')
+ #
+ # # good
+ # root to: redirect('-/instance/statistics/conversational_development_index')
+ #
+
+ class AvoidRouteRedirectLeadingSlash < RuboCop::Cop::Cop
+ MSG = 'Do not use a leading "/" in route redirects'
+
+ def_node_matcher :leading_slash_in_redirect?, <<~PATTERN
+ (send nil? :redirect (str #has_leading_slash?))
+ PATTERN
+
+ def on_send(node)
+ return unless in_routes?(node)
+ return unless leading_slash_in_redirect?(node)
+
+ add_offense(node)
+ end
+
+ def has_leading_slash?(str)
+ str.start_with?("/")
+ end
+
+ def in_routes?(node)
+ path = node.location.expression.source_buffer.name
+ dirname = File.dirname(path)
+ filename = File.basename(path)
+ dirname.end_with?('config/routes') || filename.end_with?('routes.rb')
+ end
+
+ def autocorrect(node)
+ lambda do |corrector|
+ corrector.replace(node.loc.expression, remove_leading_slash(node))
+ end
+ end
+
+ def remove_leading_slash(node)
+ node.source.sub('/', '')
+ end
+ end
+ end
+end
diff --git a/rubocop/cop/code_reuse/active_record.rb b/rubocop/cop/code_reuse/active_record.rb
new file mode 100644
index 00000000000..d25e8548fd0
--- /dev/null
+++ b/rubocop/cop/code_reuse/active_record.rb
@@ -0,0 +1,170 @@
+# frozen_string_literal: true
+
+require_relative '../../code_reuse_helpers'
+
+module RuboCop
+ module Cop
+ module CodeReuse
+ # Cop that blacklists the use of ActiveRecord methods outside of models.
+ class ActiveRecord < RuboCop::Cop::Cop
+ include CodeReuseHelpers
+
+ MSG = 'This method can only be used inside an ActiveRecord model'
+
+ # Various methods from ActiveRecord::Querying that are blacklisted. We
+ # exclude some generic ones such as `any?` and `first`, as these may
+ # lead to too many false positives, since `Array` also supports these
+ # methods.
+ #
+ # The keys of this Hash are the blacklisted method names. The values are
+ # booleans that indicate if the method should only be blacklisted if any
+ # arguments are provided.
+ NOT_ALLOWED = {
+ average: true,
+ calculate: true,
+ count_by_sql: true,
+ create_with: true,
+ distinct: false,
+ eager_load: true,
+ except: true,
+ exists?: true,
+ find_by: true,
+ find_by!: true,
+ find_by_sql: true,
+ find_each: true,
+ find_in_batches: true,
+ find_or_create_by: true,
+ find_or_create_by!: true,
+ find_or_initialize_by: true,
+ first!: false,
+ first_or_create: true,
+ first_or_create!: true,
+ first_or_initialize: true,
+ from: true,
+ group: true,
+ having: true,
+ ids: false,
+ includes: true,
+ joins: true,
+ limit: true,
+ lock: false,
+ many?: false,
+ none: false,
+ offset: true,
+ order: true,
+ pluck: true,
+ preload: true,
+ readonly: false,
+ references: true,
+ reorder: true,
+ rewhere: true,
+ sum: false,
+ take: false,
+ take!: false,
+ unscope: false,
+ where: false,
+ with: true
+ }.freeze
+
+ # Directories that allow the use of the blacklisted methods. These
+ # directories are checked relative to both . and ee/
+ WHITELISTED_DIRECTORIES = %w[
+ app/models
+ config
+ danger
+ db
+ lib/backup
+ lib/banzai
+ lib/gitlab/background_migration
+ lib/gitlab/cycle_analytics
+ lib/gitlab/database
+ lib/gitlab/import_export
+ lib/gitlab/project_authorizations
+ lib/gitlab/sql
+ lib/system_check
+ lib/tasks
+ qa
+ rubocop
+ spec
+ ].freeze
+
+ def on_send(node)
+ return if in_whitelisted_directory?(node)
+
+ receiver = node.children[0]
+ send_name = node.children[1]
+ first_arg = node.children[2]
+
+ if receiver && NOT_ALLOWED.key?(send_name)
+ # If the rule requires an argument to be given, but none are
+ # provided, we won't register an offense. This prevents us from
+ # adding offenses for `project.group`, while still covering
+ # `Project.group(:name)`.
+ return if NOT_ALLOWED[send_name] && !first_arg
+
+ add_offense(node, location: :selector)
+ end
+ end
+
+ # Returns true if the node resides in one of the whitelisted
+ # directories.
+ def in_whitelisted_directory?(node)
+ path = file_path_for_node(node)
+
+ WHITELISTED_DIRECTORIES.any? do |directory|
+ path.start_with?(
+ File.join(rails_root, directory),
+ File.join(rails_root, 'ee', directory)
+ )
+ end
+ end
+
+ # We can not auto correct code like this, as it requires manual
+ # refactoring. Instead, we'll just whitelist the surrounding scope.
+ #
+ # Despite this method's presence, you should not use it. This method
+ # exists to make it possible to whitelist large chunks of offenses we
+ # can't fix in the short term. If you are writing new code, follow the
+ # code reuse guidelines, instead of whitelisting any new offenses.
+ def autocorrect(node)
+ scope = surrounding_scope_of(node)
+ indent = indentation_of(scope)
+
+ lambda do |corrector|
+ # This prevents us from inserting the same enable/disable comment
+ # for a method or block that has multiple offenses.
+ next if whitelisted_scopes.include?(scope)
+
+ corrector.insert_before(
+ scope.source_range,
+ "# rubocop: disable #{cop_name}\n#{indent}"
+ )
+
+ corrector.insert_after(
+ scope.source_range,
+ "\n#{indent}# rubocop: enable #{cop_name}"
+ )
+
+ whitelisted_scopes << scope
+ end
+ end
+
+ def indentation_of(node)
+ ' ' * node.loc.expression.source_line[/\A */].length
+ end
+
+ def surrounding_scope_of(node)
+ %i[def defs block begin].each do |type|
+ if (found = node.each_ancestor(type).first)
+ return found
+ end
+ end
+ end
+
+ def whitelisted_scopes
+ @whitelisted_scopes ||= Set.new
+ end
+ end
+ end
+ end
+end
diff --git a/rubocop/cop/code_reuse/finder.rb b/rubocop/cop/code_reuse/finder.rb
new file mode 100644
index 00000000000..1d70befe79b
--- /dev/null
+++ b/rubocop/cop/code_reuse/finder.rb
@@ -0,0 +1,39 @@
+# frozen_string_literal: true
+
+require_relative '../../code_reuse_helpers'
+
+module RuboCop
+ module Cop
+ module CodeReuse
+ # Cop that enforces various code reuse rules for Finders.
+ class Finder < RuboCop::Cop::Cop
+ include CodeReuseHelpers
+
+ IN_FINDER = 'Finders can not be used inside a Finder.'
+
+ IN_MODEL_CLASS_METHOD =
+ 'Finders can not be used inside model class methods.'
+
+ SUFFIX = 'Finder'
+
+ def on_class(node)
+ if in_finder?(node)
+ check_finder(node)
+ elsif in_model?(node)
+ check_model_class_methods(node)
+ end
+ end
+
+ def check_finder(node)
+ disallow_send_to(node, SUFFIX, IN_FINDER)
+ end
+
+ def check_model_class_methods(node)
+ each_class_method(node) do |def_node|
+ disallow_send_to(def_node, SUFFIX, IN_MODEL_CLASS_METHOD)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/rubocop/cop/code_reuse/presenter.rb b/rubocop/cop/code_reuse/presenter.rb
new file mode 100644
index 00000000000..5f8f2839ca6
--- /dev/null
+++ b/rubocop/cop/code_reuse/presenter.rb
@@ -0,0 +1,41 @@
+# frozen_string_literal: true
+
+require_relative '../../code_reuse_helpers.rb'
+
+module RuboCop
+ module Cop
+ module CodeReuse
+ # Cop that enforces various code reuse rules for Presenter classes.
+ class Presenter < RuboCop::Cop::Cop
+ include CodeReuseHelpers
+
+ IN_SERVICE = 'Presenters can not be used in a Service class.'
+ IN_FINDER = 'Presenters can not be used in a Finder.'
+ IN_PRESENTER = 'Presenters can not be used in a Presenter.'
+ IN_SERIALIZER = 'Presenters can not be used in a Serializer.'
+ IN_MODEL = 'Presenters can not be used in a model.'
+ IN_WORKER = 'Presenters can not be used in a worker.'
+ SUFFIX = 'Presenter'
+
+ def on_class(node)
+ message =
+ if in_service_class?(node)
+ IN_SERVICE
+ elsif in_finder?(node)
+ IN_FINDER
+ elsif in_presenter?(node)
+ IN_PRESENTER
+ elsif in_serializer?(node)
+ IN_SERIALIZER
+ elsif in_model?(node)
+ IN_MODEL
+ elsif in_worker?(node)
+ IN_WORKER
+ end
+
+ disallow_send_to(node, SUFFIX, message) if message
+ end
+ end
+ end
+ end
+end
diff --git a/rubocop/cop/code_reuse/serializer.rb b/rubocop/cop/code_reuse/serializer.rb
new file mode 100644
index 00000000000..2212c50514e
--- /dev/null
+++ b/rubocop/cop/code_reuse/serializer.rb
@@ -0,0 +1,41 @@
+# frozen_string_literal: true
+
+require_relative '../../code_reuse_helpers.rb'
+
+module RuboCop
+ module Cop
+ module CodeReuse
+ # Cop that enforces various code reuse rules for Serializer classes.
+ class Serializer < RuboCop::Cop::Cop
+ include CodeReuseHelpers
+
+ IN_SERVICE = 'Serializers can not be used in a Service class.'
+ IN_FINDER = 'Serializers can not be used in a Finder.'
+ IN_PRESENTER = 'Serializers can not be used in a Presenter.'
+ IN_SERIALIZER = 'Serializers can not be used in a Serializer.'
+ IN_MODEL = 'Serializers can not be used in a model.'
+ IN_WORKER = 'Serializers can not be used in a worker.'
+ SUFFIX = 'Serializer'
+
+ def on_class(node)
+ message =
+ if in_service_class?(node)
+ IN_SERVICE
+ elsif in_finder?(node)
+ IN_FINDER
+ elsif in_presenter?(node)
+ IN_PRESENTER
+ elsif in_serializer?(node)
+ IN_SERIALIZER
+ elsif in_model?(node)
+ IN_MODEL
+ elsif in_worker?(node)
+ IN_WORKER
+ end
+
+ disallow_send_to(node, SUFFIX, message) if message
+ end
+ end
+ end
+ end
+end
diff --git a/rubocop/cop/code_reuse/service_class.rb b/rubocop/cop/code_reuse/service_class.rb
new file mode 100644
index 00000000000..768b43fb684
--- /dev/null
+++ b/rubocop/cop/code_reuse/service_class.rb
@@ -0,0 +1,39 @@
+# frozen_string_literal: true
+
+require_relative '../../code_reuse_helpers.rb'
+
+module RuboCop
+ module Cop
+ module CodeReuse
+ # Cop that enforces various code reuse rules for Service classes.
+ class ServiceClass < RuboCop::Cop::Cop
+ include CodeReuseHelpers
+
+ IN_FINDER = 'Service classes can not be used in a Finder.'
+ IN_PRESENTER = 'Service classes can not be used in a Presenter.'
+ IN_SERIALIZER = 'Service classes can not be used in a Serializer.'
+ IN_MODEL = 'Service classes can not be used in a model.'
+ SUFFIX = 'Service'
+
+ def on_class(node)
+ check_all_send_nodes(node)
+ end
+
+ def check_all_send_nodes(node)
+ message =
+ if in_finder?(node)
+ IN_FINDER
+ elsif in_presenter?(node)
+ IN_PRESENTER
+ elsif in_serializer?(node)
+ IN_SERIALIZER
+ elsif in_model?(node)
+ IN_MODEL
+ end
+
+ disallow_send_to(node, SUFFIX, message) if message
+ end
+ end
+ end
+ end
+end
diff --git a/rubocop/cop/code_reuse/worker.rb b/rubocop/cop/code_reuse/worker.rb
new file mode 100644
index 00000000000..e38d2783d0f
--- /dev/null
+++ b/rubocop/cop/code_reuse/worker.rb
@@ -0,0 +1,56 @@
+# frozen_string_literal: true
+
+require_relative '../../code_reuse_helpers.rb'
+
+module RuboCop
+ module Cop
+ module CodeReuse
+ # Cop that enforces various code reuse rules for workers.
+ class Worker < RuboCop::Cop::Cop
+ include CodeReuseHelpers
+
+ IN_CONTROLLER = 'Workers can not be used in a controller.'
+ IN_API = 'Workers can not be used in a Grape API.'
+ IN_FINDER = 'Workers can not be used in a Finder.'
+ IN_PRESENTER = 'Workers can not be used in a Presenter.'
+ IN_SERIALIZER = 'Workers can not be used in a Serializer.'
+
+ IN_MODEL_CLASS_METHOD =
+ 'Workers can not be used in model class methods.'
+
+ SUFFIX = 'Worker'
+
+ def on_class(node)
+ if in_model?(node)
+ check_model_class_methods(node)
+ else
+ check_all_send_nodes(node)
+ end
+ end
+
+ def check_all_send_nodes(node)
+ message =
+ if in_controller?(node)
+ IN_CONTROLLER
+ elsif in_api?(node)
+ IN_API
+ elsif in_finder?(node)
+ IN_FINDER
+ elsif in_presenter?(node)
+ IN_PRESENTER
+ elsif in_serializer?(node)
+ IN_SERIALIZER
+ end
+
+ disallow_send_to(node, SUFFIX, message) if message
+ end
+
+ def check_model_class_methods(node)
+ each_class_method(node) do |def_node|
+ disallow_send_to(def_node, SUFFIX, IN_MODEL_CLASS_METHOD)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/rubocop/cop/gitlab/union.rb b/rubocop/cop/gitlab/union.rb
new file mode 100644
index 00000000000..09541d8af3b
--- /dev/null
+++ b/rubocop/cop/gitlab/union.rb
@@ -0,0 +1,27 @@
+# frozen_string_literal: true
+require_relative '../../spec_helpers'
+
+module RuboCop
+ module Cop
+ module Gitlab
+ # Cop that disallows the use of `Gitlab::SQL::Union`, in favour of using
+ # the `FromUnion` module.
+ class Union < RuboCop::Cop::Cop
+ include SpecHelpers
+
+ MSG = 'Use the `FromUnion` concern, instead of using `Gitlab::SQL::Union` directly'
+
+ def_node_matcher :raw_union?, <<~PATTERN
+ (send (const (const (const nil? :Gitlab) :SQL) :Union) :new ...)
+ PATTERN
+
+ def on_send(node)
+ return unless raw_union?(node)
+ return if in_spec?(node)
+
+ add_offense(node, location: :expression)
+ end
+ end
+ 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
new file mode 100644
index 00000000000..beda0b7f8ba
--- /dev/null
+++ b/rubocop/cop/group_public_or_visible_to_user.rb
@@ -0,0 +1,22 @@
+# frozen_string_literal: true
+#
+module RuboCop
+ module Cop
+ # Cop that blacklists the usage of Group.public_or_visible_to_user
+ class GroupPublicOrVisibleToUser < RuboCop::Cop::Cop
+ 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 ' \
+ 'of rows being filtered is reasonable.'
+
+ def_node_matcher :public_or_visible_to_user?, <<~PATTERN
+ (send (const nil? :Group) :public_or_visible_to_user ...)
+ PATTERN
+
+ def on_send(node)
+ return unless public_or_visible_to_user?(node)
+
+ add_offense(node, location: :expression)
+ end
+ end
+ end
+end
diff --git a/rubocop/cop/line_break_around_conditional_block.rb b/rubocop/cop/line_break_around_conditional_block.rb
index 59fe6e5d98c..8118b314b63 100644
--- a/rubocop/cop/line_break_around_conditional_block.rb
+++ b/rubocop/cop/line_break_around_conditional_block.rb
@@ -77,7 +77,8 @@ module RuboCop
start_clause_line?(previous_line(node)) ||
block_start?(previous_line(node)) ||
begin_line?(previous_line(node)) ||
- assignment_line?(previous_line(node))
+ assignment_line?(previous_line(node)) ||
+ rescue_line?(previous_line(node))
end
def last_line_valid?(node)
@@ -111,6 +112,10 @@ module RuboCop
line =~ /^\s*.*=/
end
+ def rescue_line?(line)
+ line =~ /^\s*rescue/
+ end
+
def block_start?(line)
line.match(/ (do|{)( \|.*?\|)?\s?$/)
end
diff --git a/rubocop/cop/ruby_interpolation_in_translation.rb b/rubocop/cop/ruby_interpolation_in_translation.rb
index b9411fcfd6c..c431b4a1977 100644
--- a/rubocop/cop/ruby_interpolation_in_translation.rb
+++ b/rubocop/cop/ruby_interpolation_in_translation.rb
@@ -6,7 +6,6 @@ module RuboCop
MSG = "Don't use ruby interpolation \#{} inside translated strings, instead use \%{}"
TRANSLATION_METHODS = ':_ :s_ :N_ :n_'
- RUBY_INTERPOLATION_REGEX = /.*\#\{.*\}/
def_node_matcher :translation_method?, <<~PATTERN
(send nil? {#{TRANSLATION_METHODS}} $dstr ...)
diff --git a/rubocop/rubocop.rb b/rubocop/rubocop.rb
index d823fa4edb1..76d6037706e 100644
--- a/rubocop/rubocop.rb
+++ b/rubocop/rubocop.rb
@@ -3,9 +3,11 @@ require_relative 'cop/gitlab/module_with_instance_variables'
require_relative 'cop/gitlab/predicate_memoization'
require_relative 'cop/gitlab/httparty'
require_relative 'cop/gitlab/finder_with_find_by'
+require_relative 'cop/gitlab/union'
require_relative 'cop/include_sidekiq_worker'
require_relative 'cop/avoid_return_from_blocks'
require_relative 'cop/avoid_break_from_strong_memoize'
+require_relative 'cop/avoid_route_redirect_leading_slash'
require_relative 'cop/line_break_around_conditional_block'
require_relative 'cop/prefer_class_methods_over_module'
require_relative 'cop/migration/add_column'
@@ -30,3 +32,10 @@ require_relative 'cop/rspec/factories_in_migration_specs'
require_relative 'cop/sidekiq_options_queue'
require_relative 'cop/destroy_all'
require_relative 'cop/ruby_interpolation_in_translation'
+require_relative 'code_reuse_helpers'
+require_relative 'cop/code_reuse/finder'
+require_relative 'cop/code_reuse/service_class'
+require_relative 'cop/code_reuse/presenter'
+require_relative 'cop/code_reuse/serializer'
+require_relative 'cop/code_reuse/active_record'
+require_relative 'cop/group_public_or_visible_to_user'