summaryrefslogtreecommitdiff
path: root/app/services/incident_management/create_issue_service.rb
blob: 43077e03e6d1bb329a399e9ed6ff92708a3fcc23 (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
# frozen_string_literal: true

module IncidentManagement
  class CreateIssueService < BaseService
    include Gitlab::Utils::StrongMemoize

    INCIDENT_LABEL = {
      title: 'incident',
      color: '#CC0033',
      description: <<~DESCRIPTION.chomp
        Denotes a disruption to IT services and \
        the associated issues require immediate attention
      DESCRIPTION
    }.freeze

    def initialize(project, params)
      super(project, User.alert_bot, params)
    end

    def execute
      return error_with('setting disabled') unless incident_management_setting.create_issue?
      return error_with('invalid alert') unless alert.valid?

      issue = create_issue
      return error_with(issue_errors(issue)) unless issue.valid?

      success(issue: issue)
    end

    private

    def create_issue
      issue = do_create_issue(label_ids: issue_label_ids)

      # Create an unlabelled issue if we couldn't create the issue
      # due to labels errors.
      # See https://gitlab.com/gitlab-org/gitlab-foss/issues/65042
      if issue.errors.include?(:labels)
        log_label_error(issue)
        issue = do_create_issue
      end

      issue
    end

    def do_create_issue(**params)
      Issues::CreateService.new(
        project,
        current_user,
        title: issue_title,
        description: issue_description,
        **params
      ).execute
    end

    def issue_title
      alert.full_title
    end

    def issue_description
      horizontal_line = "\n\n---\n\n"

      [
        alert_summary,
        alert_markdown,
        issue_template_content
      ].compact.join(horizontal_line)
    end

    def issue_label_ids
      [
        find_or_create_label(**INCIDENT_LABEL)
      ].compact.map(&:id)
    end

    def find_or_create_label(**params)
      Labels::FindOrCreateService
        .new(current_user, project, **params)
        .execute
    end

    def alert_summary
      alert.issue_summary_markdown
    end

    def alert_markdown
      alert.alert_markdown
    end

    def alert
      strong_memoize(:alert) do
        Gitlab::Alerting::Alert.new(project: project, payload: params).present
      end
    end

    def issue_template_content
      incident_management_setting.issue_template_content
    end

    def incident_management_setting
      strong_memoize(:incident_management_setting) do
        project.incident_management_setting ||
          project.build_incident_management_setting
      end
    end

    def issue_errors(issue)
      issue.errors.full_messages.to_sentence
    end

    def log_label_error(issue)
      log_info <<~TEXT.chomp
        Cannot create incident issue with labels \
        #{issue.labels.map(&:title).inspect} \
        for "#{project.full_name}": #{issue.errors.full_messages.to_sentence}.
        Retrying without labels.
      TEXT
    end

    def error_with(message)
      log_error(%{Cannot create incident issue for "#{project.full_name}": #{message}})

      error(message)
    end
  end
end