diff options
Diffstat (limited to 'app/services/merge_requests')
-rw-r--r-- | app/services/merge_requests/approval_service.rb | 56 | ||||
-rw-r--r-- | app/services/merge_requests/base_service.rb | 16 | ||||
-rw-r--r-- | app/services/merge_requests/create_pipeline_service.rb | 20 | ||||
-rw-r--r-- | app/services/merge_requests/create_service.rb | 6 | ||||
-rw-r--r-- | app/services/merge_requests/ff_merge_service.rb | 2 | ||||
-rw-r--r-- | app/services/merge_requests/merge_base_service.rb | 2 | ||||
-rw-r--r-- | app/services/merge_requests/merge_service.rb | 3 | ||||
-rw-r--r-- | app/services/merge_requests/post_merge_service.rb | 1 | ||||
-rw-r--r-- | app/services/merge_requests/remove_approval_service.rb | 43 | ||||
-rw-r--r-- | app/services/merge_requests/squash_service.rb | 7 | ||||
-rw-r--r-- | app/services/merge_requests/update_service.rb | 56 |
11 files changed, 175 insertions, 37 deletions
diff --git a/app/services/merge_requests/approval_service.rb b/app/services/merge_requests/approval_service.rb new file mode 100644 index 00000000000..150ec85fca9 --- /dev/null +++ b/app/services/merge_requests/approval_service.rb @@ -0,0 +1,56 @@ +# frozen_string_literal: true + +module MergeRequests + class ApprovalService < MergeRequests::BaseService + def execute(merge_request) + return unless can_be_approved?(merge_request) + + approval = merge_request.approvals.new(user: current_user) + + return success unless save_approval(approval) + + reset_approvals_cache(merge_request) + create_event(merge_request) + create_approval_note(merge_request) + mark_pending_todos_as_done(merge_request) + execute_approval_hooks(merge_request, current_user) + + success + end + + private + + def can_be_approved?(merge_request) + current_user.can?(:approve_merge_request, merge_request) + end + + def reset_approvals_cache(merge_request) + merge_request.approvals.reset + end + + def execute_approval_hooks(merge_request, current_user) + # Only one approval is required for a merge request to be approved + execute_hooks(merge_request, 'approved') + end + + def save_approval(approval) + Approval.safe_ensure_unique do + approval.save + end + end + + def create_approval_note(merge_request) + SystemNoteService.approve_mr(merge_request, current_user) + end + + def mark_pending_todos_as_done(merge_request) + todo_service.resolve_todos_for_target(merge_request, current_user) + end + + def create_event(merge_request) + event_service.approve_mr(merge_request, current_user) + end + end +end + +MergeRequests::ApprovalService.prepend_if_ee('EE::MergeRequests::ApprovalService') diff --git a/app/services/merge_requests/base_service.rb b/app/services/merge_requests/base_service.rb index 7f7bfa29af7..7e301f311e9 100644 --- a/app/services/merge_requests/base_service.rb +++ b/app/services/merge_requests/base_service.rb @@ -2,6 +2,7 @@ module MergeRequests class BaseService < ::IssuableBaseService + extend ::Gitlab::Utils::Override include MergeRequests::AssignsMergeParams def create_note(merge_request, state = merge_request.state) @@ -29,6 +30,11 @@ module MergeRequests .execute_for_merge_request(merge_request) end + def cancel_review_app_jobs!(merge_request) + environments = merge_request.environments.in_review_folder.available + environments.each { |environment| environment.cancel_deployment_jobs! } + end + def source_project @source_project ||= merge_request.source_project end @@ -58,6 +64,12 @@ module MergeRequests super end + override :handle_quick_actions + def handle_quick_actions(merge_request) + super + handle_wip_event(merge_request) + end + def handle_wip_event(merge_request) if wip_event = params.delete(:wip_event) # We update the title that is provided in the params or we use the mr title @@ -90,10 +102,6 @@ module MergeRequests MergeRequests::CreatePipelineService.new(project, user).execute(merge_request) end - def can_use_merge_request_ref?(merge_request) - !merge_request.for_fork? - end - def abort_auto_merge(merge_request, reason) AutoMergeService.new(project, current_user).abort(merge_request, reason) end diff --git a/app/services/merge_requests/create_pipeline_service.rb b/app/services/merge_requests/create_pipeline_service.rb index f802aa44487..f9352f10fea 100644 --- a/app/services/merge_requests/create_pipeline_service.rb +++ b/app/services/merge_requests/create_pipeline_service.rb @@ -9,7 +9,7 @@ module MergeRequests end def create_detached_merge_request_pipeline(merge_request) - Ci::CreatePipelineService.new(merge_request.source_project, + Ci::CreatePipelineService.new(pipeline_project(merge_request), current_user, ref: pipeline_ref_for_detached_merge_request_pipeline(merge_request)) .execute(:merge_request_event, merge_request: merge_request) @@ -31,13 +31,29 @@ module MergeRequests private + def pipeline_project(merge_request) + if can_create_pipeline_in_target_project?(merge_request) + merge_request.target_project + else + merge_request.source_project + end + end + def pipeline_ref_for_detached_merge_request_pipeline(merge_request) - if can_use_merge_request_ref?(merge_request) + if can_create_pipeline_in_target_project?(merge_request) merge_request.ref_path else merge_request.source_branch end end + + def can_create_pipeline_in_target_project?(merge_request) + if Gitlab::Ci::Features.allow_to_create_merge_request_pipelines_in_target_project?(merge_request.target_project) + can?(current_user, :create_pipeline, merge_request.target_project) + else + merge_request.for_same_project? + end + end end end diff --git a/app/services/merge_requests/create_service.rb b/app/services/merge_requests/create_service.rb index 1cdfba41432..ac84a13f437 100644 --- a/app/services/merge_requests/create_service.rb +++ b/app/services/merge_requests/create_service.rb @@ -33,12 +33,6 @@ module MergeRequests super end - # Override from IssuableBaseService - def handle_quick_actions_on_create(merge_request) - super - handle_wip_event(merge_request) - end - private def set_projects! diff --git a/app/services/merge_requests/ff_merge_service.rb b/app/services/merge_requests/ff_merge_service.rb index 6f1fa607ef9..b3896d61a78 100644 --- a/app/services/merge_requests/ff_merge_service.rb +++ b/app/services/merge_requests/ff_merge_service.rb @@ -16,7 +16,7 @@ module MergeRequests merge_request.target_branch, merge_request: merge_request) - if merge_request.squash + if merge_request.squash_on_merge? merge_request.update_column(:squash_commit_sha, merge_request.in_progress_merge_commit_sha) end diff --git a/app/services/merge_requests/merge_base_service.rb b/app/services/merge_requests/merge_base_service.rb index 27b5e31faab..fe09c92aab9 100644 --- a/app/services/merge_requests/merge_base_service.rb +++ b/app/services/merge_requests/merge_base_service.rb @@ -20,7 +20,7 @@ module MergeRequests def source strong_memoize(:source) do - if merge_request.squash + if merge_request.squash_on_merge? squash_sha! else merge_request.diff_head_sha diff --git a/app/services/merge_requests/merge_service.rb b/app/services/merge_requests/merge_service.rb index 8d57a76f7d0..961a7cb1ef6 100644 --- a/app/services/merge_requests/merge_service.rb +++ b/app/services/merge_requests/merge_service.rb @@ -27,6 +27,7 @@ module MergeRequests success end end + log_info("Merge process finished on JID #{merge_jid} with state #{state}") rescue MergeError => e handle_merge_error(log_message: e.message, save_message_on_model: true) @@ -56,6 +57,8 @@ module MergeRequests 'Only fast-forward merge is allowed for your project. Please update your source branch' elsif !@merge_request.mergeable? 'Merge request is not mergeable' + elsif !@merge_request.squash && project.squash_always? + 'This project requires squashing commits when merge requests are accepted.' end raise_error(error) if error diff --git a/app/services/merge_requests/post_merge_service.rb b/app/services/merge_requests/post_merge_service.rb index 0364c0dd479..fdf8f442297 100644 --- a/app/services/merge_requests/post_merge_service.rb +++ b/app/services/merge_requests/post_merge_service.rb @@ -18,6 +18,7 @@ module MergeRequests invalidate_cache_counts(merge_request, users: merge_request.assignees) merge_request.update_project_counter_caches delete_non_latest_diffs(merge_request) + cancel_review_app_jobs!(merge_request) cleanup_environments(merge_request) end diff --git a/app/services/merge_requests/remove_approval_service.rb b/app/services/merge_requests/remove_approval_service.rb new file mode 100644 index 00000000000..3164d0b4069 --- /dev/null +++ b/app/services/merge_requests/remove_approval_service.rb @@ -0,0 +1,43 @@ +# frozen_string_literal: true + +module MergeRequests + class RemoveApprovalService < MergeRequests::BaseService + # rubocop: disable CodeReuse/ActiveRecord + def execute(merge_request) + return unless merge_request.approved_by?(current_user) + + # paranoid protection against running wrong deletes + return unless merge_request.id && current_user.id + + approval = merge_request.approvals.where(user: current_user) + + trigger_approval_hooks(merge_request) do + next unless approval.destroy_all # rubocop: disable Cop/DestroyAll + + reset_approvals_cache(merge_request) + create_note(merge_request) + end + + success + end + # rubocop: enable CodeReuse/ActiveRecord + + private + + def reset_approvals_cache(merge_request) + merge_request.approvals.reset + end + + def trigger_approval_hooks(merge_request) + yield + + execute_hooks(merge_request, 'unapproved') + end + + def create_note(merge_request) + SystemNoteService.unapprove_mr(merge_request, current_user) + end + end +end + +MergeRequests::RemoveApprovalService.prepend_if_ee('EE::MergeRequests::RemoveApprovalService') diff --git a/app/services/merge_requests/squash_service.rb b/app/services/merge_requests/squash_service.rb index 4b04d42b48e..faa2e921581 100644 --- a/app/services/merge_requests/squash_service.rb +++ b/app/services/merge_requests/squash_service.rb @@ -11,11 +11,14 @@ module MergeRequests return success(squash_sha: merge_request.diff_head_sha) end + return error(s_('MergeRequests|This project does not allow squashing commits when merge requests are accepted.')) if squash_forbidden? + if squash_in_progress? return error(s_('MergeRequests|Squash task canceled: another squash is already in progress.')) end squash! || error(s_('MergeRequests|Failed to squash. Should be done manually.')) + rescue SquashInProgressError error(s_('MergeRequests|An error occurred while checking whether another squash is in progress.')) end @@ -40,6 +43,10 @@ module MergeRequests raise SquashInProgressError, e.message end + def squash_forbidden? + target_project.squash_never? + end + def repository target_project.repository end diff --git a/app/services/merge_requests/update_service.rb b/app/services/merge_requests/update_service.rb index 561695baeab..29e0c22b155 100644 --- a/app/services/merge_requests/update_service.rb +++ b/app/services/merge_requests/update_service.rb @@ -2,6 +2,8 @@ module MergeRequests class UpdateService < MergeRequests::BaseService + extend ::Gitlab::Utils::Override + def execute(merge_request) # We don't allow change of source/target projects and source branch # after merge request was created @@ -9,14 +11,11 @@ module MergeRequests params.delete(:target_project_id) params.delete(:source_branch) - merge_from_quick_action(merge_request) if params[:merge] - if merge_request.closed_without_fork? params.delete(:target_branch) params.delete(:force_remove_source_branch) end - handle_wip_event(merge_request) update_task_event(merge_request) || update(merge_request) end @@ -77,26 +76,6 @@ module MergeRequests todo_service.update_merge_request(merge_request, current_user) end - def merge_from_quick_action(merge_request) - last_diff_sha = params.delete(:merge) - - if Feature.enabled?(:merge_orchestration_service, merge_request.project, default_enabled: true) - MergeRequests::MergeOrchestrationService - .new(project, current_user, { sha: last_diff_sha }) - .execute(merge_request) - else - return unless merge_request.mergeable_with_quick_action?(current_user, last_diff_sha: last_diff_sha) - - merge_request.update(merge_error: nil) - - if merge_request.head_pipeline_active? - AutoMergeService.new(project, current_user, { sha: last_diff_sha }).execute(merge_request, AutoMergeService::STRATEGY_MERGE_WHEN_PIPELINE_SUCCEEDS) - else - merge_request.merge_async(current_user.id, { sha: last_diff_sha }) - end - end - end - def reopen_service MergeRequests::ReopenService end @@ -134,6 +113,37 @@ module MergeRequests issuable, issuable.project, current_user, branch_type, old_branch, new_branch) end + + override :handle_quick_actions + def handle_quick_actions(merge_request) + super + merge_from_quick_action(merge_request) if params[:merge] + end + + def merge_from_quick_action(merge_request) + last_diff_sha = params.delete(:merge) + + if Feature.enabled?(:merge_orchestration_service, merge_request.project, default_enabled: true) + MergeRequests::MergeOrchestrationService + .new(project, current_user, { sha: last_diff_sha }) + .execute(merge_request) + else + return unless merge_request.mergeable_with_quick_action?(current_user, last_diff_sha: last_diff_sha) + + merge_request.update(merge_error: nil) + + if merge_request.head_pipeline_active? + AutoMergeService.new(project, current_user, { sha: last_diff_sha }).execute(merge_request, AutoMergeService::STRATEGY_MERGE_WHEN_PIPELINE_SUCCEEDS) + else + merge_request.merge_async(current_user.id, { sha: last_diff_sha }) + end + end + end + + override :quick_action_options + def quick_action_options + { merge_request_diff_head_sha: params.delete(:merge_request_diff_head_sha) } + end end end |