1# frozen_string_literal: true
2
3module Gitlab
4  module Tracking
5    InvalidEventError = Class.new(RuntimeError)
6
7    class EventDefinition
8      EVENT_SCHEMA_PATH = Rails.root.join('config', 'events', 'schema.json')
9      BASE_REPO_PATH = 'https://gitlab.com/gitlab-org/gitlab/-/blob/master'
10      SCHEMA = ::JSONSchemer.schema(Pathname.new(EVENT_SCHEMA_PATH))
11
12      attr_reader :path
13      attr_reader :attributes
14
15      class << self
16        def paths
17          @paths ||= [Rails.root.join('config', 'events', '*.yml'), Rails.root.join('ee', 'config', 'events', '*.yml')]
18        end
19
20        def definitions
21          paths.each_with_object({}) do |glob_path, definitions|
22            load_all_from_path!(definitions, glob_path)
23          end
24        end
25
26        private
27
28        def load_from_file(path)
29          definition = File.read(path)
30          definition = YAML.safe_load(definition)
31          definition.deep_symbolize_keys!
32
33          self.new(path, definition).tap(&:validate!)
34        rescue StandardError => e
35          Gitlab::ErrorTracking.track_and_raise_for_dev_exception(Gitlab::Tracking::InvalidEventError.new(e.message))
36        end
37
38        def load_all_from_path!(definitions, glob_path)
39          Dir.glob(glob_path).each do |path|
40            definition = load_from_file(path)
41            definitions[definition.path] = definition
42          end
43        end
44      end
45
46      def initialize(path, opts = {})
47        @path = path
48        @attributes = opts
49      end
50
51      def to_h
52        attributes
53      end
54      alias_method :to_dictionary, :to_h
55
56      def yaml_path
57        path.delete_prefix(Rails.root.to_s)
58      end
59
60      def validate!
61        SCHEMA.validate(attributes.stringify_keys).each do |error|
62          error_message = <<~ERROR_MSG
63            Error type: #{error['type']}
64            Data: #{error['data']}
65            Path: #{error['data_pointer']}
66            Details: #{error['details']}
67            Definition file: #{path}
68          ERROR_MSG
69
70          Gitlab::ErrorTracking.track_and_raise_for_dev_exception(Gitlab::Tracking::InvalidEventError.new(error_message))
71        end
72      end
73
74      private
75
76      def method_missing(method, *args)
77        attributes[method] || super
78      end
79    end
80  end
81end
82