Add cop to make sure we don't use ivar in a module
This commit is contained in:
parent
4cadf22e20
commit
9ae92b8caa
|
|
@ -1,3 +1,4 @@
|
|||
# rubocop:disable Cop/ModuleWithInstanceVariables
|
||||
module BoardsResponses
|
||||
def authorize_read_list
|
||||
authorize_action_for!(board.parent, :read_list)
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
# rubocop:disable Cop/ModuleWithInstanceVariables
|
||||
module CreatesCommit
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
module CycleAnalyticsParams
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
# rubocop:disable Cop/ModuleWithInstanceVariables
|
||||
def options(params)
|
||||
@options ||= { from: start_date(params), current_user: current_user }
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
# rubocop:disable Cop/ModuleWithInstanceVariables
|
||||
module IssuableActions
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
# rubocop:disable Cop/ModuleWithInstanceVariables
|
||||
module IssuableCollections
|
||||
extend ActiveSupport::Concern
|
||||
include SortingHelper
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
# rubocop:disable Cop/ModuleWithInstanceVariables
|
||||
module IssuesAction
|
||||
extend ActiveSupport::Concern
|
||||
include IssuableCollections
|
||||
|
|
|
|||
|
|
@ -90,6 +90,7 @@ module LfsRequest
|
|||
has_authentication_ability?(:build_download_code) && can?(user, :build_download_code, project)
|
||||
end
|
||||
|
||||
# rubocop:disable Cop/ModuleWithInstanceVariables
|
||||
def storage_project
|
||||
@storage_project ||= begin
|
||||
result = project
|
||||
|
|
@ -103,6 +104,7 @@ module LfsRequest
|
|||
end
|
||||
end
|
||||
|
||||
# rubocop:disable Cop/ModuleWithInstanceVariables
|
||||
def objects
|
||||
@objects ||= (params[:objects] || []).to_a
|
||||
end
|
||||
|
|
|
|||
|
|
@ -76,6 +76,7 @@ module MembershipActions
|
|||
end
|
||||
end
|
||||
|
||||
# rubocop:disable Cop/ModuleWithInstanceVariables
|
||||
def source_type
|
||||
@source_type ||= membershipable.class.to_s.humanize(capitalize: false)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
# rubocop:disable Cop/ModuleWithInstanceVariables
|
||||
module MergeRequestsAction
|
||||
extend ActiveSupport::Concern
|
||||
include IssuableCollections
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
# rubocop:disable Cop/ModuleWithInstanceVariables
|
||||
module MilestoneActions
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
# rubocop:disable Cop/ModuleWithInstanceVariables
|
||||
module NotesActions
|
||||
include RendersNotes
|
||||
extend ActiveSupport::Concern
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ module OauthApplications
|
|||
end
|
||||
end
|
||||
|
||||
# rubocop:disable Cop/ModuleWithInstanceVariables
|
||||
def load_scopes
|
||||
@scopes = Doorkeeper.configuration.scopes
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
module RendersCommits
|
||||
# rubocop:disable Cop/ModuleWithInstanceVariables
|
||||
def prepare_commits_for_rendering(commits)
|
||||
Banzai::CommitRenderer.render(commits, @project, current_user)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
module RendersNotes
|
||||
# rubocop:disable Cop/ModuleWithInstanceVariables
|
||||
def prepare_notes_for_rendering(notes, noteable = nil)
|
||||
preload_noteable_for_regular_notes(notes)
|
||||
preload_max_access_for_authors(notes, @project)
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ module RequiresWhitelistedMonitoringClient
|
|||
ip_whitelist.any? { |e| e.include?(Gitlab::RequestContext.client_ip) }
|
||||
end
|
||||
|
||||
# rubocop:disable Cop/ModuleWithInstanceVariables
|
||||
def ip_whitelist
|
||||
@ip_whitelist ||= Settings.monitoring.ip_whitelist.map(&IPAddr.method(:new))
|
||||
end
|
||||
|
|
|
|||
|
|
@ -65,6 +65,7 @@ module ServiceParams
|
|||
# Parameters to ignore if no value is specified
|
||||
FILTER_BLANK_PARAMS = [:password].freeze
|
||||
|
||||
# rubocop:disable Cop/ModuleWithInstanceVariables
|
||||
def service_params
|
||||
dynamic_params = @service.event_channel_names + @service.event_names
|
||||
service_params = params.permit(:id, service: ALLOWED_PARAMS_CE + dynamic_params)
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ module SnippetsActions
|
|||
def edit
|
||||
end
|
||||
|
||||
# rubocop:disable Cop/ModuleWithInstanceVariables
|
||||
def raw
|
||||
disposition = params[:inline] == 'false' ? 'attachment' : 'inline'
|
||||
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ module SpammableActions
|
|||
|
||||
private
|
||||
|
||||
# rubocop:disable Cop/ModuleWithInstanceVariables
|
||||
def ensure_spam_config_loaded!
|
||||
return @spam_config_loaded if defined?(@spam_config_loaded)
|
||||
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ module ToggleSubscriptionAction
|
|||
|
||||
private
|
||||
|
||||
# rubocop:disable Cop/ModuleWithInstanceVariables
|
||||
def subscribable_project
|
||||
@project || raise(NotImplementedError)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ module IgnorableColumn
|
|||
super.reject { |column| ignored_columns.include?(column.name) }
|
||||
end
|
||||
|
||||
# rubocop:disable Cop/ModuleWithInstanceVariables
|
||||
def ignored_columns
|
||||
@ignored_columns ||= Set.new
|
||||
end
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
#
|
||||
# Used by Issue, Note, MergeRequest, and Commit.
|
||||
#
|
||||
# # rubocop:disable Cop/ModuleWithInstanceVariables
|
||||
module Mentionable
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
|
|
|
|||
|
|
@ -94,6 +94,7 @@ module Milestoneish
|
|||
end
|
||||
end
|
||||
|
||||
# rubocop:disable Cop/ModuleWithInstanceVariables
|
||||
def memoize_per_user(user, method_name)
|
||||
@memoized ||= {}
|
||||
@memoized[method_name] ||= {}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ module Noteable
|
|||
#
|
||||
# noteable.class # => MergeRequest
|
||||
# noteable.human_class_name # => "merge request"
|
||||
# rubocop:disable Cop/ModuleWithInstanceVariables
|
||||
def human_class_name
|
||||
@human_class_name ||= base_class_name.titleize.downcase
|
||||
end
|
||||
|
|
@ -34,6 +35,7 @@ module Noteable
|
|||
|
||||
delegate :find_discussion, to: :discussion_notes
|
||||
|
||||
# rubocop:disable Cop/ModuleWithInstanceVariables
|
||||
def discussions
|
||||
@discussions ||= discussion_notes
|
||||
.inc_relations_for_view
|
||||
|
|
@ -46,6 +48,7 @@ module Noteable
|
|||
notes.inc_relations_for_view.grouped_diff_discussions(*args)
|
||||
end
|
||||
|
||||
# rubocop:disable Cop/ModuleWithInstanceVariables
|
||||
def resolvable_discussions
|
||||
@resolvable_discussions ||=
|
||||
if defined?(@discussions)
|
||||
|
|
@ -67,6 +70,7 @@ module Noteable
|
|||
discussions_resolvable? && !discussions_resolved?
|
||||
end
|
||||
|
||||
# rubocop:disable Cop/ModuleWithInstanceVariables
|
||||
def discussions_to_be_resolved
|
||||
@discussions_to_be_resolved ||= resolvable_discussions.select(&:to_be_resolved?)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -55,6 +55,7 @@ module Participable
|
|||
# This method processes attributes of objects in breadth-first order.
|
||||
#
|
||||
# Returns an Array of User instances.
|
||||
# rubocop:disable Cop/ModuleWithInstanceVariables
|
||||
def participants(current_user = nil)
|
||||
@participants ||= Hash.new do |hash, user|
|
||||
hash[user] = raw_participants(user)
|
||||
|
|
|
|||
|
|
@ -55,6 +55,7 @@ module ProtectedRef
|
|||
|
||||
private
|
||||
|
||||
# rubocop:disable Cop/ModuleWithInstanceVariables
|
||||
def ref_matcher
|
||||
@ref_matcher ||= ProtectedRefMatcher.new(self)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
# rubocop:disable Cop/ModuleWithInstanceVariables
|
||||
module RelativePositioning
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
# rubocop:disable Cop/ModuleWithInstanceVariables
|
||||
module ResolvableDiscussion
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
# Store object full path in separate table for easy lookup and uniq validation
|
||||
# Object must have name and path db fields and respond to parent and parent_changed? methods.
|
||||
# rubocop:disable Cop/ModuleWithInstanceVariables
|
||||
module Routable
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ module Spammable
|
|||
end
|
||||
|
||||
def spam?
|
||||
@spam
|
||||
spam
|
||||
end
|
||||
|
||||
def check_for_spam
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@ module Storage
|
|||
|
||||
private
|
||||
|
||||
# rubocop:disable Cop/ModuleWithInstanceVariables
|
||||
def old_repository_storage_paths
|
||||
@old_repository_storage_paths ||= repository_storage_paths
|
||||
end
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ module StripAttribute
|
|||
strip_attrs.concat(attrs)
|
||||
end
|
||||
|
||||
# rubocop:disable Cop/ModuleWithInstanceVariables
|
||||
def strip_attrs
|
||||
@strip_attrs ||= []
|
||||
end
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ require 'task_list/filter'
|
|||
# bugs".
|
||||
#
|
||||
# Used by MergeRequest and Issue
|
||||
# rubocop:disable Cop/ModuleWithInstanceVariables
|
||||
module Taskable
|
||||
COMPLETED = 'completed'.freeze
|
||||
INCOMPLETE = 'incomplete'.freeze
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
#
|
||||
# Used by Issue and MergeRequest.
|
||||
#
|
||||
|
||||
# rubocop:disable Cop/ModuleWithInstanceVariables
|
||||
module TimeTrackable
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
|
|
|
|||
|
|
@ -2,11 +2,13 @@ module Issues
|
|||
module ResolveDiscussions
|
||||
attr_reader :merge_request_to_resolve_discussions_of_iid, :discussion_to_resolve_id
|
||||
|
||||
# rubocop:disable Cop/ModuleWithInstanceVariables
|
||||
def filter_resolve_discussion_params
|
||||
@merge_request_to_resolve_discussions_of_iid ||= params.delete(:merge_request_to_resolve_discussions_of)
|
||||
@discussion_to_resolve_id ||= params.delete(:discussion_to_resolve)
|
||||
end
|
||||
|
||||
# rubocop:disable Cop/ModuleWithInstanceVariables
|
||||
def merge_request_to_resolve_discussions_of
|
||||
return @merge_request_to_resolve_discussions_of if defined?(@merge_request_to_resolve_discussions_of)
|
||||
|
||||
|
|
@ -15,6 +17,7 @@ module Issues
|
|||
.find_by(iid: merge_request_to_resolve_discussions_of_iid)
|
||||
end
|
||||
|
||||
# rubocop:disable Cop/ModuleWithInstanceVariables
|
||||
def discussions_to_resolve
|
||||
return [] unless merge_request_to_resolve_discussions_of
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
# Dependencies:
|
||||
# - params with :request
|
||||
#
|
||||
# rubocop:disable Cop/ModuleWithInstanceVariables
|
||||
module SpamCheckService
|
||||
def filter_spam_check_params
|
||||
@request = params.delete(:request)
|
||||
|
|
|
|||
|
|
@ -662,6 +662,7 @@ module SystemNoteService
|
|||
Rack::Utils.escape_html(text)
|
||||
end
|
||||
|
||||
# rubocop:disable Cop/ModuleWithInstanceVariables
|
||||
def url_helpers
|
||||
@url_helpers ||= Gitlab::Routing.url_helpers
|
||||
end
|
||||
|
|
|
|||
|
|
@ -8,12 +8,14 @@ module NewIssuable
|
|||
user && issuable
|
||||
end
|
||||
|
||||
# rubocop:disable Cop/ModuleWithInstanceVariables
|
||||
def set_user(user_id)
|
||||
@user = User.find_by(id: user_id)
|
||||
|
||||
log_error(User, user_id) unless @user
|
||||
end
|
||||
|
||||
# rubocop:disable Cop/ModuleWithInstanceVariables
|
||||
def set_issuable(issuable_id)
|
||||
@issuable = issuable_class.find_by(id: issuable_id)
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ module LocalCacheRegistryCleanupWithEnsure
|
|||
LocalStore =
|
||||
ActiveSupport::Cache::Strategy::LocalCache::LocalStore
|
||||
|
||||
# rubocop:disable Cop/ModuleWithInstanceVariables
|
||||
def call(env)
|
||||
LocalCacheRegistry.set_cache_for(local_cache_key, LocalStore.new)
|
||||
response = @app.call(env)
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ module RspecProfilingExt
|
|||
end
|
||||
|
||||
module Run
|
||||
# rubocop:disable Cop/ModuleWithInstanceVariables
|
||||
def example_finished(*args)
|
||||
super
|
||||
rescue => err
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
# anyway, and there is no great efficiency gain from just fetching the listed
|
||||
# attributes with our implementation, so we ignore the additional arguments.
|
||||
#
|
||||
# rubocop:disable Cop/ModuleWithInstanceVariables
|
||||
module Rugged
|
||||
class Repository
|
||||
module UseGitlabGitAttributes
|
||||
|
|
|
|||
|
|
@ -0,0 +1,183 @@
|
|||
## Usually modules with instance variables considered harmful
|
||||
|
||||
### Background
|
||||
|
||||
Rails somehow encourages people using modules and instance variables
|
||||
everywhere. For example, using instance variables in the controllers,
|
||||
helpers, and views. They're also encouraging the use of
|
||||
`ActiveSupport::Concern`, which further strengthens the idea of
|
||||
saving everything in a giant, single object, and people could access
|
||||
everything in that one giant object.
|
||||
|
||||
### The problems
|
||||
|
||||
Of course this is convenient to develop, because we just have everything
|
||||
within reach. However this has a number of downsides when that chosen object
|
||||
is growing, it would later become out of control for the same reason.
|
||||
|
||||
There are just too many things in the same context, and we don't know if
|
||||
those things are tightly coupled or not, depending on each others or not.
|
||||
It's very hard to tell when the complexity grows to a point, and it makes
|
||||
tracking the code also extremely hard. For example, a class could be using
|
||||
3 different instance variables, and all of them could be initialized and
|
||||
manipulated from 3 different modules. It's hard to track when those variables
|
||||
start giving us troubles. We don't know which module would suddenly change
|
||||
one of the variables. Everything could touch anything.
|
||||
|
||||
### Similar concerns
|
||||
|
||||
People are saying multiple inheritance is bad. Mixing multiple modules with
|
||||
multiple instance variables scattering everywhere suffer from the same issue.
|
||||
The same applies to `ActiveSupport::Concern`. See:
|
||||
[Consider replacing concerns with dedicated classes & composition](
|
||||
https://gitlab.com/gitlab-org/gitlab-ce/issues/23786)
|
||||
|
||||
There's also a similar idea:
|
||||
[Use decorators and interface segregation to solve overgrowing models problem](
|
||||
https://gitlab.com/gitlab-org/gitlab-ce/issues/13484)
|
||||
|
||||
Note that `included` doesn't solve the whole issue. They define the
|
||||
dependencies, but they still allow each modules to talk implicitly via the
|
||||
instance variables in the final giant object, and that's where the problem is.
|
||||
|
||||
### Solutions
|
||||
|
||||
We should split the giant object into multiple objects, and they communicate
|
||||
each other with the API, i.e. public methods. In short, composition over
|
||||
inheritance. This way, each smaller objects would have their own respective
|
||||
limited states, i.e. instance variables. If one instance variable goes wrong,
|
||||
we would be very clear that it's from that single small object, because
|
||||
no one else could be touching it.
|
||||
|
||||
With clearly defined API, this would make things less coupled and much easier
|
||||
to debug and track, and much more extensible for other objects to use, because
|
||||
they communicate in a clear way, rather than implicit dependencies.
|
||||
|
||||
### Exceptions
|
||||
|
||||
However, it's not all that bad when using instance variables in a module,
|
||||
as long as it's contained in the same module, that is no other modules or
|
||||
objects are touching them. If that's the case, then it would be an acceptable
|
||||
use. Unfortunately it's a bit hard to code this principle in the cop, so
|
||||
for now we rely on people turning off the cops, if they think that the use
|
||||
conform this rule.
|
||||
|
||||
Here's an acceptable case:
|
||||
|
||||
``` ruby
|
||||
# This is ok, as long as `@attributes` is never used anywhere else.
|
||||
# Consider adding some prefix or suffix to avoid name conflicts though.
|
||||
# rubocop:disable Cop/ModuleWithInstanceVariables
|
||||
module Rugged
|
||||
class Repository
|
||||
module UseGitlabGitAttributes
|
||||
def fetch_attributes(name, *)
|
||||
@attributes ||= Gitlab::Git::Attributes.new(path)
|
||||
@attributes.attributes(name)
|
||||
end
|
||||
end
|
||||
|
||||
prepend UseGitlabGitAttributes
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
Here's a bad example which we should rewrite:
|
||||
|
||||
``` ruby
|
||||
module SpamCheckService
|
||||
def filter_spam_check_params
|
||||
@request = params.delete(:request)
|
||||
@api = params.delete(:api)
|
||||
@recaptcha_verified = params.delete(:recaptcha_verified)
|
||||
@spam_log_id = params.delete(:spam_log_id)
|
||||
end
|
||||
|
||||
def spam_check(spammable, user)
|
||||
spam_service = SpamService.new(spammable, @request)
|
||||
|
||||
spam_service.when_recaptcha_verified(@recaptcha_verified, @api) do
|
||||
user.spam_logs.find_by(id: @spam_log_id)&.update!(recaptcha_verified: true)
|
||||
end
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
There are several implicit dependencies here. First, `params` should be
|
||||
defined before using. Second, `filter_spam_check_params` should be called
|
||||
before `spam_check`. These are all implicit and the includer could be using
|
||||
those instance variables without awareness.
|
||||
|
||||
This should be rewritten like:
|
||||
|
||||
``` ruby
|
||||
class SpamCheckService
|
||||
def initialize(request:, api:, recaptcha_verified:, spam_log_id:)
|
||||
@request = request
|
||||
@api = api
|
||||
@recaptcha_verified = recaptcha_verified
|
||||
@spam_log_id = spam_log_id
|
||||
end
|
||||
|
||||
def spam_check(spammable, user)
|
||||
spam_service = SpamService.new(spammable, @request)
|
||||
|
||||
spam_service.when_recaptcha_verified(@recaptcha_verified, @api) do
|
||||
user.spam_logs.find_by(id: @spam_log_id)&.update!(recaptcha_verified: true)
|
||||
end
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
And use it like:
|
||||
|
||||
``` ruby
|
||||
class UpdateSnippetService < BaseService
|
||||
def execute
|
||||
# ...
|
||||
spam = SpamCheckService.new(params.slice!(:request, :api, :recaptcha_verified, :spam_log_id))
|
||||
|
||||
spam.check(snippet, current_user)
|
||||
# ...
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
This way, all those instance variables are isolated in `SpamCheckService`
|
||||
rather than who ever include the module, and those modules which were also
|
||||
included, making it much easier to track down the issues if there's any,
|
||||
and it also reduce the chance of having name conflicts.
|
||||
|
||||
### Things we might need to ignore right now
|
||||
|
||||
Since the way how Rails helpers and mailers work, we might not be able to
|
||||
avoid the use of instance variables there. For those cases, we could ignore
|
||||
them at the moment. At least we're not going to share those modules with
|
||||
other random objects, so they're still somehow isolated.
|
||||
|
||||
### Instance variables in the views
|
||||
|
||||
They're terrible, because they're also shared between different controllers,
|
||||
and it's very hard to track where those instance variables were set when we
|
||||
saw somewhere is using it, neither do we know where those were used when we
|
||||
saw somewhere is setting up them. We hit into a number of 500 errors when we
|
||||
tried to remove some instance variables in the controller in the past.
|
||||
|
||||
Somewhere, some partials might be using it, and we don't know.
|
||||
|
||||
We're trying to use something like this instead:
|
||||
|
||||
``` haml
|
||||
= render 'projects/commits/commit', commit: commit, ref: ref, project: project
|
||||
```
|
||||
|
||||
And in the partial:
|
||||
|
||||
``` haml
|
||||
- ref = local_assigns.fetch(:ref)
|
||||
- commit = local_assigns.fetch(:commit)
|
||||
- project = local_assigns.fetch(:project)
|
||||
```
|
||||
|
||||
This way it's very clear where those values were coming from. In the future,
|
||||
we should also forbid the use of instance variables in partials.
|
||||
|
|
@ -42,11 +42,11 @@ module StdoutReporterWithScenarioLocation
|
|||
# Override the standard reporter to show filename and line number next to each
|
||||
# scenario for easy, focused re-runs
|
||||
def before_scenario_run(scenario, step_definitions = nil)
|
||||
@max_step_name_length = scenario.steps.map(&:name).map(&:length).max if scenario.steps.any?
|
||||
max_step_name_length = scenario.steps.map(&:name).map(&:length).max if scenario.steps.any?
|
||||
name = scenario.name
|
||||
|
||||
# This number has no significance, it's just to line things up
|
||||
max_length = @max_step_name_length + 19
|
||||
max_length = max_step_name_length + 19
|
||||
out.puts "\n #{'Scenario:'.green} #{name.light_green.ljust(max_length)}" \
|
||||
" # #{scenario.feature.filename}:#{scenario.line}"
|
||||
end
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ module AfterCommitQueue
|
|||
end
|
||||
end
|
||||
|
||||
# rubocop:disable Cop/ModuleWithInstanceVariables
|
||||
def _after_commit_queue
|
||||
@after_commit_queue ||= []
|
||||
end
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
require 'rack/oauth2'
|
||||
|
||||
# rubocop:disable Cop/ModuleWithInstanceVariables
|
||||
module API
|
||||
module APIGuard
|
||||
extend ActiveSupport::Concern
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
# rubocop:disable Cop/ModuleWithInstanceVariables
|
||||
module API
|
||||
module Helpers
|
||||
include Gitlab::Utils
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
# rubocop:disable Cop/ModuleWithInstanceVariables
|
||||
module API
|
||||
module Helpers
|
||||
module InternalHelpers
|
||||
|
|
@ -57,6 +58,7 @@ module API
|
|||
|
||||
private
|
||||
|
||||
# rubocop:disable Cop/ModuleWithInstanceVariables
|
||||
def set_project
|
||||
if params[:gl_repository]
|
||||
@project, @wiki = Gitlab::GlRepository.parse(params[:gl_repository])
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ module API
|
|||
forbidden! unless current_runner
|
||||
end
|
||||
|
||||
# rubocop:disable Cop/ModuleWithInstanceVariables
|
||||
def current_runner
|
||||
@runner ||= ::Ci::Runner.find_by_token(params[:token].to_s)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
# Module providing methods for dealing with separating a tree-ish string and a
|
||||
# file path string when combined in a request parameter
|
||||
# rubocop:disable Cop/ModuleWithInstanceVariables
|
||||
module ExtractsPath
|
||||
# Raised when given an invalid file path
|
||||
InvalidPathError = Class.new(StandardError)
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ module Gitlab
|
|||
klass.prepend(extension)
|
||||
end
|
||||
|
||||
# rubocop:disable Cop/ModuleWithInstanceVariables
|
||||
def request_cache_key(&block)
|
||||
if block_given?
|
||||
@request_cache_key = block
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ module Gitlab
|
|||
module Ci
|
||||
module Charts
|
||||
module DailyInterval
|
||||
# rubocop:disable Cop/ModuleWithInstanceVariables
|
||||
def grouped_count(query)
|
||||
query
|
||||
.group("DATE(#{::Ci::Pipeline.table_name}.created_at)")
|
||||
|
|
@ -9,6 +10,7 @@ module Gitlab
|
|||
.transform_keys { |date| date.strftime(@format) }
|
||||
end
|
||||
|
||||
# rubocop:disable Cop/ModuleWithInstanceVariables
|
||||
def interval_step
|
||||
@interval_step ||= 1.day
|
||||
end
|
||||
|
|
@ -28,6 +30,7 @@ module Gitlab
|
|||
end
|
||||
end
|
||||
|
||||
# rubocop:disable Cop/ModuleWithInstanceVariables
|
||||
def interval_step
|
||||
@interval_step ||= 1.month
|
||||
end
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ module Gitlab
|
|||
# script: ...
|
||||
# artifacts: ...
|
||||
#
|
||||
# rubocop:disable Cop/ModuleWithInstanceVariables
|
||||
module Configurable
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
# rubocop:disable Cop/ModuleWithInstanceVariables
|
||||
module Gitlab
|
||||
module Ci
|
||||
class Config
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ module Gitlab
|
|||
"ci_"
|
||||
end
|
||||
|
||||
# rubocop:disable Cop/ModuleWithInstanceVariables
|
||||
def model_name
|
||||
@model_name ||= ActiveModel::Name.new(self, nil, self.name.split("::").last)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@ module Gitlab
|
|||
::ApplicationSetting.create_from_defaults || in_memory_application_settings
|
||||
end
|
||||
|
||||
# rubocop:disable Cop/ModuleWithInstanceVariables
|
||||
def in_memory_application_settings
|
||||
@in_memory_application_settings ||= ::ApplicationSetting.new(::ApplicationSetting.defaults)
|
||||
rescue ActiveRecord::StatementInvalid, ActiveRecord::UnknownAttributeError
|
||||
|
|
|
|||
|
|
@ -59,6 +59,12 @@ module Gitlab
|
|||
nil
|
||||
end
|
||||
|
||||
def load_allowed_ids
|
||||
allowed_ids_finder_class
|
||||
.new(@options[:current_user], project_id: @project.id)
|
||||
.execute.where(id: event_result_ids).pluck(:id)
|
||||
end
|
||||
|
||||
def event_result_ids
|
||||
event_result.map { |event| event['id'] }
|
||||
end
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ module Gitlab
|
|||
|
||||
private
|
||||
|
||||
# rubocop:disable Cop/ModuleWithInstanceVariables
|
||||
def base_query
|
||||
@base_query ||= stage_query
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
module Gitlab
|
||||
module CycleAnalytics
|
||||
class CodeEventFetcher < BaseEventFetcher
|
||||
include MergeRequestAllowed
|
||||
|
||||
def initialize(*args)
|
||||
@projections = [mr_table[:title],
|
||||
mr_table[:iid],
|
||||
|
|
@ -20,6 +18,14 @@ module Gitlab
|
|||
def serialize(event)
|
||||
AnalyticsMergeRequestSerializer.new(project: @project).represent(event)
|
||||
end
|
||||
|
||||
def allowed_ids
|
||||
load_allowed_ids
|
||||
end
|
||||
|
||||
def allowed_ids_finder_class
|
||||
MergeRequestsFinder
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,9 +0,0 @@
|
|||
module Gitlab
|
||||
module CycleAnalytics
|
||||
module IssueAllowed
|
||||
def allowed_ids
|
||||
@allowed_ids ||= IssuesFinder.new(@options[:current_user], project_id: @project.id).execute.where(id: event_result_ids).pluck(:id)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -1,8 +1,6 @@
|
|||
module Gitlab
|
||||
module CycleAnalytics
|
||||
class IssueEventFetcher < BaseEventFetcher
|
||||
include IssueAllowed
|
||||
|
||||
def initialize(*args)
|
||||
@projections = [issue_table[:title],
|
||||
issue_table[:iid],
|
||||
|
|
@ -18,6 +16,14 @@ module Gitlab
|
|||
def serialize(event)
|
||||
AnalyticsIssueSerializer.new(project: @project).represent(event)
|
||||
end
|
||||
|
||||
def allowed_ids
|
||||
load_allowed_ids
|
||||
end
|
||||
|
||||
def allowed_ids_finder_class
|
||||
IssuesFinder
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,9 +0,0 @@
|
|||
module Gitlab
|
||||
module CycleAnalytics
|
||||
module MergeRequestAllowed
|
||||
def allowed_ids
|
||||
@allowed_ids ||= MergeRequestsFinder.new(@options[:current_user], project_id: @project.id).execute.where(id: event_result_ids).pluck(:id)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -1,3 +1,4 @@
|
|||
# rubocop:disable Cop/ModuleWithInstanceVariables
|
||||
module Gitlab
|
||||
module CycleAnalytics
|
||||
module ProductionHelper
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
module Gitlab
|
||||
module CycleAnalytics
|
||||
class ReviewEventFetcher < BaseEventFetcher
|
||||
include MergeRequestAllowed
|
||||
|
||||
def initialize(*args)
|
||||
@projections = [mr_table[:title],
|
||||
mr_table[:iid],
|
||||
|
|
@ -14,9 +12,19 @@ module Gitlab
|
|||
super(*args)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def serialize(event)
|
||||
AnalyticsMergeRequestSerializer.new(project: @project).represent(event)
|
||||
end
|
||||
|
||||
def allowed_ids
|
||||
load_allowed_ids
|
||||
end
|
||||
|
||||
def allowed_ids_finder_class
|
||||
MergeRequestsFinder
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ module Gitlab
|
|||
module RenameReservedPathsMigration
|
||||
module V1
|
||||
module MigrationClasses
|
||||
# rubocop:disable Cop/ModuleWithInstanceVariables
|
||||
module Routable
|
||||
def full_path
|
||||
if route && route.path.present?
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ module Gitlab
|
|||
raise NotImplementedError
|
||||
end
|
||||
|
||||
# rubocop:disable Cop/ModuleWithInstanceVariables
|
||||
def message
|
||||
@message ||= process_message
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
# rubocop:disable Cop/ModuleWithInstanceVariables
|
||||
module Gitlab
|
||||
module Emoji
|
||||
extend self
|
||||
|
|
|
|||
|
|
@ -13,15 +13,15 @@ module Gitlab
|
|||
vars = { "PWD" => path }
|
||||
options = { chdir: path }
|
||||
|
||||
@cmd_output = ""
|
||||
@cmd_status = 0
|
||||
cmd_output = ""
|
||||
cmd_status = 0
|
||||
Open3.popen3(vars, *cmd, options) do |stdin, stdout, stderr, wait_thr|
|
||||
@cmd_output << stdout.read
|
||||
@cmd_output << stderr.read
|
||||
@cmd_status = wait_thr.value.exitstatus
|
||||
cmd_output << stdout.read
|
||||
cmd_output << stderr.read
|
||||
cmd_status = wait_thr.value.exitstatus
|
||||
end
|
||||
|
||||
[@cmd_output, @cmd_status]
|
||||
[cmd_output, cmd_status]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@ module Gitlab
|
|||
end
|
||||
end
|
||||
|
||||
# rubocop:disable Cop/ModuleWithInstanceVariables
|
||||
def identification_cache
|
||||
@identification_cache ||= {
|
||||
email: {},
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ module Gitlab
|
|||
execute(%W(tar -#{options} #{archive} -C #{dir}))
|
||||
end
|
||||
|
||||
# rubocop:disable Cop/ModuleWithInstanceVariables
|
||||
def execute(cmd)
|
||||
output, status = Gitlab::Popen.popen(cmd)
|
||||
@shared.error(Gitlab::ImportExport::Error.new(output.to_s)) unless status.zero?
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
# rubocop:disable Cop/ModuleWithInstanceVariables
|
||||
module Gitlab
|
||||
module Metrics
|
||||
module InfluxDb
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
require 'prometheus/client'
|
||||
|
||||
# rubocop:disable Cop/ModuleWithInstanceVariables
|
||||
module Gitlab
|
||||
module Metrics
|
||||
module Prometheus
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
# rubocop:disable Cop/ModuleWithInstanceVariables
|
||||
module Gitlab
|
||||
module PathRegex
|
||||
extend self
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ module Gitlab
|
|||
load_yaml_file&.map(&:deep_symbolize_keys).freeze
|
||||
end
|
||||
|
||||
# rubocop:disable Cop/ModuleWithInstanceVariables
|
||||
def load_yaml_file
|
||||
@loaded_yaml_file ||= YAML.load_file(Rails.root.join('config/prometheus/additional_metrics.yml'))
|
||||
end
|
||||
|
|
|
|||
|
|
@ -56,6 +56,7 @@ module Gitlab
|
|||
query
|
||||
end
|
||||
|
||||
# rubocop:disable Cop/ModuleWithInstanceVariables
|
||||
def available_metrics
|
||||
@available_metrics ||= client_label_values || []
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
# rubocop:disable Cop/ModuleWithInstanceVariables
|
||||
module Gitlab
|
||||
module Regex
|
||||
extend self
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
# rubocop:disable Cop/ModuleWithInstanceVariables
|
||||
module Gitlab
|
||||
module SlashCommands
|
||||
module Presenters
|
||||
|
|
|
|||
|
|
@ -72,6 +72,7 @@ module Gitlab
|
|||
|
||||
private
|
||||
|
||||
# rubocop:disable Cop/ModuleWithInstanceVariables
|
||||
def default_id
|
||||
@default_id ||= begin
|
||||
id = Gitlab.config.gitlab.default_theme.to_i
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
require 'rainbow/ext/string'
|
||||
|
||||
# rubocop:disable Cop/ModuleWithInstanceVariables
|
||||
module Gitlab
|
||||
TaskFailedError = Class.new(StandardError)
|
||||
TaskAbortedByUserError = Class.new(StandardError)
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ module QA
|
|||
module Namespace
|
||||
extend self
|
||||
|
||||
# rubocop:disable Cop/ModuleWithInstanceVariables
|
||||
def time
|
||||
@time ||= Time.now
|
||||
end
|
||||
|
|
|
|||
|
|
@ -0,0 +1,55 @@
|
|||
module RuboCop
|
||||
module Cop
|
||||
class ModuleWithInstanceVariables < RuboCop::Cop::Cop
|
||||
MSG = <<~EOL.freeze
|
||||
Do not use instance variables in a module. Please read this
|
||||
for the rationale behind it:
|
||||
|
||||
doc/development/module_with_instance_variables.md
|
||||
|
||||
If you think the use for this is fine, please just add:
|
||||
# rubocop:disable Cop/ModuleWithInstanceVariables
|
||||
EOL
|
||||
|
||||
def on_module(node)
|
||||
return if
|
||||
rails_helper?(node) || rails_mailer?(node) || spec_helper?(node)
|
||||
|
||||
check_method_definition(node)
|
||||
|
||||
# Not sure why some module would have an extra begin wrapping around
|
||||
node.each_child_node(:begin) do |begin_node|
|
||||
check_method_definition(begin_node)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# We ignore Rails helpers right now because it's hard to workaround it
|
||||
def rails_helper?(node)
|
||||
node.source_range.source_buffer.name =~
|
||||
%r{app/helpers/\w+_helper.rb\z}
|
||||
end
|
||||
|
||||
# We ignore Rails mailers right now because it's hard to workaround it
|
||||
def rails_mailer?(node)
|
||||
node.source_range.source_buffer.name =~
|
||||
%r{app/mailers/emails/}
|
||||
end
|
||||
|
||||
# We ignore spec helpers because it usually doesn't matter
|
||||
def spec_helper?(node)
|
||||
node.source_range.source_buffer.name =~
|
||||
%r{spec/support/|features/steps/}
|
||||
end
|
||||
|
||||
def check_method_definition(node)
|
||||
node.each_child_node(:def) do |definition|
|
||||
definition.each_descendant(:ivar, :ivasgn) do |offense|
|
||||
add_offense(offense, :expression)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -6,6 +6,7 @@ require_relative 'cop/polymorphic_associations'
|
|||
require_relative 'cop/project_path_helper'
|
||||
require_relative 'cop/active_record_dependent'
|
||||
require_relative 'cop/in_batches'
|
||||
require_relative 'cop/module_with_instance_variables'
|
||||
require_relative 'cop/migration/add_column'
|
||||
require_relative 'cop/migration/add_column_with_default_to_large_table'
|
||||
require_relative 'cop/migration/add_concurrent_foreign_key'
|
||||
|
|
|
|||
|
|
@ -0,0 +1,117 @@
|
|||
require 'spec_helper'
|
||||
require 'rubocop'
|
||||
require 'rubocop/rspec/support'
|
||||
require_relative '../../../rubocop/cop/module_with_instance_variables'
|
||||
|
||||
describe RuboCop::Cop::ModuleWithInstanceVariables do
|
||||
include CopHelper
|
||||
|
||||
subject(:cop) { described_class.new }
|
||||
|
||||
shared_examples('registering offense') do
|
||||
it 'registers an offense when instance variable is used in a module' do
|
||||
inspect_source(cop, source)
|
||||
|
||||
aggregate_failures do
|
||||
expect(cop.offenses.size).to eq(offending_lines.size)
|
||||
expect(cop.offenses.map(&:line)).to eq(offending_lines)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when source is a regular module' do
|
||||
let(:source) do
|
||||
<<~RUBY
|
||||
module M
|
||||
def f
|
||||
@f ||= true
|
||||
end
|
||||
end
|
||||
RUBY
|
||||
end
|
||||
|
||||
let(:offending_lines) { [3] }
|
||||
|
||||
it_behaves_like 'registering offense'
|
||||
end
|
||||
|
||||
context 'when source is a nested module' do
|
||||
let(:source) do
|
||||
<<~RUBY
|
||||
module N
|
||||
module M
|
||||
def f
|
||||
@f = true
|
||||
end
|
||||
end
|
||||
end
|
||||
RUBY
|
||||
end
|
||||
|
||||
let(:offending_lines) { [4] }
|
||||
|
||||
it_behaves_like 'registering offense'
|
||||
end
|
||||
|
||||
context 'when source is a nested module with multiple offenses' do
|
||||
let(:source) do
|
||||
<<~RUBY
|
||||
module N
|
||||
module M
|
||||
def f
|
||||
@f ||= true
|
||||
end
|
||||
|
||||
def g
|
||||
true
|
||||
end
|
||||
|
||||
def h
|
||||
@h = true
|
||||
end
|
||||
end
|
||||
end
|
||||
RUBY
|
||||
end
|
||||
|
||||
let(:offending_lines) { [4, 12] }
|
||||
|
||||
it_behaves_like 'registering offense'
|
||||
end
|
||||
|
||||
context 'when source is offending but it is a rails helper' do
|
||||
before do
|
||||
allow(cop).to receive(:rails_helper?).and_return(true)
|
||||
end
|
||||
|
||||
it 'does not register offenses' do
|
||||
inspect_source(cop, <<~RUBY)
|
||||
module M
|
||||
def f
|
||||
@f ||= true
|
||||
end
|
||||
end
|
||||
RUBY
|
||||
|
||||
expect(cop.offenses).to be_empty
|
||||
end
|
||||
end
|
||||
|
||||
context 'when source is offending but it is a rails mailer' do
|
||||
before do
|
||||
allow(cop).to receive(:rails_mailer?).and_return(true)
|
||||
end
|
||||
|
||||
it 'does not register offenses' do
|
||||
inspect_source(cop, <<~RUBY)
|
||||
module M
|
||||
def f
|
||||
@f = true
|
||||
end
|
||||
end
|
||||
RUBY
|
||||
|
||||
expect(cop.offenses).to be_empty
|
||||
end
|
||||
end
|
||||
end
|
||||
Loading…
Reference in New Issue