Commit 91f36e73 authored by Adam Hegyi's avatar Adam Hegyi Committed by Mayra Cabrera

Use finders in VSA

This change alters the base query in VSA to use the standard Issuable
finders.
parent 936c99b2
...@@ -10,33 +10,25 @@ module EE::Gitlab::Analytics::CycleAnalytics::BaseQueryBuilder ...@@ -10,33 +10,25 @@ module EE::Gitlab::Analytics::CycleAnalytics::BaseQueryBuilder
private private
# rubocop: disable CodeReuse/ActiveRecord override :build_finder_params
def filter_by_project_ids(query) def build_finder_params(params)
project_ids = Array(params[:project_ids]) super.tap do |finder_params|
finder_params[:project_ids] = Array(params[:project_ids])
query = query.where(project_id: project_ids) if project_ids.any? end
query
end end
# rubocop: enable CodeReuse/ActiveRecord
override :filter_by_parent_model override :add_parent_model_params!
# rubocop: disable CodeReuse/ActiveRecord def add_parent_model_params!(finder_params)
def filter_by_parent_model(query)
return super unless parent_class.eql?(Group) return super unless parent_class.eql?(Group)
if subject_class.eql?(Issue) finder_params.merge!(group_id: stage.parent_id, include_subgroups: true)
join_groups(query.joins(:project))
elsif subject_class.eql?(MergeRequest)
join_groups(query.joins(:target_project))
else
raise ArgumentError, "unknown subject_class: #{subject_class}"
end
end end
# rubocop: enable CodeReuse/ActiveRecord
# rubocop: disable CodeReuse/ActiveRecord # rubocop: disable CodeReuse/ActiveRecord
def join_groups(query) def filter_by_project_ids(query)
query.joins(Arel.sql("INNER JOIN (#{stage.parent.self_and_descendants.to_sql}) namespaces ON namespaces.id=projects.namespace_id")) return query if params[:project_ids].empty?
query.where(project_id: params[:project_ids])
end end
# rubocop: enable CodeReuse/ActiveRecord # rubocop: enable CodeReuse/ActiveRecord
end end
...@@ -2,9 +2,4 @@ ...@@ -2,9 +2,4 @@
module EE::Gitlab::Analytics::CycleAnalytics::RecordsFetcher module EE::Gitlab::Analytics::CycleAnalytics::RecordsFetcher
extend ::Gitlab::Utils::Override extend ::Gitlab::Utils::Override
override :finder_params
def finder_params
super.merge({ ::Group => { group_id: stage.parent_id } })
end
end end
...@@ -43,7 +43,8 @@ module Gitlab ...@@ -43,7 +43,8 @@ module Gitlab
params: { params: {
from: @options[:from], from: @options[:from],
to: @options[:to] || DateTime.now, to: @options[:to] || DateTime.now,
project_ids: @options[:projects] project_ids: @options[:projects],
current_user: @current_user
} }
) )
end end
......
...@@ -8,6 +8,12 @@ describe Gitlab::Analytics::CycleAnalytics::BaseQueryBuilder do ...@@ -8,6 +8,12 @@ describe Gitlab::Analytics::CycleAnalytics::BaseQueryBuilder do
let_it_be(:project_in_group) { create(:project, :repository, group: group) } let_it_be(:project_in_group) { create(:project, :repository, group: group) }
let_it_be(:project_in_subgroup) { create(:project, :repository, group: subgroup) } let_it_be(:project_in_subgroup) { create(:project, :repository, group: subgroup) }
let_it_be(:project_outside_group) { create(:project, :repository, group: create(:group)) } let_it_be(:project_outside_group) { create(:project, :repository, group: create(:group)) }
let_it_be(:user) { create(:user) }
before do
group.add_maintainer(user)
project_outside_group.add_maintainer(user)
end
context 'when the subject is `Issue`' do context 'when the subject is `Issue`' do
let(:issue_in_project) { create(:issue, project: project_in_group, created_at: 5.days.ago) } let(:issue_in_project) { create(:issue, project: project_in_group, created_at: 5.days.ago) }
...@@ -27,7 +33,7 @@ describe Gitlab::Analytics::CycleAnalytics::BaseQueryBuilder do ...@@ -27,7 +33,7 @@ describe Gitlab::Analytics::CycleAnalytics::BaseQueryBuilder do
group: group group: group
}) })
result = described_class.new(stage: stage).build result = described_class.new(stage: stage, params: { current_user: user }).build
expect(result).to contain_exactly(issue_in_project, issue_in_subgroup_project) expect(result).to contain_exactly(issue_in_project, issue_in_subgroup_project)
end end
...@@ -51,7 +57,7 @@ describe Gitlab::Analytics::CycleAnalytics::BaseQueryBuilder do ...@@ -51,7 +57,7 @@ describe Gitlab::Analytics::CycleAnalytics::BaseQueryBuilder do
group: group group: group
}) })
result = described_class.new(stage: stage).build result = described_class.new(stage: stage, params: { current_user: user }).build
expect(result).to contain_exactly(mr_in_project, mr_in_subgroup_project) expect(result).to contain_exactly(mr_in_project, mr_in_subgroup_project)
end end
......
...@@ -8,21 +8,24 @@ module Gitlab ...@@ -8,21 +8,24 @@ module Gitlab
delegate :subject_class, to: :stage delegate :subject_class, to: :stage
# rubocop: disable CodeReuse/ActiveRecord FINDER_CLASSES = {
MergeRequest.to_s => MergeRequestsFinder,
Issue.to_s => IssuesFinder
}.freeze
def initialize(stage:, params: {}) def initialize(stage:, params: {})
@stage = stage @stage = stage
@params = params @params = build_finder_params(params)
end end
# rubocop: disable CodeReuse/ActiveRecord
def build def build
query = subject_class query = finder.execute
query = filter_by_parent_model(query)
query = filter_by_time_range(query)
query = stage.start_event.apply_query_customization(query) query = stage.start_event.apply_query_customization(query)
query = stage.end_event.apply_query_customization(query) query = stage.end_event.apply_query_customization(query)
query.where(duration_condition) query.where(duration_condition)
end end
# rubocop: enable CodeReuse/ActiveRecord
private private
...@@ -32,38 +35,33 @@ module Gitlab ...@@ -32,38 +35,33 @@ module Gitlab
stage.end_event.timestamp_projection.gteq(stage.start_event.timestamp_projection) stage.end_event.timestamp_projection.gteq(stage.start_event.timestamp_projection)
end end
def filter_by_parent_model(query) def finder
if parent_class.eql?(Project) FINDER_CLASSES.fetch(subject_class.to_s).new(params[:current_user], params)
if subject_class.eql?(Issue)
query.where(project_id: stage.parent_id)
elsif subject_class.eql?(MergeRequest)
query.where(target_project_id: stage.parent_id)
else
raise ArgumentError, "unknown subject_class: #{subject_class}"
end
else
raise ArgumentError, "unknown parent_class: #{parent_class}"
end
end end
def filter_by_time_range(query) def parent_class
from = params.fetch(:from, 30.days.ago) stage.parent.class
to = params[:to]
query = query.where(subject_table[:created_at].gteq(from))
query = query.where(subject_table[:created_at].lteq(to)) if to
query
end end
def subject_table def build_finder_params(params)
subject_class.arel_table {}.tap do |finder_params|
finder_params[:current_user] = params[:current_user]
add_parent_model_params!(finder_params)
add_time_range_params!(finder_params, params[:from], params[:to])
end
end end
def parent_class def add_parent_model_params!(finder_params)
stage.parent.class raise(ArgumentError, "unknown parent_class: #{parent_class}") unless parent_class.eql?(Project)
finder_params[:project_id] = stage.parent_id
end end
# rubocop: enable CodeReuse/ActiveRecord def add_time_range_params!(finder_params, from, to)
finder_params[:created_after] = from || 30.days.ago
finder_params[:created_before] = to if to
end
end end
end end
end end
......
...@@ -11,12 +11,14 @@ module Gitlab ...@@ -11,12 +11,14 @@ module Gitlab
@query = query @query = query
end end
# rubocop: disable CodeReuse/ActiveRecord
def seconds def seconds
@query = @query.select(median_duration_in_seconds.as('median')) @query = @query.select(median_duration_in_seconds.as('median')).reorder(nil)
result = execute_query(@query).first || {} result = execute_query(@query).first || {}
result['median'] || nil result['median'] || nil
end end
# rubocop: enable CodeReuse/ActiveRecord
def days def days
seconds ? seconds.fdiv(1.day) : nil seconds ? seconds.fdiv(1.day) : nil
......
...@@ -12,13 +12,11 @@ module Gitlab ...@@ -12,13 +12,11 @@ module Gitlab
MAPPINGS = { MAPPINGS = {
Issue => { Issue => {
finder_class: IssuesFinder,
serializer_class: AnalyticsIssueSerializer, serializer_class: AnalyticsIssueSerializer,
includes_for_query: { project: [:namespace], author: [] }, includes_for_query: { project: [:namespace], author: [] },
columns_for_select: %I[title iid id created_at author_id project_id] columns_for_select: %I[title iid id created_at author_id project_id]
}, },
MergeRequest => { MergeRequest => {
finder_class: MergeRequestsFinder,
serializer_class: AnalyticsMergeRequestSerializer, serializer_class: AnalyticsMergeRequestSerializer,
includes_for_query: { target_project: [:namespace], author: [] }, includes_for_query: { target_project: [:namespace], author: [] },
columns_for_select: %I[title iid id created_at author_id state_id target_project_id] columns_for_select: %I[title iid id created_at author_id state_id target_project_id]
...@@ -56,27 +54,12 @@ module Gitlab ...@@ -56,27 +54,12 @@ module Gitlab
attr_reader :stage, :query, :params attr_reader :stage, :query, :params
def finder_query
MAPPINGS
.fetch(subject_class)
.fetch(:finder_class)
.new(params.fetch(:current_user), finder_params.fetch(stage.parent.class))
.execute
end
def columns def columns
MAPPINGS.fetch(subject_class).fetch(:columns_for_select).map do |column_name| MAPPINGS.fetch(subject_class).fetch(:columns_for_select).map do |column_name|
subject_class.arel_table[column_name] subject_class.arel_table[column_name]
end end
end end
# EE will override this to include Group rules
def finder_params
{
Project => { project_id: stage.parent_id }
}
end
def default_test_stage? def default_test_stage?
stage.matches_with_stage_params?(Gitlab::Analytics::CycleAnalytics::DefaultStages.params_for_test_stage) stage.matches_with_stage_params?(Gitlab::Analytics::CycleAnalytics::DefaultStages.params_for_test_stage)
end end
...@@ -113,8 +96,7 @@ module Gitlab ...@@ -113,8 +96,7 @@ module Gitlab
end end
def records def records
results = finder_query results = ordered_and_limited_query
.merge(ordered_and_limited_query)
.select(*columns, round_duration_to_seconds.as('total_time')) .select(*columns, round_duration_to_seconds.as('total_time'))
# using preloader instead of includes to avoid AR generating a large column list # using preloader instead of includes to avoid AR generating a large column list
......
...@@ -6,7 +6,8 @@ describe Gitlab::Analytics::CycleAnalytics::BaseQueryBuilder do ...@@ -6,7 +6,8 @@ describe Gitlab::Analytics::CycleAnalytics::BaseQueryBuilder do
let_it_be(:project) { create(:project, :empty_repo) } let_it_be(:project) { create(:project, :empty_repo) }
let_it_be(:mr1) { create(:merge_request, target_project: project, source_project: project, allow_broken: true, created_at: 3.months.ago) } let_it_be(:mr1) { create(:merge_request, target_project: project, source_project: project, allow_broken: true, created_at: 3.months.ago) }
let_it_be(:mr2) { create(:merge_request, target_project: project, source_project: project, allow_broken: true, created_at: 1.month.ago) } let_it_be(:mr2) { create(:merge_request, target_project: project, source_project: project, allow_broken: true, created_at: 1.month.ago) }
let(:params) { {} } let_it_be(:user) { create(:user) }
let(:params) { { current_user: user } }
let(:records) do let(:records) do
stage = build(:cycle_analytics_project_stage, { stage = build(:cycle_analytics_project_stage, {
start_event_identifier: :merge_request_created, start_event_identifier: :merge_request_created,
...@@ -17,6 +18,7 @@ describe Gitlab::Analytics::CycleAnalytics::BaseQueryBuilder do ...@@ -17,6 +18,7 @@ describe Gitlab::Analytics::CycleAnalytics::BaseQueryBuilder do
end end
before do before do
project.add_maintainer(user)
mr1.metrics.update!(merged_at: 1.month.ago) mr1.metrics.update!(merged_at: 1.month.ago)
mr2.metrics.update!(merged_at: Time.now) mr2.metrics.update!(merged_at: Time.now)
end end
......
...@@ -23,7 +23,7 @@ describe Gitlab::Analytics::CycleAnalytics::RecordsFetcher do ...@@ -23,7 +23,7 @@ describe Gitlab::Analytics::CycleAnalytics::RecordsFetcher do
describe '#serialized_records' do describe '#serialized_records' do
shared_context 'when records are loaded by maintainer' do shared_context 'when records are loaded by maintainer' do
before do before do
project.add_user(user, Gitlab::Access::MAINTAINER) project.add_user(user, Gitlab::Access::DEVELOPER)
end end
it 'returns all records' do it 'returns all records' do
...@@ -103,6 +103,8 @@ describe Gitlab::Analytics::CycleAnalytics::RecordsFetcher do ...@@ -103,6 +103,8 @@ describe Gitlab::Analytics::CycleAnalytics::RecordsFetcher do
latest_build_finished_at: 7.days.ago, latest_build_finished_at: 7.days.ago,
pipeline: ci_build2.pipeline pipeline: ci_build2.pipeline
}) })
project.add_user(user, Gitlab::Access::MAINTAINER)
end end
context 'returns build records' do context 'returns build records' do
......
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