Commit 440f0f46 authored by Stan Hu's avatar Stan Hu Committed by Douglas Barbosa Alexandre

Limit diverging commit counts requests

In https://gitlab.com/gitlab-org/gitlab-ce/issues/66200, we saw that
many clients accidentally request diverging counts for all branches only
because there are no stale/active branches in the project. This has been
fixed on the frontend in
https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/32496.

To prevent this endpoint from calling Gitaly too many times, we require
that branch names be specified if the total number of branches exceeds
the limit (20).
parent 40cfd00d
......@@ -11,6 +11,7 @@ class Projects::BranchesController < Projects::ApplicationController
# Support legacy URLs
before_action :redirect_for_legacy_index_sort_or_search, only: [:index]
before_action :limit_diverging_commit_counts!, only: [:diverging_commit_counts]
def index
respond_to do |format|
......@@ -125,6 +126,24 @@ class Projects::BranchesController < Projects::ApplicationController
private
# It can be expensive to calculate the diverging counts for each
# branch. Normally the frontend should be specifying a set of branch
# names, but prior to
# https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/32496, the
# frontend could omit this set. To prevent excessive I/O, we require
# that a list of names be specified.
def limit_diverging_commit_counts!
return unless Feature.enabled?(:limit_diverging_commit_counts, default_enabled: true)
limit = Kaminari.config.default_per_page
# If we don't have many branches in the repository, then go ahead.
return if project.repository.branch_count <= limit
return if params[:names].present? && Array(params[:names]).length <= limit
render json: { error: "Specify at least one and at most #{limit} branch names" }, status: :unprocessable_entity
end
def ref
if params[:ref]
ref_escaped = strip_tags(sanitize(params[:ref]))
......
---
title: Limit diverging commit counts requests
merge_request: 16737
author:
type: performance
......@@ -578,7 +578,9 @@ describe Projects::BranchesController do
describe 'GET diverging_commit_counts' do
before do
sign_in(user)
end
it 'returns the commit counts behind and ahead of default branch' do
get :diverging_commit_counts,
format: :json,
params: {
......@@ -586,14 +588,58 @@ describe Projects::BranchesController do
project_id: project,
names: ['fix', 'add-pdf-file', 'branch-merged']
}
end
it 'returns the commit counts behind and ahead of default branch' do
expect(response).to have_gitlab_http_status(200)
expect(json_response).to eq(
"fix" => { "behind" => 29, "ahead" => 2 },
"branch-merged" => { "behind" => 1, "ahead" => 0 },
"add-pdf-file" => { "behind" => 0, "ahead" => 3 }
)
end
it 'returns the commits counts with no names provided' do
allow_any_instance_of(Repository).to receive(:branch_count).and_return(Kaminari.config.default_per_page)
get :diverging_commit_counts,
format: :json,
params: {
namespace_id: project.namespace,
project_id: project
}
expect(response).to have_gitlab_http_status(200)
expect(json_response.count).to be > 1
end
describe 'with many branches' do
before do
allow_any_instance_of(Repository).to receive(:branch_count).and_return(Kaminari.config.default_per_page + 1)
end
it 'returns 422 if no names are specified' do
get :diverging_commit_counts,
format: :json,
params: {
namespace_id: project.namespace,
project_id: project
}
expect(response).to have_gitlab_http_status(422)
expect(json_response['error']).to eq("Specify at least one and at most #{Kaminari.config.default_per_page} branch names")
end
it 'returns the list of counts' do
get :diverging_commit_counts,
format: :json,
params: {
namespace_id: project.namespace,
project_id: project,
names: ['fix', 'add-pdf-file', 'branch-merged']
}
expect(response).to have_gitlab_http_status(200)
expect(json_response.count).to be > 1
end
end
end
end
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