2020-04-08 14:13:33 +05:30
|
|
|
# frozen_string_literal: true
|
|
|
|
|
|
|
|
require 'spec_helper'
|
|
|
|
|
2023-04-23 21:23:45 +05:30
|
|
|
RSpec.describe MergeRequests::AfterCreateService, feature_category: :code_review_workflow do
|
2020-04-08 14:13:33 +05:30
|
|
|
let_it_be(:merge_request) { create(:merge_request) }
|
2023-07-09 08:55:56 +05:30
|
|
|
let(:project) { merge_request.project }
|
2020-04-08 14:13:33 +05:30
|
|
|
|
|
|
|
subject(:after_create_service) do
|
2021-06-08 01:23:25 +05:30
|
|
|
described_class.new(project: merge_request.target_project, current_user: merge_request.author)
|
2020-04-08 14:13:33 +05:30
|
|
|
end
|
|
|
|
|
|
|
|
describe '#execute' do
|
|
|
|
let(:event_service) { instance_double('EventCreateService', open_mr: true) }
|
|
|
|
let(:notification_service) { instance_double('NotificationService', new_merge_request: true) }
|
|
|
|
|
|
|
|
before do
|
|
|
|
allow(after_create_service).to receive(:event_service).and_return(event_service)
|
|
|
|
allow(after_create_service).to receive(:notification_service).and_return(notification_service)
|
|
|
|
end
|
|
|
|
|
2021-02-22 17:27:13 +05:30
|
|
|
subject(:execute_service) { after_create_service.execute(merge_request) }
|
|
|
|
|
2020-04-08 14:13:33 +05:30
|
|
|
it 'creates a merge request open event' do
|
|
|
|
expect(event_service)
|
|
|
|
.to receive(:open_mr).with(merge_request, merge_request.author)
|
|
|
|
|
2021-02-22 17:27:13 +05:30
|
|
|
execute_service
|
2020-04-08 14:13:33 +05:30
|
|
|
end
|
|
|
|
|
2021-03-08 18:12:59 +05:30
|
|
|
it 'calls the merge request activity counter' do
|
|
|
|
expect(Gitlab::UsageDataCounters::MergeRequestActivityUniqueCounter)
|
|
|
|
.to receive(:track_create_mr_action)
|
2023-03-04 22:38:38 +05:30
|
|
|
.with(user: merge_request.author, merge_request: merge_request)
|
2021-03-08 18:12:59 +05:30
|
|
|
|
2021-04-17 20:07:23 +05:30
|
|
|
expect(Gitlab::UsageDataCounters::MergeRequestActivityUniqueCounter)
|
|
|
|
.to receive(:track_mr_including_ci_config)
|
|
|
|
.with(user: merge_request.author, merge_request: merge_request)
|
|
|
|
|
2021-03-08 18:12:59 +05:30
|
|
|
execute_service
|
|
|
|
end
|
|
|
|
|
2020-04-08 14:13:33 +05:30
|
|
|
it 'creates a new merge request notification' do
|
|
|
|
expect(notification_service)
|
|
|
|
.to receive(:new_merge_request).with(merge_request, merge_request.author)
|
|
|
|
|
2021-02-22 17:27:13 +05:30
|
|
|
execute_service
|
2020-04-08 14:13:33 +05:30
|
|
|
end
|
|
|
|
|
|
|
|
it 'writes diffs to the cache' do
|
|
|
|
expect(merge_request)
|
|
|
|
.to receive_message_chain(:diffs, :write_cache)
|
|
|
|
|
2021-02-22 17:27:13 +05:30
|
|
|
execute_service
|
2020-04-08 14:13:33 +05:30
|
|
|
end
|
|
|
|
|
|
|
|
it 'creates cross references' do
|
|
|
|
expect(merge_request)
|
|
|
|
.to receive(:create_cross_references!).with(merge_request.author)
|
|
|
|
|
2021-02-22 17:27:13 +05:30
|
|
|
execute_service
|
2020-04-08 14:13:33 +05:30
|
|
|
end
|
|
|
|
|
|
|
|
it 'creates a pipeline and updates the HEAD pipeline' do
|
|
|
|
expect(after_create_service)
|
|
|
|
.to receive(:create_pipeline_for).with(merge_request, merge_request.author)
|
|
|
|
expect(merge_request).to receive(:update_head_pipeline)
|
|
|
|
|
2021-02-22 17:27:13 +05:30
|
|
|
execute_service
|
|
|
|
end
|
|
|
|
|
2023-07-09 08:55:56 +05:30
|
|
|
it 'executes hooks with default action' do
|
|
|
|
expect(project).to receive(:execute_hooks)
|
|
|
|
|
|
|
|
execute_service
|
|
|
|
end
|
|
|
|
|
2021-03-11 19:13:27 +05:30
|
|
|
it_behaves_like 'records an onboarding progress action', :merge_request_created do
|
|
|
|
let(:namespace) { merge_request.target_project.namespace }
|
2020-04-08 14:13:33 +05:30
|
|
|
end
|
2021-04-17 20:07:23 +05:30
|
|
|
|
|
|
|
context 'when merge request is in unchecked state' do
|
|
|
|
before do
|
|
|
|
merge_request.mark_as_unchecked!
|
|
|
|
execute_service
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'does not change its state' do
|
|
|
|
expect(merge_request.reload).to be_unchecked
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when merge request is in preparing state' do
|
|
|
|
before do
|
2022-01-26 12:08:38 +05:30
|
|
|
merge_request.mark_as_unchecked! unless merge_request.unchecked?
|
2021-04-17 20:07:23 +05:30
|
|
|
merge_request.mark_as_preparing!
|
|
|
|
end
|
|
|
|
|
2022-04-04 11:22:00 +05:30
|
|
|
it 'checks for mergeability' do
|
|
|
|
expect(merge_request).to receive(:check_mergeability).with(async: true)
|
2022-01-26 12:08:38 +05:30
|
|
|
|
2022-04-04 11:22:00 +05:30
|
|
|
execute_service
|
2021-04-17 20:07:23 +05:30
|
|
|
end
|
2022-01-26 12:08:38 +05:30
|
|
|
|
|
|
|
context 'when preparing for mergeability fails' do
|
|
|
|
before do
|
|
|
|
# This is only one of the possible cases that can fail. This is to
|
|
|
|
# simulate a failure that happens during the service call.
|
|
|
|
allow(merge_request)
|
|
|
|
.to receive(:update_head_pipeline)
|
|
|
|
.and_raise(StandardError)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'does not mark the merge request as unchecked' do
|
|
|
|
expect { execute_service }.to raise_error(StandardError)
|
|
|
|
expect(merge_request.reload).to be_preparing
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when preparing merge request fails' do
|
|
|
|
before do
|
|
|
|
# This is only one of the possible cases that can fail. This is to
|
|
|
|
# simulate a failure that happens during the service call.
|
|
|
|
allow(merge_request)
|
|
|
|
.to receive_message_chain(:diffs, :write_cache)
|
|
|
|
.and_raise(StandardError)
|
|
|
|
end
|
|
|
|
|
2022-04-04 11:22:00 +05:30
|
|
|
it 'still checks for mergeability' do
|
|
|
|
expect(merge_request).to receive(:check_mergeability).with(async: true)
|
2022-01-26 12:08:38 +05:30
|
|
|
expect { execute_service }.to raise_error(StandardError)
|
|
|
|
end
|
|
|
|
end
|
2021-04-17 20:07:23 +05:30
|
|
|
end
|
2021-04-29 21:17:54 +05:30
|
|
|
|
2023-04-23 21:23:45 +05:30
|
|
|
it 'updates the prepared_at' do
|
|
|
|
# Need to reset the `prepared_at` since it can be already set in preceding tests.
|
|
|
|
merge_request.update!(prepared_at: nil)
|
|
|
|
|
|
|
|
freeze_time do
|
|
|
|
expect { execute_service }.to change { merge_request.prepared_at }
|
|
|
|
.from(nil)
|
|
|
|
.to(Time.current)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2021-04-29 21:17:54 +05:30
|
|
|
it 'increments the usage data counter of create event' do
|
|
|
|
counter = Gitlab::UsageDataCounters::MergeRequestCounter
|
|
|
|
|
|
|
|
expect { execute_service }.to change { counter.read(:create) }.by(1)
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'todos' do
|
|
|
|
it 'does not creates todos' do
|
|
|
|
attributes = {
|
|
|
|
project: merge_request.target_project,
|
|
|
|
target_id: merge_request.id,
|
|
|
|
target_type: merge_request.class.name
|
|
|
|
}
|
|
|
|
|
|
|
|
expect { execute_service }.not_to change { Todo.where(attributes).count }
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when merge request is assigned to someone' do
|
|
|
|
let_it_be(:assignee) { create(:user) }
|
|
|
|
let_it_be(:merge_request) { create(:merge_request, assignees: [assignee]) }
|
|
|
|
|
|
|
|
it 'creates a todo for new assignee' do
|
|
|
|
attributes = {
|
|
|
|
project: merge_request.target_project,
|
|
|
|
author: merge_request.author,
|
|
|
|
user: assignee,
|
|
|
|
target_id: merge_request.id,
|
|
|
|
target_type: merge_request.class.name,
|
|
|
|
action: Todo::ASSIGNED,
|
|
|
|
state: :pending
|
|
|
|
}
|
|
|
|
|
|
|
|
expect { execute_service }.to change { Todo.where(attributes).count }.by(1)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when reviewer is assigned' do
|
|
|
|
let_it_be(:reviewer) { create(:user) }
|
|
|
|
let_it_be(:merge_request) { create(:merge_request, reviewers: [reviewer]) }
|
|
|
|
|
|
|
|
it 'creates a todo for new reviewer' do
|
|
|
|
attributes = {
|
|
|
|
project: merge_request.target_project,
|
|
|
|
author: merge_request.author,
|
|
|
|
user: reviewer,
|
|
|
|
target_id: merge_request.id,
|
|
|
|
target_type: merge_request.class.name,
|
|
|
|
action: Todo::REVIEW_REQUESTED,
|
|
|
|
state: :pending
|
|
|
|
}
|
|
|
|
|
|
|
|
expect { execute_service }.to change { Todo.where(attributes).count }.by(1)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when saving references to issues that the created merge request closes' do
|
|
|
|
let_it_be(:first_issue) { create(:issue, project: merge_request.target_project) }
|
|
|
|
let_it_be(:second_issue) { create(:issue, project: merge_request.target_project) }
|
|
|
|
|
|
|
|
it 'creates a `MergeRequestsClosingIssues` record for each issue' do
|
|
|
|
merge_request.description = "Closes #{first_issue.to_reference} and #{second_issue.to_reference}"
|
|
|
|
merge_request.source_branch = "feature"
|
|
|
|
merge_request.target_branch = merge_request.target_project.default_branch
|
|
|
|
merge_request.save!
|
|
|
|
|
|
|
|
execute_service
|
|
|
|
|
|
|
|
issue_ids = MergeRequestsClosingIssues.where(merge_request: merge_request).pluck(:issue_id)
|
|
|
|
expect(issue_ids).to match_array([first_issue.id, second_issue.id])
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'tracks merge request creation in usage data' do
|
|
|
|
expect(Gitlab::UsageDataCounters::MergeRequestCounter).to receive(:count).with(:create)
|
|
|
|
|
|
|
|
execute_service
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'calls MergeRequests::LinkLfsObjectsService#execute' do
|
|
|
|
service = instance_spy(MergeRequests::LinkLfsObjectsService)
|
2021-06-08 01:23:25 +05:30
|
|
|
allow(MergeRequests::LinkLfsObjectsService).to receive(:new).with(project: merge_request.target_project).and_return(service)
|
2021-04-29 21:17:54 +05:30
|
|
|
|
|
|
|
execute_service
|
|
|
|
|
|
|
|
expect(service).to have_received(:execute).with(merge_request)
|
|
|
|
end
|
2020-04-08 14:13:33 +05:30
|
|
|
end
|
|
|
|
end
|