summaryrefslogtreecommitdiff
path: root/rubocop/cop/migration/background_migration_missing_active_concern.rb
blob: 417472bf512213a5cf1efd26d8d74c1c7c8e8fcc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
# frozen_string_literal: true

require_relative '../../migration_helpers'

module RuboCop
  module Cop
    module Migration
      # Cop that checks `ActiveSupport::Concern` is included in EE batched background migrations
      # if they define `scope_to`.
      class BackgroundMigrationMissingActiveConcern < RuboCop::Cop::Base
        include MigrationHelpers

        MSG = <<~MSG
          Extend `ActiveSupport::Concern` in the EE background migration if it defines `scope_to`.
        MSG

        def_node_matcher :prepended_block_uses_scope_to?, <<~PATTERN
          (:block (:send nil? :prepended) (:args) `(:send nil? :scope_to ...))
        PATTERN

        def_node_matcher :scope_to?, <<~PATTERN
          (:send nil? :scope_to ...)
        PATTERN

        def_node_matcher :extend_activesupport_concern?, <<~PATTERN
          (:send nil? :extend (:const (:const nil? :ActiveSupport) :Concern))
        PATTERN

        def on_block(node)
          return unless in_ee_background_migration?(node)
          return unless prepended_block_uses_scope_to?(node)

          return if module_extends_activesupport_concern?(node)

          node.descendants.each do |descendant|
            next unless scope_to?(descendant)

            add_offense(descendant)
          end
        end

        private

        def module_extends_activesupport_concern?(node)
          while node = node.parent
            break if node.type == :module
          end

          return false unless node

          node.descendants.any? do |descendant|
            extend_activesupport_concern?(descendant)
          end
        end
      end
    end
  end
end