gitlab-styles 4.2.0 → 5.3.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 (44) hide show
  1. checksums.yaml +4 -4
  2. data/.editorconfig +18 -0
  3. data/.gitlab-ci.yml +5 -16
  4. data/.gitlab/merge_request_templates/New Static Analysis Check.md +21 -0
  5. data/.gitlab/merge_request_templates/Release.md +4 -4
  6. data/.rubocop.yml +3 -1
  7. data/Gemfile +2 -2
  8. data/gitlab-styles.gemspec +6 -5
  9. data/lib/gitlab/styles/rubocop.rb +3 -14
  10. data/lib/gitlab/styles/rubocop/cop/active_record_dependent.rb +1 -1
  11. data/lib/gitlab/styles/rubocop/cop/code_reuse/active_record.rb +131 -0
  12. data/lib/gitlab/styles/rubocop/cop/custom_error_class.rb +6 -3
  13. data/lib/gitlab/styles/rubocop/cop/gem_fetcher.rb +1 -1
  14. data/lib/gitlab/styles/rubocop/cop/line_break_after_guard_clauses.rb +1 -1
  15. data/lib/gitlab/styles/rubocop/cop/line_break_around_conditional_block.rb +132 -0
  16. data/lib/gitlab/styles/rubocop/cop/migration/update_large_table.rb +1 -1
  17. data/lib/gitlab/styles/rubocop/cop/polymorphic_associations.rb +1 -1
  18. data/lib/gitlab/styles/rubocop/cop/rspec/base.rb +18 -0
  19. data/lib/gitlab/styles/rubocop/cop/rspec/empty_line_after_let_block.rb +65 -0
  20. data/lib/gitlab/styles/rubocop/cop/rspec/empty_line_after_shared_example.rb +6 -6
  21. data/lib/gitlab/styles/rubocop/cop/rspec/example_starting_character.rb +124 -0
  22. data/lib/gitlab/styles/rubocop/cop/rspec/have_link_parameters.rb +10 -5
  23. data/lib/gitlab/styles/rubocop/cop/rspec/single_line_hook.rb +3 -2
  24. data/lib/gitlab/styles/rubocop/cop/rspec/verbose_include_metadata.rb +10 -13
  25. data/lib/gitlab/styles/rubocop/model_helpers.rb +1 -1
  26. data/lib/gitlab/styles/rubocop/rspec/helpers.rb +17 -0
  27. data/lib/gitlab/styles/version.rb +1 -1
  28. data/rubocop-all.yml +1 -0
  29. data/rubocop-bundler.yml +1 -0
  30. data/rubocop-code_reuse.yml +24 -0
  31. data/rubocop-default.yml +1 -0
  32. data/rubocop-gemspec.yml +1 -0
  33. data/rubocop-layout.yml +6 -0
  34. data/rubocop-lint.yml +63 -5
  35. data/rubocop-metrics.yml +1 -0
  36. data/rubocop-migrations.yml +1 -0
  37. data/rubocop-naming.yml +1 -0
  38. data/rubocop-performance.yml +48 -0
  39. data/rubocop-rails.yml +79 -0
  40. data/rubocop-rspec.yml +10 -0
  41. data/rubocop-security.yml +1 -0
  42. data/rubocop-style.yml +91 -1
  43. metadata +23 -15
  44. data/.rubocop_todo.yml +0 -7
@@ -40,7 +40,7 @@ module Gitlab
40
40
 
41
41
  return unless denied_tables.include?(table)
42
42
 
43
- add_offense(node, location: :expression, message: format(MSG, update_method, table))
43
+ add_offense(node, message: format(MSG, update_method, table))
44
44
  end
45
45
 
46
46
  private
@@ -19,7 +19,7 @@ module Gitlab
19
19
  node.children.last.each_node(:pair) do |pair|
20
20
  key_name = pair.children[0].children[0]
21
21
 
22
- add_offense(pair, location: :expression) if key_name == :polymorphic
22
+ add_offense(pair) if key_name == :polymorphic
23
23
  end
24
24
  end
25
25
  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
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'rubocop-rspec'
4
+ require_relative 'base'
4
5
 
5
6
  module Gitlab
6
7
  module Styles
@@ -38,8 +39,9 @@ module Gitlab
38
39
  # it_behaves_like 'does this'
39
40
  # end
40
41
  #
41
- class EmptyLineAfterSharedExample < RuboCop::Cop::RSpec::Cop
42
- include RuboCop::RSpec::BlankLineSeparation
42
+ class EmptyLineAfterSharedExample < Base
43
+ extend RuboCop::Cop::AutoCorrector
44
+ include RuboCop::RSpec::EmptyLineSeparation
43
45
 
44
46
  MSG = 'Add an empty line after `%<example>s` block.'
45
47
 
@@ -50,10 +52,8 @@ module Gitlab
50
52
  shared_examples(node) do
51
53
  break if last_child?(node)
52
54
 
