summaryrefslogtreecommitdiff
path: root/app/workers/emails_on_push_worker.rb
blob: 8551288e2f24f15b9b1a40f313712d6a89d2c87b (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
class EmailsOnPushWorker
  include Sidekiq::Worker

  sidekiq_options queue: :mailers
  attr_reader :email, :skip_premailer

  def perform(project_id, recipients, push_data, options = {})
    options.symbolize_keys!
    options.reverse_merge!(
      send_from_committer_email:  false,
      disable_diffs:              false
    )
    send_from_committer_email = options[:send_from_committer_email]
    disable_diffs = options[:disable_diffs]

    project = Project.find(project_id)
    before_sha = push_data["before"]
    after_sha = push_data["after"]
    ref = push_data["ref"]
    author_id = push_data["user_id"]

    action =
      if Gitlab::Git.blank_ref?(before_sha)
        :create
      elsif Gitlab::Git.blank_ref?(after_sha)
        :delete
      else
        :push
      end

    merge_base_sha = project.merge_base_commit(before_sha, after_sha).try(:sha)

    diff_refs = nil
    compare = nil
    reverse_compare = false
    if action == :push
      compare = Gitlab::Git::Compare.new(project.repository.raw_repository, before_sha, after_sha)

      diff_refs = Gitlab::Diff::DiffRefs.new(
        base_sha: merge_base_sha,
        start_sha: before_sha,
        head_sha: after_sha
      )

      return false if compare.same

      if compare.commits.empty?
        compare = Gitlab::Git::Compare.new(project.repository.raw_repository, after_sha, before_sha)

        diff_refs = Gitlab::Diff::DiffRefs.new(
          base_sha: merge_base_sha,
          start_sha: after_sha,
          head_sha: before_sha
        )

        reverse_compare = true

        return false if compare.commits.empty?
      end
    end

    recipients.split.each do |recipient|
      begin
        send_email(
          recipient,
          project_id,
          author_id:                 author_id,
          ref:                       ref,
          action:                    action,
          compare:                   compare,
          reverse_compare:           reverse_compare,
          diff_refs:                 diff_refs,
          send_from_committer_email: send_from_committer_email,
          disable_diffs:             disable_diffs
        )

      # These are input errors and won't be corrected even if Sidekiq retries
      rescue Net::SMTPFatalError, Net::SMTPSyntaxError => e
        logger.info("Failed to send e-mail for project '#{project.name_with_namespace}' to #{recipient}: #{e}")
      end
    end
  ensure
    @email = nil
    compare = nil
    GC.start
  end

  private

  def send_email(recipient, project_id, options)
    # Generating the body of this email can be expensive, so only do it once
    @skip_premailer ||= email.present?
    @email ||= Notify.repository_push_email(project_id, options)

    email.to = recipient
    email.add_message_id
    email.header[:skip_premailer] = true if skip_premailer
    email.deliver_now
  end
end