Newer
Older
subject { create(:merge_request) }
describe 'associations' do
it { is_expected.to belong_to(:target_project).with_foreign_key(:target_project_id).class_name('Project') }
it { is_expected.to belong_to(:source_project).with_foreign_key(:source_project_id).class_name('Project') }
it { is_expected.to belong_to(:merge_user).class_name("User") }
it { is_expected.to have_many(:merge_request_diffs).dependent(:destroy) }
describe 'modules' do
subject { described_class }
it { is_expected.to include_module(InternalId) }
it { is_expected.to include_module(Issuable) }
it { is_expected.to include_module(Referable) }
it { is_expected.to include_module(Sortable) }
it { is_expected.to include_module(Taskable) }
end
describe "act_as_paranoid" do
it { is_expected.to have_db_column(:deleted_at) }
it { is_expected.to have_db_index(:deleted_at) }
end
describe 'validation' do
it { is_expected.to validate_presence_of(:target_branch) }
it { is_expected.to validate_presence_of(:source_branch) }
context "Validation of merge user with Merge When Build succeeds" do
it "allows user to be nil when the feature is disabled" do
expect(subject).to be_valid
end
it "is invalid without merge user" do
subject.merge_when_build_succeeds = true
expect(subject).not_to be_valid
end
it "is valid with merge user" do
subject.merge_when_build_succeeds = true
subject.merge_user = build(:user)
expect(subject).to be_valid
end
end
it { is_expected.to respond_to(:unchecked?) }
it { is_expected.to respond_to(:can_be_merged?) }
it { is_expected.to respond_to(:cannot_be_merged?) }
it { is_expected.to respond_to(:merge_params) }
it { is_expected.to respond_to(:merge_when_build_succeeds) }
describe '.in_projects' do
it 'returns the merge requests for a set of projects' do
expect(described_class.in_projects(Project.all)).to eq([subject])
end
end
Douwe Maan
committed
describe '#target_branch_sha' do
Douglas Barbosa Alexandre
committed
let(:project) { create(:project) }
Douglas Barbosa Alexandre
committed
Douglas Barbosa Alexandre
committed
subject { create(:merge_request, source_project: project, target_project: project) }
Douglas Barbosa Alexandre
committed
Douglas Barbosa Alexandre
committed
context 'when the target branch does not exist' do
Douglas Barbosa Alexandre
committed
before do
project.repository.raw_repository.delete_branch(subject.target_branch)
end
it 'returns nil' do
Douwe Maan
committed
expect(subject.target_branch_sha).to be_nil
end
end
Douglas Barbosa Alexandre
committed
it 'returns memoized value' do
subject.target_branch_sha = '8ffb3c15a5475e59ae909384297fede4badcb4c7'
expect(subject.target_branch_sha).to eq '8ffb3c15a5475e59ae909384297fede4badcb4c7'
end
Douwe Maan
committed
describe '#source_branch_sha' do
let(:last_branch_commit) { subject.source_project.repository.commit(subject.source_branch) }
context 'with diffs' do
subject { create(:merge_request, :with_diffs) }
it 'returns the sha of the source branch last commit' do
Douwe Maan
committed
expect(subject.source_branch_sha).to eq(last_branch_commit.sha)
context 'without diffs' do
subject { create(:merge_request, :without_diffs) }
it 'returns the sha of the source branch last commit' do
Douwe Maan
committed
expect(subject.source_branch_sha).to eq(last_branch_commit.sha)
end
end
context 'when the merge request is being created' do
subject { build(:merge_request, source_branch: nil, compare_commits: []) }
it 'returns nil' do
Douwe Maan
committed
expect(subject.source_branch_sha).to be_nil
Douglas Barbosa Alexandre
committed
it 'returns memoized value' do
subject.source_branch_sha = '2e5d3239642f9161dcbbc4b70a211a68e5e45e2b'
expect(subject.source_branch_sha).to eq '2e5d3239642f9161dcbbc4b70a211a68e5e45e2b'
end
describe '#to_reference' do
it 'returns a String reference to the object' do
expect(subject.to_reference).to eq "!#{subject.iid}"
end
it 'supports a cross-project reference' do
cross = double('project')
expect(subject.to_reference(cross)).to eq "#{subject.source_project.to_reference}!#{subject.iid}"
end
let(:merge_request) { build(:merge_request) }
let(:options) { { paths: ['a/b', 'b/a', 'c/*'] } }
context 'when there are MR diffs' do
it 'delegates to the MR diffs' do
merge_request.merge_request_diff = MergeRequestDiff.new
expect(merge_request.merge_request_diff).to receive(:raw_diffs).with(options)
merge_request.raw_diffs(options)
end
end
context 'when there are no MR diffs' do
it 'delegates to the compare object' do
merge_request.compare = double(:compare)
expect(merge_request.compare).to receive(:raw_diffs).with(options)
merge_request.raw_diffs(options)
end
end
end
describe '#diffs' do
let(:merge_request) { build(:merge_request) }
let(:options) { { paths: ['a/b', 'b/a', 'c/*'] } }
context 'when there are MR diffs' do
it 'delegates to the MR diffs' do
expect(merge_request.merge_request_diff).to receive(:raw_diffs).with(hash_including(options))
merge_request.diffs(options)
end
end
context 'when there are no MR diffs' do
it 'delegates to the compare object' do
merge_request.compare = double(:compare)
expect(merge_request.compare).to receive(:diffs).with(options)
merge_request.diffs(options)
end
end
end
describe "#mr_and_commit_notes" do
let!(:merge_request) { create(:merge_request) }
allow(merge_request).to receive(:commits) { [merge_request.source_project.repository.commit] }
create(:note_on_commit, commit_id: merge_request.commits.first.id,
project: merge_request.project)
create(:note, noteable: merge_request, project: merge_request.project)
it "includes notes for commits" do
expect(merge_request.commits).not_to be_empty
expect(merge_request.mr_and_commit_notes.count).to eq(2)