53
- missing_separating_line(node) do |location|
54
- add_offense(node,
55
- location: location,
56
- message: format(MSG, example: node.method_name))
55
+ missing_separating_line_offense(node) do |method|
56
+ format(MSG, example: method)
57
57
  end
58
58
  end
59
59
  end
@@ -0,0 +1,124 @@
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 for common mistakes in example descriptions.
12
+ #
13
+ # This cop will correct docstrings that begin/end with space or words that start with a capital letter.
14
+ #
15
+ # @see https://gitlab.com/gitlab-org/gitlab/-/merge_requests/46336#note_442669518
16
+ #
17
+ # @example
18
+ # # bad
19
+ # it 'Does something' do
20
+ # end
21
+ #
22
+ # # good
23
+ # it 'does nothing' do
24
+ # end
25
+ #
26
+ # @example
27
+ # # bad
28
+ # it ' does something' do
29
+ # end
30
+ #
31
+ # # good
32
+ # it 'does something' do
33
+ # end
34
+ #
35
+ # @example
36
+ # # bad
37
+ # it 'does something ' do
38
+ # end
39
+ #
40
+ # # good
41
+ # it 'does something' do
42
+ # end
43
+ #
44
+ # @example
45
+ # # bad
46
+ # it ' does something ' do
47
+ # end
48
+ #
49
+ # # good
50
+ # it 'does something' do
51
+ # end
52
+ class ExampleStartingCharacter < Base
53
+ extend RuboCop::Cop::AutoCorrector
54
+
55
+ MSG = 'Only start words with lowercase alpha with no leading/trailing spaces when describing your tests.'
56
+
57
+ def_node_matcher :it_description, <<-PATTERN
58
+ (block (send _ :it ${
59
+ (str $_)
60
+ (dstr (str $_ ) ...)
61
+ } ...) ...)
62
+ PATTERN
63
+
64
+ def on_block(node)
65
+ it_description(node) do |description_node, _message|
66
+ add_wording_offense(description_node, MSG) if invalid_description?(text(description_node))
67
+ end
68
+ end
69
+
70
+ private
71
+
72
+ def add_wording_offense(node, message)
73
+ docstring = docstring(node)
74
+ add_offense(docstring, message: message) do |corrector|
75
+ corrector.replace(docstring, replacement_text(node))
76
+ end
77
+ end
78
+
79
+ def docstring(node)
80
+ expr = node.loc.expression
81
+
82
+ Parser::Source::Range.new(
83
+ expr.source_buffer,
84
+ expr.begin_pos + 1,
85
+ expr.end_pos - 1
86
+ )
87
+ end
88
+
89
+ def invalid_description?(message)
90
+ message.match?(/(^([A-Z]{1}[a-z]+\s|\s)|\s$)/)
91
+ end
92
+
93
+ def replacement_text(node)
94
+ text = text(node)
95
+
96
+ text.strip!
97
+
98
+ text = downcase_first_letter(text) if invalid_description?(text)
99
+
100
+ text
101
+ end
102
+
103
+ # Recursive processing is required to process nested dstr nodes
104
+ # that is the case for \-separated multiline strings with interpolation.
105
+ def text(node)
106
+ case node.type
107
+ when :dstr
108
+ node.node_parts.map { |child_node| text(child_node) }.join
109
+ when :str
110
+ node.value
111
+ when :begin
112
+ node.source
113
+ end
114
+ end
115
+
116
+ def downcase_first_letter(str)
117
+ str[0].downcase + str[1..]
118
+ end
119
+ end
120
+ end
121
+ end
122
+ end
123
+ end
124
+ end
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'rubocop-rspec'
4
+ require_relative 'base'
4
5
 
5
6
  module Gitlab
6
7
  module Styles
@@ -17,7 +18,9 @@ module Gitlab
17
18
  # # good
18
19
  # expect(page).to have_link('Link', href: 'https://example.com')
19
20
  # expect(page).to have_link('Example')
20
- class HaveLinkParameters < RuboCop::Cop::RSpec::Cop
21
+ class HaveLinkParameters < Base
22
+ extend RuboCop::Cop::AutoCorrector
23
+
21
24
  MESSAGE = "The second argument to `have_link` should be a Hash."
22
25
 
23
26
  def_node_matcher :unused_parameters?, <<~PATTERN
@@ -29,11 +32,13 @@ module Gitlab
29
32
  def on_send(node)
30
33
  return unless unused_parameters?(node)
31
34
 
32
- location = node.arguments[1..-1]
33
- .map(&:source_range)
34
- .reduce(:join)
35
+ location = node.arguments[1..]
36
+ .map(&:source_range)
37
+ .reduce(:join)
35
38
 
36
- add_offense(node, location: location, message: MESSAGE)
39
+ add_offense(location, message: MESSAGE) do |corrector|
40
+ corrector.insert_after(location.end, "\n")
41
+ end
37
42
  end
38
43
  end
39
44
  end
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'rubocop-rspec'
4
+ require_relative 'base'
4
5
 
5
6
  module Gitlab
6
7
  module Styles
