Huge refactoring for accepting merge requests

Signed-off-by: Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com>
This commit is contained in:
Dmitriy Zaporozhets 2015-07-16 16:03:07 +02:00
parent 26f5d6047d
commit a7fded9b95
No known key found for this signature in database
GPG Key ID: 161B5D6A44D3D88A
20 changed files with 139 additions and 133 deletions

View File

@ -875,3 +875,6 @@ DEPENDENCIES
virtus
webmock (~> 1.21.0)
wikicloth (= 0.8.1)
BUNDLED WITH
1.10.4

View File

@ -19,7 +19,7 @@ class @MergeRequestWidget
when 'merged'
location.reload()
else
setTimeout(merge_request_widget.mergeInProgress, 3000)
setTimeout(merge_request_widget.mergeInProgress, 2000)
dataType: 'json'
getMergeStatus: ->

View File

@ -1,7 +1,7 @@
class Projects::MergeRequestsController < Projects::ApplicationController
before_action :module_enabled
before_action :merge_request, only: [
:edit, :update, :show, :diffs, :commits, :automerge, :automerge_check,
:edit, :update, :show, :diffs, :commits, :merge, :merge_check,
:ci_status, :toggle_subscription
]
before_action :closes_issues, only: [:edit, :update, :show, :diffs, :commits]
@ -135,7 +135,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController
end
end
def automerge_check
def merge_check
if @merge_request.unchecked?
@merge_request.check_if_can_be_merged
end
@ -145,11 +145,11 @@ class Projects::MergeRequestsController < Projects::ApplicationController
render partial: "projects/merge_requests/widget/show.html.haml", layout: false
end
def automerge
def merge
return access_denied! unless @merge_request.can_be_merged_by?(current_user)
if @merge_request.automergeable?
AutoMergeWorker.perform_async(@merge_request.id, current_user.id, params)
if @merge_request.mergeable?
MergeWorker.perform_async(@merge_request.id, current_user.id, params)
@status = true
else
@status = false

View File

@ -41,8 +41,6 @@ class MergeRequest < ActiveRecord::Base
delegate :commits, :diffs, :last_commit, :last_commit_short_sha, to: :merge_request_diff, prefix: nil
attr_accessor :should_remove_source_branch
# When this attribute is true some MR validation is ignored
# It allows us to close or modify broken merge requests
attr_accessor :allow_broken
@ -57,7 +55,7 @@ class MergeRequest < ActiveRecord::Base
transition [:reopened, :opened] => :closed
end
event :merge do
event :mark_as_merged do
transition [:reopened, :opened, :locked] => :merged
end
@ -223,14 +221,6 @@ class MergeRequest < ActiveRecord::Base
self.target_project.events.where(target_id: self.id, target_type: "MergeRequest", action: Event::CLOSED).last
end
def automerge!(current_user, commit_message = nil)
return unless automergeable?
MergeRequests::AutoMergeService.
new(target_project, current_user).
execute(self, commit_message)
end
def open?
opened? || reopened?
end
@ -239,11 +229,11 @@ class MergeRequest < ActiveRecord::Base
title =~ /\A\[?WIP\]?:? /i
end
def automergeable?
def mergeable?
open? && !work_in_progress? && can_be_merged?
end
def automerge_status
def gitlab_merge_status
if work_in_progress?
"work_in_progress"
else
@ -445,4 +435,13 @@ class MergeRequest < ActiveRecord::Base
"refs/merge-requests/#{id}/head"
)
end
def in_locked_state
begin
lock_mr
yield
ensure
unlock_mr if locked?
end
end
end

View File

@ -70,6 +70,8 @@ class GitlabCiService < CiService
else
:error
end
rescue Errno::ECONNREFUSED
:error
end
def fork_registration(new_project, private_token)
@ -99,6 +101,8 @@ class GitlabCiService < CiService
if response.code == 200 and response["coverage"]
response["coverage"]
end
rescue Errno::ECONNREFUSED
nil
end
def build_page(sha, ref)

View File

