gl_rubocop 0.3.3 → 0.5.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/default.yml +21 -1
- data/lib/gl_rubocop/gl_cops/callback_method_names.rb +0 -2
- data/lib/gl_rubocop/gl_cops/consolidate_request_system_specs.rb +117 -0
- data/lib/gl_rubocop/gl_cops/valid_data_test_id.rb +61 -0
- data/lib/gl_rubocop/gl_cops/vcr_cassette_names.rb +72 -0
- data/lib/gl_rubocop/gl_cops/view_component_initialize_keyword_args.rb +0 -2
- data/lib/gl_rubocop/version.rb +1 -1
- metadata +6 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 83a8c15ce9c97fee3534fd6ec1b13efa8c150b4a6a06042f1408be213022c453
|
|
4
|
+
data.tar.gz: aef1892a704ffc69e5b4fc5ecc35d3c45461a8cac740c07a635e09a46811895b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 796c52aff461d138901b41715b5d677518057ae3cb81715f39036f4e4c92c9c1294732d5e149160addc245eee87065b7fc49ffaad3c936ae0d586f5263dedf42
|
|
7
|
+
data.tar.gz: 35f95f56ace1f7c2e529df369e5d397b7a6cfd741be5a4a7d53fb7a9ffd849b200919343a0006586cb772403b81d5369c3bda5e406fa924de127ec1c656e5f76
|
data/default.yml
CHANGED
|
@@ -9,14 +9,17 @@ require:
|
|
|
9
9
|
- rubocop-rake
|
|
10
10
|
- rubocop-sorbet
|
|
11
11
|
- ./lib/gl_rubocop/gl_cops/callback_method_names.rb
|
|
12
|
+
- ./lib/gl_rubocop/gl_cops/consolidate_request_system_specs.rb
|
|
12
13
|
- ./lib/gl_rubocop/gl_cops/interactor_inherits_from_interactor_base.rb
|
|
13
14
|
- ./lib/gl_rubocop/gl_cops/limit_flash_options.rb
|
|
14
15
|
- ./lib/gl_rubocop/gl_cops/no_stubbing_perform_async.rb
|
|
15
16
|
- ./lib/gl_rubocop/gl_cops/prevent_haml_files.rb
|
|
16
17
|
- ./lib/gl_rubocop/gl_cops/rails_cache.rb
|
|
17
18
|
- ./lib/gl_rubocop/gl_cops/sidekiq_inherits_from_sidekiq_job.rb
|
|
18
|
-
- ./lib/gl_rubocop/gl_cops/unique_identifier.rb
|
|
19
19
|
- ./lib/gl_rubocop/gl_cops/tailwind_no_contradicting_class_name.rb
|
|
20
|
+
- ./lib/gl_rubocop/gl_cops/unique_identifier.rb
|
|
21
|
+
- ./lib/gl_rubocop/gl_cops/valid_data_test_id.rb
|
|
22
|
+
- ./lib/gl_rubocop/gl_cops/vcr_cassette_names.rb
|
|
20
23
|
- ./lib/gl_rubocop/gl_cops/view_component_initialize_keyword_args.rb
|
|
21
24
|
|
|
22
25
|
AllCops:
|
|
@@ -43,6 +46,11 @@ Capybara/NegationMatcher:
|
|
|
43
46
|
GLCops/CallbackMethodNames:
|
|
44
47
|
Enabled: true
|
|
45
48
|
|
|
49
|
+
GLCops/ConsolidateRequestSystemSpecs:
|
|
50
|
+
Enabled: true
|
|
51
|
+
Include:
|
|
52
|
+
- "**/*spec.rb"
|
|
53
|
+
|
|
46
54
|
GLCops/InteractorInheritsFromInteractorBase:
|
|
47
55
|
Enabled: true
|
|
48
56
|
Include:
|
|
@@ -76,6 +84,18 @@ GLCops/UniqueIdentifier:
|
|
|
76
84
|
Include:
|
|
77
85
|
- "app/components/**/*.erb"
|
|
78
86
|
|
|
87
|
+
GLCops/ValidDataTestId:
|
|
88
|
+
Enabled: true
|
|
89
|
+
Include:
|
|
90
|
+
- "**/*.erb"
|
|
91
|
+
- "**/*.haml"
|
|
92
|
+
- "**/*.rb"
|
|
93
|
+
|
|
94
|
+
GLCops/VcrCassetteNames:
|
|
95
|
+
Enabled: true
|
|
96
|
+
Include:
|
|
97
|
+
- "**/*spec.rb"
|
|
98
|
+
|
|
79
99
|
GLCops/ViewComponentInitializeKeywordArgs:
|
|
80
100
|
Enabled: true
|
|
81
101
|
Include:
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
# rubocop:disable I18n/RailsI18n/DecorateString
|
|
2
1
|
module GLRubocop
|
|
3
2
|
module GLCops
|
|
4
3
|
# This cop ensures that controller callbacks are named methods, not inline blocks.
|
|
@@ -22,4 +21,3 @@ module GLRubocop
|
|
|
22
21
|
end
|
|
23
22
|
end
|
|
24
23
|
end
|
|
25
|
-
# rubocop:enable I18n/RailsI18n/DecorateString
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module GLRubocop
|
|
4
|
+
module GLCops
|
|
5
|
+
# This cop ensures request and system specs consolidate examples in a single it block,
|
|
6
|
+
# per each describe and context.
|
|
7
|
+
# Reason: Setup for specs should go in let/before blocks - which are different for each context.
|
|
8
|
+
# it blocks with the same setup should be consolidated to keep our tests fast.
|
|
9
|
+
#
|
|
10
|
+
#
|
|
11
|
+
# Good:
|
|
12
|
+
# RSpec.describe UsersController, type: :request do
|
|
13
|
+
# describe 'GET /users' do
|
|
14
|
+
# it 'returns users' do
|
|
15
|
+
# get users_path
|
|
16
|
+
# expect(response).to be_successful
|
|
17
|
+
# expect(response).to render_template(:index)
|
|
18
|
+
#
|
|
19
|
+
# get users_path, headers: {format: :json}
|
|
20
|
+
# expect(response).to be_successful
|
|
21
|
+
# expect(response.content_type).to eq('application/json')
|
|
22
|
+
# end
|
|
23
|
+
# end
|
|
24
|
+
# describe 'GET /users/id' do
|
|
25
|
+
# let(:user_id) { user.id }
|
|
26
|
+
# it 'returns user' do
|
|
27
|
+
# get user_path(user_id)
|
|
28
|
+
# expect(response).to be_successful
|
|
29
|
+
# end
|
|
30
|
+
# context 'with unknown user' do
|
|
31
|
+
# let(:user_id) { 111111 }
|
|
32
|
+
# it 'does not return user' do
|
|
33
|
+
# get user_path(user_id)
|
|
34
|
+
# expect(response).not_to be_successful
|
|
35
|
+
# end
|
|
36
|
+
# end
|
|
37
|
+
# end
|
|
38
|
+
# end
|
|
39
|
+
#
|
|
40
|
+
# Bad:
|
|
41
|
+
# RSpec.describe UsersController, type: :request do
|
|
42
|
+
# describe 'GET /users' do
|
|
43
|
+
# it 'returns success' do
|
|
44
|
+
# get users_path
|
|
45
|
+
# expect(response).to be_successful
|
|
46
|
+
# end
|
|
47
|
+
#
|
|
48
|
+
# it 'returns json' do
|
|
49
|
+
# get users_path
|
|
50
|
+
# expect(response.content_type).to eq('application/json')
|
|
51
|
+
# end
|
|
52
|
+
# end
|
|
53
|
+
# end
|
|
54
|
+
class ConsolidateRequestSystemSpecs < RuboCop::Cop::Base
|
|
55
|
+
MSG = 'Consolidate examples with the same setup in request specs and system specs. ' \
|
|
56
|
+
'Use a single it block instead of multiple it blocks.'
|
|
57
|
+
|
|
58
|
+
RSPEC_EXAMPLE_METHODS = %i[it specify example].freeze
|
|
59
|
+
|
|
60
|
+
# @!method rspec_group?(node)
|
|
61
|
+
def_node_matcher :rspec_group?, <<~PATTERN
|
|
62
|
+
(block (send _ {:describe :context} ...) ...)
|
|
63
|
+
PATTERN
|
|
64
|
+
|
|
65
|
+
# @!method request_or_system_type?(node)
|
|
66
|
+
def_node_matcher :request_or_system_type?, <<~PATTERN
|
|
67
|
+
(block (send _ _ ... (hash <(pair (sym :type) (sym {:request :system})) ...>)) ...)
|
|
68
|
+
PATTERN
|
|
69
|
+
|
|
70
|
+
def on_new_investigation
|
|
71
|
+
@spec_type_cache = {}
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def on_block(node)
|
|
75
|
+
return unless rspec_group?(node)
|
|
76
|
+
return unless request_or_system_spec?(node)
|
|
77
|
+
|
|
78
|
+
check_multiple_examples(node)
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
private
|
|
82
|
+
|
|
83
|
+
def request_or_system_spec?(node)
|
|
84
|
+
current = node
|
|
85
|
+
while current
|
|
86
|
+
if current.block_type?
|
|
87
|
+
unless @spec_type_cache.key?(current)
|
|
88
|
+
@spec_type_cache[current] =
|
|
89
|
+
request_or_system_type?(current)
|
|
90
|
+
end
|
|
91
|
+
return true if @spec_type_cache[current]
|
|
92
|
+
end
|
|
93
|
+
current = current.parent
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
false
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def check_multiple_examples(node)
|
|
100
|
+
examples = find_example_blocks(node)
|
|
101
|
+
return if examples.size <= 1
|
|
102
|
+
|
|
103
|
+
examples[1..].each do |example_node|
|
|
104
|
+
add_offense(example_node, message: MSG)
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def find_example_blocks(node)
|
|
109
|
+
return [] unless node.body
|
|
110
|
+
|
|
111
|
+
node.body.each_child_node(:block).select do |child|
|
|
112
|
+
RSPEC_EXAMPLE_METHODS.include?(child.send_node.method_name)
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
end
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative '../helpers/haml_content_helper'
|
|
4
|
+
require_relative '../helpers/erb_content_helper'
|
|
5
|
+
|
|
6
|
+
module GLRubocop
|
|
7
|
+
module GLCops
|
|
8
|
+
class ValidDataTestId < RuboCop::Cop::Cop
|
|
9
|
+
include GLRubocop::HamlContentHelper
|
|
10
|
+
include GLRubocop::ErbContentHelper
|
|
11
|
+
|
|
12
|
+
MSG = 'Use data-test-id instead of %<invalid>s'
|
|
13
|
+
|
|
14
|
+
# Invalid variations of data-test-id
|
|
15
|
+
# Matches: data-testid, data_test_id, datatestid, dataTestId, etc.
|
|
16
|
+
# Does NOT match: data-test-id (the valid format)
|
|
17
|
+
INVALID_PATTERN = /\bdata(?!-test-id\b)[-_]?test[-_]?id\b/i
|
|
18
|
+
|
|
19
|
+
def investigate(processed_source)
|
|
20
|
+
return unless haml_file? || erb_file?
|
|
21
|
+
|
|
22
|
+
content = haml_file? ? read_haml_file : read_erb_file
|
|
23
|
+
return unless content
|
|
24
|
+
|
|
25
|
+
check_file_content(content, processed_source)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def on_str(node)
|
|
29
|
+
return unless node.str_type?
|
|
30
|
+
|
|
31
|
+
check_string_content(node.value, node)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
private
|
|
35
|
+
|
|
36
|
+
def check_file_content(content, processed_source)
|
|
37
|
+
return unless content.match?(INVALID_PATTERN)
|
|
38
|
+
|
|
39
|
+
match = content.match(INVALID_PATTERN)
|
|
40
|
+
invalid_attr = match[0].split(/[=:]/).first.gsub(/["']/, '')
|
|
41
|
+
range = processed_source.buffer.source_range
|
|
42
|
+
add_offense(
|
|
43
|
+
nil,
|
|
44
|
+
location: range,
|
|
45
|
+
message: format(MSG, invalid: invalid_attr)
|
|
46
|
+
)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def check_string_content(content, node)
|
|
50
|
+
return unless content.match?(INVALID_PATTERN)
|
|
51
|
+
|
|
52
|
+
match = content.match(INVALID_PATTERN)
|
|
53
|
+
invalid_attr = match[0].split(/[=:]/).first.gsub(/["']/, '')
|
|
54
|
+
add_offense(
|
|
55
|
+
node,
|
|
56
|
+
message: format(MSG, invalid: invalid_attr)
|
|
57
|
+
)
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module GLRubocop
|
|
4
|
+
module GLCops
|
|
5
|
+
# This cop ensures that VCR cassettes have names.
|
|
6
|
+
#
|
|
7
|
+
# Good:
|
|
8
|
+
# VCR.use_cassette('cassette_name') { ... }
|
|
9
|
+
# VCR.use_cassette("cassette_name") { ... }
|
|
10
|
+
# describe '.create', vcr: { cassette_name: :chariot_connect_create } do
|
|
11
|
+
#
|
|
12
|
+
# Bad:
|
|
13
|
+
# VCR.use_cassette { ... }
|
|
14
|
+
# VCR.use_cassette() { ... }
|
|
15
|
+
# describe 'something', :vcr do
|
|
16
|
+
class VcrCassetteNames < RuboCop::Cop::Base
|
|
17
|
+
MSG = 'VCR cassettes must have a name. Example: VCR.use_cassette("cassette_name") { ... }'
|
|
18
|
+
RSPEC_MSG = 'VCR cassettes must have a name. ' \
|
|
19
|
+
'Example: describe "test", vcr: { cassette_name: :my_cassette } do'
|
|
20
|
+
|
|
21
|
+
RSPEC_METHODS = %i[describe context it specify example].freeze
|
|
22
|
+
|
|
23
|
+
# @!method vcr_use_cassette?(node)
|
|
24
|
+
def_node_matcher :vcr_use_cassette?, <<~PATTERN
|
|
25
|
+
(send (const nil? :VCR) :use_cassette ...)
|
|
26
|
+
PATTERN
|
|
27
|
+
|
|
28
|
+
# @!method vcr_use_cassette_with_name?(node)
|
|
29
|
+
def_node_matcher :vcr_use_cassette_with_name?, <<~PATTERN
|
|
30
|
+
(send (const nil? :VCR) :use_cassette {str dstr} ...)
|
|
31
|
+
PATTERN
|
|
32
|
+
|
|
33
|
+
# @!method rspec_vcr_symbol?(node)
|
|
34
|
+
def_node_matcher :rspec_vcr_symbol?, <<~PATTERN
|
|
35
|
+
(sym :vcr)
|
|
36
|
+
PATTERN
|
|
37
|
+
|
|
38
|
+
# @!method vcr_hash_without_cassette_name?(node)
|
|
39
|
+
def_node_matcher :vcr_hash_without_cassette_name?, <<~PATTERN
|
|
40
|
+
(pair (sym :vcr) !{(hash <(pair (sym :cassette_name) _) ...>)})
|
|
41
|
+
PATTERN
|
|
42
|
+
|
|
43
|
+
def on_send(node)
|
|
44
|
+
check_vcr_use_cassette(node)
|
|
45
|
+
check_rspec_metadata(node)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
private
|
|
49
|
+
|
|
50
|
+
def check_vcr_use_cassette(node)
|
|
51
|
+
return unless vcr_use_cassette?(node)
|
|
52
|
+
return if vcr_use_cassette_with_name?(node)
|
|
53
|
+
|
|
54
|
+
add_offense(node, message: MSG)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def check_rspec_metadata(node)
|
|
58
|
+
return unless RSPEC_METHODS.include?(node.method_name)
|
|
59
|
+
|
|
60
|
+
node.arguments.each do |arg|
|
|
61
|
+
if rspec_vcr_symbol?(arg)
|
|
62
|
+
add_offense(arg, message: RSPEC_MSG)
|
|
63
|
+
elsif arg.hash_type?
|
|
64
|
+
arg.pairs.each do |pair|
|
|
65
|
+
add_offense(pair, message: RSPEC_MSG) if vcr_hash_without_cassette_name?(pair)
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
# rubocop:disable I18n/RailsI18n/DecorateString
|
|
2
1
|
module GLRubocop
|
|
3
2
|
module GLCops
|
|
4
3
|
# This cop ensures that ViewComponent initialize methods use keyword arguments only.
|
|
@@ -27,4 +26,3 @@ module GLRubocop
|
|
|
27
26
|
end
|
|
28
27
|
end
|
|
29
28
|
end
|
|
30
|
-
# rubocop:enable I18n/RailsI18n/DecorateString
|
data/lib/gl_rubocop/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: gl_rubocop
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.5.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Give Lively
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2026-03-03 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rubocop
|
|
@@ -163,6 +163,7 @@ files:
|
|
|
163
163
|
- gl_rubocop.gemspec
|
|
164
164
|
- lib/gl_rubocop.rb
|
|
165
165
|
- lib/gl_rubocop/gl_cops/callback_method_names.rb
|
|
166
|
+
- lib/gl_rubocop/gl_cops/consolidate_request_system_specs.rb
|
|
166
167
|
- lib/gl_rubocop/gl_cops/interactor_inherits_from_interactor_base.rb
|
|
167
168
|
- lib/gl_rubocop/gl_cops/limit_flash_options.rb
|
|
168
169
|
- lib/gl_rubocop/gl_cops/no_stubbing_perform_async.rb
|
|
@@ -171,6 +172,8 @@ files:
|
|
|
171
172
|
- lib/gl_rubocop/gl_cops/sidekiq_inherits_from_sidekiq_job.rb
|
|
172
173
|
- lib/gl_rubocop/gl_cops/tailwind_no_contradicting_class_name.rb
|
|
173
174
|
- lib/gl_rubocop/gl_cops/unique_identifier.rb
|
|
175
|
+
- lib/gl_rubocop/gl_cops/valid_data_test_id.rb
|
|
176
|
+
- lib/gl_rubocop/gl_cops/vcr_cassette_names.rb
|
|
174
177
|
- lib/gl_rubocop/gl_cops/view_component_initialize_keyword_args.rb
|
|
175
178
|
- lib/gl_rubocop/helpers/erb_content_helper.rb
|
|
176
179
|
- lib/gl_rubocop/helpers/haml_content_helper.rb
|
|
@@ -195,7 +198,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
195
198
|
- !ruby/object:Gem::Version
|
|
196
199
|
version: '0'
|
|
197
200
|
requirements: []
|
|
198
|
-
rubygems_version: 3.
|
|
201
|
+
rubygems_version: 3.5.22
|
|
199
202
|
signing_key:
|
|
200
203
|
specification_version: 4
|
|
201
204
|
summary: A shareable configuration of Give Lively's rubocop rules.
|