carwow_rubocop 6.7.0 → 6.9.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/Gemfile.lock +19 -18
- data/carwow_rubocop.gemspec +7 -10
- data/config/rubocop-carwow.yml +8 -0
- data/lib/rubocop/carwow/version.rb +1 -1
- data/lib/rubocop/cop/carwow/product_area_required.rb +147 -0
- metadata +7 -11
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e2a4da2858ed109b02d01111b35e24184159d2d0c592855a4bc57bbd8d0d2f04
|
|
4
|
+
data.tar.gz: 8bf60cd532eae6c3a401eecb64f2460ba377c7573ba67657db2f792a1ac6b212
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 57c7b0a76743efcafe2da17ad73254f484e83ae6d7ccd7b855f8b3f60648ff64fb83de0a63d091153b69b07e72f8df8121e2736ac88bb1d64319a5f64b6f9a23
|
|
7
|
+
data.tar.gz: 157af413e04a76aa595103680d403d846d3d9ef9018cf4b41c123a6fff97feb73e88fc55b3ebf057bd68b5cd2cc13254ecfcb6ace01d6d06e7b40f19b1166b44
|
data/Gemfile.lock
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
carwow_rubocop (6.
|
|
4
|
+
carwow_rubocop (6.9.0)
|
|
5
5
|
rubocop (>= 1.75)
|
|
6
6
|
rubocop-factory_bot
|
|
7
7
|
rubocop-performance
|
|
8
|
-
rubocop-rspec (
|
|
8
|
+
rubocop-rspec (~> 3.2)
|
|
9
9
|
|
|
10
10
|
GEM
|
|
11
11
|
remote: https://rubygems.org/
|
|
@@ -13,22 +13,22 @@ GEM
|
|
|
13
13
|
ast (2.4.3)
|
|
14
14
|
coderay (1.1.3)
|
|
15
15
|
diff-lcs (1.5.1)
|
|
16
|
-
json (2.
|
|
17
|
-
language_server-protocol (3.17.0.
|
|
16
|
+
json (2.21.2)
|
|
17
|
+
language_server-protocol (3.17.0.6)
|
|
18
18
|
lint_roller (1.1.0)
|
|
19
19
|
method_source (1.1.0)
|
|
20
|
-
parallel (1.
|
|
21
|
-
parser (3.3.
|
|
20
|
+
parallel (2.1.0)
|
|
21
|
+
parser (3.3.12.0)
|
|
22
22
|
ast (~> 2.4.1)
|
|
23
23
|
racc
|
|
24
|
-
prism (1.
|
|
24
|
+
prism (1.9.0)
|
|
25
25
|
pry (0.15.2)
|
|
26
26
|
coderay (~> 1.1)
|
|
27
27
|
method_source (~> 1.0)
|
|
28
28
|
racc (1.8.1)
|
|
29
29
|
rainbow (3.1.1)
|
|
30
30
|
rake (13.2.1)
|
|
31
|
-
regexp_parser (2.
|
|
31
|
+
regexp_parser (2.12.0)
|
|
32
32
|
rspec (3.13.0)
|
|
33
33
|
rspec-core (~> 3.13.0)
|
|
34
34
|
rspec-expectations (~> 3.13.0)
|
|
@@ -42,20 +42,20 @@ GEM
|
|
|
42
42
|
diff-lcs (>= 1.2.0, < 2.0)
|
|
43
43
|
rspec-support (~> 3.13.0)
|
|
44
44
|
rspec-support (3.13.1)
|
|
45
|
-
rubocop (1.
|
|
45
|
+
rubocop (1.89.0)
|
|
46
46
|
json (~> 2.3)
|
|
47
47
|
language_server-protocol (~> 3.17.0.2)
|
|
48
48
|
lint_roller (~> 1.1.0)
|
|
49
|
-
parallel (
|
|
49
|
+
parallel (>= 1.10)
|
|
50
50
|
parser (>= 3.3.0.2)
|
|
51
51
|
rainbow (>= 2.2.2, < 4.0)
|
|
52
52
|
regexp_parser (>= 2.9.3, < 3.0)
|
|
53
|
-
rubocop-ast (>= 1.
|
|
53
|
+
rubocop-ast (>= 1.49.0, < 2.0)
|
|
54
54
|
ruby-progressbar (~> 1.7)
|
|
55
55
|
unicode-display_width (>= 2.4.0, < 4.0)
|
|
56
|
-
rubocop-ast (1.
|
|
56
|
+
rubocop-ast (1.50.0)
|
|
57
57
|
parser (>= 3.3.7.2)
|
|
58
|
-
prism (~> 1.
|
|
58
|
+
prism (~> 1.7)
|
|
59
59
|
rubocop-factory_bot (2.27.1)
|
|
60
60
|
lint_roller (~> 1.1)
|
|
61
61
|
rubocop (~> 1.72, >= 1.72.1)
|
|
@@ -63,13 +63,14 @@ GEM
|
|
|
63
63
|
lint_roller (~> 1.1)
|
|
64
64
|
rubocop (>= 1.72.1, < 2.0)
|
|
65
65
|
rubocop-ast (>= 1.38.0, < 2.0)
|
|
66
|
-
rubocop-rspec (3.
|
|
66
|
+
rubocop-rspec (3.10.2)
|
|
67
67
|
lint_roller (~> 1.1)
|
|
68
|
-
|
|
68
|
+
regexp_parser (>= 2.0)
|
|
69
|
+
rubocop (~> 1.86, >= 1.86.2)
|
|
69
70
|
ruby-progressbar (1.13.0)
|
|
70
|
-
unicode-display_width (3.
|
|
71
|
-
unicode-emoji (~> 4.
|
|
72
|
-
unicode-emoji (4.0
|
|
71
|
+
unicode-display_width (3.2.0)
|
|
72
|
+
unicode-emoji (~> 4.1)
|
|
73
|
+
unicode-emoji (4.2.0)
|
|
73
74
|
|
|
74
75
|
PLATFORMS
|
|
75
76
|
ruby
|
data/carwow_rubocop.gemspec
CHANGED
|
@@ -14,12 +14,12 @@ Gem::Specification.new do |spec|
|
|
|
14
14
|
spec.homepage = 'https://github.com/carwow/carwow_rubocop'
|
|
15
15
|
spec.license = 'MIT'
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
17
|
+
raise 'RubyGems 2.0 or newer is required to protect against public gem pushes.' unless spec.respond_to?(:metadata)
|
|
18
|
+
|
|
19
|
+
spec.metadata = {
|
|
20
|
+
'allowed_push_host' => 'https://rubygems.org',
|
|
21
|
+
'rubygems_mfa_required' => 'true'
|
|
22
|
+
}
|
|
23
23
|
|
|
24
24
|
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
|
25
25
|
f.match(%r{^(test|spec|features)/})
|
|
@@ -35,9 +35,6 @@ Gem::Specification.new do |spec|
|
|
|
35
35
|
|
|
36
36
|
spec.add_dependency 'rubocop', '>= 1.75'
|
|
37
37
|
spec.add_dependency 'rubocop-performance'
|
|
38
|
-
spec.add_dependency 'rubocop-rspec', '
|
|
38
|
+
spec.add_dependency 'rubocop-rspec', '~> 3.2'
|
|
39
39
|
spec.add_dependency 'rubocop-factory_bot'
|
|
40
|
-
spec.metadata = {
|
|
41
|
-
'rubygems_mfa_required' => 'true'
|
|
42
|
-
}
|
|
43
40
|
end
|
data/config/rubocop-carwow.yml
CHANGED
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'rubocop'
|
|
4
|
+
|
|
5
|
+
module RuboCop
|
|
6
|
+
module Cop
|
|
7
|
+
module Carwow
|
|
8
|
+
# Controllers and jobs are attributed to a team via the `product_area` DSL
|
|
9
|
+
# (CarwowCore::ProductArea::Taggable) so their Honeycomb spans and Bugsnag
|
|
10
|
+
# errors route to the owning team automatically. A class with no declared
|
|
11
|
+
# area falls back to manual triage.
|
|
12
|
+
#
|
|
13
|
+
# This only checks that `product_area` is called somewhere in the class's
|
|
14
|
+
# own body — it cannot verify, statically, that a superclass declared in
|
|
15
|
+
# another file already sets one. Shared base classes that are
|
|
16
|
+
# intentionally left untagged (e.g. ApplicationController, ApplicationJob,
|
|
17
|
+
# or a namespaced API base controller) should be added to this cop's
|
|
18
|
+
# `Exclude` in the consuming app's .rubocop.yml rather than tagged.
|
|
19
|
+
#
|
|
20
|
+
# A class nested inside another class (rather than merely inside a
|
|
21
|
+
# namespacing module) is assumed to be a helper — e.g. a custom error
|
|
22
|
+
# raised by the enclosing job — not an entry point of its own, so it is
|
|
23
|
+
# not checked. Only the enclosing class needs the tag.
|
|
24
|
+
#
|
|
25
|
+
# A class that subclasses a known Ruby exception (StandardError,
|
|
26
|
+
# RuntimeError, ...) or whose superclass name ends in `Error`/`Exception`
|
|
27
|
+
# is never checked, wherever it's defined: exceptions are raised inside
|
|
28
|
+
# an entry point, not routed to one of their own.
|
|
29
|
+
#
|
|
30
|
+
# A class that doesn't look like a controller/job entry point itself (no
|
|
31
|
+
# Controller/Job-ish superclass, no `include Sidekiq::Worker`/`Sidekiq::Job`,
|
|
32
|
+
# no `perform` method) is skipped if it sits alongside a sibling class in
|
|
33
|
+
# the same file/module that already declares `product_area` — a common
|
|
34
|
+
# pattern for small POROs colocated with the controller/job that uses
|
|
35
|
+
# them. Two genuinely independent entry points defined in the same file
|
|
36
|
+
# still both need their own tag.
|
|
37
|
+
#
|
|
38
|
+
# @example
|
|
39
|
+
# # bad
|
|
40
|
+
# class PaymentsController < ApplicationController
|
|
41
|
+
# end
|
|
42
|
+
#
|
|
43
|
+
# # good
|
|
44
|
+
# class PaymentsController < ApplicationController
|
|
45
|
+
# product_area 'smc-payments'
|
|
46
|
+
# end
|
|
47
|
+
#
|
|
48
|
+
# # good - nested error class does not need its own tag
|
|
49
|
+
# class SyncListing < ApplicationJob
|
|
50
|
+
# product_area 'salesforce'
|
|
51
|
+
#
|
|
52
|
+
# class UnknownReference < StandardError; end
|
|
53
|
+
# end
|
|
54
|
+
#
|
|
55
|
+
# # good - sibling error class, and sibling PORO helper, do not need their own tag
|
|
56
|
+
# module Payments
|
|
57
|
+
# class RefundFailed < StandardError; end
|
|
58
|
+
#
|
|
59
|
+
# class RefundsController < ApplicationController
|
|
60
|
+
# product_area 'smc-payments'
|
|
61
|
+
# end
|
|
62
|
+
#
|
|
63
|
+
# class RefundPresenter
|
|
64
|
+
# def initialize(refund); end
|
|
65
|
+
# end
|
|
66
|
+
# end
|
|
67
|
+
#
|
|
68
|
+
class ProductAreaRequired < ::RuboCop::Cop::Base
|
|
69
|
+
MSG = 'Declare a `product_area` for this class so its Honeycomb spans ' \
|
|
70
|
+
'and Bugsnag errors route to the owning team.'
|
|
71
|
+
|
|
72
|
+
KNOWN_ERROR_SUPERCLASSES = %w[StandardError RuntimeError Exception ScriptError].freeze
|
|
73
|
+
ERROR_NAME_PATTERN = /Error\z|Exception\z/
|
|
74
|
+
ENTRY_POINT_SUPERCLASS_PATTERN = /Controller|Job/
|
|
75
|
+
|
|
76
|
+
def_node_matcher :product_area_declaration?, <<~PATTERN
|
|
77
|
+
(send nil? :product_area _)
|
|
78
|
+
PATTERN
|
|
79
|
+
|
|
80
|
+
def_node_matcher :sidekiq_worker_include?, <<~PATTERN
|
|
81
|
+
(send nil? :include (const (const nil? :Sidekiq) {:Worker :Job}))
|
|
82
|
+
PATTERN
|
|
83
|
+
|
|
84
|
+
def_node_search :defines_perform_method?, <<~PATTERN
|
|
85
|
+
(def :perform ...)
|
|
86
|
+
PATTERN
|
|
87
|
+
|
|
88
|
+
def on_class(node)
|
|
89
|
+
return if nested_in_class?(node)
|
|
90
|
+
return if subclasses_known_error?(node)
|
|
91
|
+
return if declares_product_area?(node)
|
|
92
|
+
return if !looks_like_entry_point?(node) && sibling_already_tagged?(node)
|
|
93
|
+
|
|
94
|
+
class_node, = *node
|
|
95
|
+
add_offense(class_node)
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
private
|
|
99
|
+
|
|
100
|
+
def nested_in_class?(node)
|
|
101
|
+
node.each_ancestor(:class).any?
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def subclasses_known_error?(class_node)
|
|
105
|
+
_name, superclass, = *class_node
|
|
106
|
+
return false unless superclass
|
|
107
|
+
|
|
108
|
+
superclass_name = superclass.source
|
|
109
|
+
|
|
110
|
+
KNOWN_ERROR_SUPERCLASSES.include?(superclass_name) || superclass_name.match?(ERROR_NAME_PATTERN)
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def declares_product_area?(class_node)
|
|
114
|
+
top_level_statements(class_node).any? { |stmt| product_area_declaration?(stmt) }
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def looks_like_entry_point?(class_node)
|
|
118
|
+
_name, superclass, body = *class_node
|
|
119
|
+
|
|
120
|
+
return true if superclass&.source&.match?(ENTRY_POINT_SUPERCLASS_PATTERN)
|
|
121
|
+
|
|
122
|
+
statements = top_level_statements(class_node)
|
|
123
|
+
statements.any? { |stmt| sidekiq_worker_include?(stmt) } || (body && defines_perform_method?(body))
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def sibling_already_tagged?(class_node)
|
|
127
|
+
siblings_scope = class_node.each_ancestor(:module, :class, :begin).first || class_node.parent
|
|
128
|
+
return false unless siblings_scope
|
|
129
|
+
|
|
130
|
+
sibling_classes(siblings_scope, class_node).any? { |sibling| declares_product_area?(sibling) }
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def sibling_classes(scope, exclude)
|
|
134
|
+
statements = scope.begin_type? ? scope.children : [scope]
|
|
135
|
+
statements.select { |stmt| stmt&.class_type? && stmt != exclude }
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
def top_level_statements(class_node)
|
|
139
|
+
body = class_node.body
|
|
140
|
+
return [] unless body
|
|
141
|
+
|
|
142
|
+
body.begin_type? ? body.children : [body]
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: carwow_rubocop
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 6.
|
|
4
|
+
version: 6.9.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- carwow Developers
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-
|
|
11
|
+
date: 2026-08-13 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: bundler
|
|
@@ -98,22 +98,16 @@ dependencies:
|
|
|
98
98
|
name: rubocop-rspec
|
|
99
99
|
requirement: !ruby/object:Gem::Requirement
|
|
100
100
|
requirements:
|
|
101
|
-
- - "
|
|
101
|
+
- - "~>"
|
|
102
102
|
- !ruby/object:Gem::Version
|
|
103
103
|
version: '3.2'
|
|
104
|
-
- - "<"
|
|
105
|
-
- !ruby/object:Gem::Version
|
|
106
|
-
version: '3.6'
|
|
107
104
|
type: :runtime
|
|
108
105
|
prerelease: false
|
|
109
106
|
version_requirements: !ruby/object:Gem::Requirement
|
|
110
107
|
requirements:
|
|
111
|
-
- - "
|
|
108
|
+
- - "~>"
|
|
112
109
|
- !ruby/object:Gem::Version
|
|
113
110
|
version: '3.2'
|
|
114
|
-
- - "<"
|
|
115
|
-
- !ruby/object:Gem::Version
|
|
116
|
-
version: '3.6'
|
|
117
111
|
- !ruby/object:Gem::Dependency
|
|
118
112
|
name: rubocop-factory_bot
|
|
119
113
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -172,10 +166,12 @@ files:
|
|
|
172
166
|
- lib/rubocop/cop/carwow/no_change_matcher_with_browser_action.rb
|
|
173
167
|
- lib/rubocop/cop/carwow/no_stubbing_business_event.rb
|
|
174
168
|
- lib/rubocop/cop/carwow/no_vehicle_brand_model_sideload.rb
|
|
169
|
+
- lib/rubocop/cop/carwow/product_area_required.rb
|
|
175
170
|
homepage: https://github.com/carwow/carwow_rubocop
|
|
176
171
|
licenses:
|
|
177
172
|
- MIT
|
|
178
173
|
metadata:
|
|
174
|
+
allowed_push_host: https://rubygems.org
|
|
179
175
|
rubygems_mfa_required: 'true'
|
|
180
176
|
post_install_message:
|
|
181
177
|
rdoc_options: []
|
|
@@ -192,7 +188,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
192
188
|
- !ruby/object:Gem::Version
|
|
193
189
|
version: '0'
|
|
194
190
|
requirements: []
|
|
195
|
-
rubygems_version: 3.
|
|
191
|
+
rubygems_version: 3.5.20
|
|
196
192
|
signing_key:
|
|
197
193
|
specification_version: 4
|
|
198
194
|
summary: carwow's rubocop configuration
|