Commit a2c1856e authored by Douwe Maan's avatar Douwe Maan Committed by Ruben Davila

Merge branch 'repository-size-restrictions' into 'master'

Enforce repository size limit across all projects and groups, includes LFS objects in that limit.

Limit can be set globally, and overridden per group, and/or project.

Backend functionality is there and comprehensive tests are included, but there is still some frontend work to be done and documentation to be added. I'm submitting early for review as we are close to the release.

@DouweM @dbalexandre I'd appreciate it if you both could start with the review while I finish the documentation and the missing frontend parts.

/cc @JobV @regisF 

Fixes #559

Replaces gitlab-org/gitlab-ce!6020

## Screenshots (see gitlab-org/gitlab-ce!6020 for more)

![Screen_Shot_2016-09-18_at_9.55.38_PM](/uploads/66eeaced1f27c7e2115feaa4775a6e99/Screen_Shot_2016-09-18_at_9.55.38_PM.png)

![Screen_Shot_2016-09-18_at_9.57.12_PM](/uploads/d811d6c184044df527bd2f81cff651ce/Screen_Shot_2016-09-18_at_9.57.12_PM.png)

![Screen_Shot_2016-09-18_at_9.58.03_PM](/uploads/a2c5b2695454dda639537304a1bcd99b/Screen_Shot_2016-09-18_at_9.58.03_PM.png)

![Screen_Shot_2016-09-19_at_1.44.19_PM](/uploads/4cc6cca7536787bde49c0b086086cbcb/Screen_Shot_2016-09-19_at_1.44.19_PM.png)