Valery Sizov
committed
it "includes notes for commits from target project as well" do
create(:note_on_commit, commit_id: merge_request.commits.first.id,
project: merge_request.target_project)

Valery Sizov
committed
expect(merge_request.commits).not_to be_empty
expect(merge_request.mr_and_commit_notes.count).to eq(3)
end
describe '#is_being_reassigned?' do
it 'returns true if the merge_request assignee has changed' do
subject.assignee = create(:user)
expect(subject.is_being_reassigned?).to be_truthy
end
it 'returns false if the merge request assignee has not changed' do
expect(subject.is_being_reassigned?).to be_falsey
describe '#for_fork?' do
it 'returns true if the merge request is for a fork' do
subject.source_project = create(:project, namespace: create(:group))
subject.target_project = create(:project, namespace: create(:group))
expect(subject.for_fork?).to be_truthy
it 'returns false if is not for a fork' do
expect(subject.for_fork?).to be_falsey
describe 'detection of issues to be closed' do
let(:issue0) { create :issue, project: subject.project }
let(:issue1) { create :issue, project: subject.project }
let(:commit0) { double('commit0', safe_message: "Fixes #{issue0.to_reference}") }
let(:commit1) { double('commit1', safe_message: "Fixes #{issue0.to_reference}") }
let(:commit2) { double('commit2', safe_message: "Fixes #{issue1.to_reference}") }
subject.project.team << [subject.author, :developer]
allow(subject).to receive(:commits).and_return([commit0, commit1, commit2])
end
it 'accesses the set of issues that will be closed on acceptance' do
allow(subject.project).to receive(:default_branch).
and_return(subject.target_branch)
closed = subject.closes_issues
expect(closed).to include(issue0, issue1)
end
it 'only lists issues as to be closed if it targets the default branch' do
allow(subject.project).to receive(:default_branch).and_return('master')
subject.target_branch = 'something-else'
expect(subject.closes_issues).to be_empty
it 'detects issues mentioned in the description' do
issue2 = create(:issue, project: subject.project)
subject.description = "Closes #{issue2.to_reference}"
allow(subject.project).to receive(:default_branch).
and_return(subject.target_branch)
expect(subject.closes_issues).to include(issue2)
describe "#work_in_progress?" do
['WIP ', 'WIP:', 'WIP: ', '[WIP]', '[WIP] ', ' [WIP] WIP [WIP] WIP: WIP '].each do |wip_prefix|
it "detects the '#{wip_prefix}' prefix" do
subject.title = "#{wip_prefix}#{subject.title}"
expect(subject.work_in_progress?).to eq true
it "doesn't detect WIP for words starting with WIP" do
subject.title = "Wipwap #{subject.title}"
expect(subject.work_in_progress?).to eq false
end
it "doesn't detect WIP for words containing with WIP" do
subject.title = "WupWipwap #{subject.title}"
expect(subject.work_in_progress?).to eq false
it "doesn't detect WIP by default" do
expect(subject.work_in_progress?).to eq false
end
end
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
describe "#wipless_title" do
['WIP ', 'WIP:', 'WIP: ', '[WIP]', '[WIP] ', ' [WIP] WIP [WIP] WIP: WIP '].each do |wip_prefix|
it "removes the '#{wip_prefix}' prefix" do
wipless_title = subject.title
subject.title = "#{wip_prefix}#{subject.title}"
expect(subject.wipless_title).to eq wipless_title
end
it "is satisfies the #work_in_progress? method" do
subject.title = "#{wip_prefix}#{subject.title}"
subject.title = subject.wipless_title
expect(subject.work_in_progress?).to eq false
end
end
end
describe "#wip_title" do
it "adds the WIP: prefix to the title" do
wip_title = "WIP: #{subject.title}"
expect(subject.wip_title).to eq wip_title
end
it "does not add the WIP: prefix multiple times" do
wip_title = "WIP: #{subject.title}"
subject.title = subject.wip_title
subject.title = subject.wip_title
expect(subject.wip_title).to eq wip_title
end
it "is satisfies the #work_in_progress? method" do
subject.title = subject.wip_title
expect(subject.work_in_progress?).to eq true
end
end
let(:user) { create(:user) }
let(:user2) { create(:user) }
before do
subject.source_project.team << [user, :master]
subject.source_branch = "feature"
subject.target_branch = "master"
subject.save!
end
it "can't be removed when its a protected branch" do
allow(subject.source_project).to receive(:protected_branch?).and_return(true)
expect(subject.can_remove_source_branch?(user)).to be_falsey
end
it "can't remove a root ref" do
subject.source_branch = "master"
subject.target_branch = "feature"
expect(subject.can_remove_source_branch?(user)).to be_falsey
end
it "is unable to remove the source branch for a project the user cannot push to" do
expect(subject.can_remove_source_branch?(user2)).to be_falsey
end
it "can be removed if the last commit is the head of the source branch" do
allow(subject).to receive(:source_branch_head).and_return(subject.diff_head_commit)
expect(subject.can_remove_source_branch?(user)).to be_truthy
it "cannot be removed if the last commit is not also the head of the source branch" do
Douwe Maan
committed
subject.source_branch = "lfs"
expect(subject.can_remove_source_branch?(user)).to be_falsey
end
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
describe '#merge_commit_message' do
it 'includes merge information as the title' do
request = build(:merge_request, source_branch: 'source', target_branch: 'target')
expect(request.merge_commit_message)
.to match("Merge branch 'source' into 'target'\n\n")
end
it 'includes its title in the body' do
request = build(:merge_request, title: 'Remove all technical debt')
expect(request.merge_commit_message)
.to match("Remove all technical debt\n\n")
end
it 'includes its description in the body' do
request = build(:merge_request, description: 'By removing all code')
expect(request.merge_commit_message)
.to match("By removing all code\n\n")
end
it 'includes its reference in the body' do
request = build_stubbed(:merge_request)
expect(request.merge_commit_message)
.to match("See merge request #{request.to_reference}")
end
it 'excludes multiple linebreak runs when description is blank' do
request = build(:merge_request, title: 'Title', description: nil)
expect(request.merge_commit_message).not_to match("Title\n\n\n\n")
end
end
describe "#reset_merge_when_build_succeeds" do
let(:merge_if_green) do
create :merge_request, merge_when_build_succeeds: true, merge_user: create(:user),
merge_params: { "should_remove_source_branch" => "1", "commit_message" => "msg" }
end
it "sets the item to false" do
merge_if_green.reset_merge_when_build_succeeds
merge_if_green.reload
expect(merge_if_green.merge_when_build_succeeds).to be_falsey
expect(merge_if_green.merge_params["should_remove_source_branch"]).to be_nil
expect(merge_if_green.merge_params["commit_message"]).to be_nil
Kirill Zaitsev
committed
let(:attrs_hash) { subject.hook_attrs.to_h }
[:source, :target].each do |key|
describe "#{key} key" do
include_examples 'project hook data', project_key: key do
let(:data) { attrs_hash }
let(:project) { subject.send("#{key}_project") }
end
end
end
it "has all the required keys" do
Kirill Zaitsev
committed
expect(attrs_hash).to include(:source)
expect(attrs_hash).to include(:target)
expect(attrs_hash).to include(:last_commit)
expect(attrs_hash).to include(:work_in_progress)
end
describe '#diverged_commits_count' do
let(:project) { create(:project) }
let(:fork_project) { create(:project, forked_from_project: project) }
context 'when the target branch does not exist anymore' do
Douglas Barbosa Alexandre
committed
subject { create(:merge_request, source_project: project, target_project: project) }
before do
project.repository.raw_repository.delete_branch(subject.target_branch)
subject.reload
end
it 'does not crash' do
expect{ subject.diverged_commits_count }.not_to raise_error
end
it 'returns 0' do
expect(subject.diverged_commits_count).to eq(0)
end
end
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
context 'diverged on same repository' do
subject(:merge_request_with_divergence) { create(:merge_request, :diverged, source_project: project, target_project: project) }
it 'counts commits that are on target branch but not on source branch' do
expect(subject.diverged_commits_count).to eq(5)
end
end
context 'diverged on fork' do
subject(:merge_request_fork_with_divergence) { create(:merge_request, :diverged, source_project: fork_project, target_project: project) }
it 'counts commits that are on target branch but not on source branch' do
expect(subject.diverged_commits_count).to eq(5)
end
end
context 'rebased on fork' do
subject(:merge_request_rebased) { create(:merge_request, :rebased, source_project: fork_project, target_project: project) }
it 'counts commits that are on target branch but not on source branch' do
expect(subject.diverged_commits_count).to eq(0)
end
end
describe 'caching' do
before(:example) do
allow(Rails).to receive(:cache).and_return(ActiveSupport::Cache::MemoryStore.new)
end
it 'caches the output' do
expect(subject).to receive(:compute_diverged_commits_count).
once.
and_return(2)
subject.diverged_commits_count
subject.diverged_commits_count
end
it 'invalidates the cache when the source sha changes' do
expect(subject).to receive(:compute_diverged_commits_count).
twice.
and_return(2)
subject.diverged_commits_count
Douwe Maan
committed
allow(subject).to receive(:source_branch_sha).and_return('123abc')
subject.diverged_commits_count
end
it 'invalidates the cache when the target sha changes' do
expect(subject).to receive(:compute_diverged_commits_count).
twice.
and_return(2)
subject.diverged_commits_count
Douwe Maan
committed
allow(subject).to receive(:target_branch_sha).and_return('123abc')
subject.diverged_commits_count
end
end
it_behaves_like 'an editable mentionable' do
subject { create(:merge_request) }
let(:backref_text) { "merge request #{subject.to_reference}" }
let(:set_mentionable_text) { ->(txt){ subject.description = txt } }
subject { create :merge_request, :simple }
describe '#commits_sha' do
let(:commit0) { double('commit0', sha: 'sha1') }
let(:commit1) { double('commit1', sha: 'sha2') }
let(:commit2) { double('commit2', sha: 'sha3') }
before do
Kamil Trzcinski
committed
allow(subject.merge_request_diff).to receive(:commits).and_return([commit0, commit1, commit2])
end
it 'returns sha of commits' do
expect(subject.commits_sha).to contain_exactly('sha1', 'sha2', 'sha3')
end
end
describe '#pipeline' do
describe 'when the source project exists' do
Douwe Maan
committed
it 'returns the latest pipeline' do
pipeline = double(:ci_pipeline, ref: 'master')
Douwe Maan
committed
allow(subject).to receive(:diff_head_sha).and_return('123abc')
expect(subject.source_project).to receive(:pipeline_for).
with('master', '123abc').
and_return(pipeline)
expect(subject.pipeline).to eq(pipeline)
end
end
describe 'when the source project does not exist' do
it 'returns nil' do
allow(subject).to receive(:source_project).and_return(nil)
Kamil Trzcinski
committed
expect(subject.pipeline).to be_nil
describe '#all_pipelines' do
shared_examples 'returning pipelines with proper ordering' do
let!(:all_pipelines) do
subject.all_commits_sha.map do |sha|
create(:ci_empty_pipeline,
project: subject.source_project,
sha: sha,
ref: subject.source_branch)
end
end
it 'returns all pipelines' do
expect(subject.all_pipelines).not_to be_empty
expect(subject.all_pipelines).to eq(all_pipelines.reverse)
Kamil Trzcinski
committed
end
context 'with single merge_request_diffs' do
it_behaves_like 'returning pipelines with proper ordering'
end
context 'with multiple irrelevant merge_request_diffs' do
before do
subject.update(target_branch: 'v1.0.0')
end
it_behaves_like 'returning pipelines with proper ordering'
context 'with unsaved merge request' do
subject { build(:merge_request) }
let!(:pipeline) do
create(:ci_empty_pipeline,
project: subject.project,
sha: subject.diff_head_sha,
ref: subject.source_branch)
Kamil Trzcinski
committed
end
it 'returns pipelines from diff_head_sha' do
expect(subject.all_pipelines).to contain_exactly(pipeline)
end
end
describe '#all_commits_sha' do
let(:all_commits_sha) do
subject.merge_request_diffs.flat_map(&:commits).map(&:sha).uniq
end
shared_examples 'returning all SHA' do
it 'returns all SHA from all merge_request_diffs' do
expect(subject.merge_request_diffs.size).to eq(2)
expect(subject.all_commits_sha).to eq(all_commits_sha)
end
end
context 'with a completely different branch' do
before do
subject.update(target_branch: 'v1.0.0')
end
it_behaves_like 'returning all SHA'
context 'with a branch having no difference' do
before do
subject.update(target_branch: 'v1.1.0')
subject.reload # make sure commits were not cached
end
it_behaves_like 'returning all SHA'
end
end
describe '#participants' do
let(:project) { create(:project, :public) }
let(:mr) do
create(:merge_request, source_project: project, target_project: project)
end
let!(:note1) do
create(:note_on_merge_request, noteable: mr, project: project, note: 'a')
end
let!(:note2) do
create(:note_on_merge_request, noteable: mr, project: project, note: 'b')
end
it 'includes the merge request author' do
expect(mr.participants).to include(mr.author)
end
it 'includes the authors of the notes' do
expect(mr.participants).to include(note1.author, note2.author)
end
end
describe 'cached counts' do
it 'updates when assignees change' do
user1 = create(:user)
user2 = create(:user)
mr = create(:merge_request, assignee: user1)
expect(user1.assigned_open_merge_request_count).to eq(1)
expect(user2.assigned_open_merge_request_count).to eq(0)
mr.assignee = user2
mr.save
expect(user1.assigned_open_merge_request_count).to eq(0)
expect(user2.assigned_open_merge_request_count).to eq(1)
end
end
describe '#check_if_can_be_merged' do
let(:project) { create(:project, only_allow_merge_if_build_succeeds: true) }
subject { create(:merge_request, source_project: project, merge_status: :unchecked) }
context 'when it is not broken and has no conflicts' do
it 'is marked as mergeable' do
allow(subject).to receive(:broken?) { false }
Douwe Maan
committed
allow(project.repository).to receive(:can_be_merged?).and_return(true)
expect { subject.check_if_can_be_merged }.to change { subject.merge_status }.to('can_be_merged')
end
end
context 'when broken' do
before { allow(subject).to receive(:broken?) { true } }
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 }
Douwe Maan
committed
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
describe '#mergeable?' do
Rémy Coutable
committed
let(:project) { create(:project) }
subject { create(:merge_request, source_project: project) }
Rémy Coutable
committed
it 'returns false if #mergeable_state? is false' do
expect(subject).to receive(:mergeable_state?) { false }
Rémy Coutable
committed
Rémy Coutable
committed
expect(subject.mergeable?).to be_falsey
Rémy Coutable
committed
end
Rémy Coutable
committed
it 'return true if #mergeable_state? is true and the MR #can_be_merged? is true' do
Rémy Coutable
committed
allow(subject).to receive(:mergeable_state?) { true }
expect(subject).to receive(:check_if_can_be_merged)
Rémy Coutable
committed
expect(subject).to receive(:can_be_merged?) { true }
Rémy Coutable
committed
expect(subject.mergeable?).to be_truthy
end
end
describe '#mergeable_state?' do
let(:project) { create(:project) }
subject { create(:merge_request, source_project: project) }
Rémy Coutable
committed
it 'checks if merge request can be merged' do
Rémy Coutable
committed
allow(subject).to receive(:mergeable_ci_state?) { true }
expect(subject).to receive(:check_if_can_be_merged)
subject.mergeable?
end
context 'when not open' do
before { subject.close }
it 'returns false' do
Rémy Coutable
committed
expect(subject.mergeable_state?).to be_falsey
end
end
context 'when working in progress' do
before { subject.title = 'WIP MR' }
it 'returns false' do
Rémy Coutable
committed
expect(subject.mergeable_state?).to be_falsey
end
end
context 'when broken' do
before { allow(subject).to receive(:broken?) { true } }
it 'returns false' do
Rémy Coutable
committed
expect(subject.mergeable_state?).to be_falsey
end
end
context 'when failed' do
before { allow(subject).to receive(:broken?) { false } }
Rémy Coutable
committed
context 'when project settings restrict to merge only if build succeeds and build failed' do
before do
project.only_allow_merge_if_build_succeeds = true
Rémy Coutable
committed
allow(subject).to receive(:mergeable_ci_state?) { false }
Rémy Coutable
committed
end
it 'returns false' do
expect(subject.mergeable_state?).to be_falsey
Rémy Coutable
committed
describe '#mergeable_ci_state?' do
let(:project) { create(:empty_project, only_allow_merge_if_build_succeeds: true) }
let(:pipeline) { create(:ci_empty_pipeline) }
subject { build(:merge_request, target_project: project) }
Rémy Coutable
committed
context 'when it is only allowed to merge when build is green' do
context 'and a failed pipeline is associated' do
Rémy Coutable
committed
before do
pipeline.statuses << create(:commit_status, status: 'failed', project: project)
allow(subject).to receive(:pipeline) { pipeline }
Rémy Coutable
committed
end
Rémy Coutable
committed
it { expect(subject.mergeable_ci_state?).to be_falsey }
context 'when no pipeline is associated' do
Rémy Coutable
committed
before do
allow(subject).to receive(:pipeline) { nil }
Rémy Coutable
committed
end
it { expect(subject.mergeable_ci_state?).to be_truthy }
Rémy Coutable
committed
context 'when merges are not restricted to green builds' do
subject { build(:merge_request, target_project: build(:empty_project, only_allow_merge_if_build_succeeds: false)) }
context 'and a failed pipeline is associated' do
Rémy Coutable
committed
before do
pipeline.statuses << create(:commit_status, status: 'failed', project: project)
allow(subject).to receive(:pipeline) { pipeline }
Rémy Coutable
committed
end
it { expect(subject.mergeable_ci_state?).to be_truthy }
end
context 'when no pipeline is associated' do
Rémy Coutable
committed
before do
allow(subject).to receive(:pipeline) { nil }
Rémy Coutable
committed
end
it { expect(subject.mergeable_ci_state?).to be_truthy }
describe '#environments' do
let(:project) { create(:project) }
let(:merge_request) { create(:merge_request, source_project: project) }
context 'with multiple environments' do
let(:environments) { create_list(:environment, 3, project: project) }
before do
create(:deployment, environment: environments.first, ref: 'master', sha: project.commit('master').id)
create(:deployment, environment: environments.second, ref: 'feature', sha: project.commit('feature').id)
end
it 'selects deployed environments' do
expect(merge_request.environments).to contain_exactly(environments.first)
end
end
context 'with environments on source project' do
let(:source_project) do
create(:project) do |fork_project|
fork_project.create_forked_project_link(forked_to_project_id: fork_project.id, forked_from_project_id: project.id)
end
end
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
let(:merge_request) do
create(:merge_request,
source_project: source_project, source_branch: 'feature',
target_project: project)
end
let(:source_environment) { create(:environment, project: source_project) }
before do
create(:deployment, environment: source_environment, ref: 'feature', sha: merge_request.diff_head_sha)
end
it 'selects deployed environments' do
expect(merge_request.environments).to contain_exactly(source_environment)
end
context 'with environments on target project' do
let(:target_environment) { create(:environment, project: project) }
before do
create(:deployment, environment: target_environment, tag: true, sha: merge_request.diff_head_sha)
end
it 'selects deployed environments' do
expect(merge_request.environments).to contain_exactly(source_environment, target_environment)
end
end
Rémy Coutable
committed
end
context 'without a diff_head_commit' do
before do
expect(merge_request).to receive(:diff_head_commit).and_return(nil)
end
it 'returns an empty array' do
expect(merge_request.environments).to be_empty
end
describe "#reload_diff" do
let(:note) { create(:diff_note_on_merge_request, project: subject.project, noteable: subject) }
let(:commit) { subject.project.commit(sample_commit.id) }
it "does not change existing merge request diff" do
expect(subject.merge_request_diff).not_to receive(:save_git_content)
it "creates new merge request diff" do
expect { subject.reload_diff }.to change { subject.merge_request_diffs.count }.by(1)
end
it "executs diff cache service" do
expect_any_instance_of(MergeRequests::MergeRequestDiffCacheService).to receive(:execute).with(subject)
subject.reload_diff
end
it "updates diff note positions" do
old_diff_refs = subject.diff_refs
# Update merge_request_diff so that #diff_refs will return commit.diff_refs
allow(subject).to receive(:create_merge_request_diff) do
subject.merge_request_diffs.create(
base_commit_sha: commit.parent_id,
start_commit_sha: commit.parent_id,
head_commit_sha: commit.sha
)
subject.merge_request_diff(true)
end
expect(Notes::DiffPositionUpdateService).to receive(:new).with(
subject.project,
nil,
old_diff_refs: old_diff_refs,
new_diff_refs: commit.diff_refs,
paths: note.position.paths
).and_call_original
expect_any_instance_of(Notes::DiffPositionUpdateService).to receive(:execute).with(note)
expect_any_instance_of(DiffNote).to receive(:save).once
subject.reload_diff
end
end
describe '#branch_merge_base_commit' do
context 'source and target branch exist' do
it { expect(subject.branch_merge_base_commit.sha).to eq('ae73cb07c9eeaf35924a10f713b364d32b2dd34f') }
it { expect(subject.branch_merge_base_commit).to be_a(Commit) }
end
context 'when the target branch does not exist' do
before do
subject.project.repository.raw_repository.delete_branch(subject.target_branch)
end
it 'returns nil' do
expect(subject.branch_merge_base_commit).to be_nil
end
end
end
context "with diffs" do
subject { create(:merge_request, :with_diffs) }
it "does not touch the repository" do
subject # Instantiate the object
expect_any_instance_of(Repository).not_to receive(:commit)
end
it "returns expected diff_refs" do
expected_diff_refs = Gitlab::Diff::DiffRefs.new(
base_sha: subject.merge_request_diff.base_commit_sha,
start_sha: subject.merge_request_diff.start_commit_sha,
head_sha: subject.merge_request_diff.head_commit_sha
)
expect(subject.diff_sha_refs).to eq(expected_diff_refs)
end
end
end
context "discussion status" do
let(:first_discussion) { Discussion.new([create(:diff_note_on_merge_request)]) }
let(:second_discussion) { Discussion.new([create(:diff_note_on_merge_request)]) }
let(:third_discussion) { Discussion.new([create(:diff_note_on_merge_request)]) }