gitlab-styles 3.2.0 → 5.1.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 -1
- data/.gitlab-ci.yml +25 -4
- data/.gitlab/merge_request_templates/Release.md +35 -0
- data/.rubocop.yml +3 -1
- data/Gemfile +5 -2
- data/README.md +5 -0
- data/Rakefile +2 -0
- data/gitlab-styles.gemspec +8 -5
- data/lib/gitlab/styles.rb +2 -0
- data/lib/gitlab/styles/rubocop.rb +7 -0
- data/lib/gitlab/styles/rubocop/cop/active_record_dependent.rb +4 -2
- data/lib/gitlab/styles/rubocop/cop/active_record_serialize.rb +3 -1
- data/lib/gitlab/styles/rubocop/cop/code_reuse/active_record.rb +131 -0
- data/lib/gitlab/styles/rubocop/cop/custom_error_class.rb +9 -4
- data/lib/gitlab/styles/rubocop/cop/gem_fetcher.rb +4 -2
- data/lib/gitlab/styles/rubocop/cop/in_batches.rb +3 -1
- data/lib/gitlab/styles/rubocop/cop/line_break_after_guard_clauses.rb +4 -2
- data/lib/gitlab/styles/rubocop/cop/line_break_around_conditional_block.rb +132 -0
- data/lib/gitlab/styles/rubocop/cop/migration/update_large_table.rb +64 -0
- data/lib/gitlab/styles/rubocop/cop/polymorphic_associations.rb +4 -2
- data/lib/gitlab/styles/rubocop/cop/redirect_with_status.rb +3 -1
- 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 +13 -6
- data/lib/gitlab/styles/rubocop/cop/rspec/single_line_hook.rb +6 -3
- data/lib/gitlab/styles/rubocop/cop/rspec/verbose_include_metadata.rb +13 -14
- data/lib/gitlab/styles/rubocop/cop/without_reactive_cache.rb +3 -1
- data/lib/gitlab/styles/rubocop/migration_helpers.rb +2 -0
- data/lib/gitlab/styles/rubocop/model_helpers.rb +3 -1
- data/lib/gitlab/styles/rubocop/rspec/helpers.rb +17 -0
- data/lib/gitlab/styles/version.rb +3 -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 -4
- 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 +119 -15
- metadata +27 -17
- data/.rubocop_todo.yml +0 -7
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require_relative '../model_helpers'
|
2
4
|
|
3
5
|
module Gitlab
|
@@ -6,7 +8,7 @@ module Gitlab
|
|
6
8
|
module Cop
|
7
9
|
# Cop that prevents the use of `in_batches`
|
8
10
|
class InBatches < RuboCop::Cop::Cop
|
9
|
-
MSG = 'Do not use `in_batches`, use `each_batch` from the EachBatch module instead'
|
11
|
+
MSG = 'Do not use `in_batches`, use `each_batch` from the EachBatch module instead'
|
10
12
|
|
11
13
|
def on_send(node)
|
12
14
|
return unless node.children[1] == :in_batches
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Gitlab
|
2
4
|
module Styles
|
3
5
|
module Rubocop
|
@@ -56,7 +58,7 @@ module Gitlab
|
|
56
58
|
#
|
57
59
|
# do_something_more
|
58
60
|
class LineBreakAfterGuardClauses < RuboCop::Cop::Cop
|
59
|
-
MSG = 'Add a line break after guard clauses'
|
61
|
+
MSG = 'Add a line break after guard clauses'
|
60
62
|
|
61
63
|
def_node_matcher :guard_clause_node?, <<-PATTERN
|
62
64
|
[{(send nil? {:raise :fail :throw} ...) return break next} single_line?]
|
@@ -67,7 +69,7 @@ module Gitlab
|
|
67
69
|
return unless guard_clause?(node)
|
68
70
|
return if next_line(node).blank? || clause_last_line?(next_line(node)) || guard_clause?(next_sibling(node))
|
69
71
|
|
70
|
-
add_offense(node
|
72
|
+
add_offense(node)
|
71
73
|
end
|
72
74
|
|
73
75
|
def autocorrect(node)
|
@@ -0,0 +1,132 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Gitlab
|
4
|
+
module Styles
|
5
|
+
module Rubocop
|
6
|
+
module Cop
|
7
|
+
# Ensures a line break around conditional blocks.
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
# # bad
|
11
|
+
# do_something
|
12
|
+
# if condition
|
13
|
+
# do_extra_stuff
|
14
|
+
# end
|
15
|
+
# do_something_more
|
16
|
+
#
|
17
|
+
# # good
|
18
|
+
# do_something
|
19
|
+
#
|
20
|
+
# if condition
|
21
|
+
# do_extra_stuff
|
22
|
+
# end
|
23
|
+
#
|
24
|
+
# do_something_more
|
25
|
+
#
|
26
|
+
# # bad
|
27
|
+
# do_something
|
28
|
+
# unless condition
|
29
|
+
# do_extra_stuff
|
30
|
+
# end
|
31
|
+
#
|
32
|
+
# do_something_more
|
33
|
+
#
|
34
|
+
# # good
|
35
|
+
# def a_method
|
36
|
+
# if condition
|
37
|
+
# do_something
|
38
|
+
# end
|
39
|
+
# end
|
40
|
+
#
|
41
|
+
# # good
|
42
|
+
# on_block do
|
43
|
+
# if condition
|
44
|
+
# do_something
|
45
|
+
# end
|
46
|
+
# end
|
47
|
+
class LineBreakAroundConditionalBlock < RuboCop::Cop::Cop
|
48
|
+
include RuboCop::Cop::RangeHelp
|
49
|
+
|
50
|
+
MSG = 'Add a line break around conditional blocks'
|
51
|
+
|
52
|
+
def on_if(node)
|
53
|
+
# This cop causes errors in haml files, so let's skip those
|
54
|
+
return if in_haml?(node)
|
55
|
+
return if node.single_line?
|
56
|
+
return unless node.if? || node.unless?
|
57
|
+
|
58
|
+
add_offense(node) unless previous_line_valid?(node)
|
59
|
+
add_offense(node) unless last_line_valid?(node)
|
60
|
+
end
|
61
|
+
|
62
|
+
def autocorrect(node)
|
63
|
+
lambda do |corrector|
|
64
|
+
line = range_by_whole_lines(node.source_range)
|
65
|
+
|
66
|
+
corrector.insert_before(line, "\n") unless previous_line_valid?(node)
|
67
|
+
corrector.insert_after(line, "\n") unless last_line_valid?(node)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
private
|
72
|
+
|
73
|
+
def previous_line_valid?(node)
|
74
|
+
previous_line(node).empty? ||
|
75
|
+
start_clause_line?(previous_line(node)) ||
|
76
|
+
block_start?(previous_line(node)) ||
|
77
|
+
begin_line?(previous_line(node)) ||
|
78
|
+
assignment_line?(previous_line(node)) ||
|
79
|
+
rescue_line?(previous_line(node))
|
80
|
+
end
|
81
|
+
|
82
|
+
def last_line_valid?(node)
|
83
|
+
last_line(node).empty? ||
|
84
|
+
end_line?(last_line(node)) ||
|
85
|
+
end_clause_line?(last_line(node))
|
86
|
+
end
|
87
|
+
|
88
|
+
def previous_line(node)
|
89
|
+
processed_source[node.loc.line - 2]
|
90
|
+
end
|
91
|
+
|
92
|
+
def last_line(node)
|
93
|
+
processed_source[node.loc.last_line]
|
94
|
+
end
|
95
|
+
|
96
|
+
def start_clause_line?(line)
|
97
|
+
line =~ /^\s*(def|=end|#|module|class|if|unless|else|elsif|ensure|when)/
|
98
|
+
end
|
99
|
+
|
100
|
+
def end_clause_line?(line)
|
101
|
+
line =~ /^\s*(#|rescue|else|elsif|when)/
|
102
|
+
end
|
103
|
+
|
104
|
+
def begin_line?(line)
|
105
|
+
# an assignment followed by a begin or ust a begin
|
106
|
+
line =~ /^\s*(@?(\w|\|+|=|\[|\]|\s)+begin|begin)/
|
107
|
+
end
|
108
|
+
|
109
|
+
def assignment_line?(line)
|
110
|
+
line =~ /^\s*.*=/
|
111
|
+
end
|
112
|
+
|
113
|
+
def rescue_line?(line)
|
114
|
+
line =~ /^\s*rescue/
|
115
|
+
end
|
116
|
+
|
117
|
+
def block_start?(line)
|
118
|
+
line.match(/ (do|{)( \|.*?\|)?\s?(#.+)?\z/)
|
119
|
+
end
|
120
|
+
|
121
|
+
def end_line?(line)
|
122
|
+
line =~ /^\s*(end|})/
|
123
|
+
end
|
124
|
+
|
125
|
+
def in_haml?(node)
|
126
|
+
node.location.expression.source_buffer.name.end_with?('.haml.rb')
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
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, 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
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require_relative '../model_helpers'
|
2
4
|
|
3
5
|
module Gitlab
|
@@ -8,7 +10,7 @@ module Gitlab
|
|
8
10
|
class PolymorphicAssociations < RuboCop::Cop::Cop
|
9
11
|
include ModelHelpers
|
10
12
|
|
11
|
-
MSG = 'Do not use polymorphic associations, use separate tables instead'
|
13
|
+
MSG = 'Do not use polymorphic associations, use separate tables instead'
|
12
14
|
|
13
15
|
def on_send(node)
|
14
16
|
return unless in_model?(node)
|
@@ -17,7 +19,7 @@ module Gitlab
|
|
17
19
|
node.children.last.each_node(:pair) do |pair|
|
18
20
|
key_name = pair.children[0].children[0]
|
19
21
|
|
20
|
-
add_offense(pair
|
22
|
+
add_offense(pair) if key_name == :polymorphic
|
21
23
|
end
|
22
24
|
end
|
23
25
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Gitlab
|
2
4
|
module Styles
|
3
5
|
module Rubocop
|
@@ -5,7 +7,7 @@ module Gitlab
|
|
5
7
|
# This cop prevents usage of 'redirect_to' in actions 'destroy' without specifying 'status'.
|
6
8
|
# See https://gitlab.com/gitlab-org/gitlab-ce/issues/31840
|
7
9
|
class RedirectWithStatus < RuboCop::Cop::Cop
|
8
|
-
MSG = 'Do not use "redirect_to" without "status" in "destroy" action'
|
10
|
+
MSG = 'Do not use "redirect_to" without "status" in "destroy" action'
|
9
11
|
|
10
12
|
def on_def(node)
|
11
13
|
return unless in_controller?(node)
|
@@ -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
|
@@ -1,4 +1,7 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'rubocop-rspec'
|
4
|
+
require_relative 'base'
|
2
5
|
|
3
6
|
module Gitlab
|
4
7
|
module Styles
|
@@ -15,8 +18,10 @@ module Gitlab
|
|
15
18
|
# # good
|
16
19
|
# expect(page).to have_link('Link', href: 'https://example.com')
|
17
20
|
# expect(page).to have_link('Example')
|
18
|
-
class HaveLinkParameters <
|
19
|
-
|
21
|
+
class HaveLinkParameters < Base
|
22
|
+
extend RuboCop::Cop::AutoCorrector
|
23
|
+
|
24
|
+
MESSAGE = "The second argument to `have_link` should be a Hash."
|
20
25
|
|
21
26
|
def_node_matcher :unused_parameters?, <<~PATTERN
|
22
27
|
(send nil? :have_link
|
@@ -27,11 +32,13 @@ module Gitlab
|
|
27
32
|
def on_send(node)
|
28
33
|
return unless unused_parameters?(node)
|
29
34
|
|
30
|
-
location = node.arguments[1
|
31
|
-
|
32
|
-
|
35
|
+
location = node.arguments[1..]
|
36
|
+
.map(&:source_range)
|
37
|
+
.reduce(:join)
|
33
38
|
|
34
|
-
add_offense(
|
39
|
+
add_offense(location, message: MESSAGE) do |corrector|
|
40
|
+
corrector.insert_after(location.end, "\n")
|
41
|
+
end
|
35
42
|
end
|
36
43
|
end
|
37
44
|
end
|