From 7af585f1667935165701ec290e6ce37a436ad4c6 Mon Sep 17 00:00:00 2001 From: Valery Sizov Date: Wed, 13 Sep 2017 17:11:10 +0300 Subject: [PATCH] Fast forward merge: basic implemenation[ci skip] --- app/controllers/projects_controller.rb | 1 + app/models/project.rb | 17 +++++++++++++ app/models/repository.rb | 19 +++++++++++++++ app/serializers/merge_request_entity.rb | 5 ++++ .../merge_requests/ff_merge_service.rb | 24 +++++++++++++++++++ app/services/merge_requests/merge_service.rb | 5 ++++ .../_merge_request_merge_settings.html.haml | 22 +++++++++++++++++ .../import_export/safe_model_attributes.yml | 1 + 8 files changed, 94 insertions(+) create mode 100644 app/services/merge_requests/ff_merge_service.rb diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index b13034d3333..a738ca9f361 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -344,6 +344,7 @@ class ProjectsController < Projects::ApplicationController :tag_list, :visibility_level, :template_name, + :merge_method, project_feature_attributes: %i[ builds_access_level diff --git a/app/models/project.rb b/app/models/project.rb index f7221e4f3b2..cd1fa734e78 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -1557,6 +1557,23 @@ class Project < ActiveRecord::Base persisted? && path_changed? end + def merge_method + if self.merge_requests_ff_only_enabled + :ff + else + :merge + end + end + + def merge_method=(method) + self.merge_requests_ff_only_enabled = method.to_s == "ff" + end + + def ff_merge_must_be_possible? + self.merge_requests_ff_only_enabled + end + # alias_method :merge_requests_ff_only_enabled?, :merge_requests_ff_only_enabled + private def storage diff --git a/app/models/repository.rb b/app/models/repository.rb index f11cf1b065d..2df6c9c80da 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -854,6 +854,25 @@ class Repository end end + def ff_merge(user, source, target_branch, merge_request: nil) + our_commit = rugged.branches[target_branch].target + their_commit = + if source.is_a?(Gitlab::Git::Commit) + source.raw_commit + else + rugged.lookup(source) + end + + raise 'Invalid merge target' if our_commit.nil? + raise 'Invalid merge source' if their_commit.nil? + + with_branch(user, target_branch) do |start_commit| + merge_request&.update(in_progress_merge_commit_sha: their_commit.oid) + + their_commit.oid + end + end + def revert( user, commit, branch_name, message, start_branch_name: nil, start_project: project) diff --git a/app/serializers/merge_request_entity.rb b/app/serializers/merge_request_entity.rb index 07650ce6f20..1f5ce2ef58c 100644 --- a/app/serializers/merge_request_entity.rb +++ b/app/serializers/merge_request_entity.rb @@ -13,6 +13,11 @@ class MergeRequestEntity < IssuableEntity expose :target_branch expose :target_project_id + expose :ff_only_enabled do |merge_request| + merge_request.project.merge_requests_ff_only_enabled + end + + # Events expose :merge_event, using: EventEntity expose :closed_event, using: EventEntity diff --git a/app/services/merge_requests/ff_merge_service.rb b/app/services/merge_requests/ff_merge_service.rb new file mode 100644 index 00000000000..ba6853b835a --- /dev/null +++ b/app/services/merge_requests/ff_merge_service.rb @@ -0,0 +1,24 @@ +module MergeRequests + # MergeService class + # + # Do git fast-forward merge and in case of success + # mark merge request as merged and execute all hooks and notifications + # Executed when you do fast-forward merge via GitLab UI + # + class FfMergeService < MergeRequests::MergeService + private + + def commit + repository.ff_merge(current_user, + source, + merge_request.target_branch, + merge_request: merge_request) + rescue Gitlab::Git::HooksService::PreReceiveError => e + raise MergeError, e.message + rescue StandardError => e + raise MergeError, "Something went wrong during merge: #{e.message}" + ensure + merge_request.update(in_progress_merge_commit_sha: nil) + end + end +end diff --git a/app/services/merge_requests/merge_service.rb b/app/services/merge_requests/merge_service.rb index 07cbd8f92a9..0d75c68feb2 100644 --- a/app/services/merge_requests/merge_service.rb +++ b/app/services/merge_requests/merge_service.rb @@ -11,6 +11,11 @@ module MergeRequests attr_reader :merge_request, :source def execute(merge_request) + if project.merge_requests_ff_only_enabled && !self.is_a?(FfMergeService) + FfMergeService.new(project, current_user, params).execute(merge_request) + return + end + @merge_request = merge_request unless @merge_request.mergeable? diff --git a/app/views/projects/_merge_request_merge_settings.html.haml b/app/views/projects/_merge_request_merge_settings.html.haml index 1dd8778f800..0016526f788 100644 --- a/app/views/projects/_merge_request_merge_settings.html.haml +++ b/app/views/projects/_merge_request_merge_settings.html.haml @@ -1,5 +1,27 @@ - form = local_assigns.fetch(:form) +.form-group + = label_tag :merge_method_merge, class: 'label-light' do + Merge method + .radio + = label_tag :project_merge_method_merge do + = form.radio_button :merge_method, :merge, class: "js-merge-method-radio" + %strong Merge commit + %br + %span.descr + A merge commit is created for every merge, and merging is allowed as long as there are no conflicts. + + .radio + = label_tag :project_merge_method_ff do + = form.radio_button :merge_method, :ff, class: "js-merge-method-radio" + %strong Fast-forward merge + %br + %span.descr + No merge commits are created and all merges are fast-forwarded, which means that merging is only allowed if the branch could be fast-forwarded. + %br + %span.descr + When fast-forward merge is not possible, the user must first rebase locally. + .form-group .checkbox.builds-feature{ class: ("hidden" if @project && @project.project_feature.send(:builds_access_level) == 0) } = form.label :only_allow_merge_if_pipeline_succeeds do diff --git a/spec/lib/gitlab/import_export/safe_model_attributes.yml b/spec/lib/gitlab/import_export/safe_model_attributes.yml index 899d17d97c2..64b8e7f7e18 100644 --- a/spec/lib/gitlab/import_export/safe_model_attributes.yml +++ b/spec/lib/gitlab/import_export/safe_model_attributes.yml @@ -412,6 +412,7 @@ Project: - last_repository_updated_at - ci_config_path - delete_error +- merge_requests_ff_only_enabled Author: - name ProjectFeature: