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

track_inconsistency.rb « schema_validation « database « gitlab « lib - gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 6e167653d32452e7174d755372c177ae3608d21f (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
133
134
135
136
137
138
# frozen_string_literal: true

module Gitlab
  module Database
    module SchemaValidation
      class TrackInconsistency
        COLUMN_TEXT_LIMIT = 6144

        def initialize(inconsistency, project, user)
          @inconsistency = inconsistency
          @project = project
          @user = user
        end

        def execute
          return unless Gitlab.com?
          return refresh_issue if inconsistency_record.present?

          result = ::Issues::CreateService.new(
            container: project,
            current_user: user,
            params: params,
            perform_spam_check: false).execute

          track_inconsistency(result[:issue]) if result.success?
        end

        private

        attr_reader :inconsistency, :project, :user

        def track_inconsistency(issue)
          schema_inconsistency_model.create!(
            issue: issue,
            object_name: inconsistency.object_name,
            table_name: inconsistency.table_name,
            valitador_name: inconsistency.type,
            diff: inconsistency_diff
          )
        end

        def params
          {
            title: issue_title,
            description: description,
            issue_type: 'issue',
            labels: default_labels + group_labels
          }
        end

        def issue_title
          "New schema inconsistency: #{inconsistency.object_name}"
        end

        def description
          <<~MSG
            We have detected a new schema inconsistency.

            **Table name:** #{inconsistency.table_name}\
            **Object name:** #{inconsistency.object_name}\
            **Validator name:** #{inconsistency.type}\
            **Object type:** #{inconsistency.object_type}\
            **Error message:** #{inconsistency.error_message}


            **Structure.sql statement:**

            ```sql
            #{inconsistency.structure_sql_statement}
            ```

            **Database statement:**

            ```sql
            #{inconsistency.database_statement}
            ```

            **Diff:**

            ```diff
            #{inconsistency.diff}

            ```


            For more information, please contact the database team.
          MSG
        end

        def group_labels
          dictionary = YAML.safe_load(File.read(table_file_path))

          dictionary['feature_categories'].to_a.filter_map do |feature_category|
            Gitlab::Database::ConvertFeatureCategoryToGroupLabel.new(feature_category).execute
          end
        rescue Errno::ENOENT
          []
        end

        def default_labels
          %w[database database-inconsistency-report type::maintenance severity::4]
        end

        def table_file_path
          Rails.root.join(Gitlab::Database::GitlabSchema.dictionary_paths.first, "#{inconsistency.table_name}.yml")
        end

        def schema_inconsistency_model
          Gitlab::Database::SchemaValidation::SchemaInconsistency
        end

        def refresh_issue
          return if inconsistency_diff == inconsistency_record.diff # Nothing to refresh

          note = ::Notes::CreateService.new(
            inconsistency_record.issue.project,
            user,
            { noteable_type: 'Issue', noteable: inconsistency_record.issue, note: description }
          ).execute

          inconsistency_record.update!(diff: inconsistency_diff) if note.persisted?
        end

        def inconsistency_diff
          @inconsistency_diff ||= inconsistency.diff.to_s.first(COLUMN_TEXT_LIMIT)
        end

        def inconsistency_record
          @inconsistency_record ||= schema_inconsistency_model.with_open_issues.find_by(
            object_name: inconsistency.object_name,
            table_name: inconsistency.table_name,
            valitador_name: inconsistency.type
          )
        end
      end
    end
  end
end