carwow_rubocop 3.4.1 → 4.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: aca908c948096d71e8112457e5552cd13f1553e72a77034497d4b8805615dad3
4
- data.tar.gz: f9f686dcd7332b9af07cd27ee34a1e4a1f49233b0f0362bab723ac5fa2a17c45
3
+ metadata.gz: 7e205e4968385dd33b555dbe38d9de54acd6a3aa2a666a893f9e72e9ace3489c
4
+ data.tar.gz: ad4268b23619062ad1cb11840478b774e52dc0dedd823773a617fb97c8bd82a4
5
5
  SHA512:
6
- metadata.gz: 616660f882870921fdb823e752a78ea035b139bb7a0590a5d18f98b159c6d175183b36517656760c3f1b2caf27b19647cc941666e4d1df0bb3026bf9e37fa74c
7
- data.tar.gz: 6aa34ceb8bad8d55a98d33fbd8292837bc3b92935588f8ab9ba6ca124db14d7fa03faea41c2d640ae54879d12158a8cdf656ad68350da397890e886d174872cc
6
+ metadata.gz: 6fee3a916cea0cd78637e7113d67432e0ae00e11358f172bfe2812e3c399c75cd438ec750c7365e099ce50030635dacf517a1b6158e84fe4f057f8eb2c28a637
7
+ data.tar.gz: 77df54899aff739a4fe8d3fae0759caabc3b92d6d33481874183efd436404d76e2427b968080d060c8982908142f59d2dcfb4d106098368ffd8bb328f9984987
@@ -0,0 +1,73 @@
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 rake
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]
65
+
66
+ - publish_gem:
67
+ context: org-global
68
+ requires:
69
+ - tests
70
+ - lint_ruby
71
+ filters:
72
+ branches:
73
+ only: [master]
@@ -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.1)
4
+ carwow_rubocop (4.0.0)
5
5
  rubocop (>= 0.93)
6
6
  rubocop-performance
7
7
  rubocop-rspec
@@ -9,32 +9,51 @@ PATH
9
9
  GEM
10
10
  remote: https://rubygems.org/
11
11
  specs:
12
- ast (2.4.1)
13
- parallel (1.19.2)
14
- parser (2.7.2.0)
12
+ ast (2.4.2)
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 (1.8.2)
19
- rexml (3.2.4)
20
- rubocop (0.93.1)
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.1)
21
40
  parallel (~> 1.10)
22
- parser (>= 2.7.1.5)
41
+ parser (>= 3.0.0.0)
23
42
  rainbow (>= 2.2.2, < 4.0)
24
- regexp_parser (>= 1.8)
43
+ regexp_parser (>= 1.8, < 3.0)
25
44
  rexml
26
- rubocop-ast (>= 0.6.0)
45
+ rubocop-ast (>= 1.12.0, < 2.0)
27
46
  ruby-progressbar (~> 1.7)
28
- unicode-display_width (>= 1.4.0, < 2.0)
29
- rubocop-ast (0.8.0)
30
- parser (>= 2.7.1.5)
31
- rubocop-performance (1.8.1)
32
- rubocop (>= 0.87.0)
47
+ unicode-display_width (>= 1.4.0, < 3.0)
48
+ rubocop-ast (1.12.0)
49
+ parser (>= 3.0.1.1)
50
+ rubocop-performance (1.11.5)
51
+ rubocop (>= 1.7.0, < 2.0)
33
52
  rubocop-ast (>= 0.4.0)
34
- rubocop-rspec (1.43.2)
35
- rubocop (~> 0.87)
36
- ruby-progressbar (1.10.1)
37
- unicode-display_width (1.7.0)
53
+ rubocop-rspec (2.5.0)
54
+ rubocop (~> 1.19)
55
+ ruby-progressbar (1.11.0)
56
+ unicode-display_width (2.1.0)
38
57
 
39
58
  PLATFORMS
40
59
  ruby
@@ -42,7 +61,9 @@ PLATFORMS
42
61
  DEPENDENCIES
43
62
  bundler
44
63
  carwow_rubocop!
64
+ pry
45
65
  rake
66
+ rspec
46
67
 
47
68
  BUNDLED WITH
48
- 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
+ - rubocop-carwow
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,11 +1,12 @@
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
8
- spec.required_ruby_version = '>= 2.7.0'
7
+ spec.version = RuboCop::Carwow::VERSION
8
+ spec.platform = Gem::Platform::RUBY
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']
11
12
  spec.summary = "carwow's rubocop configuration"
@@ -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.0'.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,115 @@
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 allowed?(super_class(*node))
59
+ return if defining_allowed_job?(*node)
60
+
61
+ register_offenses(node)
62
+ end
63
+
64
+ private
65
+
66
+ def allowed?(superclass)
67
+ cop_config.fetch('AllowedSuperclasses').include?(superclass)
68
+ end
69
+
70
+ def defining_allowed_job?(class_node, super_node, _)
71
+ super_class_name = super_node&.const_name
72
+
73
+ allowed?(class_node.const_name) &&
74
+ (allowed?(super_class_name) || top_level?(super_class_name))
75
+ end
76
+
77
+ def register_offenses(node)
78
+ class_node, super_node, _args = *node
79
+
80
+ if allowed?(class_node.const_name)
81
+ only_allowed_inherit_from_toplevel(super_node, FORCE_TOP_LEVEL_MSG)
82
+ elsif top_level?(super_node&.const_name)
83
+ only_allowed_inherit_from_toplevel(node, TOP_LEVEL_MSG)
84
+ else
85
+ add_offense(class_node, message: MSG % allowed_str)
86
+ end
87
+ end
88
+
89
+ def super_class(_, superclass_node, _)
90
+ superclass_node&.const_name
91
+ end
92
+
93
+ def missing_config?
94
+ !(cop_config.key?('AllowedSuperclasses') && cop_config.key?('TopLevelJob'))
95
+ end
96
+
97
+ def top_level?(klass)
98
+ top_level_class == klass
99
+ end
100
+
101
+ def allowed_str
102
+ cop_config.fetch('AllowedSuperclasses').join(', ')
103
+ end
104
+
105
+ def top_level_class
106
+ cop_config.fetch('TopLevelJob')
107
+ end
108
+
109
+ def only_allowed_inherit_from_toplevel(node, msg)
110
+ add_offense(node, message: format(msg, allowed_str, top_level_class))
111
+ end
112
+ end
113
+ end
114
+ end
115
+ 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.1
4
+ version: 4.0.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: 2020-10-13 00:00:00.000000000 Z
11
+ date: 2021-10-20 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.1.6
124
172
  signing_key:
125
173
  specification_version: 4
126
174
  summary: carwow's rubocop configuration
data/default.yml DELETED
@@ -1,58 +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/Documentation:
51
- Enabled: false
52
-
53
- Style/FrozenStringLiteralComment:
54
- Enabled: false
55
-
56
- Style/DoubleNegation:
57
- Enabled: false
58
-
@@ -1,3 +0,0 @@
1
- module CarwowRubocop
2
- VERSION = '3.4.1'.freeze
3
- end