diff options
Diffstat (limited to 'app/models')
-rw-r--r-- | app/models/commit.rb | 16 | ||||
-rw-r--r-- | app/models/merge_request.rb | 9 | ||||
-rw-r--r-- | app/models/merge_request_diff.rb | 86 | ||||
-rw-r--r-- | app/models/note.rb | 26 |
4 files changed, 68 insertions, 69 deletions
diff --git a/app/models/commit.rb b/app/models/commit.rb index 3224f5457f0..ce0b85d50cf 100644 --- a/app/models/commit.rb +++ b/app/models/commit.rb @@ -12,12 +12,7 @@ class Commit attr_accessor :project - # Safe amount of changes (files and lines) in one commit to render - # Used to prevent 500 error on huge commits by suppressing diff - # - # User can force display of diff above this size - DIFF_SAFE_FILES = 100 unless defined?(DIFF_SAFE_FILES) - DIFF_SAFE_LINES = 5000 unless defined?(DIFF_SAFE_LINES) + DIFF_SAFE_LINES = Gitlab::Git::DiffCollection::DEFAULT_LIMITS[:max_lines] # Commits above this size will not be rendered in HTML DIFF_HARD_LIMIT_FILES = 1000 unless defined?(DIFF_HARD_LIMIT_FILES) @@ -36,13 +31,20 @@ class Commit # Calculate number of lines to render for diffs def diff_line_count(diffs) - diffs.reduce(0) { |sum, d| sum + d.diff.lines.count } + diffs.reduce(0) { |sum, d| sum + Gitlab::Git::Util.count_lines(d.diff) } end # Truncate sha to 8 characters def truncate_sha(sha) sha[0..7] end + + def max_diff_options + { + max_files: DIFF_HARD_LIMIT_FILES, + max_lines: DIFF_HARD_LIMIT_LINES, + } + end end attr_accessor :raw diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index 1543ef311d7..025b522cf66 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -48,7 +48,7 @@ class MergeRequest < ActiveRecord::Base after_create :create_merge_request_diff after_update :update_merge_request_diff - delegate :commits, :diffs, :diffs_no_whitespace, to: :merge_request_diff, prefix: nil + delegate :commits, :diffs, :real_size, to: :merge_request_diff, prefix: nil # When this attribute is true some MR validation is ignored # It allows us to close or modify broken merge requests @@ -56,8 +56,7 @@ class MergeRequest < ActiveRecord::Base # Temporary fields to store compare vars # when creating new merge request - attr_accessor :can_be_created, :compare_failed, - :compare_commits, :compare_diffs + attr_accessor :can_be_created, :compare_commits, :compare state_machine :state, initial: :opened do event :close do @@ -182,6 +181,10 @@ class MergeRequest < ActiveRecord::Base merge_request_diff ? merge_request_diff.first_commit : compare_commits.first end + def diff_size + merge_request_diff.size + end + def diff_base_commit if merge_request_diff merge_request_diff.base_commit diff --git a/app/models/merge_request_diff.rb b/app/models/merge_request_diff.rb index c95179d6046..df08d3a6dfb 100644 --- a/app/models/merge_request_diff.rb +++ b/app/models/merge_request_diff.rb @@ -19,14 +19,15 @@ class MergeRequestDiff < ActiveRecord::Base # Prevent store of diff if commits amount more then 500 COMMITS_SAFE_SIZE = 500 - attr_reader :commits, :diffs, :diffs_no_whitespace - belongs_to :merge_request delegate :target_branch, :source_branch, to: :merge_request, prefix: nil state_machine :state, initial: :empty do state :collected + state :overflow + # Deprecated states: these are no longer used but these values may still occur + # in the database. state :timeout state :overflow_commits_safe_size state :overflow_diff_files_limit @@ -43,19 +44,23 @@ class MergeRequestDiff < ActiveRecord::Base reload_diffs end - def diffs - @diffs ||= (load_diffs(st_diffs) || []) + def size + real_size.presence || diffs.size end - def diffs_no_whitespace - compare_result = Gitlab::CompareResult.new( - Gitlab::Git::Compare.new( - self.repository.raw_repository, - self.target_branch, - self.source_sha, - ), { ignore_whitespace_change: true } - ) - @diffs_no_whitespace ||= load_diffs(dump_commits(compare_result.diffs)) + def diffs(options={}) + if options[:ignore_whitespace_change] + @diffs_no_whitespace ||= begin + compare = Gitlab::Git::Compare.new( + self.repository.raw_repository, + self.target_branch, + self.source_sha, + ) + compare.diffs(options) + end + else + @diffs ||= load_diffs(st_diffs, options) + end end def commits @@ -94,16 +99,18 @@ class MergeRequestDiff < ActiveRecord::Base end end - def load_diffs(raw) - if raw.respond_to?(:map) - raw.map { |hash| Gitlab::Git::Diff.new(hash) } + def load_diffs(raw, options) + if raw.respond_to?(:each) + Gitlab::Git::DiffCollection.new(raw, options) + else + Gitlab::Git::DiffCollection.new([]) end end # Collect array of Git::Commit objects # between target and source branches def unmerged_commits - commits = compare_result.commits + commits = compare.commits if commits.present? commits = Commit.decorate(commits, merge_request.source_project). @@ -133,27 +140,21 @@ class MergeRequestDiff < ActiveRecord::Base if commits.size.zero? self.state = :empty - elsif commits.size > COMMITS_SAFE_SIZE - self.state = :overflow_commits_safe_size else - new_diffs = unmerged_diffs - end + diff_collection = unmerged_diffs - if new_diffs.any? - if new_diffs.size > Commit::DIFF_HARD_LIMIT_FILES - self.state = :overflow_diff_files_limit - new_diffs = new_diffs.first(Commit::DIFF_HARD_LIMIT_LINES) + if diff_collection.overflow? + # Set our state to 'overflow' to make the #empty? and #collected? + # methods (generated by StateMachine) return false. + self.state = :overflow end - if new_diffs.sum { |diff| diff.diff.lines.count } > Commit::DIFF_HARD_LIMIT_LINES - self.state = :overflow_diff_lines_limit - new_diffs = new_diffs.first(Commit::DIFF_HARD_LIMIT_LINES) - end - end + self.real_size = diff_collection.real_size - if new_diffs.present? - new_diffs = dump_commits(new_diffs) - self.state = :collected + if diff_collection.any? + new_diffs = dump_diffs(diff_collection) + self.state = :collected + end end self.st_diffs = new_diffs @@ -166,10 +167,7 @@ class MergeRequestDiff < ActiveRecord::Base # Collect array of Git::Diff objects # between target and source branches def unmerged_diffs - compare_result.diffs || [] - rescue Gitlab::Git::Diff::TimeoutError - self.state = :timeout - [] + compare.diffs(Commit.max_diff_options) end def repository @@ -181,18 +179,16 @@ class MergeRequestDiff < ActiveRecord::Base source_commit.try(:sha) end - def compare_result - @compare_result ||= + def compare + @compare ||= begin # Update ref for merge request merge_request.fetch_ref - Gitlab::CompareResult.new( - Gitlab::Git::Compare.new( - self.repository.raw_repository, - self.target_branch, - self.source_sha - ) + Gitlab::Git::Compare.new( + self.repository.raw_repository, + self.target_branch, + self.source_sha ) end end diff --git a/app/models/note.rb b/app/models/note.rb index d287e0f3c6d..1a7b2ba6d42 100644 --- a/app/models/note.rb +++ b/app/models/note.rb @@ -131,9 +131,11 @@ class Note < ActiveRecord::Base end def find_diff - return nil unless noteable && noteable.diffs.present? + return nil unless noteable + return @diff if defined?(@diff) - @diff ||= noteable.diffs.find do |d| + # Don't use ||= because nil is a valid value for @diff + @diff = noteable.diffs(Commit.max_diff_options).find do |d| Digest::SHA1.hexdigest(d.new_path) == diff_file_index if d.new_path end end @@ -165,20 +167,16 @@ class Note < ActiveRecord::Base def active? return true unless self.diff return false unless noteable + return @active if defined?(@active) - noteable.diffs.each do |mr_diff| - next unless mr_diff.new_path == self.diff.new_path + diffs = noteable.diffs(Commit.max_diff_options) + notable_diff = diffs.find { |d| d.new_path == self.diff.new_path } - lines = Gitlab::Diff::Parser.new.parse(mr_diff.diff.lines.to_a) + return @active = false if notable_diff.nil? - lines.each do |line| - if line.text == diff_line - return true - end - end - end - - false + parsed_lines = Gitlab::Diff::Parser.new.parse(notable_diff.diff.each_line) + # We cannot use ||= because @active may be false + @active = parsed_lines.any? { |line_obj| line_obj.text == diff_line } end def outdated? @@ -263,7 +261,7 @@ class Note < ActiveRecord::Base end def diff_lines - @diff_lines ||= Gitlab::Diff::Parser.new.parse(diff.diff.lines) + @diff_lines ||= Gitlab::Diff::Parser.new.parse(diff.diff.each_line) end def highlighted_diff_lines |