Welcome to mirror list, hosted at ThFree Co, Russian Federation.

analytics_instrumentation.rb « danger « tooling - gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 767ae8dfb4c9874bc2c9ffacfb67f7394fdb5f74 (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
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
# frozen_string_literal: true
# rubocop:disable Style/SignalException

module Tooling
  module Danger
    module AnalyticsInstrumentation
      METRIC_DIRS = %w[lib/gitlab/usage/metrics/instrumentations ee/lib/gitlab/usage/metrics/instrumentations].freeze
      APPROVED_LABEL = 'analytics instrumentation::approved'
      REVIEW_LABEL = 'analytics instrumentation::review pending'
      CHANGED_FILES_MESSAGE = <<~MSG
        For the following files, a review from the [Data team and Analytics Instrumentation team](https://gitlab.com/groups/gitlab-org/analytics-section/analytics-instrumentation/engineers/-/group_members?with_inherited_permissions=exclude) is recommended
        Please check the ~"analytics instrumentation" [Service Ping guide](https://docs.gitlab.com/ee/development/service_ping/) or the [Snowplow guide](https://docs.gitlab.com/ee/development/snowplow/).

        For MR review guidelines, see the [Service Ping review guidelines](https://docs.gitlab.com/ee/development/service_ping/review_guidelines.html) or the [Snowplow review guidelines](https://docs.gitlab.com/ee/development/snowplow/review_guidelines.html).

        %<changed_files>s

      MSG

      CHANGED_SCOPE_MESSAGE = <<~MSG
        The following metrics could be affected by the modified scopes and require ~"analytics instrumentation" review:

      MSG

      CHANGED_USAGE_DATA_MESSAGE = <<~MSG
        Notice that implementing metrics directly in usage_data.rb has been deprecated. ([Deprecated Usage Metrics](https://docs.gitlab.com/ee/development/service_ping/usage_data.html#usage-data-metrics-guide))
        Please use [Instrumentation Classes](https://docs.gitlab.com/ee/development/service_ping/metrics_instrumentation.html) instead.
      MSG

      WORKFLOW_LABELS = [
        APPROVED_LABEL,
        REVIEW_LABEL
      ].freeze

      def check!
        analytics_instrumentation_paths_to_review = helper.changes.by_category(:analytics_instrumentation).files

        labels_to_add = missing_labels

        return if analytics_instrumentation_paths_to_review.empty? || skip_review?

        warn format(CHANGED_FILES_MESSAGE, changed_files: helper.markdown_list(analytics_instrumentation_paths_to_review)) unless has_approved_label?

        helper.labels_to_add.concat(labels_to_add) unless labels_to_add.empty?
      end

      def check_affected_scopes!
        metric_scope_list = metric_scope_affected
        return if metric_scope_list.empty?

        warn CHANGED_SCOPE_MESSAGE + convert_to_table(metric_scope_list)
        helper.labels_to_add.concat(missing_labels) unless missing_labels.empty?
      end

      def check_usage_data_insertions!
        usage_data_changes = helper.changed_lines("lib/gitlab/usage_data.rb")
        return if usage_data_changes.none? { |change| change.start_with?("+") }

        warn format(CHANGED_USAGE_DATA_MESSAGE)
      end

      private

      def convert_to_table(items)
        message = "Scope | Affected files |\n"
        message += "--- | ----- |\n"
        items.each_key do |scope|
          affected_files = items[scope]
          message += "`#{scope}`| `#{affected_files[0]}` |\n"
          affected_files[1..]&.each do |file_name|
            message += " | `#{file_name}` |\n"
          end
        end
        message
      end

      def metric_scope_affected
        select_models(helper.modified_files).each_with_object(Hash.new { |h, k| h[k] = [] }) do |file_name, matched_files|
          helper.changed_lines(file_name).each do |mod_line, _i|
            next unless mod_line =~ /^\+\s+scope :\w+/

            affected_scope = mod_line.match(/:\w+/)
            next if affected_scope.nil?

            affected_class = File.basename(file_name, '.rb').split('_').map(&:capitalize).join
            scope_name = "#{affected_class}.#{affected_scope[0][1..]}"

            each_metric do |metric_def|
              next unless File.read(metric_def).include?("relation { #{scope_name}")

              matched_files[scope_name].push(metric_def)
            end
          end
        end
      end

      def select_models(files)
        files.select do |f|
          f.start_with?('app/models/', 'ee/app/models/')
        end
      end

      def each_metric(&block)
        METRIC_DIRS.each do |dir|
          Dir.glob(File.join(dir, '*.rb')).each(&block)
        end
      end

      def missing_labels
        return [] unless helper.ci?

        labels = []
        labels << 'analytics instrumentation' unless helper.mr_has_labels?('analytics instrumentation')
        labels << REVIEW_LABEL unless has_workflow_labels?

        labels
      end

      def has_approved_label?
        helper.mr_labels.include?(APPROVED_LABEL)
      end

      def skip_review?
        helper.mr_has_labels?('growth experiment')
      end

      def has_workflow_labels?
        (WORKFLOW_LABELS & helper.mr_labels).any?
      end
    end
  end
end