2019-07-07 11:18:12 +05:30
|
|
|
# frozen_string_literal: true
|
|
|
|
|
|
|
|
require 'spec_helper'
|
|
|
|
|
2020-07-28 23:09:34 +05:30
|
|
|
RSpec.describe MergeRequests::PushOptionsHandlerService do
|
2019-07-07 11:18:12 +05:30
|
|
|
include ProjectForksHelper
|
|
|
|
|
2020-10-24 23:57:45 +05:30
|
|
|
let_it_be(:project) { create(:project, :public, :repository) }
|
2021-04-29 21:17:54 +05:30
|
|
|
let_it_be(:user1) { create(:user, developer_projects: [project]) }
|
|
|
|
let_it_be(:user2) { create(:user, developer_projects: [project]) }
|
|
|
|
let_it_be(:user3) { create(:user, developer_projects: [project]) }
|
|
|
|
let_it_be(:forked_project) { fork_project(project, user1, repository: true) }
|
2020-10-24 23:57:45 +05:30
|
|
|
|
2021-06-08 01:23:25 +05:30
|
|
|
let(:service) { described_class.new(project: project, current_user: user1, changes: changes, push_options: push_options) }
|
2019-07-07 11:18:12 +05:30
|
|
|
let(:source_branch) { 'fix' }
|
|
|
|
let(:target_branch) { 'feature' }
|
2019-10-12 21:52:04 +05:30
|
|
|
let(:title) { 'my title' }
|
|
|
|
let(:description) { 'my description' }
|
2019-12-04 20:38:33 +05:30
|
|
|
let(:label1) { 'mylabel1' }
|
|
|
|
let(:label2) { 'mylabel2' }
|
|
|
|
let(:label3) { 'mylabel3' }
|
2019-07-07 11:18:12 +05:30
|
|
|
let(:new_branch_changes) { "#{Gitlab::Git::BLANK_SHA} 570e7b2abdd848b95f2f578043fc23bd6f6fd24d refs/heads/#{source_branch}" }
|
|
|
|
let(:existing_branch_changes) { "d14d6c0abdd253381df51a723d58691b2ee1ab08 570e7b2abdd848b95f2f578043fc23bd6f6fd24d refs/heads/#{source_branch}" }
|
|
|
|
let(:deleted_branch_changes) { "d14d6c0abdd253381df51a723d58691b2ee1ab08 #{Gitlab::Git::BLANK_SHA} refs/heads/#{source_branch}" }
|
|
|
|
let(:default_branch_changes) { "d14d6c0abdd253381df51a723d58691b2ee1ab08 570e7b2abdd848b95f2f578043fc23bd6f6fd24d refs/heads/#{project.default_branch}" }
|
2021-03-11 19:13:27 +05:30
|
|
|
let(:error_mr_required) { "A merge_request.create push option is required to create a merge request for branch #{source_branch}" }
|
2019-07-07 11:18:12 +05:30
|
|
|
|
2021-04-29 21:17:54 +05:30
|
|
|
before do
|
|
|
|
stub_licensed_features(multiple_merge_request_assignees: false)
|
2019-07-07 11:18:12 +05:30
|
|
|
end
|
|
|
|
|
|
|
|
shared_examples_for 'a service that can set the target of a merge request' do
|
|
|
|
subject(:last_mr) { MergeRequest.last }
|
|
|
|
|
|
|
|
it 'sets the target_branch' do
|
|
|
|
service.execute
|
|
|
|
|
|
|
|
expect(last_mr.target_branch).to eq(target_branch)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2019-10-12 21:52:04 +05:30
|
|
|
shared_examples_for 'a service that can set the title of a merge request' do
|
|
|
|
subject(:last_mr) { MergeRequest.last }
|
|
|
|
|
|
|
|
it 'sets the title' do
|
|
|
|
service.execute
|
|
|
|
|
|
|
|
expect(last_mr.title).to eq(title)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
shared_examples_for 'a service that can set the description of a merge request' do
|
|
|
|
subject(:last_mr) { MergeRequest.last }
|
|
|
|
|
|
|
|
it 'sets the description' do
|
|
|
|
service.execute
|
|
|
|
|
|
|
|
expect(last_mr.description).to eq(description)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2019-07-07 11:18:12 +05:30
|
|
|
shared_examples_for 'a service that can set the merge request to merge when pipeline succeeds' do
|
|
|
|
subject(:last_mr) { MergeRequest.last }
|
|
|
|
|
2019-12-26 22:10:19 +05:30
|
|
|
let(:change) { Gitlab::ChangesList.new(changes).changes.first }
|
|
|
|
|
2019-09-04 21:01:54 +05:30
|
|
|
it 'sets auto_merge_enabled' do
|
2019-07-07 11:18:12 +05:30
|
|
|
service.execute
|
|
|
|
|
2019-09-04 21:01:54 +05:30
|
|
|
expect(last_mr.auto_merge_enabled).to eq(true)
|
|
|
|
expect(last_mr.auto_merge_strategy).to eq(AutoMergeService::STRATEGY_MERGE_WHEN_PIPELINE_SUCCEEDS)
|
2021-04-29 21:17:54 +05:30
|
|
|
expect(last_mr.merge_user).to eq(user1)
|
2019-12-26 22:10:19 +05:30
|
|
|
expect(last_mr.merge_params['sha']).to eq(change[:newrev])
|
2019-07-07 11:18:12 +05:30
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2019-10-12 21:52:04 +05:30
|
|
|
shared_examples_for 'a service that can remove the source branch when it is merged' do
|
|
|
|
subject(:last_mr) { MergeRequest.last }
|
|
|
|
|
|
|
|
it 'returns true to force_remove_source_branch?' do
|
|
|
|
service.execute
|
|
|
|
|
|
|
|
expect(last_mr.force_remove_source_branch?).to eq(true)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2019-12-04 20:38:33 +05:30
|
|
|
shared_examples_for 'a service that can change labels of a merge request' do |count|
|
|
|
|
subject(:last_mr) { MergeRequest.last }
|
|
|
|
|
|
|
|
it 'changes label count' do
|
|
|
|
service.execute
|
|
|
|
|
|
|
|
expect(last_mr.label_ids.count).to eq(count)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2019-07-07 11:18:12 +05:30
|
|
|
shared_examples_for 'a service that does not update a merge request' do
|
|
|
|
it do
|
|
|
|
expect { service.execute }.not_to change { MergeRequest.maximum(:updated_at) }
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
shared_examples_for 'a service that does nothing' do
|
|
|
|
include_examples 'a service that does not create a merge request'
|
|
|
|
include_examples 'a service that does not update a merge request'
|
|
|
|
end
|
|
|
|
|
2021-04-29 21:17:54 +05:30
|
|
|
shared_examples 'with a deleted branch' do
|
|
|
|
let(:changes) { deleted_branch_changes }
|
|
|
|
|
|
|
|
it_behaves_like 'a service that does nothing'
|
|
|
|
end
|
|
|
|
|
|
|
|
shared_examples 'with the project default branch' do
|
|
|
|
let(:changes) { default_branch_changes }
|
|
|
|
|
|
|
|
it_behaves_like 'a service that does nothing'
|
|
|
|
end
|
|
|
|
|
2019-07-07 11:18:12 +05:30
|
|
|
describe '`create` push option' do
|
|
|
|
let(:push_options) { { create: true } }
|
|
|
|
|
|
|
|
context 'with a new branch' do
|
|
|
|
let(:changes) { new_branch_changes }
|
|
|
|
|
|
|
|
it_behaves_like 'a service that can create a merge request'
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'with an existing branch but no open MR' do
|
|
|
|
let(:changes) { existing_branch_changes }
|
|
|
|
|
|
|
|
it_behaves_like 'a service that can create a merge request'
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'with an existing branch that has a merge request open' do
|
|
|
|
let(:changes) { existing_branch_changes }
|
|
|
|
let!(:merge_request) { create(:merge_request, source_project: project, source_branch: source_branch)}
|
|
|
|
|
|
|
|
it_behaves_like 'a service that does not create a merge request'
|
|
|
|
end
|
|
|
|
|
2021-04-29 21:17:54 +05:30
|
|
|
it_behaves_like 'with a deleted branch'
|
|
|
|
it_behaves_like 'with the project default branch'
|
2019-07-07 11:18:12 +05:30
|
|
|
end
|
|
|
|
|
|
|
|
describe '`merge_when_pipeline_succeeds` push option' do
|
|
|
|
let(:push_options) { { merge_when_pipeline_succeeds: true } }
|
|
|
|
|
|
|
|
context 'with a new branch' do
|
|
|
|
let(:changes) { new_branch_changes }
|
|
|
|
|
|
|
|
it_behaves_like 'a service that does not create a merge request'
|
|
|
|
|
|
|
|
it 'adds an error to the service' do
|
|
|
|
service.execute
|
|
|
|
|
2021-03-11 19:13:27 +05:30
|
|
|
expect(service.errors).to include(error_mr_required)
|
2019-07-07 11:18:12 +05:30
|
|
|
end
|
|
|
|
|
|
|
|
context 'when coupled with the `create` push option' do
|
|
|
|
let(:push_options) { { create: true, merge_when_pipeline_succeeds: true } }
|
|
|
|
|
|
|
|
it_behaves_like 'a service that can create a merge request'
|
|
|
|
it_behaves_like 'a service that can set the merge request to merge when pipeline succeeds'
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'with an existing branch but no open MR' do
|
|
|
|
let(:changes) { existing_branch_changes }
|
|
|
|
|
|
|
|
it_behaves_like 'a service that does not create a merge request'
|
|
|
|
|
|
|
|
it 'adds an error to the service' do
|
|
|
|
service.execute
|
|
|
|
|
2021-03-11 19:13:27 +05:30
|
|
|
expect(service.errors).to include(error_mr_required)
|
2019-07-07 11:18:12 +05:30
|
|
|
end
|
|
|
|
|
|
|
|
context 'when coupled with the `create` push option' do
|
|
|
|
let(:push_options) { { create: true, merge_when_pipeline_succeeds: true } }
|
|
|
|
|
|
|
|
it_behaves_like 'a service that can create a merge request'
|
|
|
|
it_behaves_like 'a service that can set the merge request to merge when pipeline succeeds'
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'with an existing branch that has a merge request open' do
|
|
|
|
let(:changes) { existing_branch_changes }
|
|
|
|
let!(:merge_request) { create(:merge_request, source_project: project, source_branch: source_branch)}
|
|
|
|
|
|
|
|
it_behaves_like 'a service that does not create a merge request'
|
|
|
|
it_behaves_like 'a service that can set the merge request to merge when pipeline succeeds'
|
|
|
|
end
|
|
|
|
|
2021-04-29 21:17:54 +05:30
|
|
|
it_behaves_like 'with a deleted branch'
|
|
|
|
it_behaves_like 'with the project default branch'
|
2019-07-07 11:18:12 +05:30
|
|
|
end
|
|
|
|
|
2019-10-12 21:52:04 +05:30
|
|
|
describe '`remove_source_branch` push option' do
|
|
|
|
let(:push_options) { { remove_source_branch: true } }
|
|
|
|
|
|
|
|
context 'with a new branch' do
|
|
|
|
let(:changes) { new_branch_changes }
|
|
|
|
|
|
|
|
it_behaves_like 'a service that does not create a merge request'
|
|
|
|
|
|
|
|
it 'adds an error to the service' do
|
|
|
|
service.execute
|
|
|
|
|
2021-04-29 21:17:54 +05:30
|
|
|
expect(service.errors).to include(error_mr_required)
|
2019-10-12 21:52:04 +05:30
|
|
|
end
|
|
|
|
|
|
|
|
context 'when coupled with the `create` push option' do
|
|
|
|
let(:push_options) { { create: true, remove_source_branch: true } }
|
|
|
|
|
|
|
|
it_behaves_like 'a service that can create a merge request'
|
|
|
|
it_behaves_like 'a service that can remove the source branch when it is merged'
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'with an existing branch but no open MR' do
|
|
|
|
let(:changes) { existing_branch_changes }
|
|
|
|
|
|
|
|
it_behaves_like 'a service that does not create a merge request'
|
|
|
|
|
|
|
|
it 'adds an error to the service' do
|
|
|
|
service.execute
|
|
|
|
|
2021-03-11 19:13:27 +05:30
|
|
|
expect(service.errors).to include(error_mr_required)
|
2019-10-12 21:52:04 +05:30
|
|
|
end
|
|
|
|
|
|
|
|
context 'when coupled with the `create` push option' do
|
|
|
|
let(:push_options) { { create: true, remove_source_branch: true } }
|
|
|
|
|
|
|
|
it_behaves_like 'a service that can create a merge request'
|
|
|
|
it_behaves_like 'a service that can remove the source branch when it is merged'
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'with an existing branch that has a merge request open' do
|
|
|
|
let(:changes) { existing_branch_changes }
|
|
|
|
let!(:merge_request) { create(:merge_request, source_project: project, source_branch: source_branch)}
|
|
|
|
|
|
|
|
it_behaves_like 'a service that does not create a merge request'
|
|
|
|
it_behaves_like 'a service that can remove the source branch when it is merged'
|
|
|
|
end
|
|
|
|
|
2021-04-29 21:17:54 +05:30
|
|
|
it_behaves_like 'with a deleted branch'
|
|
|
|
it_behaves_like 'with the project default branch'
|
2019-10-12 21:52:04 +05:30
|
|
|
end
|
|
|
|
|
2019-07-07 11:18:12 +05:30
|
|
|
describe '`target` push option' do
|
|
|
|
let(:push_options) { { target: target_branch } }
|
|
|
|
|
|
|
|
context 'with a new branch' do
|
|
|
|
let(:changes) { new_branch_changes }
|
|
|
|
|
|
|
|
it_behaves_like 'a service that does not create a merge request'
|
|
|
|
|
|
|
|
it 'adds an error to the service' do
|
|
|
|
service.execute
|
|
|
|
|
2021-03-11 19:13:27 +05:30
|
|
|
expect(service.errors).to include(error_mr_required)
|
2019-07-07 11:18:12 +05:30
|
|
|
end
|
|
|
|
|
|
|
|
context 'when coupled with the `create` push option' do
|
|
|
|
let(:push_options) { { create: true, target: target_branch } }
|
|
|
|
|
|
|
|
it_behaves_like 'a service that can create a merge request'
|
|
|
|
it_behaves_like 'a service that can set the target of a merge request'
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'with an existing branch but no open MR' do
|
|
|
|
let(:changes) { existing_branch_changes }
|
|
|
|
|
|
|
|
it_behaves_like 'a service that does not create a merge request'
|
|
|
|
|
|
|
|
it 'adds an error to the service' do
|
|
|
|
service.execute
|
|
|
|
|
2021-03-11 19:13:27 +05:30
|
|
|
expect(service.errors).to include(error_mr_required)
|
2019-07-07 11:18:12 +05:30
|
|
|
end
|
|
|
|
|
|
|
|
context 'when coupled with the `create` push option' do
|
|
|
|
let(:push_options) { { create: true, target: target_branch } }
|
|
|
|
|
|
|
|
it_behaves_like 'a service that can create a merge request'
|
|
|
|
it_behaves_like 'a service that can set the target of a merge request'
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'with an existing branch that has a merge request open' do
|
|
|
|
let(:changes) { existing_branch_changes }
|
|
|
|
let!(:merge_request) { create(:merge_request, source_project: project, source_branch: source_branch)}
|
|
|
|
|
|
|
|
it_behaves_like 'a service that does not create a merge request'
|
|
|
|
it_behaves_like 'a service that can set the target of a merge request'
|
|
|
|
end
|
|
|
|
|
2021-04-29 21:17:54 +05:30
|
|
|
it_behaves_like 'with a deleted branch'
|
|
|
|
it_behaves_like 'with the project default branch'
|
2019-07-07 11:18:12 +05:30
|
|
|
end
|
|
|
|
|
2019-10-12 21:52:04 +05:30
|
|
|
describe '`title` push option' do
|
|
|
|
let(:push_options) { { title: title } }
|
|
|
|
|
|
|
|
context 'with a new branch' do
|
|
|
|
let(:changes) { new_branch_changes }
|
|
|
|
|
|
|
|
it_behaves_like 'a service that does not create a merge request'
|
|
|
|
|
|
|
|
it 'adds an error to the service' do
|
|
|
|
service.execute
|
|
|
|
|
2021-03-11 19:13:27 +05:30
|
|
|
expect(service.errors).to include(error_mr_required)
|
2019-10-12 21:52:04 +05:30
|
|
|
end
|
|
|
|
|
|
|
|
context 'when coupled with the `create` push option' do
|
|
|
|
let(:push_options) { { create: true, title: title } }
|
|
|
|
|
|
|
|
it_behaves_like 'a service that can create a merge request'
|
|
|
|
it_behaves_like 'a service that can set the title of a merge request'
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'with an existing branch but no open MR' do
|
|
|
|
let(:changes) { existing_branch_changes }
|
|
|
|
|
|
|
|
it_behaves_like 'a service that does not create a merge request'
|
|
|
|
|
|
|
|
it 'adds an error to the service' do
|
|
|
|
service.execute
|
|
|
|
|
2021-03-11 19:13:27 +05:30
|
|
|
expect(service.errors).to include(error_mr_required)
|
2019-10-12 21:52:04 +05:30
|
|
|
end
|
|
|
|
|
|
|
|
context 'when coupled with the `create` push option' do
|
|
|
|
let(:push_options) { { create: true, title: title } }
|
|
|
|
|
|
|
|
it_behaves_like 'a service that can create a merge request'
|
|
|
|
it_behaves_like 'a service that can set the title of a merge request'
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'with an existing branch that has a merge request open' do
|
|
|
|
let(:changes) { existing_branch_changes }
|
|
|
|
let!(:merge_request) { create(:merge_request, source_project: project, source_branch: source_branch)}
|
|
|
|
|
|
|
|
it_behaves_like 'a service that does not create a merge request'
|
|
|
|
it_behaves_like 'a service that can set the title of a merge request'
|
|
|
|
end
|
|
|
|
|
2021-04-29 21:17:54 +05:30
|
|
|
it_behaves_like 'with a deleted branch'
|
|
|
|
it_behaves_like 'with the project default branch'
|
2019-10-12 21:52:04 +05:30
|
|
|
end
|
|
|
|
|
|
|
|
describe '`description` push option' do
|
|
|
|
let(:push_options) { { description: description } }
|
|
|
|
|
|
|
|
context 'with a new branch' do
|
|
|
|
let(:changes) { new_branch_changes }
|
|
|
|
|
|
|
|
it_behaves_like 'a service that does not create a merge request'
|
|
|
|
|
|
|
|
it 'adds an error to the service' do
|
|
|
|
service.execute
|
|
|
|
|
2021-03-11 19:13:27 +05:30
|
|
|
expect(service.errors).to include(error_mr_required)
|
2019-10-12 21:52:04 +05:30
|
|
|
end
|
|
|
|
|
|
|
|
context 'when coupled with the `create` push option' do
|
|
|
|
let(:push_options) { { create: true, description: description } }
|
|
|
|
|
|
|
|
it_behaves_like 'a service that can create a merge request'
|
|
|
|
it_behaves_like 'a service that can set the description of a merge request'
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'with an existing branch but no open MR' do
|
|
|
|
let(:changes) { existing_branch_changes }
|
|
|
|
|
|
|
|
it_behaves_like 'a service that does not create a merge request'
|
|
|
|
|
|
|
|
it 'adds an error to the service' do
|
|
|
|
service.execute
|
|
|
|
|
2021-03-11 19:13:27 +05:30
|
|
|
expect(service.errors).to include(error_mr_required)
|
2019-10-12 21:52:04 +05:30
|
|
|
end
|
|
|
|
|
|
|
|
context 'when coupled with the `create` push option' do
|
|
|
|
let(:push_options) { { create: true, description: description } }
|
|
|
|
|
|
|
|
it_behaves_like 'a service that can create a merge request'
|
|
|
|
it_behaves_like 'a service that can set the description of a merge request'
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'with an existing branch that has a merge request open' do
|
|
|
|
let(:changes) { existing_branch_changes }
|
|
|
|
let!(:merge_request) { create(:merge_request, source_project: project, source_branch: source_branch)}
|
|
|
|
|
|
|
|
it_behaves_like 'a service that does not create a merge request'
|
|
|
|
it_behaves_like 'a service that can set the description of a merge request'
|
|
|
|
end
|
|
|
|
|
2021-04-29 21:17:54 +05:30
|
|
|
it_behaves_like 'with a deleted branch'
|
|
|
|
it_behaves_like 'with the project default branch'
|
2019-10-12 21:52:04 +05:30
|
|
|
end
|
|
|
|
|
2019-12-04 20:38:33 +05:30
|
|
|
describe '`label` push option' do
|
|
|
|
let(:push_options) { { label: { label1 => 1, label2 => 1 } } }
|
|
|
|
|
|
|
|
context 'with a new branch' do
|
|
|
|
let(:changes) { new_branch_changes }
|
|
|
|
|
|
|
|
it_behaves_like 'a service that does not create a merge request'
|
|
|
|
|
|
|
|
it 'adds an error to the service' do
|
|
|
|
service.execute
|
|
|
|
|
2021-03-11 19:13:27 +05:30
|
|
|
expect(service.errors).to include(error_mr_required)
|
2019-12-04 20:38:33 +05:30
|
|
|
end
|
|
|
|
|
|
|
|
context 'when coupled with the `create` push option' do
|
|
|
|
let(:push_options) { { create: true, label: { label1 => 1, label2 => 1 } } }
|
|
|
|
|
|
|
|
it_behaves_like 'a service that can create a merge request'
|
|
|
|
it_behaves_like 'a service that can change labels of a merge request', 2
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'with an existing branch but no open MR' do
|
|
|
|
let(:changes) { existing_branch_changes }
|
|
|
|
|
|
|
|
it_behaves_like 'a service that does not create a merge request'
|
|
|
|
|
|
|
|
it 'adds an error to the service' do
|
|
|
|
service.execute
|
|
|
|
|
2021-03-11 19:13:27 +05:30
|
|
|
expect(service.errors).to include(error_mr_required)
|
2019-12-04 20:38:33 +05:30
|
|
|
end
|
|
|
|
|
|
|
|
context 'when coupled with the `create` push option' do
|
|
|
|
let(:push_options) { { create: true, label: { label1 => 1, label2 => 1 } } }
|
|
|
|
|
|
|
|
it_behaves_like 'a service that can create a merge request'
|
|
|
|
it_behaves_like 'a service that can change labels of a merge request', 2
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'with an existing branch that has a merge request open' do
|
|
|
|
let(:changes) { existing_branch_changes }
|
|
|
|
let!(:merge_request) { create(:merge_request, source_project: project, source_branch: source_branch)}
|
|
|
|
|
|
|
|
it_behaves_like 'a service that does not create a merge request'
|
|
|
|
it_behaves_like 'a service that can change labels of a merge request', 2
|
|
|
|
end
|
|
|
|
|
2021-04-29 21:17:54 +05:30
|
|
|
it_behaves_like 'with a deleted branch'
|
|
|
|
it_behaves_like 'with the project default branch'
|
2019-12-04 20:38:33 +05:30
|
|
|
end
|
|
|
|
|
|
|
|
describe '`unlabel` push option' do
|
|
|
|
let(:push_options) { { label: { label1 => 1, label2 => 1 }, unlabel: { label1 => 1, label3 => 1 } } }
|
|
|
|
|
|
|
|
context 'with a new branch' do
|
|
|
|
let(:changes) { new_branch_changes }
|
|
|
|
|
|
|
|
it_behaves_like 'a service that does not create a merge request'
|
|
|
|
|
|
|
|
it 'adds an error to the service' do
|
|
|
|
service.execute
|
|
|
|
|
2021-04-29 21:17:54 +05:30
|
|
|
expect(service.errors).to include(error_mr_required)
|
2019-12-04 20:38:33 +05:30
|
|
|
end
|
|
|
|
|
|
|
|
context 'when coupled with the `create` push option' do
|
|
|
|
let(:push_options) { { create: true, label: { label1 => 1, label2 => 1 }, unlabel: { label1 => 1, label3 => 1 } } }
|
|
|
|
|
|
|
|
it_behaves_like 'a service that can create a merge request'
|
|
|
|
it_behaves_like 'a service that can change labels of a merge request', 1
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'with an existing branch but no open MR' do
|
|
|
|
let(:changes) { existing_branch_changes }
|
|
|
|
|
|
|
|
it_behaves_like 'a service that does not create a merge request'
|
|
|
|
|
|
|
|
it 'adds an error to the service' do
|
|
|
|
service.execute
|
|
|
|
|
2021-04-29 21:17:54 +05:30
|
|
|
expect(service.errors).to include(error_mr_required)
|
2019-12-04 20:38:33 +05:30
|
|
|
end
|
|
|
|
|
|
|
|
context 'when coupled with the `create` push option' do
|
|
|
|
let(:push_options) { { create: true, label: { label1 => 1, label2 => 1 }, unlabel: { label1 => 1, label3 => 1 } } }
|
|
|
|
|
|
|
|
it_behaves_like 'a service that can create a merge request'
|
|
|
|
it_behaves_like 'a service that can change labels of a merge request', 1
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'with an existing branch that has a merge request open' do
|
|
|
|
let(:changes) { existing_branch_changes }
|
|
|
|
let!(:merge_request) { create(:merge_request, source_project: project, source_branch: source_branch)}
|
|
|
|
|
|
|
|
it_behaves_like 'a service that does not create a merge request'
|
|
|
|
it_behaves_like 'a service that can change labels of a merge request', 1
|
|
|
|
end
|
|
|
|
|
2021-04-29 21:17:54 +05:30
|
|
|
it_behaves_like 'with a deleted branch'
|
|
|
|
it_behaves_like 'with the project default branch'
|
|
|
|
end
|
|
|
|
|
|
|
|
shared_examples 'with an existing branch that has a merge request open in foss' do
|
|
|
|
let(:changes) { existing_branch_changes }
|
|
|
|
let!(:merge_request) { create(:merge_request, source_project: project, source_branch: source_branch)}
|
2019-12-04 20:38:33 +05:30
|
|
|
|
2021-04-29 21:17:54 +05:30
|
|
|
it_behaves_like 'a service that does not create a merge request'
|
|
|
|
it_behaves_like 'a service that can change assignees of a merge request', 1
|
|
|
|
end
|
2019-12-04 20:38:33 +05:30
|
|
|
|
2021-04-29 21:17:54 +05:30
|
|
|
describe '`assign` push option' do
|
|
|
|
let(:assigned) { { user2.id => 1, user3.id => 1 } }
|
|
|
|
let(:unassigned) { nil }
|
|
|
|
let(:push_options) { { assign: assigned, unassign: unassigned } }
|
2019-12-04 20:38:33 +05:30
|
|
|
|
2021-04-29 21:17:54 +05:30
|
|
|
it_behaves_like 'with a new branch', 1
|
|
|
|
it_behaves_like 'with an existing branch but no open MR', 1
|
|
|
|
it_behaves_like 'with an existing branch that has a merge request open in foss'
|
|
|
|
|
|
|
|
it_behaves_like 'with a deleted branch'
|
|
|
|
it_behaves_like 'with the project default branch'
|
|
|
|
end
|
|
|
|
|
|
|
|
describe '`unassign` push option' do
|
|
|
|
let(:assigned) { { user2.id => 1, user3.id => 1 } }
|
|
|
|
let(:unassigned) { { user1.id => 1, user3.id => 1 } }
|
|
|
|
let(:push_options) { { assign: assigned, unassign: unassigned } }
|
|
|
|
|
|
|
|
it_behaves_like 'with a new branch', 1
|
|
|
|
it_behaves_like 'with an existing branch but no open MR', 1
|
|
|
|
it_behaves_like 'with an existing branch that has a merge request open in foss'
|
|
|
|
|
|
|
|
it_behaves_like 'with a deleted branch'
|
|
|
|
it_behaves_like 'with the project default branch'
|
2019-12-04 20:38:33 +05:30
|
|
|
end
|
|
|
|
|
2019-07-07 11:18:12 +05:30
|
|
|
describe 'multiple pushed branches' do
|
|
|
|
let(:push_options) { { create: true } }
|
|
|
|
let(:changes) do
|
|
|
|
[
|
|
|
|
new_branch_changes,
|
|
|
|
"#{Gitlab::Git::BLANK_SHA} 570e7b2abdd848b95f2f578043fc23bd6f6fd24d refs/heads/feature_conflict"
|
|
|
|
]
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'creates a merge request per branch' do
|
|
|
|
expect { service.execute }.to change { MergeRequest.count }.by(2)
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when there are too many pushed branches' do
|
|
|
|
let(:limit) { MergeRequests::PushOptionsHandlerService::LIMIT }
|
|
|
|
let(:changes) do
|
|
|
|
TestEnv::BRANCH_SHA.to_a[0..limit].map do |x|
|
|
|
|
"#{Gitlab::Git::BLANK_SHA} #{x.first} refs/heads/#{x.last}"
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'records an error' do
|
|
|
|
service.execute
|
|
|
|
|
|
|
|
expect(service.errors).to eq(["Too many branches pushed (#{limit + 1} were pushed, limit is #{limit})"])
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
describe 'no push options' do
|
|
|
|
let(:push_options) { {} }
|
|
|
|
let(:changes) { new_branch_changes }
|
|
|
|
|
|
|
|
it_behaves_like 'a service that does nothing'
|
|
|
|
end
|
|
|
|
|
|
|
|
describe 'no user' do
|
2021-04-29 21:17:54 +05:30
|
|
|
let(:user1) { nil }
|
|
|
|
let(:user2) { nil }
|
|
|
|
let(:user3) { nil }
|
2019-07-07 11:18:12 +05:30
|
|
|
let(:push_options) { { create: true } }
|
|
|
|
let(:changes) { new_branch_changes }
|
|
|
|
|
|
|
|
it 'records an error' do
|
|
|
|
service.execute
|
|
|
|
|
|
|
|
expect(service.errors).to eq(['User is required'])
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
describe 'unauthorized user' do
|
|
|
|
let(:push_options) { { create: true } }
|
|
|
|
let(:changes) { new_branch_changes }
|
|
|
|
|
|
|
|
it 'records an error' do
|
2021-04-29 21:17:54 +05:30
|
|
|
Members::DestroyService.new(user1).execute(ProjectMember.find_by!(user_id: user1.id))
|
2019-07-07 11:18:12 +05:30
|
|
|
|
|
|
|
service.execute
|
|
|
|
|
|
|
|
expect(service.errors).to eq(['User access was denied'])
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
describe 'handling unexpected exceptions' do
|
|
|
|
let(:push_options) { { create: true } }
|
|
|
|
let(:changes) { new_branch_changes }
|
|
|
|
let(:exception) { StandardError.new('My standard error') }
|
|
|
|
|
|
|
|
def run_service_with_exception
|
2020-03-13 15:44:24 +05:30
|
|
|
allow_next_instance_of(MergeRequests::BuildService) do |instance|
|
|
|
|
allow(instance).to receive(:execute).and_raise(exception)
|
|
|
|
end
|
2019-07-07 11:18:12 +05:30
|
|
|
|
|
|
|
service.execute
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'records an error' do
|
|
|
|
run_service_with_exception
|
|
|
|
|
|
|
|
expect(service.errors).to eq(['An unknown error occurred'])
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'writes to Gitlab::AppLogger' do
|
|
|
|
expect(Gitlab::AppLogger).to receive(:error).with(exception)
|
|
|
|
|
|
|
|
run_service_with_exception
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
describe 'when target is not a valid branch name' do
|
|
|
|
let(:push_options) { { create: true, target: 'my-branch' } }
|
|
|
|
let(:changes) { new_branch_changes }
|
|
|
|
|
|
|
|
it 'records an error' do
|
|
|
|
service.execute
|
|
|
|
|
|
|
|
expect(service.errors).to eq(['Branch my-branch does not exist'])
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
describe 'when MRs are not enabled' do
|
2021-04-29 21:17:54 +05:30
|
|
|
let(:project) { create(:project, :public, :repository).tap { |pr| pr.add_developer(user1) } }
|
2019-07-07 11:18:12 +05:30
|
|
|
let(:push_options) { { create: true } }
|
|
|
|
let(:changes) { new_branch_changes }
|
|
|
|
|
|
|
|
it 'records an error' do
|
|
|
|
expect(project).to receive(:merge_requests_enabled?).and_return(false)
|
|
|
|
|
|
|
|
service.execute
|
|
|
|
|
|
|
|
expect(service.errors).to eq(["Merge requests are not enabled for project #{project.full_path}"])
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
describe 'when MR has ActiveRecord errors' do
|
|
|
|
let(:push_options) { { create: true } }
|
|
|
|
let(:changes) { new_branch_changes }
|
|
|
|
|
|
|
|
it 'adds the error to its errors property' do
|
|
|
|
invalid_merge_request = MergeRequest.new
|
|
|
|
invalid_merge_request.errors.add(:base, 'my error')
|
|
|
|
|
2020-03-13 15:44:24 +05:30
|
|
|
expect_next_instance_of(MergeRequests::CreateService) do |instance|
|
|
|
|
expect(instance).to receive(:execute).and_return(invalid_merge_request)
|
|
|
|
end
|
2019-07-07 11:18:12 +05:30
|
|
|
|
|
|
|
service.execute
|
|
|
|
|
|
|
|
expect(service.errors).to eq(['my error'])
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|