carwow_rubocop 3.4.3 → 4.0.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f239eb22a4031dfe8518b292afd41cb94778355a6c721ca0b7675316a24c0b61
4
- data.tar.gz: cfbd6577b32d07dd7db5a5c921290d6b6b151450688d3b6b3b92e3cf78f4a73b
3
+ metadata.gz: c9e7c523fde37bcd34c81d97c5e5469dcdd54847c49037305202401cda4795b6
4
+ data.tar.gz: 59126df5d4eebbb7f0924396a95dd5ecd5cf9ae405d6e214dba606f1abf349b0
5
5
  SHA512:
6
- metadata.gz: 47274f7028dc42ddcc788b23c44e910f39053b5ead0aa0e7e8432199b533a74fb4968100d92f55bd50a006a727a1701957fce64ffc585fcb18c4217b61ab0e59
7
- data.tar.gz: 531b0ba1209f7e50d0d0c5979fb805fa49c613d29d6daafd88aa479dfcd6365fcce070f470004fe33fd9f09868d3708934425b75cc3fcf166810c36fe175705e
6
+ metadata.gz: '007331498b901c890b99c599d8a124fbf520527eb87cd5386681ac964cba04ad8eb8aa6cc10d2886e7a8f2dba1a746a7545a90af0996977857a99ef020b1b9e7'
7
+ data.tar.gz: 3bb9f8592367f4e95a7c8e3a5dbbf36b75ed909fcd2a7855265478b56d65192b27a48604b64980811fef68eda54d08a8def62b2133381adf3873a9be0304192f
@@ -0,0 +1,64 @@
1
+ version: 2.1
2
+
3
+ orbs:
4
+ buildevents: honeycombio/buildevents@0.2
5
+ carwow: carwow/carwow-orb@0.3
6
+
7
+
8
+ ##
9
+ # JOBs definitions
10
+ ##
11
+ jobs:
12
+ tests:
13
+ executor: carwow/ruby
14
+ steps:
15
+ - buildevents/with_job_span:
16
+ steps:
17
+ - checkout
18
+ - run:
19
+ name: Bundle
20
+ command: bundle install --jobs=4 --retry=3
21
+
22
+ - run:
23
+ name: Running gem tests
24
+ command: |
25
+ bundle exec rspec
26
+
27
+
28
+ lint_ruby:
29
+ executor: carwow/ruby
30
+ steps:
31
+ - buildevents/with_job_span:
32
+ steps:
33
+ - checkout
34
+ - run: bundle install --jobs=4 --retry=3
35
+ - run: bundle exec rubocop -p
36
+
37
+
38
+
39
+ publish_gem:
40
+ executor: carwow/ruby
41
+ steps:
42
+ - buildevents/with_job_span:
43
+ steps:
44
+ - checkout
45
+ - run: bundle install --jobs=4 --retry=3
46
+ - run: bundle exec rake upload
47
+
48
+
49
+
50
+
51
+ workflows:
52
+ version: 2
53
+ build-and-deploy:
54
+ jobs:
55
+ - carwow/start
56
+ - carwow/watch:
57
+ context: buildevents-watch
58
+ requires: [carwow/start]
59
+
60
+ - tests:
61
+ requires: [carwow/start]
62
+
63
+ - lint_ruby:
64
+ requires: [carwow/start]
@@ -0,0 +1,9 @@
1
+ version: 2
2
+
3
+ updates:
4
+ - package-ecosystem: bundler
5
+ directory: "/"
6
+ schedule:
7
+ interval: daily
8
+ time: "09:00"
9
+ open-pull-requests-limit: 10
data/.rubocop.yml CHANGED
@@ -1 +1,5 @@
1
- inherit_from: default.yml
1
+ inherit_from:
2
+ - config/default.yml
3
+
4
+ require:
5
+ - rubocop-rspec
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- carwow_rubocop (3.4.3)
4
+ carwow_rubocop (4.0.2)
5
5
  rubocop (>= 0.93)
6
6
  rubocop-performance
7
7
  rubocop-rspec
@@ -10,32 +10,50 @@ GEM
10
10
  remote: https://rubygems.org/
11
11
  specs:
12
12
  ast (2.4.2)
13
- parallel (1.20.1)
14
- parser (3.0.0.0)
13
+ coderay (1.1.3)
14
+ diff-lcs (1.4.4)
15
+ method_source (1.0.0)
16
+ parallel (1.21.0)
17
+ parser (3.0.2.0)
15
18
  ast (~> 2.4.1)
19
+ pry (0.14.1)
20
+ coderay (~> 1.1)
21
+ method_source (~> 1.0)
16
22
  rainbow (3.0.0)
