Class: RuboCop::Cop::Carwow::ProductAreaRequired

Inherits:
Base
  • Object
show all
Defined in:
lib/rubocop/cop/carwow/product_area_required.rb

Overview

Controllers and jobs are attributed to a team via the product_area DSL (CarwowCore::ProductArea::Taggable) so their Honeycomb spans and Bugsnag errors route to the owning team automatically. A class with no declared area falls back to manual triage.

This only checks that product_area is called somewhere in the class's own body — it cannot verify, statically, that a superclass declared in another file already sets one. Shared base classes that are intentionally left untagged (e.g. ApplicationController, ApplicationJob, or a namespaced API base controller) should be added to this cop's Exclude in the consuming app's .rubocop.yml rather than tagged.

A class nested inside another class (rather than merely inside a namespacing module) is assumed to be a helper — e.g. a custom error raised by the enclosing job — not an entry point of its own, so it is not checked. Only the enclosing class needs the tag.

A class that subclasses a known Ruby exception (StandardError, RuntimeError, ...) or whose superclass name ends in Error/Exception is never checked, wherever it's defined: exceptions are raised inside an entry point, not routed to one of their own.

A class that doesn't look like a controller/job entry point itself (no Controller/Job-ish superclass, no include Sidekiq::Worker/Sidekiq::Job, no perform method) is skipped if it sits alongside a sibling class in the same file/module that already declares product_area — a common pattern for small POROs colocated with the controller/job that uses them. Two genuinely independent entry points defined in the same file still both need their own tag.

Examples:

# bad
class PaymentsController < ApplicationController
end

# good
class PaymentsController < ApplicationController
  product_area 'smc-payments'
end

# good - nested error class does not need its own tag
class SyncListing < ApplicationJob
  product_area 'salesforce'

  class UnknownReference < StandardError; end
end

# good - sibling error class, and sibling PORO helper, do not need their own tag
module Payments
  class RefundFailed < StandardError; end

  class RefundsController < ApplicationController
    product_area 'smc-payments'
  end

  class RefundPresenter
    def initialize(refund); end
  end
end

Constant Summary collapse

MSG =
'Declare a `product_area` for this class so its Honeycomb spans ' \
'and Bugsnag errors route to the owning team.'
KNOWN_ERROR_SUPERCLASSES =
%w[StandardError RuntimeError Exception ScriptError].freeze
ERROR_NAME_PATTERN =
/Error\z|Exception\z/
ENTRY_POINT_SUPERCLASS_PATTERN =
/Controller|Job/

Instance Method Summary collapse

Instance Method Details

#on_class(node) ⇒ Object



88
89
90
91
92
93
94
95
96
# File 'lib/rubocop/cop/carwow/product_area_required.rb', line 88

def on_class(node)
  return if nested_in_class?(node)
  return if subclasses_known_error?(node)
  return if declares_product_area?(node)
  return if !looks_like_entry_point?(node) && sibling_already_tagged?(node)

  class_node, = *node
  add_offense(class_node)
end