summaryrefslogtreecommitdiff
path: root/app/models/integrations/pipelines_email.rb
blob: f15482dc2e18fe4a55509b9b3f936d6df62cbca6 (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
# frozen_string_literal: true

module Integrations
  class PipelinesEmail < Integration
    include NotificationBranchSelection

    RECIPIENTS_LIMIT = 30

    prop_accessor :recipients, :branches_to_be_notified
    boolean_accessor :notify_only_broken_pipelines, :notify_only_default_branch
    validates :recipients, presence: true, if: :validate_recipients?
    validate :number_of_recipients_within_limit, if: :validate_recipients?

    def initialize_properties
      super

      if properties.blank?
        self.notify_only_broken_pipelines = true
        self.branches_to_be_notified = "default"
      elsif !self.notify_only_default_branch.nil?
        # In older versions, there was only a boolean property named
        # `notify_only_default_branch`. Now we have a string property named
        # `branches_to_be_notified`. Instead of doing a background migration, we
        # opted to set a value for the new property based on the old one, if
        # users hasn't specified one already. When users edit the service and
        # selects a value for this new property, it will override everything.

        self.branches_to_be_notified ||= notify_only_default_branch? ? "default" : "all"
      end
    end

    def title
      _('Pipeline status emails')
    end

    def description
      _('Email the pipeline status to a list of recipients.')
    end

    def self.to_param
      'pipelines_email'
    end

    def self.supported_events
      %w[pipeline]
    end

    def self.default_test_event
      'pipeline'
    end

    def execute(data, force: false)
      return unless supported_events.include?(data[:object_kind])
      return unless force || should_pipeline_be_notified?(data)

      all_recipients = retrieve_recipients

      return unless all_recipients.any?

      pipeline_id = data[:object_attributes][:id]
      PipelineNotificationWorker.new.perform(pipeline_id, recipients: all_recipients)
    end

    def testable?
      project&.ci_pipelines&.any?
    end

    def fields
      [
        { type: 'textarea',
          name: 'recipients',
          help: _('Comma-separated list of email addresses.'),
          required: true },
        { type: 'checkbox',
          name: 'notify_only_broken_pipelines' },
        { type: 'select',
          name: 'branches_to_be_notified',
          title: s_('Integrations|Branches for which notifications are to be sent'),
          choices: branch_choices }
      ]
    end

    def test(data)
      result = execute(data, force: true)

      { success: true, result: result }
    rescue StandardError => error
      { success: false, result: error }
    end

    def should_pipeline_be_notified?(data)
      notify_for_branch?(data) && notify_for_pipeline?(data)
    end

    def notify_for_pipeline?(data)
      case data[:object_attributes][:status]
      when 'success'
        !notify_only_broken_pipelines?
      when 'failed'
        true
      else
        false
      end
    end

    def retrieve_recipients
      recipients.to_s.split(/[,\r\n ]+/).reject(&:empty?)
    end

    private

    def number_of_recipients_within_limit
      return if recipients.blank?

      if retrieve_recipients.size > RECIPIENTS_LIMIT
        errors.add(:recipients, s_("Integrations|can't exceed %{recipients_limit}") % { recipients_limit: RECIPIENTS_LIMIT })
      end
    end
  end
end