17
- rake (13.0.1)
18
- regexp_parser (2.1.0)
19
- rexml (3.2.4)
20
- rubocop (1.10.0)
23
+ rake (13.0.6)
24
+ regexp_parser (2.1.1)
25
+ rexml (3.2.5)
26
+ rspec (3.10.0)
27
+ rspec-core (~> 3.10.0)
28
+ rspec-expectations (~> 3.10.0)
29
+ rspec-mocks (~> 3.10.0)
30
+ rspec-core (3.10.1)
31
+ rspec-support (~> 3.10.0)
32
+ rspec-expectations (3.10.1)
33
+ diff-lcs (>= 1.2.0, < 2.0)
34
+ rspec-support (~> 3.10.0)
35
+ rspec-mocks (3.10.2)
36
+ diff-lcs (>= 1.2.0, < 2.0)
37
+ rspec-support (~> 3.10.0)
38
+ rspec-support (3.10.2)
39
+ rubocop (1.22.3)
21
40
  parallel (~> 1.10)
22
41
  parser (>= 3.0.0.0)
23
42
  rainbow (>= 2.2.2, < 4.0)
24
43
  regexp_parser (>= 1.8, < 3.0)
25
44
  rexml
26
- rubocop-ast (>= 1.2.0, < 2.0)
45
+ rubocop-ast (>= 1.12.0, < 2.0)
27
46
  ruby-progressbar (~> 1.7)
28
47
  unicode-display_width (>= 1.4.0, < 3.0)
29
- rubocop-ast (1.4.1)
30
- parser (>= 2.7.1.5)
31
- rubocop-performance (1.9.2)
32
- rubocop (>= 0.90.0, < 2.0)
48
+ rubocop-ast (1.13.0)
49
+ parser (>= 3.0.1.1)
50
+ rubocop-performance (1.12.0)
51
+ rubocop (>= 1.7.0, < 2.0)
33
52
  rubocop-ast (>= 0.4.0)
34
- rubocop-rspec (2.2.0)
35
- rubocop (~> 1.0)
36
- rubocop-ast (>= 1.1.0)
53
+ rubocop-rspec (2.6.0)
54
+ rubocop (~> 1.19)
37
55
  ruby-progressbar (1.11.0)
38
- unicode-display_width (2.0.0)
56
+ unicode-display_width (2.1.0)
39
57
 
40
58
  PLATFORMS
41
59
  ruby
@@ -43,7 +61,9 @@ PLATFORMS
43
61
  DEPENDENCIES
44
62
  bundler
45
63
  carwow_rubocop!
64
+ pry
46
65
  rake
66
+ rspec
47
67
 
48
68
  BUNDLED WITH
49
- 2.1.4
69
+ 2.2.27
data/README.md CHANGED
@@ -1,16 +1,16 @@
1
1
  # CarwowRubocop
2
2
 
