Commit e1bdb165d147ee65e89d9dacd442d4467d29a86c
Exists in
master
and in
4 other branches
Merge pull request #5014 from bladealslayer/feature/big-commit-improvements
Improved large commit handling.
Showing
11 changed files
with
108 additions
and
9 deletions
Show diff stats
app/assets/javascripts/merge_requests.js.coffee
app/contexts/commit_load_context.rb
| ... | ... | @@ -20,7 +20,8 @@ class CommitLoadContext < BaseContext |
| 20 | 20 | result[:notes_count] = project.notes.for_commit_id(commit.id).count |
| 21 | 21 | |
| 22 | 22 | begin |
| 23 | - result[:suppress_diff] = true if commit.diffs.size > Commit::DIFF_SAFE_SIZE && !params[:force_show_diff] | |
| 23 | + result[:suppress_diff] = true if commit.diff_suppress? && !params[:force_show_diff] | |
| 24 | + result[:force_suppress_diff] = commit.diff_force_suppress? | |
| 24 | 25 | rescue Grit::Git::GitTimeout |
| 25 | 26 | result[:suppress_diff] = true |
| 26 | 27 | result[:status] = :huge_commit | ... | ... |
app/controllers/projects/commit_controller.rb
app/controllers/projects/compare_controller.rb
| ... | ... | @@ -15,6 +15,10 @@ class Projects::CompareController < Projects::ApplicationController |
| 15 | 15 | @diffs = compare.diffs |
| 16 | 16 | @refs_are_same = compare.same |
| 17 | 17 | @line_notes = [] |
| 18 | + | |
| 19 | + diff_line_count = Commit::diff_line_count(@diffs) | |
| 20 | + @suppress_diff = Commit::diff_suppress?(@diffs, diff_line_count) && !params[:force_show_diff] | |
| 21 | + @force_suppress_diff = Commit::diff_force_suppress?(@diffs, diff_line_count) | |
| 18 | 22 | end |
| 19 | 23 | |
| 20 | 24 | def create | ... | ... |
app/controllers/projects/merge_requests_controller.rb
| ... | ... | @@ -40,6 +40,10 @@ class Projects::MergeRequestsController < Projects::ApplicationController |
| 40 | 40 | @comments_target = {noteable_type: 'MergeRequest', |
| 41 | 41 | noteable_id: @merge_request.id} |
| 42 | 42 | @line_notes = @merge_request.notes.where("line_code is not null") |
| 43 | + | |
| 44 | + diff_line_count = Commit::diff_line_count(@merge_request.diffs) | |
| 45 | + @suppress_diff = Commit::diff_suppress?(@merge_request.diffs, diff_line_count) && !params[:force_show_diff] | |
| 46 | + @force_suppress_diff = Commit::diff_force_suppress?(@merge_request.diffs, diff_line_count) | |
| 43 | 47 | end |
| 44 | 48 | |
| 45 | 49 | def new | ... | ... |
app/models/commit.rb
| ... | ... | @@ -6,15 +6,41 @@ class Commit |
| 6 | 6 | |
| 7 | 7 | attr_mentionable :safe_message |
| 8 | 8 | |
| 9 | - # Safe amount of files with diffs in one commit to render | |
| 9 | + # Safe amount of changes (files and lines) in one commit to render | |
| 10 | 10 | # Used to prevent 500 error on huge commits by suppressing diff |
| 11 | 11 | # |
| 12 | - DIFF_SAFE_SIZE = 100 | |
| 12 | + # User can force display of diff above this size | |
| 13 | + DIFF_SAFE_FILES = 100 | |
| 14 | + DIFF_SAFE_LINES = 5000 | |
| 15 | + # Commits above this size will not be rendered in HTML | |
| 16 | + DIFF_HARD_LIMIT_FILES = 500 | |
| 17 | + DIFF_HARD_LIMIT_LINES = 10000 | |
| 13 | 18 | |
| 14 | 19 | def self.decorate(commits) |
| 15 | 20 | commits.map { |c| self.new(c) } |
| 16 | 21 | end |
| 17 | 22 | |
| 23 | + # Calculate number of lines to render for diffs | |
| 24 | + def self.diff_line_count(diffs) | |
| 25 | + diffs.reduce(0){|sum, d| sum + d.diff.lines.count} | |
| 26 | + end | |
| 27 | + | |
| 28 | + def self.diff_suppress?(diffs, line_count = nil) | |
| 29 | + # optimize - check file count first | |
| 30 | + return true if diffs.size > DIFF_SAFE_FILES | |
| 31 | + | |
| 32 | + line_count ||= Commit::diff_line_count(diffs) | |
| 33 | + line_count > DIFF_SAFE_LINES | |
| 34 | + end | |
| 35 | + | |
| 36 | + def self.diff_force_suppress?(diffs, line_count = nil) | |
| 37 | + # optimize - check file count first | |
| 38 | + return true if diffs.size > DIFF_HARD_LIMIT_FILES | |
| 39 | + | |
| 40 | + line_count ||= Commit::diff_line_count(diffs) | |
| 41 | + line_count > DIFF_HARD_LIMIT_LINES | |
| 42 | + end | |
| 43 | + | |
| 18 | 44 | attr_accessor :raw |
| 19 | 45 | |
| 20 | 46 | def initialize(raw_commit) |
| ... | ... | @@ -27,6 +53,19 @@ class Commit |
| 27 | 53 | @raw.id |
| 28 | 54 | end |
| 29 | 55 | |
| 56 | + def diff_line_count | |
| 57 | + @diff_line_count ||= Commit::diff_line_count(self.diffs) | |
| 58 | + @diff_line_count | |
| 59 | + end | |
| 60 | + | |
| 61 | + def diff_suppress? | |
| 62 | + Commit::diff_suppress?(self.diffs, diff_line_count) | |
| 63 | + end | |
| 64 | + | |
| 65 | + def diff_force_suppress? | |
| 66 | + Commit::diff_force_suppress?(self.diffs, diff_line_count) | |
| 67 | + end | |
| 68 | + | |
| 30 | 69 | # Returns a string describing the commit for use in a link title |
| 31 | 70 | # |
| 32 | 71 | # Example | ... | ... |
app/views/projects/commits/_diffs.html.haml
| 1 | +- @suppress_diff ||= @suppress_diff || @force_suppress_diff | |
| 1 | 2 | - if @suppress_diff |
| 2 | 3 | .alert.alert-block |
| 3 | 4 | %p |
| 4 | - %strong Warning! Large commit with more than #{Commit::DIFF_SAFE_SIZE} files changed. | |
| 5 | - %p To preserve performance the diff is not shown. | |
| 5 | + %strong Warning! This is a large diff. | |
| 6 | 6 | %p |
| 7 | - But if you still want to see the diff | |
| 8 | - = link_to "click this link", project_commit_path(project, @commit, force_show_diff: true), class: "underlined_link" | |
| 7 | + To preserve performance the diff is not shown. | |
| 8 | + - if current_controller?(:commit) or current_controller?(:merge_requests) | |
| 9 | + Please, download the diff as | |
| 10 | + - if current_controller?(:commit) | |
| 11 | + = link_to "plain diff", project_commit_path(@project, @commit, format: :diff), class: "underlined_link" | |
| 12 | + or | |
| 13 | + = link_to "email patch", project_commit_path(@project, @commit, format: :patch), class: "underlined_link" | |
| 14 | + - else | |
| 15 | + = link_to "plain diff", project_merge_request_path(@project, @merge_request, format: :diff), class: "underlined_link" | |
| 16 | + or | |
| 17 | + = link_to "email patch", project_merge_request_path(@project, @merge_request, format: :patch), class: "underlined_link" | |
| 18 | + instead. | |
| 19 | + - unless @force_suppress_diff | |
| 20 | + %p | |
| 21 | + If you still want to see the diff | |
| 22 | + = link_to "click this link", url_for(force_show_diff: true), class: "underlined_link" | |
| 9 | 23 | |
| 10 | 24 | %p.commit-stat-summary |
| 11 | 25 | Showing | ... | ... |
features/project/commits/commits.feature
| ... | ... | @@ -27,3 +27,11 @@ Feature: Project Browse commits |
| 27 | 27 | Scenario: I browse commits stats |
| 28 | 28 | Given I visit my project's commits stats page |
| 29 | 29 | Then I see commits stats |
| 30 | + | |
| 31 | + Scenario: I browse big commit | |
| 32 | + Given I visit big commit page | |
| 33 | + Then I see big commit warning | |
| 34 | + | |
| 35 | + Scenario: I browse huge commit | |
| 36 | + Given I visit huge commit page | |
| 37 | + Then I see huge commit message | ... | ... |
features/steps/project/project_browse_commits.rb
| ... | ... | @@ -58,4 +58,24 @@ class ProjectBrowseCommits < Spinach::FeatureSteps |
| 58 | 58 | page.should have_content 'Total commits' |
| 59 | 59 | page.should have_content 'Authors' |
| 60 | 60 | end |
| 61 | + | |
| 62 | + Given 'I visit big commit page' do | |
| 63 | + visit project_commit_path(@project, BigCommits::BIG_COMMIT_ID) | |
| 64 | + end | |
| 65 | + | |
| 66 | + Then 'I see big commit warning' do | |
| 67 | + page.should have_content BigCommits::BIG_COMMIT_MESSAGE | |
| 68 | + page.should have_content "Warning! This is a large diff" | |
| 69 | + page.should have_content "If you still want to see the diff" | |
| 70 | + end | |
| 71 | + | |
| 72 | + Given 'I visit huge commit page' do | |
| 73 | + visit project_commit_path(@project, BigCommits::HUGE_COMMIT_ID) | |
| 74 | + end | |
| 75 | + | |
| 76 | + Then 'I see huge commit message' do | |
| 77 | + page.should have_content BigCommits::HUGE_COMMIT_MESSAGE | |
| 78 | + page.should have_content "Warning! This is a large diff" | |
| 79 | + page.should_not have_content "If you still want to see the diff" | |
| 80 | + end | |
| 61 | 81 | end | ... | ... |
features/support/env.rb
| ... | ... | @@ -14,7 +14,7 @@ require 'spinach/capybara' |
| 14 | 14 | require 'sidekiq/testing/inline' |
| 15 | 15 | |
| 16 | 16 | |
| 17 | -%w(valid_commit select2_helper chosen_helper test_env).each do |f| | |
| 17 | +%w(valid_commit big_commits select2_helper chosen_helper test_env).each do |f| | |
| 18 | 18 | require Rails.root.join('spec', 'support', f) |
| 19 | 19 | end |
| 20 | 20 | ... | ... |
| ... | ... | @@ -0,0 +1,8 @@ |
| 1 | +module BigCommits | |
| 2 | + HUGE_COMMIT_ID = "7f92534f767fa20357a11c63f973ae3b79cc5b85" | |
| 3 | + HUGE_COMMIT_MESSAGE = "pybments.rb version up. gitignore improved" | |
| 4 | + | |
| 5 | + BIG_COMMIT_ID = "d62200cad430565bd9f80befaf329297120330b5" | |
| 6 | + BIG_COMMIT_MESSAGE = "clean-up code" | |
| 7 | +end | |
| 8 | + | ... | ... |