debian-mirror-gitlab/spec/services/merge_requests/refresh_service_spec.rb

537 lines
21 KiB
Ruby
Raw Normal View History

2015-04-26 12:48:37 +05:30
require 'spec_helper'
2017-09-10 17:25:29 +05:30
describe MergeRequests::RefreshService do
2018-03-17 18:26:18 +05:30
include ProjectForksHelper
2017-08-17 22:00:37 +05:30
let(:project) { create(:project, :repository) }
2015-04-26 12:48:37 +05:30
let(:user) { create(:user) }
2017-09-10 17:25:29 +05:30
let(:service) { described_class }
2015-04-26 12:48:37 +05:30
2016-08-24 12:49:21 +05:30
describe '#execute' do
2015-04-26 12:48:37 +05:30
before do
@user = create(:user)
group = create(:group)
group.add_owner(@user)
2017-08-17 22:00:37 +05:30
@project = create(:project, :repository, namespace: group)
2018-03-17 18:26:18 +05:30
@fork_project = fork_project(@project, @user, repository: true)
2015-09-11 14:41:01 +05:30
@merge_request = create(:merge_request,
source_project: @project,
2015-04-26 12:48:37 +05:30
source_branch: 'master',
target_branch: 'feature',
2015-12-23 02:04:40 +05:30
target_project: @project,
2017-08-17 22:00:37 +05:30
merge_when_pipeline_succeeds: true,
2015-12-23 02:04:40 +05:30
merge_user: @user)
2015-04-26 12:48:37 +05:30
2018-05-09 12:01:36 +05:30
@another_merge_request = create(:merge_request,
source_project: @project,
source_branch: 'master',
target_branch: 'test',
target_project: @project,
merge_when_pipeline_succeeds: true,
merge_user: @user)
2015-09-11 14:41:01 +05:30
@fork_merge_request = create(:merge_request,
source_project: @fork_project,
2015-04-26 12:48:37 +05:30
source_branch: 'master',
target_branch: 'feature',
target_project: @project)
2016-06-02 11:05:42 +05:30
@build_failed_todo = create(:todo,
:build_failed,
user: @user,
project: @project,
target: @merge_request,
author: @user)
@fork_build_failed_todo = create(:todo,
:build_failed,
user: @user,
project: @project,
target: @merge_request,
author: @user)
2015-04-26 12:48:37 +05:30
@commits = @merge_request.commits
@oldrev = @commits.last.id
@newrev = @commits.first.id
end
context 'push to origin repo source branch' do
2015-09-11 14:41:01 +05:30
let(:refresh_service) { service.new(@project, @user) }
2018-05-09 12:01:36 +05:30
let(:notification_service) { spy('notification_service') }
2017-08-17 22:00:37 +05:30
2015-04-26 12:48:37 +05:30
before do
2015-09-11 14:41:01 +05:30
allow(refresh_service).to receive(:execute_hooks)
2018-05-09 12:01:36 +05:30
allow(NotificationService).to receive(:new) { notification_service }
2015-04-26 12:48:37 +05:30
end
2016-09-13 17:45:13 +05:30
it 'executes hooks with update action' do
2018-03-17 18:26:18 +05:30
refresh_service.execute(@oldrev, @newrev, 'refs/heads/master')
reload_mrs
2017-09-10 17:25:29 +05:30
expect(refresh_service).to have_received(:execute_hooks)
2018-03-17 18:26:18 +05:30
.with(@merge_request, 'update', old_rev: @oldrev)
2017-08-17 22:00:37 +05:30
2018-05-09 12:01:36 +05:30
expect(notification_service).to have_received(:push_to_merge_request)
.with(@merge_request, @user, new_commits: anything, existing_commits: anything)
expect(notification_service).to have_received(:push_to_merge_request)
.with(@another_merge_request, @user, new_commits: anything, existing_commits: anything)
2017-08-17 22:00:37 +05:30
expect(@merge_request.notes).not_to be_empty
expect(@merge_request).to be_open
expect(@merge_request.merge_when_pipeline_succeeds).to be_falsey
expect(@merge_request.diff_head_sha).to eq(@newrev)
expect(@fork_merge_request).to be_open
expect(@fork_merge_request.notes).to be_empty
expect(@build_failed_todo).to be_done
expect(@fork_build_failed_todo).to be_done
end
2018-03-17 18:26:18 +05:30
it 'reloads source branch MRs memoization' do
refresh_service.execute(@oldrev, @newrev, 'refs/heads/master')
expect { refresh_service.execute(@oldrev, @newrev, 'refs/heads/master') }.to change {
refresh_service.instance_variable_get("@source_merge_requests").first.merge_request_diff
}
end
context 'when source branch ref does not exists' do
before do
DeleteBranchService.new(@project, @user).execute(@merge_request.source_branch)
end
it 'closes MRs without source branch ref' do
expect { refresh_service.execute(@oldrev, @newrev, 'refs/heads/master') }
.to change { @merge_request.reload.state }
.from('opened')
.to('closed')
expect(@fork_merge_request.reload).to be_open
end
it 'does not change the merge request diff' do
expect { refresh_service.execute(@oldrev, @newrev, 'refs/heads/master') }
.not_to change { @merge_request.reload.merge_request_diff }
end
end
end
context 'when pipeline exists for the source branch' do
let!(:pipeline) { create(:ci_empty_pipeline, ref: @merge_request.source_branch, project: @project, sha: @commits.first.sha)}
subject { service.new(@project, @user).execute(@oldrev, @newrev, 'refs/heads/master') }
it 'updates the head_pipeline_id for @merge_request' do
expect { subject }.to change { @merge_request.reload.head_pipeline_id }.from(nil).to(pipeline.id)
end
it 'does not update the head_pipeline_id for @fork_merge_request' do
expect { subject }.not_to change { @fork_merge_request.reload.head_pipeline_id }
end
2017-08-17 22:00:37 +05:30
end
context 'push to origin repo source branch when an MR was reopened' do
let(:refresh_service) { service.new(@project, @user) }
2018-05-09 12:01:36 +05:30
let(:notification_service) { spy('notification_service') }
2017-08-17 22:00:37 +05:30
before do
@merge_request.update(state: :reopened)
allow(refresh_service).to receive(:execute_hooks)
2018-05-09 12:01:36 +05:30
allow(NotificationService).to receive(:new) { notification_service }
2017-08-17 22:00:37 +05:30
refresh_service.execute(@oldrev, @newrev, 'refs/heads/master')
reload_mrs
2015-09-11 14:41:01 +05:30
end
2017-08-17 22:00:37 +05:30
it 'executes hooks with update action' do
2017-09-10 17:25:29 +05:30
expect(refresh_service).to have_received(:execute_hooks)
2018-03-17 18:26:18 +05:30
.with(@merge_request, 'update', old_rev: @oldrev)
2018-05-09 12:01:36 +05:30
expect(notification_service).to have_received(:push_to_merge_request)
.with(@merge_request, @user, new_commits: anything, existing_commits: anything)
expect(notification_service).to have_received(:push_to_merge_request)
.with(@another_merge_request, @user, new_commits: anything, existing_commits: anything)
2017-08-17 22:00:37 +05:30
expect(@merge_request.notes).not_to be_empty
expect(@merge_request).to be_open
expect(@merge_request.merge_when_pipeline_succeeds).to be_falsey
expect(@merge_request.diff_head_sha).to eq(@newrev)
expect(@fork_merge_request).to be_open
expect(@fork_merge_request.notes).to be_empty
expect(@build_failed_todo).to be_done
expect(@fork_build_failed_todo).to be_done
end
2015-04-26 12:48:37 +05:30
end
context 'push to origin repo target branch' do
2017-09-10 17:25:29 +05:30
context 'when all MRs to the target branch had diffs' do
before do
service.new(@project, @user).execute(@oldrev, @newrev, 'refs/heads/feature')
reload_mrs
end
it 'updates the merge state' do
expect(@merge_request.notes.last.note).to include('merged')
expect(@merge_request).to be_merged
expect(@fork_merge_request).to be_merged
expect(@fork_merge_request.notes.last.note).to include('merged')
expect(@build_failed_todo).to be_done
expect(@fork_build_failed_todo).to be_done
end
2015-04-26 12:48:37 +05:30
end
2017-09-10 17:25:29 +05:30
context 'when an MR to be closed was empty already' do
let!(:empty_fork_merge_request) do
create(:merge_request,
source_project: @fork_project,
source_branch: 'master',
target_branch: 'master',
target_project: @project)
end
before do
# This spec already has a fake push, so pretend that we were targeting
# feature all along.
empty_fork_merge_request.update_columns(target_branch: 'feature')
service.new(@project, @user).execute(@oldrev, @newrev, 'refs/heads/feature')
reload_mrs
empty_fork_merge_request.reload
end
it 'only updates the non-empty MRs' do
expect(@merge_request).to be_merged
expect(@merge_request.notes.last.note).to include('merged')
expect(@fork_merge_request).to be_merged
expect(@fork_merge_request.notes.last.note).to include('merged')
expect(empty_fork_merge_request).to be_open
expect(empty_fork_merge_request.merge_request_diff.state).to eq('empty')
expect(empty_fork_merge_request.notes).to be_empty
end
2017-08-17 22:00:37 +05:30
end
2015-04-26 12:48:37 +05:30
end
2015-11-26 14:37:03 +05:30
context 'manual merge of source branch' do
before do
# Merge master -> feature branch
2018-03-17 18:26:18 +05:30
@project.repository.merge(@user, @merge_request.diff_head_sha, @merge_request, 'Test message')
2015-11-26 14:37:03 +05:30
commit = @project.repository.commit('feature')
service.new(@project, @user).execute(@oldrev, commit.id, 'refs/heads/feature')
reload_mrs
end
2017-08-17 22:00:37 +05:30
it 'updates the merge state' do
expect(@merge_request.notes.last.note).to include('merged')
expect(@merge_request).to be_merged
expect(@merge_request.diffs.size).to be > 0
expect(@fork_merge_request).to be_merged
expect(@fork_merge_request.notes.last.note).to include('merged')
expect(@build_failed_todo).to be_done
expect(@fork_build_failed_todo).to be_done
end
2015-11-26 14:37:03 +05:30
end
2015-04-26 12:48:37 +05:30
context 'push to fork repo source branch' do
2015-09-11 14:41:01 +05:30
let(:refresh_service) { service.new(@fork_project, @user) }
2015-04-26 12:48:37 +05:30
2017-08-17 22:00:37 +05:30
context 'open fork merge request' do
before do
allow(refresh_service).to receive(:execute_hooks)
refresh_service.execute(@oldrev, @newrev, 'refs/heads/master')
reload_mrs
end
it 'executes hooks with update action' do
2017-09-10 17:25:29 +05:30
expect(refresh_service).to have_received(:execute_hooks)
2018-03-17 18:26:18 +05:30
.with(@fork_merge_request, 'update', old_rev: @oldrev)
2017-08-17 22:00:37 +05:30
expect(@merge_request.notes).to be_empty
expect(@merge_request).to be_open
expect(@fork_merge_request.notes.last.note).to include('added 28 commits')
expect(@fork_merge_request).to be_open
expect(@build_failed_todo).to be_pending
expect(@fork_build_failed_todo).to be_pending
end
2015-09-11 14:41:01 +05:30
end
2017-08-17 22:00:37 +05:30
context 'closed fork merge request' do
before do
@fork_merge_request.close!
allow(refresh_service).to receive(:execute_hooks)
refresh_service.execute(@oldrev, @newrev, 'refs/heads/master')
reload_mrs
end
it 'do not execute hooks with update action' do
expect(refresh_service).not_to have_received(:execute_hooks)
end
it 'updates merge request to closed state' do
expect(@merge_request.notes).to be_empty
expect(@merge_request).to be_open
expect(@fork_merge_request.notes).to be_empty
expect(@fork_merge_request).to be_closed
expect(@build_failed_todo).to be_pending
expect(@fork_build_failed_todo).to be_pending
end
end
2015-04-26 12:48:37 +05:30
end
context 'push to fork repo target branch' do
2017-08-17 22:00:37 +05:30
describe 'changes to merge requests' do
before do
service.new(@fork_project, @user).execute(@oldrev, @newrev, 'refs/heads/feature')
reload_mrs
end
it 'updates the merge request state' do
expect(@merge_request.notes).to be_empty
expect(@merge_request).to be_open
expect(@fork_merge_request.notes).to be_empty
expect(@fork_merge_request).to be_open
expect(@build_failed_todo).to be_pending
expect(@fork_build_failed_todo).to be_pending
end
2015-04-26 12:48:37 +05:30
end
2017-08-17 22:00:37 +05:30
describe 'merge request diff' do
it 'does not reload the diff of the merge request made from fork' do
expect do
service.new(@fork_project, @user).execute(@oldrev, @newrev, 'refs/heads/feature')
end.not_to change { @fork_merge_request.reload.merge_request_diff }
end
end
2015-04-26 12:48:37 +05:30
end
2018-12-13 13:39:08 +05:30
context 'forked projects with the same source branch name as target branch' do
let!(:first_commit) do
@fork_project.repository.create_file(@user, 'test1.txt', 'Test data',
message: 'Test commit',
branch_name: 'master')
end
let!(:second_commit) do
@fork_project.repository.create_file(@user, 'test2.txt', 'More test data',
message: 'Second test commit',
branch_name: 'master')
end
let!(:forked_master_mr) do
create(:merge_request,
source_project: @fork_project,
source_branch: 'master',
target_branch: 'master',
target_project: @project)
end
let(:force_push_commit) { @project.commit('feature').id }
it 'should reload a new diff for a push to the forked project' do
expect do
service.new(@fork_project, @user).execute(@oldrev, first_commit, 'refs/heads/master')
reload_mrs
end.to change { forked_master_mr.merge_request_diffs.count }.by(1)
end
it 'should reload a new diff for a force push to the source branch' do
expect do
service.new(@fork_project, @user).execute(@oldrev, force_push_commit, 'refs/heads/master')
reload_mrs
end.to change { forked_master_mr.merge_request_diffs.count }.by(1)
end
it 'should reload a new diff for a force push to the target branch' do
expect do
service.new(@project, @user).execute(@oldrev, force_push_commit, 'refs/heads/master')
reload_mrs
end.to change { forked_master_mr.merge_request_diffs.count }.by(1)
end
it 'should reload a new diff for a push to the target project that contains a commit in the MR' do
expect do
service.new(@project, @user).execute(@oldrev, first_commit, 'refs/heads/master')
reload_mrs
end.to change { forked_master_mr.merge_request_diffs.count }.by(1)
end
it 'should not increase the diff count for a new push to target branch' do
new_commit = @project.repository.create_file(@user, 'new-file.txt', 'A new file',
message: 'This is a test',
branch_name: 'master')
expect do
service.new(@project, @user).execute(@newrev, new_commit, 'refs/heads/master')
reload_mrs
end.not_to change { forked_master_mr.merge_request_diffs.count }
end
end
2015-04-26 12:48:37 +05:30
context 'push to origin repo target branch after fork project was removed' do
before do
@fork_project.destroy
service.new(@project, @user).execute(@oldrev, @newrev, 'refs/heads/feature')
reload_mrs
end
2017-08-17 22:00:37 +05:30
it 'updates the merge request state' do
expect(@merge_request.notes.last.note).to include('merged')
expect(@merge_request).to be_merged
expect(@fork_merge_request).to be_open
expect(@fork_merge_request.notes).to be_empty
expect(@build_failed_todo).to be_done
expect(@fork_build_failed_todo).to be_done
end
2015-04-26 12:48:37 +05:30
end
2015-10-24 18:46:33 +05:30
context 'push new branch that exists in a merge request' do
let(:refresh_service) { service.new(@fork_project, @user) }
it 'refreshes the merge request' do
2017-09-10 17:25:29 +05:30
expect(refresh_service).to receive(:execute_hooks)
2018-03-17 18:26:18 +05:30
.with(@fork_merge_request, 'update', old_rev: Gitlab::Git::BLANK_SHA)
2015-10-24 18:46:33 +05:30
allow_any_instance_of(Repository).to receive(:merge_base).and_return(@oldrev)
refresh_service.execute(Gitlab::Git::BLANK_SHA, @newrev, 'refs/heads/master')
reload_mrs
expect(@merge_request.notes).to be_empty
expect(@merge_request).to be_open
notes = @fork_merge_request.notes.reorder(:created_at).map(&:note)
2017-08-17 22:00:37 +05:30
expect(notes[0]).to include('restored source branch `master`')
expect(notes[1]).to include('added 28 commits')
2015-10-24 18:46:33 +05:30
expect(@fork_merge_request).to be_open
end
end
2016-09-29 09:46:39 +05:30
context 'merge request metrics' do
let(:issue) { create :issue, project: @project }
let(:commit_author) { create :user }
let(:commit) { project.commit }
before do
2018-03-17 18:26:18 +05:30
project.add_developer(commit_author)
project.add_developer(user)
2016-09-29 09:46:39 +05:30
allow(commit).to receive_messages(
safe_message: "Closes #{issue.to_reference}",
references: [issue],
author_name: commit_author.name,
author_email: commit_author.email,
committed_date: Time.now
)
allow_any_instance_of(MergeRequest).to receive(:commits).and_return([commit])
end
context 'when the merge request is sourced from the same project' do
it 'creates a `MergeRequestsClosingIssues` record for each issue closed by a commit' do
merge_request = create(:merge_request, target_branch: 'master', source_branch: 'feature', source_project: @project)
refresh_service = service.new(@project, @user)
allow(refresh_service).to receive(:execute_hooks)
refresh_service.execute(@oldrev, @newrev, 'refs/heads/feature')
issue_ids = MergeRequestsClosingIssues.where(merge_request: merge_request).pluck(:issue_id)
expect(issue_ids).to eq([issue.id])
end
end
context 'when the merge request is sourced from a different project' do
it 'creates a `MergeRequestsClosingIssues` record for each issue closed by a commit' do
2018-03-17 18:26:18 +05:30
forked_project = fork_project(@project, @user, repository: true)
2016-09-29 09:46:39 +05:30
merge_request = create(:merge_request,
target_branch: 'master',
source_branch: 'feature',
target_project: @project,
source_project: forked_project)
refresh_service = service.new(@project, @user)
allow(refresh_service).to receive(:execute_hooks)
refresh_service.execute(@oldrev, @newrev, 'refs/heads/feature')
issue_ids = MergeRequestsClosingIssues.where(merge_request: merge_request).pluck(:issue_id)
expect(issue_ids).to eq([issue.id])
end
end
end
2017-08-17 22:00:37 +05:30
context 'marking the merge request as work in progress' do
let(:refresh_service) { service.new(@project, @user) }
before do
allow(refresh_service).to receive(:execute_hooks)
end
it 'marks the merge request as work in progress from fixup commits' do
fixup_merge_request = create(:merge_request,
source_project: @project,
source_branch: 'wip',
target_branch: 'master',
target_project: @project)
commits = fixup_merge_request.commits
oldrev = commits.last.id
newrev = commits.first.id
refresh_service.execute(oldrev, newrev, 'refs/heads/wip')
fixup_merge_request.reload
expect(fixup_merge_request.work_in_progress?).to eq(true)
expect(fixup_merge_request.notes.last.note).to match(
/marked as a \*\*Work In Progress\*\* from #{Commit.reference_pattern}/
)
end
it 'references the commit that caused the Work in Progress status' do
2018-03-17 18:26:18 +05:30
wip_merge_request = create(:merge_request,
source_project: @project,
source_branch: 'wip',
target_branch: 'master',
target_project: @project)
commits = wip_merge_request.commits
oldrev = commits.last.id
newrev = commits.first.id
wip_commit = wip_merge_request.commits.find(&:work_in_progress?)
refresh_service.execute(oldrev, newrev, 'refs/heads/wip')
expect(wip_merge_request.reload.notes.last.note).to eq(
"marked as a **Work In Progress** from #{wip_commit.id}"
2017-08-17 22:00:37 +05:30
)
end
it 'does not mark as WIP based on commits that do not belong to an MR' do
allow(refresh_service).to receive(:find_new_commits)
refresh_service.instance_variable_set("@commits", [
double(
id: 'aaaaaaa',
sha: 'aaaaaaa',
short_id: 'aaaaaaa',
title: 'Fix issue',
work_in_progress?: false
),
double(
id: 'bbbbbbb',
sha: 'bbbbbbbb',
short_id: 'bbbbbbb',
title: 'fixup! Fix issue',
work_in_progress?: true,
to_reference: 'bbbbbbb'
)
])
refresh_service.execute(@oldrev, @newrev, 'refs/heads/master')
reload_mrs
expect(@merge_request.work_in_progress?).to be_falsey
end
end
2015-04-26 12:48:37 +05:30
def reload_mrs
@merge_request.reload
@fork_merge_request.reload
2016-06-02 11:05:42 +05:30
@build_failed_todo.reload
@fork_build_failed_todo.reload
2015-04-26 12:48:37 +05:30
end
end
end