gitlab-styles 4.0.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 (43) hide show
  1. checksums.yaml +4 -4
  2. data/.editorconfig +18 -0
  3. data/.gitlab-ci.yml +4 -15
  4. data/.gitlab/merge_request_templates/Release.md +4 -4
  5. data/.rubocop.yml +3 -1
  6. data/Gemfile +3 -2
  7. data/README.md +1 -0
  8. data/gitlab-styles.gemspec +5 -4
  9. data/lib/gitlab/styles/rubocop.rb +5 -0
  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 +64 -0
  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 +65 -0
  21. data/lib/gitlab/styles/rubocop/cop/rspec/have_link_parameters.rb +10 -5
  22. data/lib/gitlab/styles/rubocop/cop/rspec/single_line_hook.rb +3 -2
  23. data/lib/gitlab/styles/rubocop/cop/rspec/verbose_include_metadata.rb +10 -13
  24. data/lib/gitlab/styles/rubocop/model_helpers.rb +1 -1
  25. data/lib/gitlab/styles/rubocop/rspec/helpers.rb +17 -0
  26. data/lib/gitlab/styles/version.rb +1 -1
  27. data/rubocop-all.yml +1 -0
  28. data/rubocop-bundler.yml +1 -0
  29. data/rubocop-code_reuse.yml +24 -0
  30. data/rubocop-default.yml +2 -0
  31. data/rubocop-gemspec.yml +1 -0
  32. data/rubocop-layout.yml +6 -0
  33. data/rubocop-lint.yml +63 -5
  34. data/rubocop-metrics.yml +1 -0
  35. data/rubocop-migrations.yml +22 -0
  36. data/rubocop-naming.yml +1 -0
  37. data/rubocop-performance.yml +48 -0
  38. data/rubocop-rails.yml +79 -0
  39. data/rubocop-rspec.yml +14 -0
  40. data/rubocop-security.yml +1 -0
  41. data/rubocop-style.yml +90 -1
  42. metadata +26 -17
  43. data/.rubocop_todo.yml +0 -7
@@ -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
@@ -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
@@ -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,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.0.0'
5
+ VERSION = '5.1.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
@@ -1,3 +1,4 @@
1
+ ---
1
2
  require:
2
3
  - rubocop-gitlab-security
3
4
  - rubocop-performance
@@ -12,6 +13,7 @@ inherit_from:
12
13
  - rubocop-layout.yml
13
14
  - rubocop-lint.yml
14
15
  - rubocop-metrics.yml
16
+ - rubocop-migrations.yml
15
17
  - rubocop-naming.yml
16
18
  - rubocop-performance.yml
17
19
  - rubocop-rails.yml
@@ -1,3 +1,4 @@
1
+ ---
1
2
  # Dependencies in the gemspec should be alphabetically sorted
2
3
  # Configuration parameters: Include, TreatCommentsAsGroupSeparators.
3
4
  Gemspec/OrderedDependencies:
@@ -1,3 +1,4 @@
1
+ ---
1
2
  # Check indentation of private/protected visibility modifiers.
2
3
  Layout/AccessModifierIndentation:
3
4
  Enabled: true
@@ -60,6 +61,11 @@ Layout/EmptyLines:
60
61
  Layout/EmptyLinesAroundAccessModifier:
61
62
  Enabled: true
62
63
 
64
+ # Checks for a newline after an attribute accessor or a group of them
65
+ # https://docs.rubocop.org/rubocop/0.89/cops_layout.html#layoutemptylinesaroundattributeaccessor
66
+ Layout/EmptyLinesAroundAttributeAccessor:
67
+ Enabled: true
68
+
63
69
  # Keeps track of empty lines around block bodies.
64
70
  Layout/EmptyLinesAroundBlockBody:
65
71
  Enabled: true