Commit cd5b3e33 authored by Jan Provaznik's avatar Jan Provaznik

Merge branch '324687-expose-limited-record-count-in-vsa' into 'master'

Expose stage counts in VSA

See merge request gitlab-org/gitlab!59642
parents 6bf05c3a a9aafa5f
......@@ -9,7 +9,8 @@ module Groups
before_action :load_group
before_action :load_value_stream
before_action :validate_params, only: %i[median average records duration_chart average_duration_chart]
before_action :validate_params, only: %i[median average records duration_chart average_duration_chart count]
before_action :authorize_read_group_stage, only: %i[median average records duration_chart average_duration_chart count]
def index
return render_403 unless can?(current_user, :read_group_cycle_analytics, @group)
......@@ -42,20 +43,14 @@ module Groups
end
def median
return render_403 unless can?(current_user, :read_group_stage, @group)
render json: { value: data_collector.median.seconds }
end
def average
return render_403 unless can?(current_user, :read_group_stage, @group)
render json: { value: data_collector.average.seconds }
end
def records
return render_403 unless can?(current_user, :read_group_stage, @group)
serialized_records = data_collector.serialized_records do |relation|
add_pagination_headers(relation)
end
......@@ -64,17 +59,17 @@ module Groups
end
def duration_chart
return render_403 unless can?(current_user, :read_group_stage, @group)
render json: ::Analytics::CycleAnalytics::DurationChartItemEntity.represent(data_collector.duration_chart_data)
end
def average_duration_chart
return render_403 unless can?(current_user, :read_group_stage, @group)
render json: ::Analytics::CycleAnalytics::DurationChartAverageItemEntity.represent(data_collector.duration_chart_average_data)
end
def count
render json: { count: data_collector.count }
end
private
def data_collector
......@@ -156,6 +151,10 @@ module Groups
params: permitted_cycle_analytics_params
).execute(exclude_total_headers: true, data_without_counts: true)
end
def authorize_read_group_stage
return render_403 unless can?(current_user, :delete_group_stage, @group)
end
end
end
end
......
......@@ -32,6 +32,7 @@ constraints(::Constraints::GroupUrlConstrainer.new) do
get :median
get :average
get :records
get :count
end
end
resources :value_streams, only: [:index, :create, :update, :destroy] do
......@@ -42,6 +43,7 @@ constraints(::Constraints::GroupUrlConstrainer.new) do
get :median
get :average
get :records
get :count
end
end
end
......
......@@ -110,6 +110,12 @@ RSpec.describe Gitlab::Analytics::CycleAnalytics::DataCollector do
})
end
end
describe '#count' do
subject(:count) { data_collector.count }
it { is_expected.to eq(3) }
end
end
shared_examples 'test various start and end event combinations' do
......@@ -692,4 +698,52 @@ RSpec.describe Gitlab::Analytics::CycleAnalytics::DataCollector do
end
end
end
describe 'limit count' do
let_it_be(:user) { create(:user) }
let_it_be(:group) { create(:group) }
let_it_be(:project) { create(:project, :repository, group: group) }
let(:merge_request) { merge_requests.first }
let(:stage) do
Analytics::CycleAnalytics::GroupStage.new(
name: 'My Stage',
group: group,
start_event_identifier: :merge_request_created,
end_event_identifier: :merge_request_merged
)
end
before do
merge_requests = create_list(:merge_request, 3, :unique_branches, target_project: project, source_project: project)
merge_requests.each { |mr| mr.metrics.update!(merged_at: 10.days.from_now) }
project.add_user(user, Gitlab::Access::DEVELOPER)
end
subject(:count) do
described_class.new(stage: stage, params: {
from: 5.months.ago,
to: 5.months.from_now,
current_user: user
}).count
end
context 'when limit is reached' do
before do
stub_const('Gitlab::Analytics::CycleAnalytics::DataCollector::MAX_COUNT', 2)
end
it 'shows the MAX COUNT' do
is_expected.to eq(2)
end
end
context 'when limit is not reached' do
it 'shows the actual count' do
is_expected.to eq(3)
end
end
end
end
......@@ -280,6 +280,20 @@ RSpec.shared_examples 'Value Stream Analytics Stages controller' do
include_examples 'Value Stream Analytics data endpoint examples'
include_examples 'group permission check on the controller level'
end
describe 'GET #count' do
subject { get :count, params: params }
it 'matches the response schema' do
subject
expect(response).to be_successful
expect(json_response['count']).to eq(0)
end
include_examples 'Value Stream Analytics data endpoint examples'
include_examples 'group permission check on the controller level'
end
end
end
......
......@@ -12,6 +12,8 @@ module Gitlab
class DataCollector
include Gitlab::Utils::StrongMemoize
MAX_COUNT = 1001
delegate :serialized_records, to: :records_fetcher
def initialize(stage:, params: {})
......@@ -37,6 +39,12 @@ module Gitlab
end
end
def count
strong_memoize(:count) do
limit_count
end
end
private
attr_reader :stage, :params
......@@ -44,6 +52,13 @@ module Gitlab
def query
BaseQueryBuilder.new(stage: stage, params: params).build
end
# Limiting the maximum number of records so the COUNT(*) query stays efficient for large groups.
# COUNT = 1001, show 1000+ on the UI
# COUNT < 1001, show the actual number on the UI
def limit_count
query.limit(MAX_COUNT).count
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