Commit 2b6b7b2e authored by 🤖 GitLab Bot 🤖's avatar 🤖 GitLab Bot 🤖

Merge remote-tracking branch 'upstream/master' into ce-to-ee-2018-10-02

# Conflicts:
#	db/schema.rb
#	locale/gitlab.pot
#	qa/qa/page/menu/admin.rb

[ci skip]
parents e672c821 eda6b43c
Pipeline #31817523 skipped
6.1.1
7.0.0
\ No newline at end of file
/**
* Highlights the current user in existing elements with a user ID data attribute.
*
* @param elements DOM elements that represent user mentions
*/
export default function highlightCurrentUser(elements) {
const currentUserId = gon && gon.current_user_id;
if (!currentUserId) {
return;
}
elements.forEach(element => {
if (parseInt(element.dataset.user, 10) === currentUserId) {
element.classList.add('current-user');
}
});
}
......@@ -2,6 +2,7 @@ import $ from 'jquery';
import syntaxHighlight from '~/syntax_highlight';
import renderMath from './render_math';
import renderMermaid from './render_mermaid';
import highlightCurrentUser from './highlight_current_user';
// Render GitLab flavoured Markdown
//
......@@ -11,6 +12,7 @@ $.fn.renderGFM = function renderGFM() {
syntaxHighlight(this.find('.js-syntax-highlight'));
renderMath(this.find('.js-render-math'));
renderMermaid(this.find('.js-render-mermaid'));
highlightCurrentUser(this.find('.gfm-project_member').get());
return this;
};
......
......@@ -31,11 +31,17 @@ function blockTagText(text, textArea, blockTag, selected) {
}
}
function moveCursor(textArea, tag, wrapped, removedLastNewLine) {
function moveCursor({ textArea, tag, wrapped, removedLastNewLine, select }) {
var pos;
if (!textArea.setSelectionRange) {
return;
}
if (select && select.length > 0) {
// calculate the part of the text to be selected
const startPosition = textArea.selectionStart - (tag.length - tag.indexOf(select));
const endPosition = startPosition + select.length;
return textArea.setSelectionRange(startPosition, endPosition);
}
if (textArea.selectionStart === textArea.selectionEnd) {
if (wrapped) {
pos = textArea.selectionStart - tag.length;
......@@ -51,7 +57,7 @@ function moveCursor(textArea, tag, wrapped, removedLastNewLine) {
}
}
export function insertMarkdownText(textArea, text, tag, blockTag, selected, wrap) {
export function insertMarkdownText({ textArea, text, tag, blockTag, selected, wrap, select }) {
var textToInsert, inserted, selectedSplit, startChar, removedLastNewLine, removedFirstNewLine, currentLineEmpty, lastNewLine;
removedLastNewLine = false;
removedFirstNewLine = false;
......@@ -82,11 +88,16 @@ export function insertMarkdownText(textArea, text, tag, blockTag, selected, wrap
startChar = !wrap && !currentLineEmpty && textArea.selectionStart > 0 ? '\n' : '';
const textPlaceholder = '{text}';
if (selectedSplit.length > 1 && (!wrap || (blockTag != null && blockTag !== ''))) {
if (blockTag != null && blockTag !== '') {
textToInsert = blockTagText(text, textArea, blockTag, selected);
} else {
textToInsert = selectedSplit.map(function(val) {
if (tag.indexOf(textPlaceholder) > -1) {
return tag.replace(textPlaceholder, val);
}
if (val.indexOf(tag) === 0) {
return "" + (val.replace(tag, ''));
} else {
......@@ -94,6 +105,8 @@ export function insertMarkdownText(textArea, text, tag, blockTag, selected, wrap
}
}).join('\n');
}
} else if (tag.indexOf(textPlaceholder) > -1) {
textToInsert = tag.replace(textPlaceholder, selected);
} else {
textToInsert = "" + startChar + tag + selected + (wrap ? tag : ' ');
}
......@@ -107,17 +120,17 @@ export function insertMarkdownText(textArea, text, tag, blockTag, selected, wrap
}
insertText(textArea, textToInsert);
return moveCursor(textArea, tag, wrap, removedLastNewLine);
return moveCursor({ textArea, tag: tag.replace(textPlaceholder, selected), wrap, removedLastNewLine, select });
}
function updateText(textArea, tag, blockTag, wrap) {
function updateText({ textArea, tag, blockTag, wrap, select }) {
var $textArea, selected, text;
$textArea = $(textArea);
textArea = $textArea.get(0);
text = $textArea.val();
selected = selectedText(text, textArea);
$textArea.focus();
return insertMarkdownText(textArea, text, tag, blockTag, selected, wrap);
return insertMarkdownText({ textArea, text, tag, blockTag, selected, wrap, select });
}
function replaceRange(s, start, end, substitute) {
......@@ -127,7 +140,12 @@ function replaceRange(s, start, end, substitute) {
export function addMarkdownListeners(form) {
return $('.js-md', form).off('click').on('click', function() {
const $this = $(this);
return updateText($this.closest('.md-area').find('textarea'), $this.data('mdTag'), $this.data('mdBlock'), !$this.data('mdPrepend'));
return updateText({
textArea: $this.closest('.md-area').find('textarea'),
tag: $this.data('mdTag'),
blockTag: $this.data('mdBlock'),
wrap: !$this.data('mdPrepend'),
select: $this.data('mdSelect') });
});
}
......
......@@ -11,6 +11,7 @@ import commentForm from './comment_form.vue';
import placeholderNote from '../../vue_shared/components/notes/placeholder_note.vue';
import placeholderSystemNote from '../../vue_shared/components/notes/placeholder_system_note.vue';
import skeletonLoadingContainer from '../../vue_shared/components/notes/skeleton_note.vue';
import highlightCurrentUser from '~/behaviors/markdown/highlight_current_user';
export default {
name: 'NotesApp',
......@@ -96,6 +97,9 @@ export default {
});
}
},
updated() {
this.$nextTick(() => highlightCurrentUser(this.$el.querySelectorAll('.gfm-project_member')));
},
methods: {
...mapActions({
fetchDiscussions: 'fetchDiscussions',
......
......@@ -105,6 +105,12 @@
button-title="Insert code"
icon="code"
/>
<toolbar-button
tag="[{text}](url)"
tag-select="url"
button-title="Add a link"
icon="link"
/>
<toolbar-button
:prepend="true"
tag="* "
......
......@@ -27,6 +27,11 @@
required: false,
default: '',
},
tagSelect: {
type: String,
required: false,
default: '',
},
prepend: {
type: Boolean,
required: false,
......@@ -40,6 +45,7 @@
<button
v-tooltip
:data-md-tag="tag"
:data-md-select="tagSelect"
:data-md-block="tagBlock"
:data-md-prepend="prepend"
:title="buttonTitle"
......
......@@ -11,6 +11,10 @@
padding: 0 2px;
background-color: $blue-100;
border-radius: $border-radius-default;
&.current-user {
background-color: $orange-100;
}
}
.gfm-color_chip {
......
......@@ -14,6 +14,8 @@ class Projects::ArtifactsController < Projects::ApplicationController
before_action :entry, only: [:file]
def download
return render_404 unless artifacts_file
send_upload(artifacts_file, attachment: artifacts_file.filename)
end
......@@ -100,7 +102,7 @@ class Projects::ArtifactsController < Projects::ApplicationController
# rubocop: enable CodeReuse/ActiveRecord
def artifacts_file
@artifacts_file ||= build.artifacts_file
@artifacts_file ||= build.artifacts_file_for_type(params[:file_type] || :archive)
end
def entry
......
......@@ -255,7 +255,8 @@ module ApplicationSettingsHelper
:user_default_internal_regex,
:user_oauth_applications,
:version_check_enabled,
:web_ide_clientside_preview_enabled
:web_ide_clientside_preview_enabled,
:diff_max_patch_bytes
]
end
......
......@@ -329,11 +329,15 @@ module IssuablesHelper
end
def issuable_button_visibility(issuable, closed)
return 'hidden' if issuable_button_hidden?(issuable, closed)
end
def issuable_button_hidden?(issuable, closed)
case issuable
when Issue
issue_button_visibility(issuable, closed)
issue_button_hidden?(issuable, closed)
when MergeRequest
merge_request_button_visibility(issuable, closed)
merge_request_button_hidden?(issuable, closed)
end
end
......
......@@ -66,7 +66,11 @@ module IssuesHelper
end
def issue_button_visibility(issue, closed)
return 'hidden' if issue.closed? == closed
return 'hidden' if issue_button_hidden?(issue, closed)
end
def issue_button_hidden?(issue, closed)
issue.closed? == closed || (!closed && issue.discussion_locked)
end
def confidential_icon(issue)
......
......@@ -82,7 +82,11 @@ module MergeRequestsHelper
end
def merge_request_button_visibility(merge_request, closed)
return 'hidden' if merge_request.closed? == closed || (merge_request.merged? == closed && !merge_request.closed?) || merge_request.closed_without_fork?
return 'hidden' if merge_request_button_hidden?(merge_request, closed)
end
def merge_request_button_hidden?(merge_request, closed)
merge_request.closed? == closed || (merge_request.merged? == closed && !merge_request.closed?) || merge_request.closed_without_fork?
end
def merge_request_version_path(project, merge_request, merge_request_diff, start_sha = nil)
......
......@@ -183,6 +183,12 @@ class ApplicationSetting < ActiveRecord::Base
numericality: { less_than_or_equal_to: :gitaly_timeout_default },
if: :gitaly_timeout_default
validates :diff_max_patch_bytes,
presence: true,
numericality: { only_integer: true,
greater_than_or_equal_to: Gitlab::Git::Diff::DEFAULT_MAX_PATCH_BYTES,
less_than_or_equal_to: Gitlab::Git::Diff::MAX_PATCH_BYTES_UPPER_BOUND }
validates :user_default_internal_regex, js_regex: true, allow_nil: true
SUPPORTED_KEY_TYPES.each do |type|
......@@ -294,7 +300,8 @@ class ApplicationSetting < ActiveRecord::Base
user_default_external: false,
user_default_internal_regex: nil,
user_show_add_ssh_key_message: true,
usage_stats_set_by_user_id: nil
usage_stats_set_by_user_id: nil,
diff_max_patch_bytes: Gitlab::Git::Diff::DEFAULT_MAX_PATCH_BYTES
}
end
......
......@@ -526,6 +526,13 @@ module Ci
self.job_artifacts.update_all(expire_at: nil)
end
def artifacts_file_for_type(type)
file = job_artifacts.find_by(file_type: Ci::JobArtifact.file_types[type])&.file
# TODO: to be removed once legacy artifacts is removed
file ||= legacy_artifacts_file if type == :archive
file
end
def coverage_regex
super || project.try(:build_coverage_regex)
end
......
......@@ -17,6 +17,7 @@ module Ci
metadata: nil,
trace: nil,
junit: 'junit.xml',
codequality: 'codequality.json',
sast: 'gl-sast-report.json',
dependency_scanning: 'gl-dependency-scanning-report.json',
container_scanning: 'gl-container-scanning-report.json',
......@@ -28,6 +29,7 @@ module Ci
metadata: :gzip,
trace: :raw,
junit: :gzip,
codequality: :gzip,
sast: :gzip,
dependency_scanning: :gzip,
container_scanning: :gzip,
......@@ -76,7 +78,8 @@ module Ci
sast: 5, ## EE-specific
dependency_scanning: 6, ## EE-specific
container_scanning: 7, ## EE-specific
dast: 8 ## EE-specific
dast: 8, ## EE-specific
codequality: 9 ## EE-specific
}
enum file_format: {
......
......@@ -5,8 +5,10 @@ module Storage
extend ActiveSupport::Concern
def move_dir
if any_project_has_container_registry_tags?
raise Gitlab::UpdatePathError.new('Namespace cannot be moved, because at least one project has tags in container registry')
proj_with_tags = first_project_with_container_registry_tags
if proj_with_tags
raise Gitlab::UpdatePathError.new("Namespace #{name} (#{id}) cannot be moved because at least one project (e.g. #{proj_with_tags.name} (#{proj_with_tags.id})) has tags in container registry")
end
parent_was = if parent_changed? && parent_id_was.present?
......
......@@ -136,6 +136,10 @@ class Namespace < ActiveRecord::Base
all_projects.any?(&:has_container_registry_tags?)
end
def first_project_with_container_registry_tags
all_projects.find(&:has_container_registry_tags?)
end
def send_update_instructions
projects.each do |project|
project.send_move_instructions("#{full_path_was}/#{project.path}")
......
......@@ -1381,6 +1381,18 @@ class Project < ActiveRecord::Base
end
end
# Filters `users` to return only authorized users of the project
def members_among(users)
if users.is_a?(ActiveRecord::Relation) && !users.loaded?
authorized_users.merge(users)
else
return [] if users.empty?
user_ids = authorized_users.where(users: { id: users.map(&:id) }).pluck(:id)
users.select { |user| user_ids.include?(user.id) }
end
end
def default_branch
@default_branch ||= repository.root_ref if repository.exists?
end
......
= form_for @application_setting, url: admin_application_settings_path(anchor: 'js-merge-request-settings'), html: { class: 'fieldset-form' } do |f|
= form_errors(@application_setting)
%fieldset
.form-group
= f.label :diff_max_patch_bytes, 'Maximum diff patch size (Bytes)', class: 'label-light'
= f.number_field :diff_max_patch_bytes, class: 'form-control'
%span.form-text.text-muted
Diff files surpassing this limit will be presented as 'too large'
and won't be expandable.
= link_to icon('question-circle'),
help_page_path('user/admin_area/diff_limits',
anchor: 'maximum-diff-patch-size')
= f.submit _('Save changes'), class: 'btn btn-success'
......@@ -24,6 +24,17 @@
.settings-content
= render 'account_and_limit'
%section.settings.as-diff-limits.no-animate#js-merge-request-settings{ class: ('expanded' if expanded_by_default?) }
.settings-header
%h4
= _('Diff limits')
%button.btn.js-settings-toggle{ type: 'button' }
= expanded_by_default? ? _('Collapse') : _('Expand')
%p
= _('Diff content limits')
.settings-content
= render 'diff_limits'
%section.settings.as-signup.no-animate#js-signup-settings{ class: ('expanded' if expanded_by_default?) }
.settings-header
%h4
......
......@@ -18,14 +18,15 @@
Preview
%li.md-header-toolbar.active
= markdown_toolbar_button({ icon: "bold", data: { "md-tag" => "**" }, title: "Add bold text" })
= markdown_toolbar_button({ icon: "italic", data: { "md-tag" => "*" }, title: "Add italic text" })
= markdown_toolbar_button({ icon: "quote", data: { "md-tag" => "> ", "md-prepend" => true }, title: "Insert a quote" })
= markdown_toolbar_button({ icon: "code", data: { "md-tag" => "`", "md-block" => "```" }, title: "Insert code" })
= markdown_toolbar_button({ icon: "list-bulleted", data: { "md-tag" => "* ", "md-prepend" => true }, title: "Add a bullet list" })
= markdown_toolbar_button({ icon: "list-numbered", data: { "md-tag" => "1. ", "md-prepend" => true }, title: "Add a numbered list" })
= markdown_toolbar_button({ icon: "task-done", data: { "md-tag" => "* [ ] ", "md-prepend" => true }, title: "Add a task list" })
%button.toolbar-btn.toolbar-fullscreen-btn.js-zen-enter.has-tooltip{ type: "button", tabindex: -1, "aria-label": "Go full screen", title: "Go full screen", data: { container: "body" } }
= markdown_toolbar_button({ icon: "bold", data: { "md-tag" => "**" }, title: s_("MarkdownToolbar|Add bold text") })
= markdown_toolbar_button({ icon: "italic", data: { "md-tag" => "*" }, title: s_("MarkdownToolbar|Add italic text") })
= markdown_toolbar_button({ icon: "quote", data: { "md-tag" => "> ", "md-prepend" => true }, title: s_("MarkdownToolbar|Insert a quote") })
= markdown_toolbar_button({ icon: "code", data: { "md-tag" => "`", "md-block" => "```" }, title: s_("MarkdownToolbar|Insert code") })
= markdown_toolbar_button({ icon: "link", data: { "md-tag" => "[{text}](url)", "md-select" => "url" }, title: s_("MarkdownToolbar|Add a link") })
= markdown_toolbar_button({ icon: "list-bulleted", data: { "md-tag" => "* ", "md-prepend" => true }, title: s_("MarkdownToolbar|Add a bullet list") })
= markdown_toolbar_button({ icon: "list-numbered", data: { "md-tag" => "1. ", "md-prepend" => true }, title: s_("MarkdownToolbar|Add a numbered list") })
= markdown_toolbar_button({ icon: "task-done", data: { "md-tag" => "* [ ] ", "md-prepend" => true }, title: s_("MarkdownToolbar|Add a task list") })
%button.toolbar-btn.toolbar-fullscreen-btn.js-zen-enter.has-tooltip{ type: "button", tabindex: -1, "aria-label": "Go full screen", title: s_("MarkdownToolbar|Go full screen"), data: { container: "body" } }
= sprite_icon("screen-full")
.md-write-holder
......
.group-empty-state.row.align-items-center.justify-content-center.qa-groups-empty-state
.group-empty-state.row.align-items-center.justify-content-center
.icon.text-center.order-md-2
= custom_icon("icon_empty_groups")
......
= form_tag request.path, method: :get, class: "group-filter-form js-group-filter-form", id: 'group-filter-form' do |f|
= search_field_tag :filter, params[:filter], placeholder: s_('GroupsTree|Search by name'), class: 'group-filter-form-field form-control js-groups-list-filter', spellcheck: false, id: 'group-filter-form-field', tabindex: "2"
= search_field_tag :filter, params[:filter], placeholder: s_('GroupsTree|Search by name'), class: 'group-filter-form-field form-control js-groups-list-filter qa-groups-filter', spellcheck: false, id: 'group-filter-form-field', tabindex: "2"
- is_current_user = issuable_author_is_current_user(issuable)
- display_issuable_type = issuable_display_type(issuable)
- button_method = issuable_close_reopen_button_method(issuable)
- are_close_and_open_buttons_hidden = issuable_button_hidden?(issuable, true) && issuable_button_hidden?(issuable, false)
- if can_update
- if is_current_user
- if is_current_user
- if can_update
= link_to "Close #{display_issuable_type}", close_issuable_path(issuable), method: button_method,
class: "d-none d-sm-none d-md-block btn btn-grouped btn-close js-btn-issue-action #{issuable_button_visibility(issuable, true)}", title: "Close #{display_issuable_type}"
- else
= render 'shared/issuable/close_reopen_report_toggle', issuable: issuable
- if can_reopen && is_current_user
- if can_reopen
= link_to "Reopen #{display_issuable_type}", reopen_issuable_path(issuable), method: button_method,
class: "d-none d-sm-none d-md-block btn btn-grouped btn-reopen js-btn-issue-action #{issuable_button_visibility(issuable, false)}", title: "Reopen #{display_issuable_type}"
- else
= link_to 'Report abuse', new_abuse_report_path(user_id: issuable.author.id, ref_url: issuable_url(issuable)),
class: 'd-none d-sm-none d-md-block btn btn-grouped btn-close-color', title: 'Report abuse'
- if can_update && !are_close_and_open_buttons_hidden
= render 'shared/issuable/close_reopen_report_toggle', issuable: issuable
- else
= link_to 'Report abuse', new_abuse_report_path(user_id: issuable.author.id, ref_url: issuable_url(issuable)),
class: 'd-none d-sm-none d-md-block btn btn-grouped btn-close-color', title: 'Report abuse'
---
title: Add link button to markdown editor toolbar
merge_request: 18579
author: Jan Beckmann
type: added
---
title: Hides Close Merge request btn on merged Merge request
merge_request: 21840
author: Jacopo Beschi @jacopo-beschi
type: fixed
---
title: Fix migration to avoid an exception during upgrade
merge_request: 22055
author:
type: fixed
---
title: Use local tiller for Auto DevOps
merge_request: 22036
author:
type: changed
---
title: Show SHA for pre-release versions on the help page
merge_request: 22026
author:
type: changed
---
title: Make single diff patch limit configurable
merge_request: 21886
author:
type: added
---
title: Improve logging when username update fails due to registry tags
merge_request: 22038
author:
type: other
---
title: Highlight current user in comments
merge_request: 21406
author:
type: changed
# frozen_string_literal: true
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
class AddDiffMaxPatchBytesToApplicationSettings < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
# Set this constant to true if this migration requires downtime.
DOWNTIME = false
disable_ddl_transaction!
def up
add_column_with_default(:application_settings,
:diff_max_patch_bytes,
:integer,
default: 100.kilobytes,
allow_null: false)
end
def down
remove_column(:application_settings, :diff_max_patch_bytes)
end
end
......@@ -5,6 +5,8 @@ class RenameLoginRootNamespaces < ActiveRecord::Migration
DOWNTIME = false
disable_ddl_transaction!
# We're taking over the /login namespace as part of a fix for the Jira integration
def up
disable_statement_timeout do
......
......@@ -11,7 +11,11 @@
#
# It's strongly recommended that you check this file into your version control system.
<<<<<<< HEAD
ActiveRecord::Schema.define(version: 20180924070647) do
=======
ActiveRecord::Schema.define(version: 20180924141949) do
>>>>>>> upstream/master
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
......@@ -217,6 +221,7 @@ ActiveRecord::Schema.define(version: 20180924070647) do
t.integer "custom_project_templates_group_id"
t.integer "usage_stats_set_by_user_id"
t.integer "receive_max_input_size"
t.integer "diff_max_patch_bytes", default: 102400, null: false
end
create_table "approvals", force: :cascade do |t|
......
......@@ -56,6 +56,7 @@ Learn how to install, configure, update, and maintain your GitLab instance.
- [Enforcing Terms of Service](../user/admin_area/settings/terms.md)
- [Third party offers](../user/admin_area/settings/third_party_offers.md)
- [Compliance](compliance.md): A collection of features from across the application that you may configure to help ensure that your GitLab instance and DevOps workflow meet compliance standards.
- [Diff limits](../user/admin_area/diff_limits.md): Configure the diff rendering size limits of branch comparison pages.
#### Customizing GitLab's appearance
......
......@@ -2,13 +2,10 @@
Currently we rely on different sources to present diffs, these include:
- Rugged gem
- Gitaly service
- Database (through `merge_request_diff_files`)
- Redis (cached highlighted diffs)
We're constantly moving Rugged calls to Gitaly and the progress can be followed through [Gitaly repo](https://gitlab.com/gitlab-org/gitaly).
## Architecture overview
### Merge request diffs
......@@ -19,8 +16,9 @@ we fetch the comparison information using `Gitlab::Git::Compare`, which fetches
The diffs fetching process _limits_ single file diff sizes and the overall size of the whole diff through a series of constant values. Raw diff files are
then persisted on `merge_request_diff_files` table.
Even though diffs higher than 10kb are collapsed (`Gitlab::Git::Diff::COLLAPSE_LIMIT`), we still keep them on Postgres. However, diff files over _safety limits_
(see the [Diff limits section](#diff-limits)) are _not_ persisted.
Even though diffs larger than 10% of the value of `ApplicationSettings#diff_max_patch_bytes` are collapsed,
we still keep them on Postgres. However, diff files larger than defined _safety limits_
(see the [Diff limits section](#diff-limits)) are _not_ persisted in the database.
In order to present diffs information on the Merge Request diffs page, we:
......@@ -102,23 +100,20 @@ Gitaly will only return the safe amount of data to be persisted on `merge_reques
Limits that act onto each diff file of a collection. Files number, lines number and files size are considered.
```ruby
Gitlab::Git::Diff::COLLAPSE_LIMIT = 10.kilobytes
```
#### Expandable patches (collapsed)
File diff will be collapsed (but be expandable) if it is larger than 10 kilobytes.
Diff patches are collapsed when surpassing 10% of the value set in `ApplicationSettings#diff_max_patch_bytes`.
That is, it's equivalent to 10kb if the maximum allowed value is 100kb.
The diff will still be persisted and expandable if the patch size doesn't
surpass `ApplicationSettings#diff_max_patch_bytes`.
*Note:* Although this nomenclature (Collapsing) is also used on Gitaly, this limit is only used on GitLab (hardcoded - not sent to Gitaly).
Gitaly will only return `Diff.Collapsed` (RPC) when surpassing collection limits.
```ruby
Gitlab::Git::Diff::SIZE_LIMIT = 100.kilobytes
```
File diff will not be rendered if it's larger than 100 kilobytes.
#### Not expandable patches (too large)
*Note:* This limit is currently hardcoded and applied on Gitaly and the RPC returns `Diff.TooLarge` when this limit is surpassed.
Although we're still also applying it on GitLab, we should remove the redundancy from GitLab once we're confident with the Gitaly integration.
The patch not be rendered if it's larger than `ApplicationSettings#diff_max_patch_bytes`.
Users will see a `This source diff could not be displayed because it is too large` message.
```ruby
Commit::DIFF_SAFE_LINES = Gitlab::Git::DiffCollection::DEFAULT_LIMITS[:max_lines] = 5000
......
# Diff limits administration
NOTE: **Note:**
Merge requests and branch comparison views will be affected.
CAUTION: **Caution:**
These settings are currently under experimental state. They'll
increase the resource consumption of your instance and should
be edited mindfully.
1. Access **Admin area > Settings > General**
1. Expand **Diff limits**
### Maximum diff patch size
This is the content size each diff file (patch) is allowed to reach before
it's collapsed, without the possibility of being expanded. A link redirecting
to the blob view will be presented for the patches that surpass this limit.
Patches surpassing 10% of this content size will be automatically collapsed,
but expandable (a link to expand the diff will be presented).
......@@ -11,7 +11,7 @@ module Gitlab
include Validatable
include Attributable
ALLOWED_KEYS = %i[junit sast dependency_scanning container_scanning dast].freeze
ALLOWED_KEYS = %i[junit codequality sast dependency_scanning container_scanning dast].freeze