Commit 8608c632 authored by Zeger-Jan van de Weg's avatar Zeger-Jan van de Weg

Refactor MergeWhenBuildSucceedsService and incorporate feedback

parent 53b285c9
Please view this file on the master branch, on stable branches it's out of date. Please view this file on the master branch, on stable branches it's out of date.
v 8.3.0 (unreleased) v 8.3.0 (unreleased)
- Merge when build succeeds (Zeger-Jan van de Weg)
v 8.2.0 v 8.2.0
- Fix grouping of contributors by email in graph. - Fix grouping of contributors by email in graph.
...@@ -28,10 +29,6 @@ v 8.2.0 ...@@ -28,10 +29,6 @@ v 8.2.0
- Allow to define cache in `.gitlab-ci.yml` - Allow to define cache in `.gitlab-ci.yml`
- Fix: 500 error returned if destroy request without HTTP referer (Kazuki Shimizu) - Fix: 500 error returned if destroy request without HTTP referer (Kazuki Shimizu)
- Remove deprecated CI events from project settings page - Remove deprecated CI events from project settings page
- Use issue editor as cross reference comment author when issue is edited with a new mention.
- Merge when build succeeds (Zeger-Jan van de Weg)
v 8.1.1
- [API] Add ability to fetch the commit ID of the last commit that actually touched a file - [API] Add ability to fetch the commit ID of the last commit that actually touched a file
- Fix omniauth documentation setting for omnibus configuration (Jon Cairns) - Fix omniauth documentation setting for omnibus configuration (Jon Cairns)
- Add "New file" link to dropdown on project page - Add "New file" link to dropdown on project page
......
...@@ -151,14 +151,9 @@ class Projects::MergeRequestsController < Projects::ApplicationController ...@@ -151,14 +151,9 @@ class Projects::MergeRequestsController < Projects::ApplicationController
end end
def cancel_merge_when_build_succeeds def cancel_merge_when_build_succeeds
unless @merge_request.can_be_merged_by?(current_user) || @merge_request.author == current_user return access_denied! unless @merge_request.can_cancel_merge_when_build_succeeds?(current_user)
return access_denied!
end
if @merge_request.merge_when_build_succeeds? MergeRequests::MergeWhenBuildSucceedsService.new(@project, current_user).cancel(@merge_request)
@merge_request.reset_merge_when_build_succeeds
SystemNoteService.cancel_merge_when_build_succeeds(merge_request, @project, @current_user)
end
end end
def merge def merge
...@@ -171,7 +166,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController ...@@ -171,7 +166,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController
@merge_request.update(merge_error: nil) @merge_request.update(merge_error: nil)
if params[:merge_when_build_succeeds] && @merge_request.ci_commit.active? if params[:merge_when_build_succeeds] && @merge_request.ci_commit && @merge_request.ci_commit.active?
MergeRequests::MergeWhenBuildSucceedsService.new(@project, current_user, merge_params) MergeRequests::MergeWhenBuildSucceedsService.new(@project, current_user, merge_params)
.execute(@merge_request) .execute(@merge_request)
@status = :merge_when_build_succeeds @status = :merge_when_build_succeeds
......
...@@ -254,8 +254,15 @@ class MergeRequest < ActiveRecord::Base ...@@ -254,8 +254,15 @@ class MergeRequest < ActiveRecord::Base
end end
end end
def mergeable_by_or_author(user) def can_cancel_merge_when_build_succeeds?(user)
self.can_be_merged_by?(user) || self.author == user can_be_merged_by?(user) || self.author == user
end
def can_remove_source_branch?
for_fork? &&
!project.protected_branch(source_branch) &&
!project.repository.root_ref(source_branch) &&
can?(current_user, :push_code, project)
end end
def mr_and_commit_notes def mr_and_commit_notes
......
module MergeRequests module MergeRequests
class MergeWhenBuildSucceedsService < MergeRequests::BaseService class MergeWhenBuildSucceedsService < MergeRequests::BaseService
# Marks the passed `merge_request` to be marked when the build succeeds or
# updates the params for the automatic merge
def execute(merge_request) def execute(merge_request)
merge_request.merge_params.merge!(params) merge_request.merge_params.merge!(params)
...@@ -14,10 +16,11 @@ module MergeRequests ...@@ -14,10 +16,11 @@ module MergeRequests
merge_request.save merge_request.save
unless already_approved unless already_approved
SystemNoteService.merge_when_build_succeeds(merge_request, @project, @current_user) SystemNoteService.merge_when_build_succeeds(merge_request, @project, @current_user, merge_request.ci_commit)
end end
end end
# Triggers the automatic merge of merge_request once the build succeeds
def trigger(build) def trigger(build)
merge_requests = merge_request_from(build) merge_requests = merge_request_from(build)
...@@ -31,6 +34,18 @@ module MergeRequests ...@@ -31,6 +34,18 @@ module MergeRequests
end end
end end
# Cancels the automatic merge
def cancel(merge_request)
if merge_request.merge_when_build_succeeds? && merge_request.open? && !merge_request.merged?
merge_request.reset_merge_when_build_succeeds
SystemNoteService.cancel_merge_when_build_succeeds(merge_request, @project, @current_user)
success
else
error("Can't cancel the automatic merge", 406)
end
end
private private
def merge_request_from(build) def merge_request_from(build)
......
...@@ -131,8 +131,8 @@ class SystemNoteService ...@@ -131,8 +131,8 @@ class SystemNoteService
end end
# Called when 'merge when build succeeds' is executed # Called when 'merge when build succeeds' is executed
def self.merge_when_build_succeeds(noteable, project, author) def self.merge_when_build_succeeds(noteable, project, author, ci_commit)
body = "This merge request will be automatically merged when the build for #{noteable.ci_commit.short_sha} succeeds" body = "Approved an automatic merge when the build for #{ci_commit.sha} succeeds"
create_note(noteable: noteable, project: project, author: author, note: body) create_note(noteable: noteable, project: project, author: author, note: body)
end end
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
- else - else
= f.button class: "btn btn-create btn-grouped accept_merge_request #{status_class}" do = f.button class: "btn btn-create btn-grouped accept_merge_request #{status_class}" do
Accept Merge Request Accept Merge Request
- if can_remove_branch?(@merge_request.source_project, @merge_request.source_branch) && !@merge_request.for_fork? - if @merge_request.can_remove_source_branch?
.accept-control.checkbox .accept-control.checkbox
= label_tag :should_remove_source_branch, class: "remove_source_checkbox" do = label_tag :should_remove_source_branch, class: "remove_source_checkbox" do
= check_box_tag :should_remove_source_branch = check_box_tag :should_remove_source_branch
......
...@@ -8,20 +8,17 @@ ...@@ -8,20 +8,17 @@
The changes will be merged into The changes will be merged into
%span.label-branch= @merge_request.target_branch %span.label-branch= @merge_request.target_branch
The source branch will be removed. The source branch will be removed.
- elsif can_remove_branch?(@merge_request.source_project, @merge_request.source_branch)
- remove_source_branch_button = true
%p %p
= succeed '.' do = succeed '.' do
The changes will be merged into The changes will be merged into
%span.label-branch= @merge_request.target_branch %span.label-branch= @merge_request.target_branch
The source branch won't be removed. The source branch will not be removed.
- if remove_source_branch_button || @merge_request.can_be_merged_by?(current_user)
.clearfix.prepend-top-10 .clearfix.prepend-top-10
- if remove_source_branch_button - if @merge_request.can_remove_source_branch? && !@merge_request.merge_params["should_remove_source_branch"].present?
= link_to merge_namespace_project_merge_request_path(@merge_request.target_project.namespace, @merge_request.target_project, @merge_request, merge_when_build_succeeds: true, should_remove_source_branch: true), remote: true, method: :post, class: "btn btn-grouped btn-primary btn-sm remove_source_branch" do = link_to merge_namespace_project_merge_request_path(@merge_request.target_project.namespace, @merge_request.target_project, @merge_request, merge_when_build_succeeds: true, should_remove_source_branch: true), remote: true, method: :post, class: "btn btn-grouped btn-primary btn-sm remove_source_branch" do
= icon('times') = icon('times')
Remove Source Branch When Merged Remove Source Branch When Merged
- if @merge_request.can_be_merged_by?(current_user) || @merge_request.author == current_user - if @merge_request.merge_when_build_succeeds
= link_to cancel_merge_when_build_succeeds_namespace_project_merge_request_path(@merge_request.target_project.namespace, @merge_request.target_project, @merge_request), remote: true, method: :post, class: "btn btn-grouped btn-warning btn-sm" do = link_to cancel_merge_when_build_succeeds_namespace_project_merge_request_path(@merge_request.target_project.namespace, @merge_request.target_project, @merge_request), remote: true, method: :post, class: "btn btn-grouped btn-warning btn-sm" do
Cancel Automatic Merge Cancel Automatic Merge
...@@ -570,6 +570,7 @@ Gitlab::Application.routes.draw do ...@@ -570,6 +570,7 @@ Gitlab::Application.routes.draw do
member do member do
get :diffs get :diffs
get :commits get :commits
get :merge_check
post :merge post :merge
post :cancel_merge_when_build_succeeds post :cancel_merge_when_build_succeeds
get :ci_status get :ci_status
......
...@@ -421,7 +421,6 @@ ActiveRecord::Schema.define(version: 20151116144118) do ...@@ -421,7 +421,6 @@ ActiveRecord::Schema.define(version: 20151116144118) do
end end
add_index "labels", ["project_id"], name: "index_labels_on_project_id", using: :btree add_index "labels", ["project_id"], name: "index_labels_on_project_id", using: :btree
add_index "labels", ["title"], name: "index_labels_on_title", using: :btree
create_table "lfs_objects", force: true do |t| create_table "lfs_objects", force: true do |t|
t.string "oid", null: false t.string "oid", null: false
...@@ -525,7 +524,6 @@ ActiveRecord::Schema.define(version: 20151116144118) do ...@@ -525,7 +524,6 @@ ActiveRecord::Schema.define(version: 20151116144118) do
add_index "milestones", ["due_date"], name: "index_milestones_on_due_date", using: :btree add_index "milestones", ["due_date"], name: "index_milestones_on_due_date", using: :btree
add_index "milestones", ["project_id", "iid"], name: "index_milestones_on_project_id_and_iid", unique: true, using: :btree add_index "milestones", ["project_id", "iid"], name: "index_milestones_on_project_id_and_iid", unique: true, using: :btree
add_index "milestones", ["project_id"], name: "index_milestones_on_project_id", using: :btree add_index "milestones", ["project_id"], name: "index_milestones_on_project_id", using: :btree
add_index "milestones", ["title"], name: "index_milestones_on_title", using: :btree
create_table "namespaces", force: true do |t| create_table "namespaces", force: true do |t|
t.string "name", null: false t.string "name", null: false
......
...@@ -296,7 +296,7 @@ Parameters: ...@@ -296,7 +296,7 @@ Parameters:
- `merge_request_id` (required) - ID of MR - `merge_request_id` (required) - ID of MR
- `merge_commit_message` (optional) - Custom merge commit message - `merge_commit_message` (optional) - Custom merge commit message
- `should_remove_source_branch` (optional) - if `true` removes the source branch - `should_remove_source_branch` (optional) - if `true` removes the source branch
- `merge_when_build_succeeds` (optional) - if `true` the MR is merge when the build succeeds - `merged_when_build_succeeds` (optional) - if `true` the MR is merge when the build succeeds
```json ```json
{ {
...@@ -329,15 +329,13 @@ Parameters: ...@@ -329,15 +329,13 @@ Parameters:
## Cancel Merge When Build Succeeds ## Cancel Merge When Build Succeeds
Cancels the merge when build succeeds and reset the merge parameters If successful you'll get `200 OK`.
If successfull you'll get `200 OK`.
If you don't have permissions to accept this merge request - you'll get a 401 If you don't have permissions to accept this merge request - you'll get a 401
If the merge request is already merged or closed - you get 405 and error message 'Method Not Allowed' If the merge request is already merged or closed - you get 405 and error message 'Method Not Allowed'
In case the merge request is not set to be merged when the build succeeds, you'll also get a 405 with the error message 'Method Not Allowed' In case the merge request is not set to be merged when the build succeeds, you'll also get a 406 error.
``` ```
PUT /projects/:id/merge_request/:merge_request_id/cancel_merge_when_build_succeeds PUT /projects/:id/merge_request/:merge_request_id/cancel_merge_when_build_succeeds
``` ```
......
...@@ -182,39 +182,35 @@ module API ...@@ -182,39 +182,35 @@ module API
# id (required) - The ID of a project # id (required) - The ID of a project
# merge_request_id (required) - ID of MR # merge_request_id (required) - ID of MR
# merge_commit_message (optional) - Custom merge commit message # merge_commit_message (optional) - Custom merge commit message
# merge_when_build_succeeds (optional) - truethy when this MR should be merged when the build is succesfull # should_remove_source_branch - When true, the source branch will be deleted if possible
# merge_when_build_succeeds (optional) - When true, this MR will be merged when the build succeeds
# Example: # Example:
# PUT /projects/:id/merge_request/:merge_request_id/merge # PUT /projects/:id/merge_request/:merge_request_id/merge
# #
put ":id/merge_request/:merge_request_id/merge" do put ":id/merge_request/:merge_request_id/merge" do
merge_request = user_project.merge_requests.find(params[:merge_request_id]) merge_request = user_project.merge_requests.find(params[:merge_request_id])
allowed = ::Gitlab::GitAccess.new(current_user, user_project).
can_push_to_branch?(merge_request.target_branch)
# Merge request can not be merged # Merge request can not be merged
# because user dont have permissions to push into target branch # because user dont have permissions to push into target branch
unauthorized! unless allowed unauthorized! unless merge_request.can_be_merged_by?(current_user)
not_allowed! unless merge_request.open? not_allowed! unless merge_request.open? && !merge_request.work_in_progress?
merge_request.check_if_can_be_merged if merge_request.unchecked? merge_request.check_if_can_be_merged if merge_request.unchecked?
render_api_error!('Branch cannot be merged', 406) if merge_request.can_be_merged?
merge_params = { merge_params = {
commit_message: params[:merge_commit_message], commit_message: params[:merge_commit_message],
should_remove_source_branch: params[:should_remove_source_branch] should_remove_source_branch: params[:should_remove_source_branch]
} }
if !merge_request.work_in_progress? if parse_boolean(params[:merge_when_build_succeeds]) && merge_request.ci_commit && merge_request.ci_commit.active?
if parse_boolean(params[:merge_when_build_succeeds]) ::MergeRequest::MergeWhenBuildSucceedsService.new(merge_request.target_project, current_user, merge_params).
::MergeRequest::MergeWhenBuildSucceedsService.new(merge_request.target_project, current_user, merge_params). execute(merge_request)
execute(merge_request)
else
::MergeRequests::MergeService.new(merge_request.target_project, current_user, merge_params).
execute(merge_request, merge_params)
end
else else
render_api_error!('Branch cannot be merged', 405) ::MergeRequests::MergeService.new(merge_request.target_project, current_user, merge_params).
execute(merge_request)
end end
present merge_request, with: Entities::MergeRequest present merge_request, with: Entities::MergeRequest
...@@ -233,15 +229,9 @@ module API ...@@ -233,15 +229,9 @@ module API
# Merge request can not be merged # Merge request can not be merged
# because user dont have permissions to push into target branch # because user dont have permissions to push into target branch
unauthorized! unless allowed unauthorized! unless merge_request.can_cancel_merge_when_build_succeeds?(current_user)
if merge_request.merged? || !merge_request.open? || !merge_request.merge_when_build_succeeds? ::MergeRequest::MergeWhenBuildSucceedsService.new(merge_request.target_project, current_user).cancel(merge_request)
not_allowed!
end
merge_request.reset_merge_when_build_succeeds
present merge_request, with: Entities::MergeRequest
end end
# Get a merge request's comments # Get a merge request's comments
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment