2018-03-17 18:26:18 +05:30
|
|
|
require 'spec_helper'
|
|
|
|
|
|
|
|
describe Gitlab::GithubImport::Importer::PullRequestImporter, :clean_gitlab_redis_cache do
|
|
|
|
let(:project) { create(:project, :repository) }
|
|
|
|
let(:client) { double(:client) }
|
|
|
|
let(:user) { create(:user) }
|
|
|
|
let(:created_at) { Time.new(2017, 1, 1, 12, 00) }
|
|
|
|
let(:updated_at) { Time.new(2017, 1, 1, 12, 15) }
|
|
|
|
let(:merged_at) { Time.new(2017, 1, 1, 12, 17) }
|
|
|
|
|
|
|
|
let(:source_commit) { project.repository.commit('feature') }
|
|
|
|
let(:target_commit) { project.repository.commit('master') }
|
|
|
|
let(:milestone) { create(:milestone, project: project) }
|
2019-07-07 11:18:12 +05:30
|
|
|
let(:state) { :closed }
|
2018-03-17 18:26:18 +05:30
|
|
|
|
|
|
|
let(:pull_request) do
|
|
|
|
alice = Gitlab::GithubImport::Representation::User.new(id: 4, login: 'alice')
|
|
|
|
|
|
|
|
Gitlab::GithubImport::Representation::PullRequest.new(
|
|
|
|
iid: 42,
|
|
|
|
title: 'My Pull Request',
|
|
|
|
description: 'This is my pull request',
|
|
|
|
source_branch: 'feature',
|
|
|
|
source_branch_sha: source_commit.id,
|
|
|
|
target_branch: 'master',
|
|
|
|
target_branch_sha: target_commit.id,
|
|
|
|
source_repository_id: 400,
|
|
|
|
target_repository_id: 200,
|
|
|
|
source_repository_owner: 'alice',
|
2019-07-07 11:18:12 +05:30
|
|
|
state: state,
|
2018-03-17 18:26:18 +05:30
|
|
|
milestone_number: milestone.iid,
|
|
|
|
author: alice,
|
|
|
|
assignee: alice,
|
|
|
|
created_at: created_at,
|
|
|
|
updated_at: updated_at,
|
2019-07-07 11:18:12 +05:30
|
|
|
merged_at: state == :closed && merged_at
|
2018-03-17 18:26:18 +05:30
|
|
|
)
|
|
|
|
end
|
|
|
|
|
|
|
|
let(:importer) { described_class.new(pull_request, project, client) }
|
|
|
|
|
|
|
|
describe '#execute' do
|
|
|
|
it 'imports the pull request' do
|
2018-11-08 19:23:39 +05:30
|
|
|
mr = double(:merge_request, id: 10)
|
|
|
|
|
2018-03-17 18:26:18 +05:30
|
|
|
expect(importer)
|
|
|
|
.to receive(:create_merge_request)
|
2018-11-08 19:23:39 +05:30
|
|
|
.and_return([mr, false])
|
|
|
|
|
|
|
|
expect(importer)
|
|
|
|
.to receive(:insert_git_data)
|
|
|
|
.with(mr, false)
|
2018-03-17 18:26:18 +05:30
|
|
|
|
|
|
|
expect_any_instance_of(Gitlab::GithubImport::IssuableFinder)
|
|
|
|
.to receive(:cache_database_id)
|
2018-11-08 19:23:39 +05:30
|
|
|
.with(mr.id)
|
2018-03-17 18:26:18 +05:30
|
|
|
|
|
|
|
importer.execute
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
describe '#create_merge_request' do
|
|
|
|
before do
|
|
|
|
allow(importer.milestone_finder)
|
|
|
|
.to receive(:id_for)
|
|
|
|
.with(pull_request)
|
|
|
|
.and_return(milestone.id)
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when the author could be found' do
|
|
|
|
before do
|
|
|
|
allow(importer.user_finder)
|
|
|
|
.to receive(:author_id_for)
|
|
|
|
.with(pull_request)
|
|
|
|
.and_return([user.id, true])
|
|
|
|
|
|
|
|
allow(importer.user_finder)
|
|
|
|
.to receive(:assignee_id_for)
|
|
|
|
.with(pull_request)
|
|
|
|
.and_return(user.id)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'imports the pull request with the pull request author as the merge request author' do
|
2018-11-20 20:47:30 +05:30
|
|
|
expect(importer)
|
2018-03-17 18:26:18 +05:30
|
|
|
.to receive(:insert_and_return_id)
|
|
|
|
.with(
|
|
|
|
{
|
|
|
|
iid: 42,
|
|
|
|
title: 'My Pull Request',
|
|
|
|
description: 'This is my pull request',
|
|
|
|
source_project_id: project.id,
|
|
|
|
target_project_id: project.id,
|
2019-03-02 22:35:43 +05:30
|
|
|
source_branch: 'github/fork/alice/feature',
|
2018-03-17 18:26:18 +05:30
|
|
|
target_branch: 'master',
|
|
|
|
state: :merged,
|
2019-07-31 22:56:46 +05:30
|
|
|
state_id: 3,
|
2018-03-17 18:26:18 +05:30
|
|
|
milestone_id: milestone.id,
|
|
|
|
author_id: user.id,
|
|
|
|
assignee_id: user.id,
|
|
|
|
created_at: created_at,
|
|
|
|
updated_at: updated_at
|
|
|
|
},
|
|
|
|
project.merge_requests
|
|
|
|
)
|
|
|
|
.and_call_original
|
|
|
|
|
|
|
|
importer.create_merge_request
|
|
|
|
end
|
|
|
|
|
2018-11-08 19:23:39 +05:30
|
|
|
it 'returns the created merge request' do
|
|
|
|
mr, exists = importer.create_merge_request
|
2018-03-17 18:26:18 +05:30
|
|
|
|
2018-11-08 19:23:39 +05:30
|
|
|
expect(mr).to be_instance_of(MergeRequest)
|
|
|
|
expect(exists).to eq(false)
|
2018-03-17 18:26:18 +05:30
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when the author could not be found' do
|
|
|
|
it 'imports the pull request with the project creator as the merge request author' do
|
|
|
|
allow(importer.user_finder)
|
|
|
|
.to receive(:author_id_for)
|
|
|
|
.with(pull_request)
|
|
|
|
.and_return([project.creator_id, false])
|
|
|
|
|
|
|
|
allow(importer.user_finder)
|
|
|
|
.to receive(:assignee_id_for)
|
|
|
|
.with(pull_request)
|
|
|
|
.and_return(user.id)
|
|
|
|
|
2018-11-20 20:47:30 +05:30
|
|
|
expect(importer)
|
2018-03-17 18:26:18 +05:30
|
|
|
.to receive(:insert_and_return_id)
|
|
|
|
.with(
|
|
|
|
{
|
|
|
|
iid: 42,
|
|
|
|
title: 'My Pull Request',
|
|
|
|
description: "*Created by: alice*\n\nThis is my pull request",
|
|
|
|
source_project_id: project.id,
|
|
|
|
target_project_id: project.id,
|
2019-03-02 22:35:43 +05:30
|
|
|
source_branch: 'github/fork/alice/feature',
|
2018-03-17 18:26:18 +05:30
|
|
|
target_branch: 'master',
|
|
|
|
state: :merged,
|
2019-07-31 22:56:46 +05:30
|
|
|
state_id: 3,
|
2018-03-17 18:26:18 +05:30
|
|
|
milestone_id: milestone.id,
|
|
|
|
author_id: project.creator_id,
|
|
|
|
assignee_id: user.id,
|
|
|
|
created_at: created_at,
|
|
|
|
updated_at: updated_at
|
|
|
|
},
|
|
|
|
project.merge_requests
|
|
|
|
)
|
|
|
|
.and_call_original
|
|
|
|
|
|
|
|
importer.create_merge_request
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when the source and target branch are identical' do
|
|
|
|
it 'uses a generated source branch name for the merge request' do
|
|
|
|
allow(importer.user_finder)
|
|
|
|
.to receive(:author_id_for)
|
|
|
|
.with(pull_request)
|
|
|
|
.and_return([user.id, true])
|
|
|
|
|
|
|
|
allow(importer.user_finder)
|
|
|
|
.to receive(:assignee_id_for)
|
|
|
|
.with(pull_request)
|
|
|
|
.and_return(user.id)
|
|
|
|
|
|
|
|
allow(pull_request)
|
|
|
|
.to receive(:source_repository_id)
|
|
|
|
.and_return(pull_request.target_repository_id)
|
|
|
|
|
|
|
|
allow(pull_request)
|
|
|
|
.to receive(:source_branch)
|
|
|
|
.and_return('master')
|
|
|
|
|
2018-11-20 20:47:30 +05:30
|
|
|
expect(importer)
|
2018-03-17 18:26:18 +05:30
|
|
|
.to receive(:insert_and_return_id)
|
|
|
|
.with(
|
|
|
|
{
|
|
|
|
iid: 42,
|
|
|
|
title: 'My Pull Request',
|
|
|
|
description: 'This is my pull request',
|
|
|
|
source_project_id: project.id,
|
|
|
|
target_project_id: project.id,
|
|
|
|
source_branch: 'master-42',
|
|
|
|
target_branch: 'master',
|
|
|
|
state: :merged,
|
2019-07-31 22:56:46 +05:30
|
|
|
state_id: 3,
|
2018-03-17 18:26:18 +05:30
|
|
|
milestone_id: milestone.id,
|
|
|
|
author_id: user.id,
|
|
|
|
assignee_id: user.id,
|
|
|
|
created_at: created_at,
|
|
|
|
updated_at: updated_at
|
|
|
|
},
|
|
|
|
project.merge_requests
|
|
|
|
)
|
|
|
|
.and_call_original
|
|
|
|
|
|
|
|
importer.create_merge_request
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when the import fails due to a foreign key error' do
|
|
|
|
it 'does not raise any errors' do
|
|
|
|
allow(importer.user_finder)
|
|
|
|
.to receive(:author_id_for)
|
|
|
|
.with(pull_request)
|
|
|
|
.and_return([user.id, true])
|
|
|
|
|
|
|
|
allow(importer.user_finder)
|
|
|
|
.to receive(:assignee_id_for)
|
|
|
|
.with(pull_request)
|
|
|
|
.and_return(user.id)
|
|
|
|
|
2018-11-20 20:47:30 +05:30
|
|
|
expect(importer)
|
2018-03-17 18:26:18 +05:30
|
|
|
.to receive(:insert_and_return_id)
|
|
|
|
.and_raise(ActiveRecord::InvalidForeignKey, 'invalid foreign key')
|
|
|
|
|
|
|
|
expect { importer.create_merge_request }.not_to raise_error
|
|
|
|
end
|
|
|
|
end
|
2018-11-08 19:23:39 +05:30
|
|
|
|
|
|
|
context 'when the merge request already exists' do
|
|
|
|
before do
|
|
|
|
allow(importer.user_finder)
|
|
|
|
.to receive(:author_id_for)
|
|
|
|
.with(pull_request)
|
|
|
|
.and_return([user.id, true])
|
|
|
|
|
|
|
|
allow(importer.user_finder)
|
|
|
|
.to receive(:assignee_id_for)
|
|
|
|
.with(pull_request)
|
|
|
|
.and_return(user.id)
|
|
|
|
end
|
|
|
|
|
2019-01-03 12:48:30 +05:30
|
|
|
it 'returns the existing merge request' do
|
2018-11-08 19:23:39 +05:30
|
|
|
mr1, exists1 = importer.create_merge_request
|
|
|
|
mr2, exists2 = importer.create_merge_request
|
|
|
|
|
|
|
|
expect(mr2).to eq(mr1)
|
|
|
|
expect(exists1).to eq(false)
|
|
|
|
expect(exists2).to eq(true)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
describe '#insert_git_data' do
|
|
|
|
before do
|
|
|
|
allow(importer.milestone_finder)
|
|
|
|
.to receive(:id_for)
|
|
|
|
.with(pull_request)
|
|
|
|
.and_return(milestone.id)
|
|
|
|
|
|
|
|
allow(importer.user_finder)
|
|
|
|
.to receive(:author_id_for)
|
|
|
|
.with(pull_request)
|
|
|
|
.and_return([user.id, true])
|
|
|
|
|
|
|
|
allow(importer.user_finder)
|
|
|
|
.to receive(:assignee_id_for)
|
|
|
|
.with(pull_request)
|
|
|
|
.and_return(user.id)
|
|
|
|
end
|
|
|
|
|
2019-03-02 22:35:43 +05:30
|
|
|
it 'does not create the source branch if merge request is merged' do
|
2019-07-07 11:18:12 +05:30
|
|
|
mr = insert_git_data
|
2019-03-02 22:35:43 +05:30
|
|
|
|
|
|
|
expect(project.repository.branch_exists?(mr.source_branch)).to be_falsey
|
|
|
|
expect(project.repository.branch_exists?(mr.target_branch)).to be_truthy
|
|
|
|
end
|
|
|
|
|
2019-07-07 11:18:12 +05:30
|
|
|
context 'when merge request is open' do
|
|
|
|
let(:state) { :opened }
|
2019-03-02 22:35:43 +05:30
|
|
|
|
2019-07-07 11:18:12 +05:30
|
|
|
it 'creates the source branch' do
|
|
|
|
# Ensure the project creator is creating the branches because the
|
|
|
|
# merge request author may not have access to push to this
|
|
|
|
# repository. The project owner may also be a group.
|
|
|
|
allow(project.repository).to receive(:add_branch).with(project.creator, anything, anything).and_call_original
|
2019-05-18 00:54:41 +05:30
|
|
|
|
2019-07-07 11:18:12 +05:30
|
|
|
mr = insert_git_data
|
2019-05-18 00:54:41 +05:30
|
|
|
|
2019-07-07 11:18:12 +05:30
|
|
|
expect(project.repository.branch_exists?(mr.source_branch)).to be_truthy
|
|
|
|
expect(project.repository.branch_exists?(mr.target_branch)).to be_truthy
|
|
|
|
end
|
2019-05-18 00:54:41 +05:30
|
|
|
|
2019-07-07 11:18:12 +05:30
|
|
|
it 'is able to retry on pre-receive errors' do
|
|
|
|
expect(importer).to receive(:insert_or_replace_git_data).twice.and_call_original
|
|
|
|
expect(project.repository).to receive(:add_branch).and_raise('exception')
|
2019-05-18 00:54:41 +05:30
|
|
|
|
2019-07-07 11:18:12 +05:30
|
|
|
expect { insert_git_data }.to raise_error('exception')
|
2019-05-18 00:54:41 +05:30
|
|
|
|
2019-07-07 11:18:12 +05:30
|
|
|
expect(project.repository).to receive(:add_branch).with(project.creator, anything, anything).and_call_original
|
|
|
|
|
|
|
|
mr = insert_git_data
|
|
|
|
|
|
|
|
expect(project.repository.branch_exists?(mr.source_branch)).to be_truthy
|
|
|
|
expect(project.repository.branch_exists?(mr.target_branch)).to be_truthy
|
|
|
|
expect(mr.merge_request_diffs).to be_one
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'ignores Git command errors when creating a branch' do
|
|
|
|
expect(project.repository).to receive(:add_branch).and_raise(Gitlab::Git::CommandError)
|
|
|
|
expect(Gitlab::Sentry).to receive(:track_acceptable_exception).and_call_original
|
|
|
|
|
|
|
|
mr = insert_git_data
|
|
|
|
|
|
|
|
expect(project.repository.branch_exists?(mr.source_branch)).to be_falsey
|
|
|
|
expect(project.repository.branch_exists?(mr.target_branch)).to be_truthy
|
|
|
|
end
|
2019-03-02 22:35:43 +05:30
|
|
|
end
|
|
|
|
|
2018-11-08 19:23:39 +05:30
|
|
|
it 'creates the merge request diffs' do
|
2019-07-07 11:18:12 +05:30
|
|
|
mr = insert_git_data
|
2018-11-08 19:23:39 +05:30
|
|
|
|
|
|
|
expect(mr.merge_request_diffs.exists?).to eq(true)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'creates the merge request diff commits' do
|
2019-07-07 11:18:12 +05:30
|
|
|
mr = insert_git_data
|
2018-11-08 19:23:39 +05:30
|
|
|
|
2019-07-07 11:18:12 +05:30
|
|
|
diff = mr.merge_request_diffs.reload.first
|
2018-11-08 19:23:39 +05:30
|
|
|
|
|
|
|
expect(diff.merge_request_diff_commits.exists?).to eq(true)
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when the merge request exists' do
|
|
|
|
it 'creates the merge request diffs if they do not yet exist' do
|
|
|
|
mr, _ = importer.create_merge_request
|
|
|
|
|
|
|
|
mr.merge_request_diffs.delete_all
|
|
|
|
|
|
|
|
importer.insert_git_data(mr, true)
|
|
|
|
|
|
|
|
expect(mr.merge_request_diffs.exists?).to eq(true)
|
|
|
|
end
|
|
|
|
end
|
2019-07-07 11:18:12 +05:30
|
|
|
|
|
|
|
def insert_git_data
|
|
|
|
mr, exists = importer.create_merge_request
|
|
|
|
importer.insert_git_data(mr, exists)
|
|
|
|
mr
|
|
|
|
end
|
2018-03-17 18:26:18 +05:30
|
|
|
end
|
|
|
|
end
|