Commit a82496ba authored by Nick Thomas's avatar Nick Thomas

Merge branch '29494-handle-empty-merge-request-diff-gracefully' into 'master'

Handle missing MergeRequestDiff gracefully

See merge request gitlab-org/gitlab!24559
parents 11a40cc8 b341e2dc
...@@ -48,6 +48,7 @@ class MergeRequest < ApplicationRecord ...@@ -48,6 +48,7 @@ class MergeRequest < ApplicationRecord
# 1. There are arguments - in which case we might be trying to force-reload. # 1. There are arguments - in which case we might be trying to force-reload.
# 2. This association is already loaded. # 2. This association is already loaded.
# 3. The latest diff does not exist. # 3. The latest diff does not exist.
# 4. It doesn't have any merge_request_diffs - it returns an empty MergeRequestDiff
# #
# The second one in particular is important - MergeRequestDiff#merge_request # The second one in particular is important - MergeRequestDiff#merge_request
# is the inverse of MergeRequest#merge_request_diff, which means it may not be # is the inverse of MergeRequest#merge_request_diff, which means it may not be
...@@ -56,7 +57,7 @@ class MergeRequest < ApplicationRecord ...@@ -56,7 +57,7 @@ class MergeRequest < ApplicationRecord
def merge_request_diff def merge_request_diff
fallback = latest_merge_request_diff unless association(:merge_request_diff).loaded? fallback = latest_merge_request_diff unless association(:merge_request_diff).loaded?
fallback || super fallback || super || MergeRequestDiff.new(merge_request_id: id)
end end
belongs_to :head_pipeline, foreign_key: "head_pipeline_id", class_name: "Ci::Pipeline" belongs_to :head_pipeline, foreign_key: "head_pipeline_id", class_name: "Ci::Pipeline"
...@@ -404,7 +405,7 @@ class MergeRequest < ApplicationRecord ...@@ -404,7 +405,7 @@ class MergeRequest < ApplicationRecord
end end
def commits(limit: nil) def commits(limit: nil)
return merge_request_diff.commits(limit: limit) if persisted? return merge_request_diff.commits(limit: limit) if merge_request_diff.persisted?
commits_arr = if compare_commits commits_arr = if compare_commits
reversed_commits = compare_commits.reverse reversed_commits = compare_commits.reverse
...@@ -421,7 +422,7 @@ class MergeRequest < ApplicationRecord ...@@ -421,7 +422,7 @@ class MergeRequest < ApplicationRecord
end end
def commits_count def commits_count
if persisted? if merge_request_diff.persisted?
merge_request_diff.commits_count merge_request_diff.commits_count
elsif compare_commits elsif compare_commits
compare_commits.size compare_commits.size
...@@ -431,7 +432,7 @@ class MergeRequest < ApplicationRecord ...@@ -431,7 +432,7 @@ class MergeRequest < ApplicationRecord
end end
def commit_shas(limit: nil) def commit_shas(limit: nil)
return merge_request_diff.commit_shas(limit: limit) if persisted? return merge_request_diff.commit_shas(limit: limit) if merge_request_diff.persisted?
shas = shas =
if compare_commits if compare_commits
...@@ -492,11 +493,11 @@ class MergeRequest < ApplicationRecord ...@@ -492,11 +493,11 @@ class MergeRequest < ApplicationRecord
end end
def first_commit def first_commit
merge_request_diff ? merge_request_diff.first_commit : compare_commits.first compare_commits.present? ? compare_commits.first : merge_request_diff.first_commit
end end
def raw_diffs(*args) def raw_diffs(*args)
merge_request_diff ? merge_request_diff.raw_diffs(*args) : compare.raw_diffs(*args) compare.present? ? compare.raw_diffs(*args) : merge_request_diff.raw_diffs(*args)
end end
def diffs(diff_options = {}) def diffs(diff_options = {})
...@@ -557,7 +558,7 @@ class MergeRequest < ApplicationRecord ...@@ -557,7 +558,7 @@ class MergeRequest < ApplicationRecord
end end
def diff_base_commit def diff_base_commit
if persisted? if merge_request_diff.persisted?
merge_request_diff.base_commit merge_request_diff.base_commit
else else
branch_merge_base_commit branch_merge_base_commit
...@@ -565,7 +566,7 @@ class MergeRequest < ApplicationRecord ...@@ -565,7 +566,7 @@ class MergeRequest < ApplicationRecord
end end
def diff_start_commit def diff_start_commit
if persisted? if merge_request_diff.persisted?
merge_request_diff.start_commit merge_request_diff.start_commit
else else
target_branch_head target_branch_head
...@@ -573,7 +574,7 @@ class MergeRequest < ApplicationRecord ...@@ -573,7 +574,7 @@ class MergeRequest < ApplicationRecord
end end
def diff_head_commit def diff_head_commit
if persisted? if merge_request_diff.persisted?
merge_request_diff.head_commit merge_request_diff.head_commit
else else
source_branch_head source_branch_head
...@@ -581,7 +582,7 @@ class MergeRequest < ApplicationRecord ...@@ -581,7 +582,7 @@ class MergeRequest < ApplicationRecord
end end
def diff_start_sha def diff_start_sha
if persisted? if merge_request_diff.persisted?
merge_request_diff.start_commit_sha merge_request_diff.start_commit_sha
else else
target_branch_head.try(:sha) target_branch_head.try(:sha)
...@@ -589,7 +590,7 @@ class MergeRequest < ApplicationRecord ...@@ -589,7 +590,7 @@ class MergeRequest < ApplicationRecord
end end
def diff_base_sha def diff_base_sha
if persisted? if merge_request_diff.persisted?
merge_request_diff.base_commit_sha merge_request_diff.base_commit_sha
else else
branch_merge_base_commit.try(:sha) branch_merge_base_commit.try(:sha)
...@@ -597,7 +598,7 @@ class MergeRequest < ApplicationRecord ...@@ -597,7 +598,7 @@ class MergeRequest < ApplicationRecord
end end
def diff_head_sha def diff_head_sha
if persisted? if merge_request_diff.persisted?
merge_request_diff.head_commit_sha merge_request_diff.head_commit_sha
else else
source_branch_head.try(:sha) source_branch_head.try(:sha)
...@@ -758,7 +759,7 @@ class MergeRequest < ApplicationRecord ...@@ -758,7 +759,7 @@ class MergeRequest < ApplicationRecord
end end
def ensure_merge_request_diff def ensure_merge_request_diff
merge_request_diff || create_merge_request_diff merge_request_diff.persisted? || create_merge_request_diff
end end
def create_merge_request_diff def create_merge_request_diff
...@@ -1005,7 +1006,7 @@ class MergeRequest < ApplicationRecord ...@@ -1005,7 +1006,7 @@ class MergeRequest < ApplicationRecord
def closes_issues(current_user = self.author) def closes_issues(current_user = self.author)
if target_branch == project.default_branch if target_branch == project.default_branch
messages = [title, description] messages = [title, description]
messages.concat(commits.map(&:safe_message)) if merge_request_diff messages.concat(commits.map(&:safe_message)) if merge_request_diff.persisted?
Gitlab::ClosingIssueExtractor.new(project, current_user) Gitlab::ClosingIssueExtractor.new(project, current_user)
.closed_by_message(messages.join("\n")) .closed_by_message(messages.join("\n"))
...@@ -1421,7 +1422,7 @@ class MergeRequest < ApplicationRecord ...@@ -1421,7 +1422,7 @@ class MergeRequest < ApplicationRecord
end end
def has_commits? def has_commits?
merge_request_diff && commits_count.to_i > 0 merge_request_diff.persisted? && commits_count.to_i > 0
end end
def has_no_commits? def has_no_commits?
......
...@@ -77,6 +77,18 @@ describe Projects::MergeRequestsController do ...@@ -77,6 +77,18 @@ describe Projects::MergeRequestsController do
end end
end end
context 'when diff is missing' do
render_views
it 'renders merge request page' do
merge_request.merge_request_diff.destroy
go(format: :html)
expect(response).to be_successful
end
end
it "renders merge request page" do it "renders merge request page" do
expect(::Gitlab::GitalyClient).to receive(:allow_ref_name_caching).and_call_original expect(::Gitlab::GitalyClient).to receive(:allow_ref_name_caching).and_call_original
......
...@@ -52,10 +52,10 @@ describe Gitlab::ImportExport::MergeRequestParser do ...@@ -52,10 +52,10 @@ describe Gitlab::ImportExport::MergeRequestParser do
context 'when the diff is invalid' do context 'when the diff is invalid' do
let(:merge_request_diff) { build(:merge_request_diff, merge_request: merge_request, base_commit_sha: 'foobar') } let(:merge_request_diff) { build(:merge_request_diff, merge_request: merge_request, base_commit_sha: 'foobar') }
it 'sets the diff to nil' do it 'sets the diff to empty diff' do
expect(merge_request_diff).to be_invalid expect(merge_request_diff).to be_invalid
expect(merge_request_diff.merge_request).to eq merge_request expect(merge_request_diff.merge_request).to eq merge_request
expect(parsed_merge_request.merge_request_diff).to be_nil expect(parsed_merge_request.merge_request_diff).to be_empty
end end
end end
end end
......
...@@ -662,13 +662,12 @@ describe MergeRequest do ...@@ -662,13 +662,12 @@ describe MergeRequest do
end end
describe '#raw_diffs' do describe '#raw_diffs' do
let(:merge_request) { build(:merge_request) }
let(:options) { { paths: ['a/b', 'b/a', 'c/*'] } } let(:options) { { paths: ['a/b', 'b/a', 'c/*'] } }
context 'when there are MR diffs' do context 'when there are MR diffs' do
it 'delegates to the MR diffs' do let(:merge_request) { create(:merge_request, :with_diffs) }
merge_request.merge_request_diff = MergeRequestDiff.new
it 'delegates to the MR diffs' do
expect(merge_request.merge_request_diff).to receive(:raw_diffs).with(options) expect(merge_request.merge_request_diff).to receive(:raw_diffs).with(options)
merge_request.raw_diffs(options) merge_request.raw_diffs(options)
...@@ -676,6 +675,8 @@ describe MergeRequest do ...@@ -676,6 +675,8 @@ describe MergeRequest do
end end
context 'when there are no MR diffs' do context 'when there are no MR diffs' do
let(:merge_request) { build(:merge_request) }
it 'delegates to the compare object' do it 'delegates to the compare object' do
merge_request.compare = double(:compare) merge_request.compare = double(:compare)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment