summaryrefslogtreecommitdiff
path: root/app/services/projects/update_remote_mirror_service.rb
blob: 13a467a3ef9b1ba593c734fc40bc9e4f61acc60f (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
# frozen_string_literal: true

module Projects
  class UpdateRemoteMirrorService < BaseService
    MAX_TRIES = 3

    def execute(remote_mirror, tries)
      return success unless remote_mirror.enabled?

      update_mirror(remote_mirror)

      success
    rescue Gitlab::Git::CommandError => e
      # This happens if one of the gitaly calls above fail, for example when
      # branches have diverged, or the pre-receive hook fails.
      retry_or_fail(remote_mirror, e.message, tries)

      error(e.message)
    rescue => e
      remote_mirror.mark_as_failed!(e.message)
      raise e
    end

    private

    def update_mirror(remote_mirror)
      remote_mirror.update_start!

      remote_mirror.ensure_remote!
      repository.fetch_remote(remote_mirror.remote_name, ssh_auth: remote_mirror, no_tags: true)

      opts = {}
      if remote_mirror.only_protected_branches?
        opts[:only_branches_matching] = project.protected_branches.select(:name).map(&:name)
      end

      remote_mirror.update_repository(opts)

      remote_mirror.update_finish!
    end

    def retry_or_fail(mirror, message, tries)
      if tries < MAX_TRIES
        mirror.mark_for_retry!(message)
      else
        # It's not likely we'll be able to recover from this ourselves, so we'll
        # notify the users of the problem, and don't trigger any sidekiq retries
        # Instead, we'll wait for the next change to try the push again, or until
        # a user manually retries.
        mirror.mark_as_failed!(message)
      end
    end
  end
end