See merge request !740
parent ffa3e2da
......@@ -5,6 +5,7 @@ v 8.12.0 (Unreleased)
- [ES] Instrument Elasticsearch::Git::Repository
- Request only the LDAP attributes we need
- Add 'Sync now' to group members page !704
- Add repository size limits and enforce them !740
- [ES] Instrument other Gitlab::Elastic classes
- [ES] Fix: Elasticsearch does not find partial matches in project names
- Faster Active Directory group membership resolution !719
......
......@@ -134,6 +134,7 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
:usage_ping_enabled,
:repository_storage,
:enabled_git_access_protocol,
:repository_size_limit,
restricted_visibility_levels: [],
import_sources: [],
disabled_oauth_sign_in_sources: []
......
......@@ -66,6 +66,7 @@ class Admin::GroupsController < Admin::ApplicationController
:lfs_enabled,
:name,
:path,
:repository_size_limit,
:request_access_enabled,
:visibility_level
)
......
......@@ -131,12 +131,13 @@ class GroupsController < Groups::ApplicationController
:avatar,
:description,
:lfs_enabled,
:membership_lock,
:name,
:path,
:public,
:repository_size_limit,
:request_access_enabled,
:share_with_group_lock,
:membership_lock,
:visibility_level
)
end
......
......@@ -68,7 +68,9 @@ class Projects::GitHttpController < Projects::GitHttpClientController
def render_denied
if user && user.can?(:read_project, project)
render plain: 'Access denied', status: :forbidden
message = project.above_size_limit? ? access_check.message : 'Access denied'
render plain: message, status: :forbidden
else
# Do not leak information about project existence
render_not_found
......
......@@ -331,6 +331,7 @@ class ProjectsController < Projects::ApplicationController
:mirror,
:mirror_user_id,
:mirror_trigger_builds,
:repository_size_limit,
:reset_approvals_on_push
)
end
......
......@@ -41,6 +41,12 @@ module GroupsHelper
end
end
def size_limit_message_for_group(group)
show_lfs = group.lfs_enabled? ? 'and their respective LFS files' : ''
"Repositories within this group #{show_lfs} will be restricted to this maximum size. Can be overridden inside each project. 0 for unlimited. Leave empty to inherit the global value."
end
def group_lfs_status(group)
status = group.lfs_enabled? ? 'enabled' : 'disabled'
......
module LfsHelper
include Gitlab::Routing.url_helpers
def require_lfs_enabled!
return if Gitlab.config.lfs.enabled
render(
json: {
message: 'Git LFS is not enabled on this GitLab server, contact your admin.',
documentation_url: "#{Gitlab.config.gitlab.url}/help",
documentation_url: help_url,
},
status: 501
)
......@@ -16,7 +18,11 @@ module LfsHelper
return if upload_request? && lfs_upload_access?
if project.public? || (user && user.can?(:read_project, project))
render_lfs_forbidden
if project.above_size_limit? || objects_exceed_repo_limit?
render_size_error
else
render_lfs_forbidden
end
else
render_lfs_not_found
end
......@@ -38,15 +44,25 @@ module LfsHelper
def lfs_upload_access?
return false unless project.lfs_enabled?
return false if project.above_size_limit? || objects_exceed_repo_limit?
has_authentication_ability?(:push_code) && can?(user, :push_code, project)
end
def objects_exceed_repo_limit?
return false unless project.size_limit_enabled?
return @limit_exceeded if defined?(@limit_exceeded)
size_of_objects = objects.sum { |o| o[:size] }
@limit_exceeded = (project.repository_and_lfs_size + size_of_objects.to_mb) > project.actual_size_limit
end
def render_lfs_forbidden
render(
json: {
message: 'Access forbidden. Check your access level.',
documentation_url: "#{Gitlab.config.gitlab.url}/help",
documentation_url: help_url,
},
content_type: "application/vnd.git-lfs+json",
status: 403
......@@ -57,13 +73,24 @@ module LfsHelper
render(
json: {
message: 'Not found.',
documentation_url: "#{Gitlab.config.gitlab.url}/help",
documentation_url: help_url,
},
content_type: "application/vnd.git-lfs+json",
status: 404
)
end
def render_size_error
render(
json: {
message: Gitlab::RepositorySizeError.new(project).push_error,
documentation_url: help_url,
},
content_type: "application/vnd.git-lfs+json",
status: 406
)
end
def storage_project
@storage_project ||= begin
result = project
......
......@@ -214,6 +214,12 @@ module ProjectsHelper
end
end
def size_limit_message(project)
show_lfs = project.lfs_enabled? ? 'including files in LFS' : ''
"The total size of this project's repository #{show_lfs} will be limited to this size. 0 for unlimited. Leave empty to inherit the group/global value."
end
def git_user_name
if current_user
current_user.name
......@@ -231,8 +237,12 @@ module ProjectsHelper
end
def repository_size(project = @project)
size_in_bytes = project.repository_size * 1.megabyte
number_to_human_size(size_in_bytes, delimiter: ',', precision: 2)
size_in_bytes = project.repository_and_lfs_size * 1.megabyte
limit_in_bytes = project.actual_size_limit * 1.megabyte
limit_text = limit_in_bytes.zero? ? '' : "/#{number_to_human_size(limit_in_bytes, delimiter: ',', precision: 2)}"
"#{number_to_human_size(size_in_bytes, delimiter: ',', precision: 2)}#{limit_text}"
end
def default_url_to_repo(project = @project)
......
......@@ -63,6 +63,10 @@ class ApplicationSetting < ActiveRecord::Base
presence: true,
numericality: { only_integer: true, greater_than: 0 }
validates :repository_size_limit,
presence: true,
numericality: { only_integer: true, greater_than_or_equal_to: 0 }
validates :container_registry_token_expire_delay,
presence: true,
numericality: { only_integer: true, greater_than: 0 }
......
......@@ -33,6 +33,9 @@ class Group < Namespace
validates :avatar, file_size: { maximum: 200.kilobytes.to_i }
validates :repository_size_limit,
numericality: { only_integer: true, greater_than_or_equal_to: 0, allow_nil: true }
mount_uploader :avatar, AvatarUploader
after_create :post_create_hook
......@@ -199,6 +202,12 @@ class Group < Namespace
system_hook_service.execute_hooks_for(self, :destroy)
end
def actual_size_limit
return current_application_settings.repository_size_limit if repository_size_limit.nil?
repository_size_limit
end
def system_hook_service
SystemHooksService.new
end
......
......@@ -147,6 +147,10 @@ class Namespace < ActiveRecord::Base
Gitlab.config.lfs.enabled
end
def actual_size_limit
current_application_settings.repository_size_limit
end
private
def repository_storage_paths
......
......@@ -182,6 +182,9 @@ class Project < ActiveRecord::Base
presence: true,
inclusion: { in: ->(_object) { Gitlab.config.repositories.storages.keys } }
validates :repository_size_limit,
numericality: { only_integer: true, greater_than_or_equal_to: 0, allow_nil: true }
with_options if: :mirror? do |project|
project.validates :import_url, presence: true
project.validates :mirror_user, presence: true
......@@ -1531,6 +1534,34 @@ class Project < ActiveRecord::Base
Gitlab::Redis.with { |redis| redis.del(pushes_since_gc_redis_key) }
end
def repository_and_lfs_size
repository_size + lfs_objects.sum(:size).to_i.to_mb
end
def above_size_limit?
return false unless size_limit_enabled?
repository_and_lfs_size > actual_size_limit
end
def size_to_remove
repository_and_lfs_size - actual_size_limit
end
def actual_size_limit
return namespace.actual_size_limit if repository_size_limit.nil?
repository_size_limit
end
def size_limit_enabled?
actual_size_limit != 0
end
def changes_will_exceed_size_limit?(size_mb)
size_limit_enabled? && (size_mb > actual_size_limit || size_mb + repository_and_lfs_size > actual_size_limit)
end
private
def pushes_since_gc_redis_key
......
......@@ -49,6 +49,10 @@ module Files
def validate
allowed = ::Gitlab::UserAccess.new(current_user, project: project).can_push_to_branch?(@target_branch)
if project.above_size_limit?
raise_error(Gitlab::RepositorySizeError.new(project).commit_error)
end
unless allowed
raise_error("You are not allowed to push into this branch")
end
......
......@@ -18,6 +18,12 @@ module MergeRequests
return error('Merge request is not mergeable') unless @merge_request.mergeable?
if @merge_request.target_project.above_size_limit?
message = Gitlab::RepositorySizeError.new(@merge_request.target_project).merge_error
@merge_request.update(merge_error: message)
return error(message)
end
merge_request.in_locked_state do
if commit
after_merge
......
......@@ -99,6 +99,11 @@
= f.label :max_attachment_size, 'Maximum attachment size (MB)', class: 'control-label col-sm-2'
.col-sm-10
= f.number_field :max_attachment_size, class: 'form-control'
.form-group
= f.label :repository_size_limit, 'Per repository size limit (MB)', class: 'control-label col-sm-2'
.col-sm-10
= f.number_field :repository_size_limit, class: 'form-control', min: 0
%span.help-block#repository_size_limit_help_block Includes LFS objects. It can be overridden per group, or per project. 0 for unlimited
.form-group
= f.label :session_expire_delay, 'Session duration (minutes)', class: 'control-label col-sm-2'
.col-sm-10
......
......@@ -2,6 +2,8 @@
= form_errors(@group)
= render 'shared/group_form', f: f
= render 'groups/repository_size_limit_setting', f: f
.form-group.group-description-holder
= f.label :avatar, "Group avatar", class: 'control-label'
.col-sm-10
......
- if current_user.admin?
.form-group
= f.label :repository_size_limit, class: 'control-label' do
Repository size limit (MB)
.col-sm-10
= f.number_field :repository_size_limit, class: 'form-control', min: 0
%span.help-block#repository_size_limit_help_block
= size_limit_message_for_group(@group)
......@@ -6,6 +6,8 @@
= form_errors(@group)
= render 'shared/group_form', f: f
= render 'repository_size_limit_setting', f: f
.form-group
.col-sm-offset-2.col-sm-10
= image_tag group_icon(@group), alt: '', class: 'avatar group-avatar s160'
......
......@@ -34,6 +34,14 @@
= visibility_level_label(@project.visibility_level)
.light= visibility_level_description(@project.visibility_level, @project)
- if current_user.admin?
.form-group
= f.label :repository_size_limit, class: 'label-light' do
Repository size limit (MB)
= f.number_field :repository_size_limit, class: 'form-control', min: 0
%span.help-block#repository_size_limit_help_block
= size_limit_message(@project)
.form-group
= render 'shared/allow_request_access', form: f
......
......@@ -11,6 +11,8 @@
= render 'projects/merge_requests/widget/open/geo'
- if @project.archived?
= render 'projects/merge_requests/widget/open/archived'
- elsif @project.above_size_limit?
= render 'projects/merge_requests/widget/open/size_limit_reached'
- elsif @merge_request.commits.blank?
= render 'projects/merge_requests/widget/open/nothing'
- elsif @merge_request.branch_missing?
......
- error_messages = Gitlab::RepositorySizeError.new(@project)
%h4.size-limit-reached
= icon("exclamation-triangle")
= error_messages.merge_error
%p
= error_messages.more_info_message
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
class AddRepositorySizeLimitToApplicationSettings < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def change
add_column :application_settings, :repository_size_limit, :integer, default: 0
end
end
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
class AddRepositorySizeLimitToProjects < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def change
add_column :projects, :repository_size_limit, :integer
end
end
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
class AddRepositorySizeLimitToNamespaces < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def change
add_column :namespaces, :repository_size_limit, :integer
end
end
......@@ -100,6 +100,7 @@ ActiveRecord::Schema.define(version: 20160913212128) do
t.boolean "usage_ping_enabled", default: true, null: false
t.boolean "koding_enabled"
t.string "koding_url"
t.integer "repository_size_limit", default: 0
end
create_table "approvals", force: :cascade do |t|
......@@ -739,6 +740,7 @@ ActiveRecord::Schema.define(version: 20160913212128) do
t.datetime "ldap_sync_last_successful_update_at"
t.datetime "ldap_sync_last_sync_at"
t.boolean "lfs_enabled"
t.integer "repository_size_limit"
end
add_index "namespaces", ["created_at"], name: "index_namespaces_on_created_at", using: :btree
......@@ -959,6 +961,7 @@ ActiveRecord::Schema.define(version: 20160913212128) do
t.boolean "has_external_wiki"
t.boolean "repository_read_only"
t.boolean "lfs_enabled"
t.integer "repository_size_limit"
end
add_index "projects", ["ci_id"], name: "index_projects_on_ci_id", using: :btree
......
......@@ -68,6 +68,7 @@
- [High Availability](administration/high_availability/README.md) Configure multiple servers for scaling or high availability.
- [Container Registry](administration/container_registry.md) Configure Docker Registry with GitLab.
- [Multiple mountpoints for the repositories storage](administration/repository_storages.md) Define multiple repository storage paths to distribute the storage load.
- [Repository restrictions](administration/repository_restrictions.md) Define size restrictions for your repositories to limit the space they occupy in your storage device. Includes LFS objects.
## Contributor documentation
......
# Repository size restrictions
> Introduced with GitLab Enterprise Edition 8.12
Repositories within your GitLab instance can grow quickly, specially if you are
using LFS. Their size can grow exponentially and eat up your storage device quite
quickly.
In order to avoid this from happening, you can set a hard limit for your repositories.
You can set this limit globally, per group, or per project, with per project limits
taking the highest priority.
These settings can be found within each project, or group settings and within
the Application Settings for the global value.
Setting the limit to `0` means there is no restrictions.
# Restrictions
When a project has reached its size limit, you will not be able to push to it,
create new merge request, or merge existing ones. You will still be able to create
new issues, and clone the project.
Uploading LFS objects will also be denied.
In order to lift these restrictions, the administrator of the GitLab instance
needs to increase the limit on the particular project that exceeded it.
# Limitations
The first push of a new project cannot be checked for size as of now, so the first
push will allow you to upload more than the limit dictates, but every subsequent
push will be denied.
LFS objects, however, can be checked on first push and **will** be rejected if the
sum of their sizes exceeds the maximum allowed repository size.
\ No newline at end of file
module EE
module Gitlab
module Deltas
def self.delta_size_check(change, repo)
size_of_deltas = 0
begin
tree_a = repo.lookup(change[:oldrev])
tree_b = repo.lookup(change[:newrev])
diff = tree_a.diff(tree_b)
diff.each_delta do |d|
new_file_size = d.deleted? ? 0 : ::Gitlab::Git::Blob.raw(repo, d.new_file[:oid]).size
size_of_deltas += new_file_size
end
size_of_deltas
rescue Rugged::OdbError, Rugged::ReferenceError, Rugged::InvalidError
size_of_deltas
end
end
end
end
end
......@@ -104,9 +104,9 @@ module Gitlab
return build_status_object(true)
end
unless project.repository.exists?
return build_status_object(false, "A repository for this project does not exist yet.")
end
return build_status_object(false, "A repository for this project does not exist yet.") unless project.repository.exists?
return build_status_object(false, Gitlab::RepositorySizeError.new(project).push_error) if project.above_size_limit?
if ::License.block_changes?
message = ::LicenseHelper.license_message(signed_in: true, is_admin: (user && user.is_admin?))
......@@ -115,6 +115,8 @@ module Gitlab
changes_list = Gitlab::ChangesList.new(changes)
push_size_in_bytes = 0
# Iterate over all changes to find if user allowed all of them to be applied
changes_list.each do |change|
status = change_access_check(change)
......@@ -122,6 +124,14 @@ module Gitlab
# If user does not have access to make at least one change - cancel all push
return status
end
if project.size_limit_enabled?
push_size_in_bytes += EE::Gitlab::Deltas.delta_size_check(change, project.repository)
end
end
if project.changes_will_exceed_size_limit?(push_size_in_bytes.to_mb)
return build_status_object(false, Gitlab::RepositorySizeError.new(project).new_changes_error)
end
build_status_object(true)
......
module Gitlab
class RepositorySizeError < StandardError
include ActionView::Helpers
attr_reader :project
def initialize(project)
@project = project
end
def to_s
"The size of this repository (#{current_size}) exceeds the limit of #{limit} by #{size_to_remove}."
end
def commit_error
"Your changes could not be committed, #{base_message}"
end
def merge_error
"This merge request cannot be merged, #{base_message}"
end
def push_error
"Your push has been rejected, #{base_message}. #{more_info_message}"
end
def new_changes_error
"Your push to this repository would cause it to exceed the size limit of #{limit} so it has been rejected. #{more_info_message}"
end
def more_info_message
'Please contact your GitLab administrator for more information.'
end
private
def base_message
"because this repository has exceeded its size limit of #{limit} by #{size_to_remove}"
end
def current_size
format_number(project.repository_and_lfs_size)
end
def limit
format_number(project.actual_size_limit)
end
def size_to_remove
format_number(project.size_to_remove)
end
def format_number(number)
number_to_human_size(number * 1.megabyte, delimiter: ',', precision: 2)
end
end
end
......@@ -618,6 +618,24 @@ describe Gitlab::GitAccess, lib: true do
expect(access.push_access_check('cfe32cf61b73a0d5e9f13e774abde7ff789b1660 913c66a37b4a45b9769037c55c2d238bd0942d2e refs/heads/master')).to be_allowed
end
end
describe 'repository size restrictions' do
before do
project.update_attribute(:repository_size_limit, 50)
end
it 'returns false when blob is too big' do
allow_any_instance_of(Gitlab::Git::Blob).to receive(:size).and_return(100.megabytes.to_i)
expect(access.push_access_check('cfe32cf61b73a0d5e9f13e774abde7ff789b1660 913c66a37b4a45b9769037c55c2d238bd0942d2e refs/heads/master')).not_to be_allowed
end
it 'returns true when blob is just right' do
allow_any_instance_of(Gitlab::Git::Blob).to receive(:size).and_return(2.megabytes.to_i)
expect(access.push_access_check('cfe32cf61b73a0d5e9f13e774abde7ff789b1660 913c66a37b4a45b9769037c55c2d238bd0942d2e refs/heads/master')).to be_allowed
end
end
end
end
......
require 'spec_helper'
describe Gitlab::RepositorySizeError, lib: true do
let(:project) { create(:empty_project, repository_size: 15) }
let(:message) { Gitlab::RepositorySizeError.new(project) }
let(:base_message) { 'because this repository has exceeded its size limit of 10 MB by 5 MB' }
before do
allow(project).to receive(:actual_size_limit).and_return(10)
end
describe 'error messages' do
describe '#to_s' do
it 'returns the correct message' do
expect(message.to_s).to eq('The size of this repository (15 MB) exceeds the limit of 10 MB by 5 MB.')
end
end
describe '#commit_error' do
it 'returns the correct message' do
expect(message.commit_error).to eq("Your changes could not be committed, #{base_message}")
end
end
describe '#merge_error' do
it 'returns the correct message' do
expect(message.merge_error).to eq("This merge request cannot be merged, #{base_message}")
end
end
describe '#push_error' do
it 'returns the correct message' do
expect(message.push_error).to eq("Your push has been rejected, #{base_message}. #{message.more_info_message}")
end
end
describe '#new_changes_error' do
it 'returns the correct message' do
expect(message.new_changes_error).to eq("Your push to this repository would cause it to exceed the size limit of 10 MB so it has been rejected. #{message.more_info_message}")
end
end
end
end
......@@ -85,4 +85,22 @@ describe Group, models: true do
expect { group.mark_ldap_sync_as_failed('Error') }.not_to raise_error
end
end
describe '#actual_size_limit' do
let(:group) { build(:group) }
before do
allow_any_instance_of(ApplicationSetting).to receive(:repository_size_limit).and_return(50)
end
it 'returns the value set globally' do
expect(group.actual_size_limit).to eq(50)
end
it 'returns the value set locally' do
group.update_attribute(:repository_size_limit, 75)
expect(group.actual_size_limit).to eq(75)
end
end
end
......@@ -87,6 +87,18 @@ describe Namespace, models: true do
end
end
describe '#actual_size_limit' do
let(:namespace) { build(:namespace) }
before do
allow_any_instance_of(ApplicationSetting).to receive(:repository_size_limit).and_return(50)
end
it 'returns the correct size limit' do
expect(namespace.actual_size_limit).to eq(50)
end
end
describe :rm_dir do
let!(:project) { create(:project, namespace: namespace) }
let!(:path) { File.join(Gitlab.config.repositories.storages.default, namespace.path) }
......
......@@ -482,6 +482,76 @@ describe Project, models: true do
end
end
describe 'repository size restrictions' do
let(:project) { build(:empty_project) }
before do
allow_any_instance_of(ApplicationSetting).to receive(:repository_size_limit).and_return(50)
end
describe '#changes_will_exceed_size_limit?' do
before do
allow(project).to receive(:repository_and_lfs_size).and_return(49)
end
it 'returns true when changes go over' do
expect(project.changes_will_exceed_size_limit?(5)).to be_truthy
end
end
describe '#actual_size_limit' do
it 'returns the limit set in the application settings' do
expect(project.actual_size_limit).to eq(50)
end
it 'returns the value set in the group' do
group = create(:group, repository_size_limit: 100)
project.update_attribute(:namespace_id, group.id)
expect(project.actual_size_limit).to eq(100)
end
it 'returns the value set locally' do
project.update_attribute(:repository_size_limit, 75)
expect(project.actual_size_limit).to eq(75)
end
end
describe '#size_limit_enabled?' do
it 'returns false when disabled' do
project.update_attribute(:repository_size_limit, 0)
expect(project.size_limit_enabled?).to be_falsey
end
it 'returns true when a limit is set' do
project.update_attribute(:repository_size_limit, 75)
expect(project.size_limit_enabled?).to be_truthy
end
end
describe '#above_size_limit?' do
it 'returns true when above the limit' do
allow(project).to receive(:repository_and_lfs_size).and_return(100)
expect(project.above_size_limit?).to be_truthy
end
it 'returns false when not over the limit' do
expect(project.above_size_limit?).to be_falsey
end
end
describe '#size_to_remove' do
it 'returns the correct value' do
allow(project).to receive(:repository_and_lfs_size).and_return(100)
expect(project.size_to_remove).to eq(50)
end
end
end
describe '#default_issues_tracker?' do
let(:project) { create(:project) }
let(:ext_project) { create(:redmine_project) }
......
......@@ -222,6 +222,22 @@ describe 'Git HTTP requests', lib: true do
end
end
context "when repository is above size limit" do
let(:env) { { user: user.username, password: user.password } }
before do
project.team << [user, :master]
end
it 'responds with status 403' do
allow_any_instance_of(Project).to receive(:above_size_limit?).and_return(true)
upload(path, env) do |response|
expect(response).to have_http_status(403)
end
end
end
context "when username and password are provided" do
let(:env) { { user: user.username, password: 'nope' } }
......
......@@ -634,7 +634,7 @@ describe 'Git LFS API and storage' do
{ 'operation' => 'upload',
'objects' => [
{ 'oid' => '91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897',
'size' => 1575078
'size' => 157507855
}]
}
end
......@@ -646,10 +646,31 @@ describe 'Git LFS API and storage' do
it 'responds with upload hypermedia link' do
expect(json_response['objects']).to be_kind_of(Array)
expect(json_response['objects'].first['oid']).to eq("91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897")
expect(json_response['objects'].first['size']).to eq(1575078)
expect(json_response['objects'].first['actions']['upload']['href']).to eq("#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}.git/gitlab-lfs/objects/91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897/1575078")
expect(json_response['objects'].first['size']).to eq(157507855)
expect(json_response['objects'].first['actions']['upload']['href']).to eq("#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}.git/gitlab-lfs/objects/91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897/157507855")
expect(json_response['objects'].first['actions']['upload']['header']).to eq('Authorization' => authorization)
end
context 'and project is above the limit' do
let(:update_lfs_permissions) do
allow_any_instance_of(Project).to receive(:above_size_limit?).and_return(true)
end
it 'responds with status 406' do
expect(response).to have_http_status(406)
end
end
context 'and project will go over the limit' do
let(:update_lfs_permissions) do
allow_any_instance_of(Project).to receive_messages(actual_size_limit: 145, size_limit_enabled?: true)
end
it 'responds with status 406' do
expect(response).to have_http_status(406)
expect(json_response['documentation_url']).to include('/help')
end
end
end
context 'when pushing one new and one existing lfs object' do
......
......@@ -38,6 +38,22 @@ describe MergeRequests::MergeService, services: true do
end
end
context 'project has exceeded size limit' do
let(:service) { MergeRequests::MergeService.new(project, user, commit_message: 'Awesome message') }
before do
allow(project).to receive(:above_size_limit?).and_return(true)
perform_enqueued_jobs do
service.execute(merge_request)
end
end
it 'returns the correct error message' do
expect(merge_request.merge_error).to include('This merge request cannot be merged')
end
end
context 'remove source branch by author' do
let(:service) do
merge_request.merge_params['force_remove_source_branch'] = '1'
......
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