@@ -23,7 +24,7 @@ module Gitlab
23
24
  # after(:each) do
24
25
  # undo_something
25
26
  # end
26
- class SingleLineHook < RuboCop::Cop::RSpec::Cop
27
+ class SingleLineHook < Base
27
28
  MESSAGE = "Don't use single-line hook blocks."
28
29
 
29
30
  def_node_search :rspec_hook?, <<~PATTERN
@@ -34,7 +35,7 @@ module Gitlab
34
35
  return unless node.single_line?
35
36
  return unless rspec_hook?(node)
36
37
 
37
- add_offense(node, location: :expression, message: MESSAGE)
38
+ add_offense(node, message: MESSAGE)
38
39
  end
39
40
  end
40
41
  end
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'rubocop-rspec'
4
+ require_relative 'base'
4
5
 
5
6
  module Gitlab
6
7
  module Styles
@@ -17,7 +18,9 @@ module Gitlab
17
18
  # # good
18
19
  # describe MyClass, :js do
19
20
  # end
20
- class VerboseIncludeMetadata < RuboCop::Cop::RSpec::Cop
21
+ class VerboseIncludeMetadata < Base
22
+ extend RuboCop::Cop::AutoCorrector
23
+
21
24
  MSG = 'Use `%s` instead of `%s`.'
22
25
 
23
26
  SELECTORS = %i[describe context feature example_group it specify example scenario its].freeze
@@ -37,25 +40,19 @@ module Gitlab
37
40
 
38
41
  def on_send(node)
39
42
  invalid_metadata_matches(node) do |match|
40
- add_offense(node, location: :expression, message: format(MSG, good(match), bad(match)))
41
- end
42
- end
43
-
44
- def autocorrect(node)
45
- lambda do |corrector|
46
- invalid_metadata_matches(node) do |match|
47
- corrector.replace(match.loc.expression, good(match))
43
+ add_offense(node, message: format(MSG, good(match), bad(match))) do |corrector|
44
+ invalid_metadata_matches(node) do |match|
45
+ corrector.replace(match.loc.expression, good(match))
46
+ end
48
47
  end
49
48
  end
50
49
  end
51
50
 
52
51
  private
53
52
 
54
- def invalid_metadata_matches(node)
53
+ def invalid_metadata_matches(node, &block)
55
54
  include_metadata(node) do |matches|
56
- matches.select(&method(:invalid_metadata?)).each do |match|
57
- yield match
58
- end
55
+ matches.select(&method(:invalid_metadata?)).each(&block)
59
56
  end
60
57
  end
61
58
 
@@ -7,7 +7,7 @@ module Gitlab
7
7
  # Returns true if the given node originated from the models directory.
8
8
  def in_model?(node)
9
9
  path = node.location.expression.source_buffer.name
10
- pwd = RuboCop::PathUtil.pwd
10
+ pwd = Dir.pwd
11
11
  models_path = File.join(pwd, 'app', 'models')
12
12
  ee_models_path = File.join(pwd, 'ee', 'app', 'models')
13
13
 
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rubocop-rspec'
4
+
5
+ module Gitlab
6
+ module Styles
7
+ module Rubocop
8
+ module Rspec
9
+ module Helpers
10
+ include RuboCop::RSpec::Language
11
+
12
+ LET = SelectorSet.new(%i[let_it_be]) + RuboCop::RSpec::Language::Helpers::ALL
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Gitlab
4
4
  module Styles
5
- VERSION = '4.2.0'
5
+ VERSION = '5.3.0'
6
6
  end
7
7
  end
@@ -1,3 +1,4 @@
1
+ ---
1
2
  AllCops:
2
3
  TargetRubyVersion: 2.6
3
4
  # Cop names are not displayed in offense messages by default. Change behavior
@@ -1,3 +1,4 @@
1
+ ---
1
2
  # Gems in consecutive lines should be alphabetically sorted
2
3
  Bundler/OrderedGems:
3
4
  Enabled: false
@@ -0,0 +1,24 @@
1
+ # Denies the use of ActiveRecord methods outside of configured
2
+ # excluded directories
3
+ # Directories that allow the use of the denied methods.
4
+ # To start we provide a default configuration that matches
5
+ # a standard Rails app and enable.
6
+ # The default configuration can be overridden by
7
+ # providing your own Exclusion list as follows:
8
+ # CodeReuse/ActiveRecord:
9
+ # Enabled: true
10
+ # Exclude:
11
+ # - app/models/**/*.rb
12
+ # - config/**/*.rb
13
+ # - db/**/*.rb
14
+ # - lib/tasks/**/*.rb
15
+ # - spec/**/*.rb
16
+ # - lib/gitlab/**/*.rb
17
+ CodeReuse/ActiveRecord:
18
+ Enabled: true
19
+ Exclude:
20
+ - app/models/**/*.rb
21
+ - config/**/*.rb
22
+ - db/**/*.rb
23
+ - lib/tasks/**/*.rb
24
+ - spec/**/*.rb