gitlab-styles 3.4.0 → 5.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.editorconfig +18 -0
- data/.gitignore +3 -0
- data/.gitlab/merge_request_templates/Release.md +1 -1
- data/Gemfile +3 -2
- data/README.md +1 -0
- data/gitlab-styles.gemspec +5 -4
- data/lib/gitlab/styles/rubocop.rb +4 -0
- data/lib/gitlab/styles/rubocop/cop/code_reuse/active_record.rb +131 -0
- data/lib/gitlab/styles/rubocop/cop/migration/update_large_table.rb +64 -0
- data/lib/gitlab/styles/rubocop/cop/rspec/base.rb +18 -0
- data/lib/gitlab/styles/rubocop/cop/rspec/empty_line_after_let_block.rb +65 -0
- data/lib/gitlab/styles/rubocop/cop/rspec/empty_line_after_shared_example.rb +65 -0
- data/lib/gitlab/styles/rubocop/cop/rspec/have_link_parameters.rb +10 -5
- data/lib/gitlab/styles/rubocop/cop/rspec/single_line_hook.rb +3 -2
- data/lib/gitlab/styles/rubocop/cop/rspec/verbose_include_metadata.rb +10 -13
- data/lib/gitlab/styles/rubocop/model_helpers.rb +1 -1
- data/lib/gitlab/styles/rubocop/rspec/helpers.rb +17 -0
- data/lib/gitlab/styles/version.rb +1 -1
- data/rubocop-all.yml +2 -1
- data/rubocop-bundler.yml +1 -0
- data/rubocop-code_reuse.yml +24 -0
- data/rubocop-default.yml +2 -0
- data/rubocop-gemspec.yml +1 -0
- data/rubocop-layout.yml +38 -22
- data/rubocop-lint.yml +81 -19
- data/rubocop-metrics.yml +1 -6
- data/rubocop-migrations.yml +22 -0
- data/rubocop-naming.yml +9 -8
- data/rubocop-performance.yml +48 -0
- data/rubocop-rails.yml +79 -0
- data/rubocop-rspec.yml +14 -0
- data/rubocop-security.yml +1 -0
- data/rubocop-style.yml +118 -14
- metadata +21 -12
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f34644596ecbfd782a8a8d5781251743cbe2f0ef079467416c4e15c784769693
|
4
|
+
data.tar.gz: 531fb802e1a50564fbbfad34e96f66b8a2227e6c182999750a39456f2ae17c98
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9a4036572db91754b18045e0e9ec40d9747a633773c49fb3edcdc53d0ac8b6ae2743f94ffe5fc2ce6cc8a60a51216eb7b85c89dfb039f747370cca4831c9cc41
|
7
|
+
data.tar.gz: 78eb2aaec9c221dad33fb99c719c3ad838a39f4978381b2f99ef011f87c8c8ee67a24d9b6e26af2eea4d1b3a03e03e80aab5c2718afaa998764a3cf68d8153e4
|
data/.editorconfig
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
# top-most EditorConfig file
|
2
|
+
root = true
|
3
|
+
|
4
|
+
# Unix-style newlines with a newline ending every file
|
5
|
+
[*]
|
6
|
+
end_of_line = lf
|
7
|
+
trim_trailing_whitespace = true
|
8
|
+
insert_final_newline = true
|
9
|
+
|
10
|
+
[*.{rb,yml}]
|
11
|
+
indent_size = 2
|
12
|
+
|
13
|
+
[*.{rb,yml,md}]
|
14
|
+
indent_style = space
|
15
|
+
charset = utf-8
|
16
|
+
|
17
|
+
[*.{md,markdown}]
|
18
|
+
trim_trailing_whitespace = false
|
data/.gitignore
CHANGED
@@ -32,4 +32,4 @@ with the latest commit from https://gitlab.com/gitlab-org/gitlab-styles/commits/
|
|
32
32
|
- Checklist after merging:
|
33
33
|
- [ ] [Create a tag for the new release version](docs/release_process.md#how-to).
|
34
34
|
|
35
|
-
/label ~"Engineering Productivity" ~
|
35
|
+
/label ~"Engineering Productivity" ~"tooling::workflow"
|
data/Gemfile
CHANGED
@@ -7,6 +7,7 @@ gemspec
|
|
7
7
|
|
8
8
|
group :test do
|
9
9
|
# Pin these dependencies, otherwise a new rule could break the CI pipelines
|
10
|
-
gem 'rubocop', '0.
|
11
|
-
gem 'rubocop-rspec', '1.
|
10
|
+
gem 'rubocop', '0.89.1'
|
11
|
+
gem 'rubocop-rspec', '1.44.1'
|
12
|
+
gem 'rspec-parameterized', '0.4.2', require: false
|
12
13
|
end
|
data/README.md
CHANGED
data/gitlab-styles.gemspec
CHANGED
@@ -5,6 +5,7 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
5
5
|
require 'gitlab/styles/version'
|
6
6
|
|
7
7
|
Gem::Specification.new do |spec|
|
8
|
+
spec.required_ruby_version = '>= 2.6'
|
8
9
|
spec.name = 'gitlab-styles'
|
9
10
|
spec.version = Gitlab::Styles::VERSION
|
10
11
|
spec.authors = ['GitLab']
|
@@ -21,11 +22,11 @@ Gem::Specification.new do |spec|
|
|
21
22
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
22
23
|
spec.require_paths = ['lib']
|
23
24
|
|
24
|
-
spec.add_dependency 'rubocop', '~> 0.
|
25
|
+
spec.add_dependency 'rubocop', '~> 0.89.1'
|
25
26
|
spec.add_dependency 'rubocop-gitlab-security', '~> 0.1.0'
|
26
|
-
spec.add_dependency 'rubocop-performance', '~> 1.
|
27
|
-
spec.add_dependency 'rubocop-rails', '~> 2.
|
28
|
-
spec.add_dependency 'rubocop-rspec', '~> 1.
|
27
|
+
spec.add_dependency 'rubocop-performance', '~> 1.8.1'
|
28
|
+
spec.add_dependency 'rubocop-rails', '~> 2.8'
|
29
|
+
spec.add_dependency 'rubocop-rspec', '~> 1.44'
|
29
30
|
|
30
31
|
spec.add_development_dependency 'bundler', '~> 1.16'
|
31
32
|
spec.add_development_dependency 'rake', '~> 10.0'
|
@@ -8,10 +8,14 @@ require 'gitlab/styles/rubocop/cop/polymorphic_associations'
|
|
8
8
|
require 'gitlab/styles/rubocop/cop/active_record_dependent'
|
9
9
|
require 'gitlab/styles/rubocop/cop/in_batches'
|
10
10
|
require 'gitlab/styles/rubocop/cop/line_break_after_guard_clauses'
|
11
|
+
require 'gitlab/styles/rubocop/cop/code_reuse/active_record'
|
12
|
+
require 'gitlab/styles/rubocop/cop/migration/update_large_table'
|
11
13
|
require 'gitlab/styles/rubocop/cop/without_reactive_cache'
|
12
14
|
require 'gitlab/styles/rubocop/cop/rspec/single_line_hook'
|
13
15
|
require 'gitlab/styles/rubocop/cop/rspec/have_link_parameters'
|
14
16
|
require 'gitlab/styles/rubocop/cop/rspec/verbose_include_metadata'
|
17
|
+
require 'gitlab/styles/rubocop/cop/rspec/empty_line_after_shared_example'
|
18
|
+
require 'gitlab/styles/rubocop/cop/rspec/empty_line_after_let_block'
|
15
19
|
|
16
20
|
module Gitlab
|
17
21
|
module Styles
|
@@ -0,0 +1,131 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Gitlab
|
4
|
+
module Styles
|
5
|
+
module Rubocop
|
6
|
+
module Cop
|
7
|
+
module CodeReuse
|
8
|
+
# Cop that denies the use of ActiveRecord methods outside of models.
|
9
|
+
class ActiveRecord < RuboCop::Cop::Cop
|
10
|
+
MSG = 'This method can only be used inside an ActiveRecord model: ' \
|
11
|
+
'https://gitlab.com/gitlab-org/gitlab-foss/issues/49653'
|
12
|
+
|
13
|
+
# Various methods from ActiveRecord::Querying that are denied. We
|
14
|
+
# exclude some generic ones such as `any?` and `first`, as these may
|
15
|
+
# lead to too many false positives, since `Array` also supports these
|
16
|
+
# methods.
|
17
|
+
#
|
18
|
+
# The keys of this Hash are the denied method names. The values are
|
19
|
+
# booleans that indicate if the method should only be denied if any
|
20
|
+
# arguments are provided.
|
21
|
+
NOT_ALLOWED = {
|
22
|
+
average: true,
|
23
|
+
calculate: true,
|
24
|
+
count_by_sql: true,
|
25
|
+
create_with: true,
|
26
|
+
distinct: false,
|
27
|
+
eager_load: true,
|
28
|
+
exists?: true,
|
29
|
+
find_by: true,
|
30
|
+
find_by!: true,
|
31
|
+
find_by_sql: true,
|
32
|
+
find_each: true,
|
33
|
+
find_in_batches: true,
|
34
|
+
find_or_create_by: true,
|
35
|
+
find_or_create_by!: true,
|
36
|
+
find_or_initialize_by: true,
|
37
|
+
first!: false,
|
38
|
+
first_or_create: true,
|
39
|
+
first_or_create!: true,
|
40
|
+
first_or_initialize: true,
|
41
|
+
from: true,
|
42
|
+
group: true,
|
43
|
+
having: true,
|
44
|
+
ids: false,
|
45
|
+
includes: true,
|
46
|
+
joins: true,
|
47
|
+
limit: true,
|
48
|
+
lock: false,
|
49
|
+
many?: false,
|
50
|
+
offset: true,
|
51
|
+
order: true,
|
52
|
+
pluck: true,
|
53
|
+
preload: true,
|
54
|
+
readonly: false,
|
55
|
+
references: true,
|
56
|
+
reorder: true,
|
57
|
+
rewhere: true,
|
58
|
+
take: false,
|
59
|
+
take!: false,
|
60
|
+
unscope: false,
|
61
|
+
where: false,
|
62
|
+
with: true
|
63
|
+
}.freeze
|
64
|
+
|
65
|
+
def on_send(node)
|
66
|
+
receiver = node.children[0]
|
67
|
+
send_name = node.children[1]
|
68
|
+
first_arg = node.children[2]
|
69
|
+
|
70
|
+
return unless receiver && NOT_ALLOWED.key?(send_name)
|
71
|
+
|
72
|
+
# If the rule requires an argument to be given, but none are
|
73
|
+
# provided, we won't register an offense. This prevents us from
|
74
|
+
# adding offenses for `project.group`, while still covering
|
75
|
+
# `Project.group(:name)`.
|
76
|
+
return if NOT_ALLOWED[send_name] && !first_arg
|
77
|
+
|
78
|
+
add_offense(node, location: :selector)
|
79
|
+
end
|
80
|
+
|
81
|
+
# We can not auto correct code like this, as it requires manual
|
82
|
+
# refactoring. Instead, we'll just allow the surrounding scope.
|
83
|
+
#
|
84
|
+
# Despite this method's presence, you should not use it. This method
|
85
|
+
# exists to make it possible to allow large chunks of offenses we
|
86
|
+
# can't fix in the short term. If you are writing new code, follow the
|
87
|
+
# code reuse guidelines, instead of allowing any new offenses.
|
88
|
+
def autocorrect(node)
|
89
|
+
scope = surrounding_scope_of(node)
|
90
|
+
indent = indentation_of(scope)
|
91
|
+
|
92
|
+
lambda do |corrector|
|
93
|
+
# This prevents us from inserting the same enable/disable comment
|
94
|
+
# for a method or block that has multiple offenses.
|
95
|
+
next if allowed_scopes.include?(scope)
|
96
|
+
|
97
|
+
corrector.insert_before(
|
98
|
+
scope.source_range,
|
99
|
+
"# rubocop: disable #{cop_name}\n#{indent}"
|
100
|
+
)
|
101
|
+
|
102
|
+
corrector.insert_after(
|
103
|
+
scope.source_range,
|
104
|
+
"\n#{indent}# rubocop: enable #{cop_name}"
|
105
|
+
)
|
106
|
+
|
107
|
+
allowed_scopes << scope
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def indentation_of(node)
|
112
|
+
' ' * node.loc.expression.source_line[/\A */].length
|
113
|
+
end
|
114
|
+
|
115
|
+
def surrounding_scope_of(node)
|
116
|
+
%i[def defs block begin].each do |type|
|
117
|
+
if (found = node.each_ancestor(type).first)
|
118
|
+
return found
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
def allowed_scopes
|
124
|
+
@allowed_scopes ||= Set.new
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require_relative '../../migration_helpers'
|
3
|
+
|
4
|
+
module Gitlab
|
5
|
+
module Styles
|
6
|
+
module Rubocop
|
7
|
+
module Cop
|
8
|
+
module Migration
|
9
|
+
# This cop checks for methods that may lead to batch type issues on a table that's been
|
10
|
+
# explicitly denied because of its size.
|
11
|
+
#
|
12
|
+
# Even though though these methods perform functions to avoid
|
13
|
+
# downtime, using it with tables with millions of rows still causes a
|
14
|
+
# significant delay in the deploy process and is best avoided.
|
15
|
+
#
|
16
|
+
# See https://gitlab.com/gitlab-com/infrastructure/issues/1602 for more
|
17
|
+
# information.
|
18
|
+
class UpdateLargeTable < RuboCop::Cop::Cop
|
19
|
+
include MigrationHelpers
|
20
|
+
|
21
|
+
MSG = 'Using `%s` on the `%s` table will take a long time to ' \
|
22
|
+
'complete, and should be avoided unless absolutely ' \
|
23
|
+
'necessary'
|
24
|
+
|
25
|
+
def_node_matcher :batch_update?, <<~PATTERN
|
26
|
+
(send nil? ${#denied_method?}
|
27
|
+
(sym $...)
|
28
|
+
...)
|
29
|
+
PATTERN
|
30
|
+
|
31
|
+
def on_send(node)
|
32
|
+
return if denied_tables.empty? || denied_methods.empty?
|
33
|
+
return unless in_migration?(node)
|
34
|
+
|
35
|
+
matches = batch_update?(node)
|
36
|
+
return unless matches
|
37
|
+
|
38
|
+
update_method = matches.first
|
39
|
+
table = matches.last.to_a.first
|
40
|
+
|
41
|
+
return unless denied_tables.include?(table)
|
42
|
+
|
43
|
+
add_offense(node, location: :expression, message: format(MSG, update_method, table))
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def denied_tables
|
49
|
+
cop_config['DeniedTables'] || []
|
50
|
+
end
|
51
|
+
|
52
|
+
def denied_method?(method_name)
|
53
|
+
denied_methods.include?(method_name)
|
54
|
+
end
|
55
|
+
|
56
|
+
def denied_methods
|
57
|
+
cop_config['DeniedMethods'] || []
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rubocop-rspec'
|
4
|
+
require_relative '../../rspec/helpers'
|
5
|
+
|
6
|
+
module Gitlab
|
7
|
+
module Styles
|
8
|
+
module Rubocop
|
9
|
+
module Cop
|
10
|
+
module RSpec
|
11
|
+
class Base < RuboCop::Cop::RSpec::Base
|
12
|
+
include Rubocop::Rspec::Helpers
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rubocop-rspec'
|
4
|
+
require_relative 'base'
|
5
|
+
|
6
|
+
module Gitlab
|
7
|
+
module Styles
|
8
|
+
module Rubocop
|
9
|
+
module Cop
|
10
|
+
module RSpec
|
11
|
+
# Checks if there is an empty line after let blocks.
|
12
|
+
#
|
13
|
+
# @example
|
14
|
+
# # bad
|
15
|
+
# RSpec.describe Foo do
|
16
|
+
# let(:something) { 'something' }
|
17
|
+
# let(:another_thing) do
|
18
|
+
# end
|
19
|
+
# let(:something_else) do
|
20
|
+
# end
|
21
|
+
# let(:last_thing) { 'last thing' }
|
22
|
+
# end
|
23
|
+
#
|
24
|
+
# # good
|
25
|
+
# RSpec.describe Foo do
|
26
|
+
# let(:something) { 'something' }
|
27
|
+
# let(:another_thing) do
|
28
|
+
# end
|
29
|
+
#
|
30
|
+
# let(:something_else) do
|
31
|
+
# end
|
32
|
+
#
|
33
|
+
# let(:last_thing) { 'last thing' }
|
34
|
+
# end
|
35
|
+
#
|
36
|
+
# # good - it's ok to have non-separated without do/end blocks
|
37
|
+
# RSpec.describe Foo do
|
38
|
+
# let(:something) { 'something' }
|
39
|
+
# let(:last_thing) { 'last thing' }
|
40
|
+
# end
|
41
|
+
#
|
42
|
+
class EmptyLineAfterLetBlock < Base
|
43
|
+
extend RuboCop::Cop::AutoCorrector
|
44
|
+
include RuboCop::RSpec::EmptyLineSeparation
|
45
|
+
|
46
|
+
MSG = 'Add an empty line after `%<let>s` block.'
|
47
|
+
|
48
|
+
def_node_matcher :lets, LET.block_pattern
|
49
|
+
|
50
|
+
def on_block(node)
|
51
|
+
lets(node) do
|
52
|
+
break if last_child?(node)
|
53
|
+
next if node.single_line?
|
54
|
+
|
55
|
+
missing_separating_line_offense(node) do |method|
|
56
|
+
format(MSG, let: method)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rubocop-rspec'
|
4
|
+
require_relative 'base'
|
5
|
+
|
6
|
+
module Gitlab
|
7
|
+
module Styles
|
8
|
+
module Rubocop
|
9
|
+
module Cop
|
10
|
+
module RSpec
|
11
|
+
# Checks if there is an empty line after shared example blocks.
|
12
|
+
#
|
13
|
+
# @example
|
14
|
+
# # bad
|
15
|
+
# RSpec.describe Foo do
|
16
|
+
# it_behaves_like 'do this first'
|
17
|
+
# it_behaves_like 'does this' do
|
18
|
+
# end
|
19
|
+
# it_behaves_like 'does that' do
|
20
|
+
# end
|
21
|
+
# it_behaves_like 'do some more'
|
22
|
+
# end
|
23
|
+
#
|
24
|
+
# # good
|
25
|
+
# RSpec.describe Foo do
|
26
|
+
# it_behaves_like 'do this first'
|
27
|
+
# it_behaves_like 'does this' do
|
28
|
+
# end
|
29
|
+
#
|
30
|
+
# it_behaves_like 'does that' do
|
31
|
+
# end
|
32
|
+
#
|
33
|
+
# it_behaves_like 'do some more'
|
34
|
+
# end
|
35
|
+
#
|
36
|
+
# # fair - it's ok to have non-separated without blocks
|
37
|
+
# RSpec.describe Foo do
|
38
|
+
# it_behaves_like 'do this first'
|
39
|
+
# it_behaves_like 'does this'
|
40
|
+
# end
|
41
|
+
#
|
42
|
+
class EmptyLineAfterSharedExample < Base
|
43
|
+
extend RuboCop::Cop::AutoCorrector
|
44
|
+
include RuboCop::RSpec::EmptyLineSeparation
|
45
|
+
|
46
|
+
MSG = 'Add an empty line after `%<example>s` block.'
|
47
|
+
|
48
|
+
def_node_matcher :shared_examples,
|
49
|
+
(SharedGroups::ALL + Includes::ALL).block_pattern
|
50
|
+
|
51
|
+
def on_block(node)
|
52
|
+
shared_examples(node) do
|
53
|
+
break if last_child?(node)
|
54
|
+
|
55
|
+
missing_separating_line_offense(node) do |method|
|
56
|
+
format(MSG, example: method)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|