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.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/.editorconfig +18 -0
  3. data/.gitignore +3 -1
  4. data/.gitlab-ci.yml +25 -4
  5. data/.gitlab/merge_request_templates/Release.md +35 -0
  6. data/.rubocop.yml +3 -1
  7. data/Gemfile +5 -2
  8. data/README.md +5 -0
  9. data/Rakefile +2 -0
  10. data/gitlab-styles.gemspec +8 -5
  11. data/lib/gitlab/styles.rb +2 -0
  12. data/lib/gitlab/styles/rubocop.rb +7 -0
  13. data/lib/gitlab/styles/rubocop/cop/active_record_dependent.rb +4 -2
  14. data/lib/gitlab/styles/rubocop/cop/active_record_serialize.rb +3 -1
  15. data/lib/gitlab/styles/rubocop/cop/code_reuse/active_record.rb +131 -0
  16. data/lib/gitlab/styles/rubocop/cop/custom_error_class.rb +9 -4
  17. data/lib/gitlab/styles/rubocop/cop/gem_fetcher.rb +4 -2
  18. data/lib/gitlab/styles/rubocop/cop/in_batches.rb +3 -1
  19. data/lib/gitlab/styles/rubocop/cop/line_break_after_guard_clauses.rb +4 -2
  20. data/lib/gitlab/styles/rubocop/cop/line_break_around_conditional_block.rb +132 -0
  21. data/lib/gitlab/styles/rubocop/cop/migration/update_large_table.rb +64 -0
  22. data/lib/gitlab/styles/rubocop/cop/polymorphic_associations.rb +4 -2
  23. data/lib/gitlab/styles/rubocop/cop/redirect_with_status.rb +3 -1
  24. data/lib/gitlab/styles/rubocop/cop/rspec/base.rb +18 -0
  25. data/lib/gitlab/styles/rubocop/cop/rspec/empty_line_after_let_block.rb +65 -0
  26. data/lib/gitlab/styles/rubocop/cop/rspec/empty_line_after_shared_example.rb +65 -0
  27. data/lib/gitlab/styles/rubocop/cop/rspec/have_link_parameters.rb +13 -6
  28. data/lib/gitlab/styles/rubocop/cop/rspec/single_line_hook.rb +6 -3
  29. data/lib/gitlab/styles/rubocop/cop/rspec/verbose_include_metadata.rb +13 -14
  30. data/lib/gitlab/styles/rubocop/cop/without_reactive_cache.rb +3 -1
  31. data/lib/gitlab/styles/rubocop/migration_helpers.rb +2 -0
  32. data/lib/gitlab/styles/rubocop/model_helpers.rb +3 -1
  33. data/lib/gitlab/styles/rubocop/rspec/helpers.rb +17 -0
  34. data/lib/gitlab/styles/version.rb +3 -1
  35. data/rubocop-all.yml +2 -1
  36. data/rubocop-bundler.yml +1 -0
  37. data/rubocop-code_reuse.yml +24 -0
  38. data/rubocop-default.yml +2 -0
  39. data/rubocop-gemspec.yml +1 -0
  40. data/rubocop-layout.yml +38 -22
  41. data/rubocop-lint.yml +81 -19
  42. data/rubocop-metrics.yml +1 -4
  43. data/rubocop-migrations.yml +22 -0
  44. data/rubocop-naming.yml +9 -8
  45. data/rubocop-performance.yml +48 -0
  46. data/rubocop-rails.yml +79 -0
  47. data/rubocop-rspec.yml +14 -0
  48. data/rubocop-security.yml +1 -0
  49. data/rubocop-style.yml +119 -15
  50. metadata +27 -17
  51. 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'.freeze
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'.freeze
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, location: :expression, message: MSG)
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'.freeze
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, location: :expression) if key_name == :polymorphic
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'.freeze
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 < RuboCop::Cop::RSpec::Cop
19
- MESSAGE = "The second argument to `have_link` should be a Hash.".freeze
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..-1]
31
- .map(&:source_range)
32
- .reduce(:join)
35
+ location = node.arguments[1..]
36
+ .map(&:source_range)
37
+ .reduce(:join)
33
38
 
34
- add_offense(node, location: location, message: MESSAGE)
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