@ -31,6 +31,10 @@ class BaseService
SystemHooksService.new
end
def repository
project.repository
end
# Add an error to the specified model for restricted visibility levels
def deny_visibility_level(model, denied_visibility_level = nil)
denied_visibility_level ||= model.visibility_level

View File

@ -33,15 +33,8 @@ module Files
private
def repository
project.repository
end
def after_commit(sha, branch)
commit = repository.commit(sha)
full_ref = 'refs/heads/' + branch
old_sha = commit.parent_id || Gitlab::Git::BLANK_SHA
GitPushService.new.execute(project, current_user, old_sha, sha, full_ref)
PostCommitService.new(project, current_user).execute(sha, branch)
end
def current_branch

View File

@ -1,62 +0,0 @@
module MergeRequests
# AutoMergeService class
#
# Do git merge and in case of success
# mark merge request as merged and execute all hooks and notifications
# Called when you do merge via GitLab UI
class AutoMergeService < BaseMergeService
attr_reader :merge_request, :commit_message
def execute(merge_request, commit_message)
@commit_message = commit_message
@merge_request = merge_request
merge_request.lock_mr
if merge!
merge_request.merge
create_merge_event(merge_request, current_user)
create_note(merge_request)
notification_service.merge_mr(merge_request, current_user)
execute_hooks(merge_request, 'merge')
true
else
merge_request.unlock_mr
false
end
rescue
merge_request.unlock_mr if merge_request.locked?
merge_request.mark_as_unmergeable
false
end
def merge!
if sha = commit
after_commit(sha, merge_request.target_branch)
end
end
def commit
committer = repository.user_to_comitter(current_user)
options = {
message: commit_message,
author: committer,
committer: committer
}
repository.merge(merge_request.source_sha, merge_request.target_branch, options)
end
def after_commit(sha, branch)
commit = repository.commit(sha)
full_ref = 'refs/heads/' + branch
old_sha = commit.parent_id || Gitlab::Git::BLANK_SHA
GitPushService.new.execute(project, current_user, old_sha, sha, full_ref)
end
def repository
project.repository
end
end
end

View File

@ -1,10 +0,0 @@
module MergeRequests
class BaseMergeService < MergeRequests::BaseService
private
def create_merge_event(merge_request, current_user)
EventCreateService.new.merge_mr(merge_request, current_user)
end
end
end

View File

@ -1,22 +1,57 @@
module MergeRequests
# MergeService class
#
# Mark existing merge request as merged
# and execute all hooks and notifications
# Called when you do merge via command line and push code
# to target branch
class MergeService < BaseMergeService
# Do git merge and in case of success
# mark merge request as merged and execute all hooks and notifications
# Executed when you do merge via GitLab UI
#
class MergeService < MergeRequests::BaseService
attr_reader :merge_request, :commit_message
def execute(merge_request, commit_message)
merge_request.merge
@commit_message = commit_message
@merge_request = merge_request
create_merge_event(merge_request, current_user)
create_note(merge_request)
notification_service.merge_mr(merge_request, current_user)
execute_hooks(merge_request, 'merge')
unless @merge_request.mergeable?
return error('Merge request is not mergeable')
end
true
rescue
false
merge_request.in_locked_state do
if merge_changes
after_merge
success
else
error('Can not merge changes')
end
end
end
private
def merge_changes
if sha = commit
after_commit(sha, merge_request.target_branch)
end
end
def commit
committer = repository.user_to_comitter(current_user)
options = {
message: commit_message,
author: committer,
committer: committer
}
repository.merge(merge_request.source_sha, merge_request.target_branch, options)
end
def after_commit(sha, branch)
PostCommitService.new(project, current_user).execute(sha, branch)
end
def after_merge
MergeRequests::PostMergeService.new(project, current_user).execute(merge_request)
end
end
end

View File

@ -0,0 +1,22 @@
module MergeRequests
# PostMergeService class
#
# Mark existing merge request as merged
# and execute all hooks and notifications
#
class PostMergeService < MergeRequests::BaseService
def execute(merge_request)
merge_request.mark_as_merged
create_merge_event(merge_request, current_user)
create_note(merge_request)
notification_service.merge_mr(merge_request, current_user)
execute_hooks(merge_request, 'merge')
end
private
def create_merge_event(merge_request, current_user)
EventCreateService.new.merge_mr(merge_request, current_user)
end
end
end

