summaryrefslogtreecommitdiff
path: root/lib/gitlab/satellite/merge_action.rb
blob: 067a9ce85f2a2f0ffba38ea83eb5ea5339870359 (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
module Gitlab
  module Satellite
    class MergeAction < Action
      attr_accessor :merge_request, :user

      def initialize(merge_request, user)
        super merge_request.project
        @merge_request = merge_request
        @user = user
      end

      def can_be_merged?
        in_locked_and_timed_satellite do |merge_repo|
          merge_in_satellite!(merge_repo)
        end
      end

      # Merges the source branch into the target branch in the satellite and
      # pushes it back to Gitolite.
      # It also removes the source branch if requested in the merge request.
      #
      # Returns false if the merge produced conflicts
      # Returns false if pushing from the satellite to Gitolite failed or was rejected
      # Returns true otherwise
      def merge!
        in_locked_and_timed_satellite do |merge_repo|
          if merge_in_satellite!(merge_repo)
            # push merge back to Gitolite
            # will raise CommandFailed when push fails
            merge_repo.git.push({raise: true}, :origin, merge_request.target_branch)

            # remove source branch
            if merge_request.should_remove_source_branch && !project.root_ref?(merge_request.source_branch)
              # will raise CommandFailed when push fails
              merge_repo.git.push({raise: true}, :origin, ":#{merge_request.source_branch}")
            end

            # merge, push and branch removal successful
            true
          end
        end
      rescue Grit::Git::CommandFailed => ex
        Gitlab::GitLogger.error(ex.message)
        false
      end

      private

      # Merges the source_branch into the target_branch in the satellite.
      #
      # Note: it will clear out the satellite before doing anything
      #
      # Returns false if the merge produced conflicts
      # Returns true otherwise
      def merge_in_satellite!(repo)
        prepare_satellite!(repo)

        # create target branch in satellite at the corresponding commit from Gitolite
        repo.git.checkout({b: true}, merge_request.target_branch, "origin/#{merge_request.target_branch}")

        # merge the source branch from Gitolite into the satellite
        # will raise CommandFailed when merge fails
        repo.git.pull({no_ff: true, raise: true}, :origin, merge_request.source_branch)
      rescue Grit::Git::CommandFailed => ex
        Gitlab::GitLogger.error(ex.message)
        false
      end

      # * Clears the satellite
      # * Updates the satellite from Gitolite
      # * Sets up Git variables for the user
      def prepare_satellite!(repo)
        project.satellite.clear

        repo.git.reset(hard: true)
        repo.git.fetch({}, :origin)

        repo.git.config({}, "user.name", user.name)
        repo.git.config({}, "user.email", user.email)
      end
    end
  end
end