diff options
author | Oswaldo Ferreira <oswaldo@gitlab.com> | 2019-06-11 13:08:25 -0300 |
---|---|---|
committer | Oswaldo Ferreira <oswaldo@gitlab.com> | 2019-06-11 13:08:25 -0300 |
commit | 00a273d3a90975d22f39b142fdb85c06779d7b63 (patch) | |
tree | 0ae0468745947a5019044052d1a1a3887bd64767 | |
parent | 74850f1f8e17d3e1e6ee21a1d1daadc6ceeeb2b4 (diff) | |
download | gitlab-ce-00a273d3a90975d22f39b142fdb85c06779d7b63.tar.gz |
Revert "Automatically update MR merge-ref along merge status"
-rw-r--r-- | app/controllers/projects/merge_requests_controller.rb | 6 | ||||
-rw-r--r-- | app/models/merge_request.rb | 36 | ||||
-rw-r--r-- | app/services/merge_requests/merge_to_ref_service.rb | 20 | ||||
-rw-r--r-- | app/services/merge_requests/mergeability_check_service.rb | 82 | ||||
-rw-r--r-- | app/services/service_response.rb | 15 | ||||
-rw-r--r-- | changelogs/unreleased/osw-sync-merge-ref-upon-mergeability-check.yml | 5 | ||||
-rw-r--r-- | doc/api/merge_requests.md | 22 | ||||
-rw-r--r-- | lib/api/entities.rb | 2 | ||||
-rw-r--r-- | lib/api/merge_requests.rb | 24 | ||||
-rw-r--r-- | spec/models/merge_request_spec.rb | 87 | ||||
-rw-r--r-- | spec/requests/api/merge_requests_spec.rb | 61 | ||||
-rw-r--r-- | spec/services/merge_requests/merge_to_ref_service_spec.rb | 41 | ||||
-rw-r--r-- | spec/services/merge_requests/mergeability_check_service_spec.rb | 187 | ||||
-rw-r--r-- | spec/services/service_response_spec.rb | 16 |
14 files changed, 223 insertions, 381 deletions
diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb index 135117926be..a3ceb76845e 100644 --- a/app/controllers/projects/merge_requests_controller.rb +++ b/app/controllers/projects/merge_requests_controller.rb @@ -33,7 +33,7 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo def show close_merge_request_if_no_source_project - @merge_request.check_mergeability + mark_merge_request_mergeable respond_to do |format| format.html do @@ -251,6 +251,10 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo @merge_request.has_no_commits? && !@merge_request.target_branch_exists? end + def mark_merge_request_mergeable + @merge_request.check_if_can_be_merged + end + def merge! # Disable the CI check if auto_merge_strategy is specified since we have # to wait until CI completes to know diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index 4fcaac75655..7481f1939ad 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -725,16 +725,19 @@ class MergeRequest < ApplicationRecord MergeRequests::ReloadDiffsService.new(self, current_user).execute end - - def check_mergeability - MergeRequests::MergeabilityCheckService.new(self).execute - end # rubocop: enable CodeReuse/ServiceClass - # Returns boolean indicating the merge_status should be rechecked in order to - # switch to either can_be_merged or cannot_be_merged. - def recheck_merge_status? - self.class.state_machines[:merge_status].check_state?(merge_status) + def check_if_can_be_merged + return unless self.class.state_machines[:merge_status].check_state?(merge_status) && Gitlab::Database.read_write? + + can_be_merged = + !broken? && project.repository.can_be_merged?(diff_head_sha, target_branch) + + if can_be_merged + mark_as_mergeable + else + mark_as_unmergeable + end end def merge_event @@ -760,7 +763,7 @@ class MergeRequest < ApplicationRecord def mergeable?(skip_ci_check: false) return false unless mergeable_state?(skip_ci_check: skip_ci_check) - check_mergeability + check_if_can_be_merged can_be_merged? && !should_be_rebased? end @@ -775,6 +778,15 @@ class MergeRequest < ApplicationRecord true end + def mergeable_to_ref? + return false unless mergeable_state?(skip_ci_check: true, skip_discussions_check: true) + + # Given the `merge_ref_path` will have the same + # state the `target_branch` would have. Ideally + # we need to check if it can be merged to it. + project.repository.can_be_merged?(diff_head_sha, target_branch) + end + def ff_merge_possible? project.repository.ancestor?(target_branch_sha, diff_head_sha) end @@ -1087,12 +1099,6 @@ class MergeRequest < ApplicationRecord target_project.repository.fetch_source_branch!(source_project.repository, source_branch, ref_path) end - # Returns the current merge-ref HEAD commit. - # - def merge_ref_head - project.repository.commit(merge_ref_path) - end - def ref_path "refs/#{Repository::REF_MERGE_REQUEST}/#{iid}/head" end diff --git a/app/services/merge_requests/merge_to_ref_service.rb b/app/services/merge_requests/merge_to_ref_service.rb index 8670b9ccf3d..87147d90c32 100644 --- a/app/services/merge_requests/merge_to_ref_service.rb +++ b/app/services/merge_requests/merge_to_ref_service.rb @@ -20,14 +20,20 @@ module MergeRequests raise_error('Conflicts detected during merge') unless commit_id - success(commit_id: commit_id) - rescue MergeError, ArgumentError => error + commit = project.commit(commit_id) + target_id, source_id = commit.parent_ids + + success(commit_id: commit.id, + target_id: target_id, + source_id: source_id) + rescue MergeError => error error(error.message) end private def validate! + authorization_check! error_check! end @@ -37,13 +43,21 @@ module MergeRequests error = if !hooks_validation_pass?(merge_request) hooks_validation_error(merge_request) - elsif source.blank? + elsif !@merge_request.mergeable_to_ref? + "Merge request is not mergeable to #{target_ref}" + elsif !source 'No source for merge' end raise_error(error) if error end + def authorization_check! + unless Ability.allowed?(current_user, :admin_merge_request, project) + raise_error("You are not allowed to merge to this ref") + end + end + def target_ref merge_request.merge_ref_path end diff --git a/app/services/merge_requests/mergeability_check_service.rb b/app/services/merge_requests/mergeability_check_service.rb deleted file mode 100644 index ef833774e65..00000000000 --- a/app/services/merge_requests/mergeability_check_service.rb +++ /dev/null @@ -1,82 +0,0 @@ -# frozen_string_literal: true - -module MergeRequests - class MergeabilityCheckService < ::BaseService - include Gitlab::Utils::StrongMemoize - - delegate :project, to: :@merge_request - delegate :repository, to: :project - - def initialize(merge_request) - @merge_request = merge_request - end - - # Updates the MR merge_status. Whenever it switches to a can_be_merged state, - # the merge-ref is refreshed. - # - # Returns a ServiceResponse indicating merge_status is/became can_be_merged - # and the merge-ref is synced. Success in case of being/becoming mergeable, - # error otherwise. - def execute - return ServiceResponse.error(message: 'Invalid argument') unless merge_request - return ServiceResponse.error(message: 'Unsupported operation') if Gitlab::Database.read_only? - - update_merge_status - - unless merge_request.can_be_merged? - return ServiceResponse.error(message: 'Merge request is not mergeable') - end - - unless payload.fetch(:merge_ref_head) - return ServiceResponse.error(message: 'Merge ref was not found') - end - - ServiceResponse.success(payload: payload) - end - - private - - attr_reader :merge_request - - def payload - strong_memoize(:payload) do - { - merge_ref_head: merge_ref_head_payload - } - end - end - - def merge_ref_head_payload - commit = merge_request.merge_ref_head - - return unless commit - - target_id, source_id = commit.parent_ids - - { - commit_id: commit.id, - source_id: source_id, - target_id: target_id - } - end - - def update_merge_status - return unless merge_request.recheck_merge_status? - - if can_git_merge? - merge_to_ref && merge_request.mark_as_mergeable - else - merge_request.mark_as_unmergeable - end - end - - def can_git_merge? - !merge_request.broken? && repository.can_be_merged?(merge_request.diff_head_sha, merge_request.target_branch) - end - - def merge_to_ref - result = MergeRequests::MergeToRefService.new(project, merge_request.author).execute(merge_request) - result[:status] == :success - end - end -end diff --git a/app/services/service_response.rb b/app/services/service_response.rb index f3437ba16de..1de30e68d87 100644 --- a/app/services/service_response.rb +++ b/app/services/service_response.rb @@ -1,20 +1,19 @@ # frozen_string_literal: true class ServiceResponse - def self.success(message: nil, payload: {}) - new(status: :success, message: message, payload: payload) + def self.success(message: nil) + new(status: :success, message: message) end - def self.error(message:, payload: {}, http_status: nil) - new(status: :error, message: message, payload: payload, http_status: http_status) + def self.error(message:, http_status: nil) + new(status: :error, message: message, http_status: http_status) end - attr_reader :status, :message, :http_status, :payload + attr_reader :status, :message, :http_status - def initialize(status:, message: nil, payload: {}, http_status: nil) + def initialize(status:, message: nil, http_status: nil) self.status = status self.message = message - self.payload = payload self.http_status = http_status end @@ -28,5 +27,5 @@ class ServiceResponse private - attr_writer :status, :message, :http_status, :payload + attr_writer :status, :message, :http_status end diff --git a/changelogs/unreleased/osw-sync-merge-ref-upon-mergeability-check.yml b/changelogs/unreleased/osw-sync-merge-ref-upon-mergeability-check.yml deleted file mode 100644 index 1f40089adb8..00000000000 --- a/changelogs/unreleased/osw-sync-merge-ref-upon-mergeability-check.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Sync merge ref upon mergeability check -merge_request: 28513 -author: -type: added diff --git a/doc/api/merge_requests.md b/doc/api/merge_requests.md index 96a956ad03a..dd7810c3403 100644 --- a/doc/api/merge_requests.md +++ b/doc/api/merge_requests.md @@ -1191,29 +1191,33 @@ Parameters: } ``` -## Returns the up to date merge-ref HEAD commit +## Merge to default merge ref path -Merge the changes between the merge request source and target branches into `refs/merge-requests/:iid/merge` -ref, of the target project repository, if possible. This ref will have the state the target branch would have if +Merge the changes between the merge request source and target branches into `refs/merge-requests/:iid/merge` +ref, of the target project repository. This ref will have the state the target branch would have if a regular merge action was taken. -This is not a regular merge action given it doesn't change the merge request target branch state in any manner. +This is not a regular merge action given it doesn't change the merge request state in any manner. -This ref (`refs/merge-requests/:iid/merge`) isn't necessarily overwritten when submitting -requests to this API, though it'll make sure the ref has the latest possible state. +This ref (`refs/merge-requests/:iid/merge`) is **always** overwritten when submitting +requests to this API, so none of its state is kept or used in the process. -If the merge request has conflicts, is empty or already merged, you'll get a `400` and a descriptive error message. +If the merge request has conflicts, is empty or already merged, +you'll get a `400` and a descriptive error message. If you don't have permissions to do so, +you'll get a `403`. -It returns the HEAD commit of `refs/merge-requests/:iid/merge` in the response body in case of `200`. +It returns the HEAD commit of `refs/merge-requests/:iid/merge` in the response body in +case of `200`. ``` -GET /projects/:id/merge_requests/:merge_request_iid/merge_ref +PUT /projects/:id/merge_requests/:merge_request_iid/merge_to_ref ``` Parameters: - `id` (required) - The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user - `merge_request_iid` (required) - Internal ID of MR +- `merge_commit_message` (optional) - Custom merge commit message ```json { diff --git a/lib/api/entities.rb b/lib/api/entities.rb index f8b950cb55d..880b07d0a84 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -701,7 +701,7 @@ module API # See https://gitlab.com/gitlab-org/gitlab-ce/issues/42344 for more # information. expose :merge_status do |merge_request| - merge_request.check_mergeability + merge_request.check_if_can_be_merged merge_request.merge_status end expose :diff_head_sha, as: :sha diff --git a/lib/api/merge_requests.rb b/lib/api/merge_requests.rb index 5bbf6df78b0..955624404f1 100644 --- a/lib/api/merge_requests.rb +++ b/lib/api/merge_requests.rb @@ -397,16 +397,28 @@ module API present merge_request, with: Entities::MergeRequest, current_user: current_user, project: user_project end - desc 'Returns the up to date merge-ref HEAD commit' - get ':id/merge_requests/:merge_request_iid/merge_ref' do + desc 'Merge a merge request to its default temporary merge ref path' + params do + optional :merge_commit_message, type: String, desc: 'Custom merge commit message' + end + put ':id/merge_requests/:merge_request_iid/merge_to_ref' do merge_request = find_project_merge_request(params[:merge_request_iid]) - result = ::MergeRequests::MergeabilityCheckService.new(merge_request).execute + authorize! :admin_merge_request, user_project + + merge_params = { + commit_message: params[:merge_commit_message] + } + + result = ::MergeRequests::MergeToRefService + .new(merge_request.target_project, current_user, merge_params) + .execute(merge_request) - if result.success? - present :commit_id, result.payload.dig(:merge_ref_head, :commit_id) + if result[:status] == :success + present result.slice(:commit_id), 200 else - render_api_error!(result.message, 400) + http_status = result[:http_status] || 400 + render_api_error!(result[:message], http_status) end end diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb index fc28c216b21..c6251326c22 100644 --- a/spec/models/merge_request_spec.rb +++ b/spec/models/merge_request_spec.rb @@ -1996,6 +1996,57 @@ describe MergeRequest do end end + describe '#check_if_can_be_merged' do + let(:project) { create(:project, only_allow_merge_if_pipeline_succeeds: true) } + + shared_examples 'checking if can be merged' do + context 'when it is not broken and has no conflicts' do + before do + allow(subject).to receive(:broken?) { false } + allow(project.repository).to receive(:can_be_merged?).and_return(true) + end + + it 'is marked as mergeable' do + expect { subject.check_if_can_be_merged }.to change { subject.merge_status }.to('can_be_merged') + end + end + + context 'when broken' do + before do + allow(subject).to receive(:broken?) { true } + allow(project.repository).to receive(:can_be_merged?).and_return(false) + end + + it 'becomes unmergeable' do + expect { subject.check_if_can_be_merged }.to change { subject.merge_status }.to('cannot_be_merged') + end + end + + context 'when it has conflicts' do + before do + allow(subject).to receive(:broken?) { false } + allow(project.repository).to receive(:can_be_merged?).and_return(false) + end + + it 'becomes unmergeable' do + expect { subject.check_if_can_be_merged }.to change { subject.merge_status }.to('cannot_be_merged') + end + end + end + + context 'when merge_status is unchecked' do + subject { create(:merge_request, source_project: project, merge_status: :unchecked) } + + it_behaves_like 'checking if can be merged' + end + + context 'when merge_status is unchecked' do + subject { create(:merge_request, source_project: project, merge_status: :cannot_be_merged_recheck) } + + it_behaves_like 'checking if can be merged' + end + end + describe '#mergeable?' do let(:project) { create(:project) } @@ -2009,7 +2060,7 @@ describe MergeRequest do it 'return true if #mergeable_state? is true and the MR #can_be_merged? is true' do allow(subject).to receive(:mergeable_state?) { true } - expect(subject).to receive(:check_mergeability) + expect(subject).to receive(:check_if_can_be_merged) expect(subject).to receive(:can_be_merged?) { true } expect(subject.mergeable?).to be_truthy @@ -2023,7 +2074,7 @@ describe MergeRequest do it 'checks if merge request can be merged' do allow(subject).to receive(:mergeable_ci_state?) { true } - expect(subject).to receive(:check_mergeability) + expect(subject).to receive(:check_if_can_be_merged) subject.mergeable? end @@ -3091,6 +3142,38 @@ describe MergeRequest do end end + describe '#mergeable_to_ref?' do + it 'returns true when merge request is mergeable' do + subject = create(:merge_request) + + expect(subject.mergeable_to_ref?).to be(true) + end + + it 'returns false when merge request is already merged' do + subject = create(:merge_request, :merged) + + expect(subject.mergeable_to_ref?).to be(false) + end + + it 'returns false when merge request is closed' do + subject = create(:merge_request, :closed) + + expect(subject.mergeable_to_ref?).to be(false) + end + + it 'returns false when merge request is work in progress' do + subject = create(:merge_request, title: 'WIP: The feature') + + expect(subject.mergeable_to_ref?).to be(false) + end + + it 'returns false when merge request has no commits' do + subject = create(:merge_request, source_branch: 'empty-branch', target_branch: 'master') + + expect(subject.mergeable_to_ref?).to be(false) + end + end + describe '#merge_participants' do it 'contains author' do expect(subject.merge_participants).to eq([subject.author]) diff --git a/spec/requests/api/merge_requests_spec.rb b/spec/requests/api/merge_requests_spec.rb index 4cb4fcc890d..9f9180bc8c9 100644 --- a/spec/requests/api/merge_requests_spec.rb +++ b/spec/requests/api/merge_requests_spec.rb @@ -1546,65 +1546,52 @@ describe API::MergeRequests do end end - describe "GET /projects/:id/merge_requests/:merge_request_iid/merge_ref" do - before do - merge_request.mark_as_unchecked! - end - - let(:merge_request_iid) { merge_request.iid } - + describe "PUT /projects/:id/merge_requests/:merge_request_iid/merge_to_ref" do + let(:pipeline) { create(:ci_pipeline_without_jobs) } let(:url) do - "/projects/#{project.id}/merge_requests/#{merge_request_iid}/merge_ref" + "/projects/#{project.id}/merge_requests/#{merge_request.iid}/merge_to_ref" end it 'returns the generated ID from the merge service in case of success' do - get api(url, user) + put api(url, user), params: { merge_commit_message: 'Custom message' } + + commit = project.commit(json_response['commit_id']) expect(response).to have_gitlab_http_status(200) - expect(json_response['commit_id']).to eq(merge_request.merge_ref_head.sha) + expect(json_response['commit_id']).to be_present + expect(commit.message).to eq('Custom message') end it "returns 400 if branch can't be merged" do - merge_request.update!(merge_status: 'cannot_be_merged') + merge_request.update!(state: 'merged') - get api(url, user) + put api(url, user) expect(response).to have_gitlab_http_status(400) - expect(json_response['message']).to eq('Merge request is not mergeable') + expect(json_response['message']) + .to eq("Merge request is not mergeable to #{merge_request.merge_ref_path}") end - context 'when user has no access to the MR' do - let(:project) { create(:project, :private) } - let(:merge_request) { create(:merge_request, source_project: project, target_project: project) } - - it 'returns 404' do - project.add_guest(user) + it 'returns 403 if user has no permissions to merge to the ref' do + user2 = create(:user) + project.add_reporter(user2) - get api(url, user) + put api(url, user2) - expect(response).to have_gitlab_http_status(404) - expect(json_response['message']).to eq('404 Not found') - end + expect(response).to have_gitlab_http_status(403) + expect(json_response['message']).to eq('403 Forbidden') end - context 'when invalid merge request IID' do - let(:merge_request_iid) { '12345' } - - it 'returns 404' do - get api(url, user) + it 'returns 404 for an invalid merge request IID' do + put api("/projects/#{project.id}/merge_requests/12345/merge_to_ref", user) - expect(response).to have_gitlab_http_status(404) - end + expect(response).to have_gitlab_http_status(404) end - context 'when merge request ID is used instead IID' do - let(:merge_request_iid) { merge_request.id } - - it 'returns 404' do - get api(url, user) + it "returns 404 if the merge request id is used instead of iid" do + put api("/projects/#{project.id}/merge_requests/#{merge_request.id}/merge", user) - expect(response).to have_gitlab_http_status(404) - end + expect(response).to have_gitlab_http_status(404) end end diff --git a/spec/services/merge_requests/merge_to_ref_service_spec.rb b/spec/services/merge_requests/merge_to_ref_service_spec.rb index 5d492e4b013..0ac23050caf 100644 --- a/spec/services/merge_requests/merge_to_ref_service_spec.rb +++ b/spec/services/merge_requests/merge_to_ref_service_spec.rb @@ -32,8 +32,10 @@ describe MergeRequests::MergeToRefService do expect(result[:status]).to eq(:success) expect(result[:commit_id]).to be_present + expect(result[:source_id]).to eq(merge_request.source_branch_sha) + expect(result[:target_id]).to eq(merge_request.target_branch_sha) expect(repository.ref_exists?(target_ref)).to be(true) - expect(ref_head.sha).to eq(result[:commit_id]) + expect(ref_head.id).to eq(result[:commit_id]) end end @@ -70,6 +72,10 @@ describe MergeRequests::MergeToRefService do let(:merge_request) { create(:merge_request, :simple) } let(:project) { merge_request.project } + before do + project.add_maintainer(user) + end + describe '#execute' do let(:service) do described_class.new(project, user, commit_message: 'Awesome message', @@ -86,12 +92,6 @@ describe MergeRequests::MergeToRefService do it_behaves_like 'successfully evaluates pre-condition checks' context 'commit history comparison with regular MergeService' do - before do - # The merge service needs an authorized user while merge-to-ref - # doesn't. - project.add_maintainer(user) - end - let(:merge_ref_service) do described_class.new(project, user, {}) end @@ -136,9 +136,9 @@ describe MergeRequests::MergeToRefService do let(:merge_method) { :merge } it 'returns error' do - allow(project).to receive_message_chain(:repository, :merge_to_ref) { nil } + allow(merge_request).to receive(:mergeable_to_ref?) { false } - error_message = 'Conflicts detected during merge' + error_message = "Merge request is not mergeable to #{merge_request.merge_ref_path}" result = service.execute(merge_request) @@ -170,5 +170,28 @@ describe MergeRequests::MergeToRefService do it { expect(todo).not_to be_done } end + + context 'when merge request is WIP state' do + it 'fails to merge' do + merge_request = create(:merge_request, title: 'WIP: The feature') + + result = service.execute(merge_request) + + expect(result[:status]).to eq(:error) + expect(result[:message]).to eq("Merge request is not mergeable to #{merge_request.merge_ref_path}") + end + end + + it 'returns error when user has no authorization to admin the merge request' do + unauthorized_user = create(:user) + project.add_reporter(unauthorized_user) + + service = described_class.new(project, unauthorized_user) + + result = service.execute(merge_request) + + expect(result[:status]).to eq(:error) + expect(result[:message]).to eq('You are not allowed to merge to this ref') + end end end diff --git a/spec/services/merge_requests/mergeability_check_service_spec.rb b/spec/services/merge_requests/mergeability_check_service_spec.rb deleted file mode 100644 index aa0485467ed..00000000000 --- a/spec/services/merge_requests/mergeability_check_service_spec.rb +++ /dev/null @@ -1,187 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -describe MergeRequests::MergeabilityCheckService do - shared_examples_for 'unmergeable merge request' do - it 'updates or keeps merge status as cannot_be_merged' do - subject - - expect(merge_request.merge_status).to eq('cannot_be_merged') - end - - it 'does not change the merge ref HEAD' do - expect { subject }.not_to change(merge_request, :merge_ref_head) - end - - it 'returns ServiceResponse.error' do - result = subject - - expect(result).to be_a(ServiceResponse) - expect(result).to be_error - end - end - - shared_examples_for 'mergeable merge request' do - it 'updates or keeps merge status as can_be_merged' do - subject - - expect(merge_request.merge_status).to eq('can_be_merged') - end - - it 'updates the merge ref' do - expect { subject }.to change(merge_request, :merge_ref_head).from(nil) - end - - it 'returns ServiceResponse.success' do - result = subject - - expect(result).to be_a(ServiceResponse) - expect(result).to be_success - end - - it 'ServiceResponse has merge_ref_head payload' do - result = subject - - expect(result.payload.keys).to contain_exactly(:merge_ref_head) - expect(result.payload[:merge_ref_head].keys) - .to contain_exactly(:commit_id, :target_id, :source_id) - end - end - - describe '#execute' do - let(:project) { create(:project, :repository) } - let(:merge_request) { create(:merge_request, merge_status: :unchecked, source_project: project, target_project: project) } - let(:repo) { project.repository } - - subject { described_class.new(merge_request).execute } - - before do - project.add_developer(merge_request.author) - end - - it_behaves_like 'mergeable merge request' - - context 'when multiple calls to the service' do - it 'returns success' do - subject - result = subject - - expect(result).to be_a(ServiceResponse) - expect(result.success?).to be(true) - end - - it 'second call does not change the merge-ref' do - expect { subject }.to change(merge_request, :merge_ref_head).from(nil) - expect { subject }.not_to change(merge_request, :merge_ref_head) - end - end - - context 'when broken' do - before do - allow(merge_request).to receive(:broken?) { true } - allow(project.repository).to receive(:can_be_merged?) { false } - end - - it_behaves_like 'unmergeable merge request' - - it 'returns ServiceResponse.error' do - result = subject - - expect(result).to be_a(ServiceResponse) - expect(result.error?).to be(true) - expect(result.message).to eq('Merge request is not mergeable') - end - end - - context 'when it has conflicts' do - before do - allow(merge_request).to receive(:broken?) { false } - allow(project.repository).to receive(:can_be_merged?) { false } - end - - it_behaves_like 'unmergeable merge request' - - it 'returns ServiceResponse.error' do - result = subject - - expect(result).to be_a(ServiceResponse) - expect(result.error?).to be(true) - expect(result.message).to eq('Merge request is not mergeable') - end - end - - context 'when MR cannot be merged and has no merge ref' do - before do - merge_request.mark_as_unmergeable! - end - - it_behaves_like 'unmergeable merge request' - - it 'returns ServiceResponse.error' do - result = subject - - expect(result).to be_a(ServiceResponse) - expect(result.error?).to be(true) - expect(result.message).to eq('Merge request is not mergeable') - end - end - - context 'when MR cannot be merged and has outdated merge ref' do - before do - MergeRequests::MergeToRefService.new(project, merge_request.author).execute(merge_request) - merge_request.mark_as_unmergeable! - end - - it_behaves_like 'unmergeable merge request' - - it 'returns ServiceResponse.error' do - result = subject - - expect(result).to be_a(ServiceResponse) - expect(result.error?).to be(true) - expect(result.message).to eq('Merge request is not mergeable') - end - end - - context 'when merge request is not given' do - subject { described_class.new(nil).execute } - - it 'returns ServiceResponse.error' do - result = subject - - expect(result).to be_a(ServiceResponse) - expect(result.message).to eq('Invalid argument') - end - end - - context 'when read only DB' do - it 'returns ServiceResponse.error' do - allow(Gitlab::Database).to receive(:read_only?) { true } - - result = subject - - expect(result).to be_a(ServiceResponse) - expect(result.message).to eq('Unsupported operation') - end - end - - context 'when MR is mergeable but merge-ref does not exists' do - before do - merge_request.mark_as_mergeable! - end - - it 'keeps merge status as can_be_merged' do - expect { subject }.not_to change(merge_request, :merge_status).from('can_be_merged') - end - - it 'returns ServiceResponse.error' do - result = subject - - expect(result).to be_a(ServiceResponse) - expect(result.error?).to be(true) - expect(result.message).to eq('Merge ref was not found') - end - end - end -end diff --git a/spec/services/service_response_spec.rb b/spec/services/service_response_spec.rb index e790d272e61..30bd4d6820b 100644 --- a/spec/services/service_response_spec.rb +++ b/spec/services/service_response_spec.rb @@ -16,13 +16,6 @@ describe ServiceResponse do expect(response).to be_success expect(response.message).to eq('Good orange') end - - it 'creates a successful response with payload' do - response = described_class.success(payload: { good: 'orange' }) - - expect(response).to be_success - expect(response.payload).to eq(good: 'orange') - end end describe '.error' do @@ -40,15 +33,6 @@ describe ServiceResponse do expect(response.message).to eq('Bad apple') expect(response.http_status).to eq(400) end - - it 'creates a failed response with payload' do - response = described_class.error(message: 'Bad apple', - payload: { bad: 'apple' }) - - expect(response).to be_error - expect(response.message).to eq('Bad apple') - expect(response.payload).to eq(bad: 'apple') - end end describe '#success?' do |