View File

@ -33,9 +33,9 @@ module MergeRequests
merge_requests.uniq.select(&:source_project).each do |merge_request|
MergeRequests::MergeService.
MergeRequests::PostMergeService
new(merge_request.target_project, @current_user).
execute(merge_request, nil)
execute(merge_request)
end
end

View File

@ -0,0 +1,8 @@
class PostCommitService < BaseService
def execute(sha, branch)
commit = repository.commit(sha)
full_ref = 'refs/heads/' + branch
old_sha = commit.parent_id || Gitlab::Git::BLANK_SHA
GitPushService.new.execute(project, current_user, old_sha, sha, full_ref)
end
end

View File

@ -11,10 +11,10 @@
var merge_request_widget;
merge_request_widget = new MergeRequestWidget({
url_to_automerge_check: "#{automerge_check_namespace_project_merge_request_path(@project.namespace, @project, @merge_request)}",
url_to_automerge_check: "#{merge_check_namespace_project_merge_request_path(@project.namespace, @project, @merge_request)}",
check_enable: #{@merge_request.unchecked? ? "true" : "false"},
url_to_ci_check: "#{ci_status_namespace_project_merge_request_path(@project.namespace, @project, @merge_request)}",
ci_enable: #{@project.ci_service ? "true" : "false"},
current_status: "#{@merge_request.automerge_status}",
current_status: "#{@merge_request.gitlab_merge_status}",
});

View File

@ -1,4 +1,4 @@
= form_for [:automerge, @project.namespace.becomes(Namespace), @project, @merge_request], remote: true, method: :post, html: { class: 'accept-mr-form js-requires-input' } do |f|
= form_for [:merge, @project.namespace.becomes(Namespace), @project, @merge_request], remote: true, method: :post, html: { class: 'accept-mr-form js-requires-input' } do |f|
= hidden_field_tag :authenticity_token, form_authenticity_token
.accept-merge-holder.clearfix.js-toggle-container
.accept-action

View File

@ -1,13 +0,0 @@
class AutoMergeWorker
include Sidekiq::Worker
sidekiq_options queue: :default
def perform(merge_request_id, current_user_id, params)
params = params.with_indifferent_access
current_user = User.find(current_user_id)
merge_request = MergeRequest.find(merge_request_id)
merge_request.should_remove_source_branch = params[:should_remove_source_branch]
merge_request.automerge!(current_user, params[:commit_message])
end
end

View File

@ -0,0 +1,19 @@
class MergeWorker
include Sidekiq::Worker
sidekiq_options queue: :default
def perform(merge_request_id, current_user_id, params)
params = params.with_indifferent_access
current_user = User.find(current_user_id)
merge_request = MergeRequest.find(merge_request_id)
result = MergeRequests::MergeService.new(merge_request.target_project, current_user).
execute(merge_request, params[:commit_message])
if result[:status] == :success && params[:should_remove_source_branch].present?
DeleteBranchService.new(merge_request.source_project, current_user).
execute(merge_request.source_branch)
end
end
end

View File

@ -458,8 +458,8 @@ Gitlab::Application.routes.draw do
member do
get :diffs
get :commits
post :automerge
get :automerge_check
post :merge
get :merge_check
get :ci_status
post :toggle_subscription
end

View File

@ -198,7 +198,11 @@ module API
if merge_request.open? && !merge_request.work_in_progress?
if merge_request.can_be_merged?
merge_request.automerge!(current_user, params[:merge_commit_message] || merge_request.merge_commit_message)
commit_message = params[:merge_commit_message] || merge_request.merge_commit_message
MergeRequests::MergeService.new(merge_request.target_project, current_user).
execute(merge_request, commit_message)
present merge_request, with: Entities::MergeRequest
else
render_api_error!('Branch cannot be merged', 405)