3
- Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/carwow_rubocop`. To experiment with that code, run `bin/console` for an interactive prompt.
3
+ carwow specific analysis for [RuboCop][rubocop].
4
+
5
+ It contains carwow's internally used configuration for [RuboCop][rubocop] and [RuboCop RSpec][rubocop-rspec].
6
+ It also includes a handful custom rules that are not currently addressed by other projects.
4
7
 
5
- TODO: Delete this and the text above, and describe your gem
6
8
 
7
9
  ## Installation
8
10
 
9
- Add this line to your application's Gemfile:
11
+ Just put this in your `Gemfile` it depends on the appropriate version of rubocop and rubocop-rspec.
10
12
 
11
- ```ruby
12
- gem 'carwow_rubocop'
13
- ```
13
+ gem 'carwow_rubocop'
14
14
 
15
15
  And then execute:
16
16
 
@@ -20,20 +20,83 @@ Or install it yourself as:
20
20
 
21
21
  $ gem install carwow_rubocop
22
22
 
23
+
23
24
  ## Usage
24
25
 
25
- TODO: Write usage instructions here
26
+ You need to tell RuboCop to load the carwow extension. There are three
27
+ ways to do this:
28
+
29
+ ### RuboCop configuration file
30
+ First Create a new file `.rubocop_carwow.yml` in the same directory as your `.rubocop.yml`
31
+ this file should contain
32
+
33
+ require:
34
+ - carwow_rubocop
35
+
36
+ Next add the following to `.rubocop.yml`
37
+ or add before `.rubocop_todo.yml` in your existing `inherit_from`
38
+
39
+ inherit_from:
40
+ - .rubocop_carwow.yml
41
+ - .rubocop_todo.yml
42
+
43
+ You need to inherit `.rubocop_carwow.yml` from another file because of Rubocop order of operations.
44
+ It runs `inherit_from` before `require` commands. If the configuration is not in a separate file
45
+ you could potentially experience a bunch of warnings from `.rubocop_todo.yml` for non-existant
46
+ `Carwow` rules.
47
+
48
+ Now you can run `rubocop` and it will automatically load the RuboCop Carwow
49
+ cops together with the standard cops.
50
+
51
+ ### Command line
52
+
53
+ rubocop --require rubocop-carwow
54
+
55
+ ## The Cops
56
+
57
+ All cops are located under
58
+ [`lib/rubocop/cop/carwow`](lib/rubocop/cop/carwow), and contain examples/documentation.
59
+
60
+ In your `.rubocop.yml`, you may treat the carwow cops just like any other cop. For example:
61
+
62
+ Carwow/NoStubbingBusinessEvent:
63
+ Exclude:
64
+ - spec/my_poorly_named_spec_file.rb
65
+
66
+
26
67
 
27
68
  ## Development
28
69
 
29
70
  After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
30
71
 
31
- To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
72
+ To install this gem onto your local machine, run `bundle exec rake install`.
73
+
74
+ To update the carwow rubocop rules, edit the file: `config/default.yml`.
75
+
76
+ To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
32
77
 
33
78
  ## Contributing
34
79
 
35
80
  Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/carwow_rubocop.
36
81
 
82
+ ### How to write custom cops?
83
+
84
+ The [official docs](https://docs.rubocop.org/rubocop/development.html) will teach you how to develop new cops.
85
+
86
+ Read [Node pattern](https://github.com/rubocop/rubocop-ast/blob/master/docs/modules/ROOT/pages/node_pattern.adoc) to understand better how to write _node matches_ for your custom cop.
87
+
88
+ ### How other companies are doing it?
89
+
90
+ There are a lot of companies with public repositories sharing their Cops.
91
+
92
+ - [Airbnb](https://github.com/airbnb/ruby/tree/master/rubocop-airbnb)
93
+ - [Github](https://github.com/github/rubocop-github)
94
+
37
95
  ## License
38
96
 
39
97
  The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
98
+
99
+
100
+
101
+ [rubocop]: https://github.com/rubocop-hq/rubocop
102
+ [rubocop-rspec]: https://github.com/backus/rubocop-rspec
data/Rakefile CHANGED
@@ -3,7 +3,7 @@ task default: :spec
3
3
 
4
4
  desc "Upload to rubygems"
5
5
  task :upload => :build do
6
- # Check if tag with v#{ResearchSiteApiClient::VERSION} version exists, if so, return with error
6
+ # Check if tag with v#{RuboCop::Carwow::VERSION} version exists, if so, return with error
7
7
 
8
8
  if tag_exists?(current_tag_name)
9
9
  puts "Tag exists, did you run rake increase_revision_number after merging with master?"
@@ -16,7 +16,7 @@ end
16
16
 
17
17
  desc "Increase the revision number"
18
18
  task :increase_revision_number do
19
- version_file = "lib/carwow_rubocop/version.rb"
19
+ version_file = "lib/rubocop/carwow/version.rb"
20
20
  file_content = File.read(version_file)
21
21
  rule = /(\d+\.\d+\.)(\d+)/
22
22
  new_revision_number = rule.match(file_content)[2].to_i + 1
@@ -38,5 +38,5 @@ def create_tag(tag_name)
38
38
  end
39
39
 
40
40
  def current_tag_name
41
- "v#{CarwowRubocop::VERSION}"
41
+ "v#{RuboCop::Carwow::VERSION}"
42
42
  end
@@ -1,10 +1,11 @@
1
1
  lib = File.expand_path('lib', __dir__)
2
2
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
- require 'carwow_rubocop/version'
3
+ require 'rubocop/carwow/version'
4
4
 
5
5
  Gem::Specification.new do |spec|
6
6
  spec.name = 'carwow_rubocop'
7
- spec.version = CarwowRubocop::VERSION
7
+ spec.version = RuboCop::Carwow::VERSION
8
+ spec.platform = Gem::Platform::RUBY
8
9
  spec.required_ruby_version = Gem::Requirement.new('>= 2.7.0')
9
10
  spec.authors = ['carwow Developers']
10
11
  spec.email = ['developers@carwow.co.uk']
@@ -17,7 +18,7 @@ Gem::Specification.new do |spec|
17
18
  spec.metadata['allowed_push_host'] = 'https://rubygems.org'
18
19
  else
19
20
  raise 'RubyGems 2.0 or newer is required to protect against ' \
20
- 'public gem pushes.'
21
+ 'public gem pushes.'
21
22
  end
22
23
 
23
24
  spec.files = `git ls-files -z`.split("\x0").reject do |f|
@@ -29,6 +30,9 @@ Gem::Specification.new do |spec|
29
30
 
30
31
  spec.add_development_dependency 'bundler'
31
32
  spec.add_development_dependency 'rake'
33
+ spec.add_development_dependency 'rspec'
34
+ spec.add_development_dependency 'pry'
35
+
32
36
  spec.add_dependency 'rubocop', '>= 0.93'
33
37
  spec.add_dependency 'rubocop-performance'
34
38
  spec.add_dependency 'rubocop-rspec'
@@ -0,0 +1,34 @@
1
+ require:
2
+ - rubocop-rspec
3
+ - rubocop-performance
4
+ - ../lib/rubocop/carwow
5
+
6
+ ##############
7
+ # Global rules
8
+
9
+ AllCops:
10
+ TargetRubyVersion: 2.7
11
+ NewCops: enable
12
+ Exclude:
13
+ - '.git/**/*'
14
+ - 'Rakefile'
15
+ - 'bin/**/*'
16
+ - 'db/*schema*'
17
+ - 'node_modules/**/*'
18
+ - 'public/**/*'
19
+ - 'tmp/**/*'
20
+ - 'vendor/**/*'
21
+
22
+ inherit_from:
23
+ - './rubocop-bundler.yml'
24
+ - './rubocop-carwow.yml'
25
+ - './rubocop-gemspec.yml'
26
+ - './rubocop-layout.yml'
27
+ - './rubocop-lint.yml'
28
+ - './rubocop-metrics.yml'
29
+ - './rubocop-naming.yml'
30
+ - './rubocop-performance.yml'
31
+ - './rubocop-rails.yml'
32
+ - './rubocop-rspec.yml'
33
+ - './rubocop-security.yml'
34
+ - './rubocop-style.yml'
@@ -0,0 +1,5 @@
1
+ Bundler/DuplicatedGem:
2
+ Enabled: true
3
+
4
+ Bundler/InsecureProtocolSource:
5
+ Enabled: false
@@ -0,0 +1,33 @@
1
+ # All of these rules are implemented in this gem.
2
+ # They are custom built for use inside carwow and address issues
3
+ # that we have experienced in testing and production.
4
+
5
+ Carwow/Jobs:
6
+ Enabled: true
7
+ Include: &jobs_only
8
+ - "**/jobs/**/*.rb"
9
+ AllowedSuperclasses: &job_classes
10
+ - ApplicationJob
11
+ - ScheduledJob
12
+ TopLevelJob: "ActiveJob::Base"
13
+
14
+ Carwow/JobsMustDefineQueue:
15
+ Enabled: true
16
+ Include: *jobs_only
17
+ JobClasses: *job_classes
18
+ KnownQueues:
19
+ - seconds
20
+ - minutes
21
+ - hour
22
+ - hours
23
+
24
+ Carwow/JobsQueueNameStyle:
25
+ Enabled: true
26
+ Include: *jobs_only
27
+ QueueNameAs: Symbol
28
+
29
+ Carwow/NoStubbingBusinessEvent:
30
+ Enabled: true
31
+ Include: &spec_only
32
+ - "**/*_spec.rb"
33
+ - "**/spec/**/*"
@@ -0,0 +1,12 @@
1
+ Gemspec/OrderedDependencies:
2
+ Enabled: false
3
+
4
+ Gemspec/RequiredRubyVersion:
5
+ Description: Checks that `required_ruby_version` of gemspec and `TargetRubyVersion` of
6
+ .rubocop.yml are equal.
7
+ Enabled: false
8
+ Include:
9
+ - '**/*.gemspec'
10
+
11
+ Gemspec/RubyVersionGlobalsUsage:
12
+ Enabled: true
@@ -0,0 +1,14 @@
1
+ Layout/ArgumentAlignment:
2
+ EnforcedStyle: with_fixed_indentation
3
+
4
+ Layout/LineLength:
5
+ Max: 120
6
+
7
+ Layout/MultilineMethodCallBraceLayout:
8
+ EnforcedStyle: new_line
9
+
10
+ Layout/MultilineMethodCallIndentation:
11
+ EnforcedStyle: indented
12
+
13
+ Layout/ParameterAlignment:
14
+ EnforcedStyle: with_fixed_indentation
@@ -0,0 +1,6 @@
1
+ Lint/DuplicateBranch:
2
+ IgnoreLiteralBranches: true
3
+
4
+ Lint/Debugger:
5
+ Description: Check for debugger calls.
6
+ Enabled: true
@@ -0,0 +1,8 @@
1
+ Metrics/BlockLength:
2
+ Exclude:
3
+ - 'config/routes.rb'
4
+ - 'spec/**/*'
5
+ - '**/*.rake'
6
+ - '**/*.gemspec'
7
+ - 'config/environments/*.rb'
8
+ - 'config/initializers/*.rb'
@@ -0,0 +1,2 @@
1
+ Naming/RescuedExceptionsVariableName:
2
+ Enabled: false
File without changes
File without changes
@@ -0,0 +1,25 @@
1
+ require:
2
+ - rubocop-rspec
3
+
4
+ RSpec:
5
+ Include:
6
+ - _spec.rb
7
+ - "(?:^|/)spec/"
8
+ RSpec/FactoryBot:
9
+ Patterns:
10
+ - spec/factories/**/*.rb
11
+ - features/support/factories/**/*.rb
12
+
13
+ RSpec/ContextWording:
14
+ Enabled: False
15
+
16
+ RSpec/ExampleLength:
17
+ Max: 10
18
+
19
+ RSpec/NotToNot:
20
+ Description: 'Enforces the usage of the same method on all negative message expectations.'
21
+ Enabled: true
22
+ EnforcedStyle: not_to
23
+ SupportedStyles:
24
+ - not_to
25
+ - to_not
@@ -0,0 +1,3 @@
1
+ Security/Eval:
2
+ Description: The use of eval represents a serious security risk.
3
+ Enabled: true
@@ -0,0 +1,11 @@
1
+ Style/AsciiComments:
2
+ Enabled: false
3
+
4
+ Style/Documentation:
5
+ Enabled: false
6
+
7
+ Style/DoubleNegation:
8
+ Enabled: false
9
+
10
+ Style/FrozenStringLiteralComment:
11
+ Enabled: false
@@ -1,5 +1,10 @@
1
- require 'carwow_rubocop/version'
1
+ require 'pathname'
2
+ require 'yaml'
2
3
 
3
- module CarwowRubocop
4
- # Nothing to do here
5
- end
4
+ require 'rubocop'
5
+
6
+ require 'rubocop/carwow'
7
+ require 'rubocop/carwow/inject'
8
+ require 'rubocop/carwow/version'
9
+
10
+ RuboCop::Carwow::Inject.defaults!
@@ -0,0 +1,20 @@
1
+ # Straight up ripped from the custom Rspec rubocop
2
+ # https://github.com/nevir/rubocop-rspec/blob/master/lib/rubocop/rspec/inject.rb
3
+ require 'yaml'
4
+
5
+ module RuboCop
6
+ module Carwow
7
+ # Because RuboCop doesn't yet support plugins, we have to monkey patch in a
8
+ # bit of our configuration.
9
+ module Inject
10
+ def self.defaults!
11
+ path = CONFIG_DEFAULT.to_s
12
+ hash = ConfigLoader.load_file(path).to_hash
13
+ config = Config.new(hash, path)
14
+ puts "configuration from #{path}" if ConfigLoader.debug?
15
+ config = ConfigLoader.merge_with_default(config, path)
16
+ ConfigLoader.instance_variable_set(:@default_configuration, config)
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,5 @@
1
+ module RuboCop
2
+ module Carwow
3
+ VERSION = '4.0.2'.freeze
4
+ end
5
+ end
@@ -0,0 +1,18 @@
1
+ require 'pathname'
2
+ require 'psych'
3
+
4
+ Dir.glob(File.expand_path('cop/**/*.rb', File.dirname(__FILE__))).sort.each do |file|
5
+ require file
6
+ end
7
+
8
+ module RuboCop
9
+ # RuboCop Carwow project namespace
10
+ module Carwow
11
+ PROJECT_ROOT =
12
+ Pathname.new(__FILE__).parent.parent.parent.expand_path.freeze
13
+ CONFIG_DEFAULT = PROJECT_ROOT.join('config', 'default.yml').freeze
14
+ CONFIG = Psych.safe_load(CONFIG_DEFAULT.read).freeze
15
+
16
+ private_constant(*constants(false))
17
+ end
18
+ end
@@ -0,0 +1,125 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rubocop'
4
+
5
+ module RuboCop
6
+ module Cop
7
+ module Carwow
8
+ # Jobs are important in our systems and having observability well configured
9
+ # is essential. All Job classes must behave as we expect, and only a few
10
+ # well-defined classes can be super classes for other jobs.
11
+ #
12
+ # We use ActiveJob as framework for declaring jobs, being `ActiveJob::Base`
13
+ # the top level class. However, our jobs are generally split into two big
14
+ # hierarchies: ApplicationJob and ScheduledJob; and all jobs should inherit
15
+ # from these classes rather than `ActiveJob::Base`.
16
+ #
17
+ # We understand that each application may introduce its own exceptions,
18
+ # so the Cop can be configured to change the allowed super classes and even
19
+ # the top level class!
20
+ #
21
+ #
22
+ # @config
23
+ #
24
+ # # Mandatory configs
25
+ # Carwow/Jobs:
26
+ # AllowedSuperclasses:
27
+ # - ApplicationJob
28
+ # - ScheduledJob
29
+ # TopLevelJob: "ActiveJob::Base"
30
+ #
31
+ #
32
+ # @example
33
+ # # bad
34
+ # class Bad < ActiveJob::Base; end
35
+ #
36
+ # # bad
37
+ # class Bad < NotAllowedJob; end
38
+ #
39
+ # # good
40
+ # class Good < ApplicationJob; end
41
+ #
42
+ # # good
43
+ # class ScheduledJob < ApplicationJob; end
44
+ #
45
+ # # good
46
+ # class ApplicationJob < ActiveJob::Base; end
47
+ #
48
+ #
49
+ class Jobs < ::RuboCop::Cop::Base
50
+ MSG = 'Jobs should subclass from one of: %s.'
51
+ TOP_LEVEL_MSG = 'Only %s can inherit from %s.'
52
+ FORCE_TOP_LEVEL_MSG = 'It should inherit from %s or %s.'
53
+ NOT_CONFIGURED = 'AllowedSuperclasses and TopLevelJob configs must be set before proceeding.'
54
+
55
+ def on_class(node)
56
+ return add_global_offense(NOT_CONFIGURED) if missing_config?
57
+
58
+ return if any_class_in_the_file_allowed?(node)
59
+ return if defining_allowed_job?(*node)
60
+
61
+ register_offenses(node)
62
+ end
63
+
64
+ private
65
+
66
+ def any_class_in_the_file_allowed?(class_node)
67
+ root_node = class_node.root? ? class_node : class_node.ancestors.last
68
+
69
+ return true if root_node.class_type? && allowed?(super_class(*root_node))
70
+
71
+ root_node.each_descendant(:class).any? do |node|
72
+ allowed?(super_class(*node))
73
+ end
74
+ end
75
+
76
+ def allowed?(superclass)
77
+ cop_config.fetch('AllowedSuperclasses').include?(superclass)
78
+ end
79
+
80
+ def defining_allowed_job?(class_node, super_node, _)
81
+ super_class_name = super_node&.const_name
82
+
83
+ allowed?(class_node.const_name) &&
84
+ (allowed?(super_class_name) || top_level?(super_class_name))
85
+ end
86
+
87
+ def register_offenses(node)
88
+ class_node, super_node, _args = *node
89
+
90
+ if allowed?(class_node.const_name)
91
+ only_allowed_inherit_from_toplevel(super_node, FORCE_TOP_LEVEL_MSG)
92
+ elsif top_level?(super_node&.const_name)
93
+ only_allowed_inherit_from_toplevel(node, TOP_LEVEL_MSG)
94
+ else
95
+ add_offense(class_node, message: MSG % allowed_str)
96
+ end
97
+ end
98
+
99
+ def super_class(_, superclass_node, _)
100
+ superclass_node&.const_name
101
+ end
102
+
103
+ def missing_config?
104
+ !(cop_config.key?('AllowedSuperclasses') && cop_config.key?('TopLevelJob'))
105
+ end
106
+
107
+ def top_level?(klass)
108
+ top_level_class == klass
109
+ end
110
+
111
+ def allowed_str
112
+ cop_config.fetch('AllowedSuperclasses').join(', ')
113
+ end
114
+
115
+ def top_level_class
116
+ cop_config.fetch('TopLevelJob')
117
+ end
118
+
119
+ def only_allowed_inherit_from_toplevel(node, msg)
120
+ add_offense(node, message: format(msg, allowed_str, top_level_class))
121
+ end
122
+ end
123
+ end
124
+ end
125
+ end
@@ -0,0 +1,150 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rubocop'
4
+
5
+ module RuboCop
6
+ module Cop
7
+ module Carwow
8
+ # Jobs are important in our systems and having a unified way to write them
9
+ # is essential. All Job classes must define the queue to be executed in.
10
+ # The `queue_as` defines in which queue the Job will be executed and can
11
+ # only be defined once. Even more, the _queue_ defined must be known by
12
+ # the system and declared in the configs: `KnownQueues`.
13
+ #
14
+ # We understand that each application may introduce its own exceptions,
15
+ # so the Cop can be configured to change the allowed classes to identify
16
+ # job classes and also the known queues.
17
+ #
18
+ #
19
+ # @config
20
+ #
21
+ # # Mandatory configs
22
+ # Carwow/Jobs:
23
+ # JobClasses:
24
+ # - ApplicationJob
25
+ # - ScheduledJob
26
+ # KnownQueues:
27
+ # - seconds
28
+ # - minutes
29
+ # - hour
30
+ # - hours
31
+ #
32
+ #
33
+ # @example
34
+ #
35
+ # # bad
36
+ # class Bad < ApplicationJob
37
+ # end
38
+ #
39
+ # # bad
40
+ # class Bad < ApplicationJob
41
+ # queue_as :minutes
42
+ # queue_as :hours
43
+ # end
44
+ #
45
+ # # bad
46
+ # class Bad < ApplicationJob
47
+ # queue_as :unknown_queue
48
+ # end
49
+ #
50
+ # # good
51
+ # class Ok < ApplicationJob
52
+ # queue_as :minutes
53
+ # end
54
+ #
55
+ #
56
+ class JobsMustDefineQueue < ::RuboCop::Cop::Base
57
+ def_node_matcher :on_queue_definition, <<~PATTERN
58
+ (send nil? :queue_as $_)
59
+ PATTERN
60
+
61
+ MISSING_QUEUE_MSG = 'Manually set a queue; the default is not executed!'
62
+ UNKNOWN_QUEUE_MSG = 'Unknown queue name'
63
+ MULTIPLE_DEFINITIONS_MSG = 'Jobs must define a queue only once!'
64
+ NOT_CONFIGURED = 'JobClasses and KnownQueues configs must be set before proceeding.'
65
+
66
+ def on_class(node)
67
+ return add_global_offense(NOT_CONFIGURED) if missing_config?
68
+
69
+ return if skip_on_class?(node)
70
+
71
+ queue_definitions = all_queue_definitions(node)
72
+
73
+ case queue_definitions.size
74
+ when 0
75
+ missing_queue_offense(node)
76
+ when 1
77
+ # This is ok!
78
+ else
79
+ multiple_definitions_offense(queue_definitions)
80
+ end
81
+ end
82
+
83
+ # optimization: don't call `on_send` unless the method name is in this list
84
+ RESTRICT_ON_SEND = %i[queue_as].freeze
85
+
86
+ def on_send(node)
87
+ return add_global_offense(NOT_CONFIGURED) if missing_config?
88
+
89
+ # If the class is not a Job, no need to proceed.
90
+ return unless application_job_top_level?(node.parent)
91
+
92
+ _, _queue_as, queue_name_node = *node
93
+ queue_name, _other = *queue_name_node
94
+
95
+ return if known_queues.include?(queue_name.to_s)
96
+
97
+ add_offense(queue_name_node, message: UNKNOWN_QUEUE_MSG)
98
+ end
99
+
100
+ private
101
+
102
+ def missing_config?
103
+ !cop_config.key?('JobClasses')
104
+ end
105
+
106
+ def skip_on_class?(node)
107
+ class_node, super_node, _other = *node
108
+
109
+ return true if super_node.nil?
110
+ return true unless application_job?(super_node.const_name)
111
+
112
+ # If the class defined is listed as JobClasses, we don't require a queue.
113
+ application_job?(class_node.const_name)
114
+ end
115
+
116
+ def application_job_top_level?(node)
117
+ _, super_node, _other = *(node.type == :class ? node : node.parent)
118
+
119
+ application_job?(super_node.const_name)
120
+ end
121
+
122
+ def application_job?(job_name)
123
+ cop_config.fetch('JobClasses').include?(job_name)
124
+ end
125
+
126
+ def known_queues
127
+ cop_config.fetch('KnownQueues', [])
128
+ end
129
+
130
+ def all_queue_definitions(node)
131
+ return [] unless node.body
132
+
133
+ node = node.body if node.body.type == :begin
134
+
135
+ node
136
+ .each_child_node
137
+ .filter_map { |n| on_queue_definition(n) }
138
+ end
139
+
140
+ def missing_queue_offense(node)
141
+ add_offense(node, message: MISSING_QUEUE_MSG)
142
+ end
143
+
144
+ def multiple_definitions_offense(all_definitions)
145
+ add_offense(all_definitions.last, message: MULTIPLE_DEFINITIONS_MSG)
146
+ end
147
+ end
148
+ end
149
+ end
150
+ end
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rubocop'
4
+
5
+ module RuboCop
6
+ module Cop
7
+ module Carwow
8
+ #
9
+ # @config
10
+ #
11
+ # # Optional configs
12
+ # Carwow/Jobs:
13
+ # QueueNameAs: "Symbol" # default
14
+ #
15
+ #
16
+ # @example
17
+ # # bad
18
+ # class Bad < ApplicationJob
19
+ # queue_as "with_string"
20
+ # end
21
+ #
22
+ # # good
23
+ # class Good < ApplicationJob
24
+ # queue_as :with_symbol
25
+ # end
26
+ #
27
+ #
28
+ class JobsQueueNameStyle < ::RuboCop::Cop::Base
29
+ extend AutoCorrector
30
+
31
+ MSG = 'Prefer `queue_as` with symbol instead of String'
32
+ MSG_STRING = 'Prefer `queue_as` with String instead of Symbol'
33
+
34
+ def_node_matcher :on_queue_definition_with_symbol?, <<~PATTERN
35
+ (send nil? :queue_as (sym _))
36
+ PATTERN
37
+
38
+ def_node_matcher :on_queue_definition_with_string?, <<~PATTERN
39
+ (send nil? :queue_as (str _))
40
+ PATTERN
41
+
42
+ # optimization: don't call `on_send` unless the method name is in this list
43
+ RESTRICT_ON_SEND = %i[queue_as].freeze
44
+ def on_send(node)
45
+ _, _queue_as, queue_name = *node
46
+
47
+ return if prefer_symbol? && queue_name.sym_type?
48
+ return if prefer_string? && queue_name.str_type?
49
+
50
+ add_offense(queue_name, message: (prefer_symbol? ? MSG : MSG_STRING)) do |corrector|
51
+ content, _other = *queue_name
52
+ fix = prefer_symbol? ? ":#{content}" : content.to_s.inspect
53
+
54
+ corrector.replace(queue_name, fix)
55
+ end
56
+ end
57
+
58
+ private
59
+
60
+ def prefer_symbol?
61
+ !cop_config.fetch('QueueNameAs', 'Symbol').casecmp('string').zero?
62
+ end
63
+
64
+ def prefer_string?
65
+ !prefer_symbol?
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rubocop'
4
+
5
+ module RuboCop
6
+ module Cop
7
+ module Carwow
8
+ # Never mock (or double) the BusinessEvent class, it won't validate the schema
9
+ # and it reduces the quality of your tests!
10
+ #
11
+ # [See discussion](https://carwow.discourse.team/t/schema-validations-for-business-events/414)
12
+ #
13
+ # @example
14
+ # # bad
15
+ # expect(BusinessEvent).to have_received(:publish).with(:topic, :event, payload: payload)
16
+ #
17
+ # # good - preferred
18
+ # expect { subject }.to have_published_event(:topic, :event).with(payload)
19
+ #
20
+ # # good
21
+ # expect(topic: :event).to have_been_published.with(payload)
22
+ #
23
+ # # bad
24
+ # expect(BusinessEvent).not_to have_received(:publish)
25
+ #
26
+ # # good - preferred
27
+ # expect { subject }.not_to have_published_event
28
+ #
29
+ # # good
30
+ # expect(topic: :event).not_to have_been_published
31
+ #
32
+ class NoStubbingBusinessEvent < ::RuboCop::Cop::Base
33
+ def_node_matcher :stub_on_business_event?, <<~PATTERN
34
+ (send nil? {:allow | :expect} (const nil? :BusinessEvent))
35
+ PATTERN
36
+
37
+ # optimization: don't call `on_send` unless the method name is in this list
38
+ RESTRICT_ON_SEND = %i[allow expect].freeze
39
+ MSG = 'Stub BusinessEvent is discouraged!'
40
+
41
+ def on_send(node)
42
+ stub_on_business_event?(node) do
43
+ add_offense(node)
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
49
+ 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: 3.4.3
4
+ version: 4.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - carwow Developers
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-02-23 00:00:00.000000000 Z
11
+ date: 2021-11-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -38,6 +38,34 @@ dependencies:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: pry
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
41
69
  - !ruby/object:Gem::Dependency
42
70
  name: rubocop
43
71
  requirement: !ruby/object:Gem::Requirement
@@ -87,6 +115,8 @@ executables: []
87
115
  extensions: []
88
116
  extra_rdoc_files: []
89
117
  files:
118
+ - ".circleci/config.yml"
119
+ - ".github/dependabot.yml"
90
120
  - ".gitignore"
91
121
  - ".rubocop.yml"
92
122
  - Gemfile
@@ -97,9 +127,27 @@ files:
97
127
  - bin/console
98
128
  - bin/setup
99
129
  - carwow_rubocop.gemspec
100
- - default.yml
130
+ - config/default.yml
131
+ - config/rubocop-bundler.yml
132
+ - config/rubocop-carwow.yml
133
+ - config/rubocop-gemspec.yml
134
+ - config/rubocop-layout.yml
135
+ - config/rubocop-lint.yml
136
+ - config/rubocop-metrics.yml
137
+ - config/rubocop-naming.yml
138
+ - config/rubocop-performance.yml
139
+ - config/rubocop-rails.yml
140
+ - config/rubocop-rspec.yml
141
+ - config/rubocop-security.yml
142
+ - config/rubocop-style.yml
101
143
  - lib/carwow_rubocop.rb
102
- - lib/carwow_rubocop/version.rb
144
+ - lib/rubocop/carwow.rb
145
+ - lib/rubocop/carwow/inject.rb
146
+ - lib/rubocop/carwow/version.rb
147
+ - lib/rubocop/cop/carwow/jobs.rb
148
+ - lib/rubocop/cop/carwow/jobs_must_define_queue.rb
149
+ - lib/rubocop/cop/carwow/jobs_queue_name_style.rb
150
+ - lib/rubocop/cop/carwow/no_stubbing_business_event.rb
103
151
  homepage: https://github.com/carwow/carwow_rubocop
104
152
  licenses:
105
153
  - MIT
@@ -120,7 +168,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
120
168
  - !ruby/object:Gem::Version
121
169
  version: '0'
122
170
  requirements: []
123
- rubygems_version: 3.1.4
171
+ rubygems_version: 3.2.31
124
172
  signing_key:
125
173
  specification_version: 4
126
174
  summary: carwow's rubocop configuration
data/default.yml DELETED
@@ -1,61 +0,0 @@
1
- require:
2
- - rubocop-rspec
3
- - rubocop-performance
4
-
5
- AllCops:
6
- TargetRubyVersion: 2.7
7
- NewCops: enable
8
- Exclude:
9
- - 'Rakefile'
10
- - 'vendor/**/*'
11
- - 'db/*schema*'
12
- - 'node_modules/**/*'
13
- - 'bin/**/*'
14
- - 'tmp/**/*'
15
- - 'public/**/*'
16
-
17
- Layout/ArgumentAlignment:
18
- EnforcedStyle: with_fixed_indentation
19
-
20
- Layout/LineLength:
21
- Max: 120
22
-
23
- Layout/MultilineMethodCallBraceLayout:
24
- EnforcedStyle: new_line
25
-
26
- Layout/MultilineMethodCallIndentation:
27
- EnforcedStyle: indented
28
-
29
- Layout/ParameterAlignment:
30
- EnforcedStyle: with_fixed_indentation
31
-
32
- Metrics/BlockLength:
33
- Exclude:
34
- - 'config/routes.rb'
35
- - 'spec/**/*'
36
- - '**/*.rake'
37
- - '**/*.gemspec'
38
- - 'config/environments/*.rb'
39
- - 'config/initializers/*.rb'
40
-
41
- Naming/RescuedExceptionsVariableName:
42
- Enabled: false
43
-
44
- RSpec/ContextWording:
45
- Enabled: False
46
-
47
- RSpec/ExampleLength:
48
- Max: 10
49
-
50
- Style/AsciiComments:
51
- Enabled: false
52
-
53
- Style/Documentation:
54
- Enabled: false
55
-
56
- Style/DoubleNegation:
57
- Enabled: false
58
-
59
- Style/FrozenStringLiteralComment:
60
- Enabled: false
61
-
@@ -1,3 +0,0 @@
1
- module CarwowRubocop
2
- VERSION = '3.4.3'.freeze
3
- end