Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMałgorzata Ksionek <mksionek@gitlab.com>2019-07-04 17:42:31 +0300
committerMałgorzata Ksionek <mksionek@gitlab.com>2019-07-15 16:06:40 +0300
commitbeaa63530669d10c7244d187fa386144bc5da7eb (patch)
treebc541f200d5a5b2c37ff50e1a75ad1b848e6c396 /lib/gitlab/cycle_analytics
parent0e8af2525f16d871510c24e6e15f1bc80f133edd (diff)
Add class for group level analytics
Add specs for group level Update entities Update base classes Add groups-centric changes Update plan and review stage Add summary classes Add summary spec Update specs files Add to specs test cases for group Add changelog entry Add group serializer Fix typo Fix typo Add fetching namespace in sql query Update specs Add rubocop fix Add rubocop fix Modify method to be in sync with code review Add counting deploys from subgroup To group summary stage Add subgroups handling In group stage summary Add additional spec Add additional specs Add more precise inheritance Add attr reader to group level Fix rubocop offence Fix problems with specs Add cr remarks Renaming median method and a lot of calls in specs Move spec setup Rename method in specs Add code review remarks regarding module Add proper module name
Diffstat (limited to 'lib/gitlab/cycle_analytics')
-rw-r--r--lib/gitlab/cycle_analytics/base_event_fetcher.rb21
-rw-r--r--lib/gitlab/cycle_analytics/base_query.rb14
-rw-r--r--lib/gitlab/cycle_analytics/base_stage.rb24
-rw-r--r--lib/gitlab/cycle_analytics/code_event_fetcher.rb6
-rw-r--r--lib/gitlab/cycle_analytics/group_stage_summary.rb24
-rw-r--r--lib/gitlab/cycle_analytics/issue_event_fetcher.rb6
-rw-r--r--lib/gitlab/cycle_analytics/issue_helper.rb3
-rw-r--r--lib/gitlab/cycle_analytics/metrics_tables.rb8
-rw-r--r--lib/gitlab/cycle_analytics/permissions.rb2
-rw-r--r--lib/gitlab/cycle_analytics/plan_event_fetcher.rb6
-rw-r--r--lib/gitlab/cycle_analytics/plan_helper.rb13
-rw-r--r--lib/gitlab/cycle_analytics/production_event_fetcher.rb6
-rw-r--r--lib/gitlab/cycle_analytics/review_event_fetcher.rb6
-rw-r--r--lib/gitlab/cycle_analytics/summary/group/base.rb24
-rw-r--r--lib/gitlab/cycle_analytics/summary/group/deploy.rb29
-rw-r--r--lib/gitlab/cycle_analytics/summary/group/issue.rb25
16 files changed, 188 insertions, 29 deletions
diff --git a/lib/gitlab/cycle_analytics/base_event_fetcher.rb b/lib/gitlab/cycle_analytics/base_event_fetcher.rb
index 0cacef5b278..96aa799e864 100644
--- a/lib/gitlab/cycle_analytics/base_event_fetcher.rb
+++ b/lib/gitlab/cycle_analytics/base_event_fetcher.rb
@@ -5,12 +5,11 @@ module Gitlab
class BaseEventFetcher
include BaseQuery
- attr_reader :projections, :query, :stage, :order, :project, :options
+ attr_reader :projections, :query, :stage, :order, :options
MAX_EVENTS = 50
- def initialize(project: nil, stage:, options:)
- @project = project
+ def initialize(stage:, options:)
@stage = stage
@options = options
end
@@ -68,11 +67,23 @@ module Gitlab
end
def allowed_ids_source
- { project_id: project.id }
+ group ? { group_id: group.id, include_subgroups: true } : { project_id: project.id }
+ end
+
+ def serialization_context
+ {}
end
def projects
- [project]
+ group ? Project.inside_path(group.full_path) : [project]
+ end
+
+ def group
+ @group ||= options.fetch(:group, nil)
+ end
+
+ def project
+ @project ||= options.fetch(:project, nil)
end
end
end
diff --git a/lib/gitlab/cycle_analytics/base_query.rb b/lib/gitlab/cycle_analytics/base_query.rb
index 39fc1759cfc..9c98c0bfbf2 100644
--- a/lib/gitlab/cycle_analytics/base_query.rb
+++ b/lib/gitlab/cycle_analytics/base_query.rb
@@ -16,17 +16,25 @@ module Gitlab
def stage_query(project_ids)
query = mr_closing_issues_table.join(issue_table).on(issue_table[:id].eq(mr_closing_issues_table[:issue_id]))
.join(issue_metrics_table).on(issue_table[:id].eq(issue_metrics_table[:issue_id]))
+ .join(projects_table).on(issue_table[:project_id].eq(projects_table[:id]))
+ .join(routes_table).on(projects_table[:namespace_id].eq(routes_table[:source_id]))
.project(issue_table[:project_id].as("project_id"))
.where(issue_table[:project_id].in(project_ids))
+ .where(routes_table[:source_type].eq('Namespace'))
.where(issue_table[:created_at].gteq(options[:from]))
# Load merge_requests
- query = query.join(mr_table, Arel::Nodes::OuterJoin)
+
+ query = load_merge_requests(query)
+
+ query
+ end
+
+ def load_merge_requests(query)
+ query.join(mr_table, Arel::Nodes::OuterJoin)
.on(mr_table[:id].eq(mr_closing_issues_table[:merge_request_id]))
.join(mr_metrics_table)
.on(mr_table[:id].eq(mr_metrics_table[:merge_request_id]))
-
- query
end
end
end
diff --git a/lib/gitlab/cycle_analytics/base_stage.rb b/lib/gitlab/cycle_analytics/base_stage.rb
index 98b86e54340..678a891e941 100644
--- a/lib/gitlab/cycle_analytics/base_stage.rb
+++ b/lib/gitlab/cycle_analytics/base_stage.rb
@@ -5,10 +5,9 @@ module Gitlab
class BaseStage
include BaseQuery
- attr_reader :project, :options
+ attr_reader :options
- def initialize(project: nil, options:)
- @project = project
+ def initialize(options:)
@options = options
end
@@ -24,7 +23,7 @@ module Gitlab
raise NotImplementedError.new("Expected #{self.name} to implement title")
end
- def median
+ def project_median
return if project.nil?
BatchLoader.for(project.id).batch(key: name) do |project_ids, loader|
@@ -42,6 +41,10 @@ module Gitlab
end
end
+ def group_median
+ median_query(projects.map(&:id))
+ end
+
def median_query(project_ids)
# Build a `SELECT` query. We find the first of the `end_time_attrs` that isn't `NULL` (call this end_time).
# Next, we find the first of the start_time_attrs that isn't `NULL` (call this start_time).
@@ -67,8 +70,7 @@ module Gitlab
private
def event_fetcher
- @event_fetcher ||= Gitlab::CycleAnalytics::EventFetcher[name].new(project: project,
- stage: name,
+ @event_fetcher ||= Gitlab::CycleAnalytics::EventFetcher[name].new(stage: name,
options: event_options)
end
@@ -77,7 +79,15 @@ module Gitlab
end
def projects
- [project]
+ group ? Project.inside_path(group.full_path) : [project]
+ end
+
+ def group
+ @group ||= options.fetch(:group, nil)
+ end
+
+ def project
+ @project ||= options.fetch(:project, nil)
end
end
end
diff --git a/lib/gitlab/cycle_analytics/code_event_fetcher.rb b/lib/gitlab/cycle_analytics/code_event_fetcher.rb
index 9e7ca529579..1e4e9b9e02c 100644
--- a/lib/gitlab/cycle_analytics/code_event_fetcher.rb
+++ b/lib/gitlab/cycle_analytics/code_event_fetcher.rb
@@ -11,7 +11,9 @@ module Gitlab
mr_table[:id],
mr_table[:created_at],
mr_table[:state],
- mr_table[:author_id]]
+ mr_table[:author_id],
+ projects_table[:name],
+ routes_table[:path]]
@order = mr_table[:created_at]
super(*args)
@@ -20,7 +22,7 @@ module Gitlab
private
def serialize(event)
- AnalyticsMergeRequestSerializer.new(project: project).represent(event)
+ AnalyticsMergeRequestSerializer.new(serialization_context).represent(event)
end
def allowed_ids_finder_class
diff --git a/lib/gitlab/cycle_analytics/group_stage_summary.rb b/lib/gitlab/cycle_analytics/group_stage_summary.rb
new file mode 100644
index 00000000000..7b5c74e1a1b
--- /dev/null
+++ b/lib/gitlab/cycle_analytics/group_stage_summary.rb
@@ -0,0 +1,24 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module CycleAnalytics
+ class GroupStageSummary
+ def initialize(group, from:, current_user:)
+ @group = group
+ @from = from
+ @current_user = current_user
+ end
+
+ def data
+ [serialize(Summary::Group::Issue.new(group: @group, from: @from, current_user: @current_user)),
+ serialize(Summary::Group::Deploy.new(group: @group, from: @from))]
+ end
+
+ private
+
+ def serialize(summary_object)
+ AnalyticsSummarySerializer.new.represent(summary_object)
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/cycle_analytics/issue_event_fetcher.rb b/lib/gitlab/cycle_analytics/issue_event_fetcher.rb
index bb3520ae920..2d03e425a6a 100644
--- a/lib/gitlab/cycle_analytics/issue_event_fetcher.rb
+++ b/lib/gitlab/cycle_analytics/issue_event_fetcher.rb
@@ -10,7 +10,9 @@ module Gitlab
issue_table[:iid],
issue_table[:id],
issue_table[:created_at],
- issue_table[:author_id]]
+ issue_table[:author_id],
+ projects_table[:name],
+ routes_table[:path]]
super(*args)
end
@@ -18,7 +20,7 @@ module Gitlab
private
def serialize(event)
- AnalyticsIssueSerializer.new(project: project).represent(event)
+ AnalyticsIssueSerializer.new(serialization_context).represent(event)
end
def allowed_ids_finder_class
diff --git a/lib/gitlab/cycle_analytics/issue_helper.rb b/lib/gitlab/cycle_analytics/issue_helper.rb
index ac836b8bf0f..0fc4f1dd41a 100644
--- a/lib/gitlab/cycle_analytics/issue_helper.rb
+++ b/lib/gitlab/cycle_analytics/issue_helper.rb
@@ -5,8 +5,11 @@ module Gitlab
module IssueHelper
def stage_query(project_ids)
query = issue_table.join(issue_metrics_table).on(issue_table[:id].eq(issue_metrics_table[:issue_id]))
+ .join(projects_table).on(issue_table[:project_id].eq(projects_table[:id]))
+ .join(routes_table).on(projects_table[:namespace_id].eq(routes_table[:source_id]))
.project(issue_table[:project_id].as("project_id"))
.where(issue_table[:project_id].in(project_ids))
+ .where(routes_table[:source_type].eq('Namespace'))
.where(issue_table[:created_at].gteq(options[:from]))
.where(issue_metrics_table[:first_added_to_board_at].not_eq(nil).or(issue_metrics_table[:first_associated_with_milestone_at].not_eq(nil)))
diff --git a/lib/gitlab/cycle_analytics/metrics_tables.rb b/lib/gitlab/cycle_analytics/metrics_tables.rb
index 3e0302d308d..015f7bfde24 100644
--- a/lib/gitlab/cycle_analytics/metrics_tables.rb
+++ b/lib/gitlab/cycle_analytics/metrics_tables.rb
@@ -35,6 +35,14 @@ module Gitlab
User.arel_table
end
+ def projects_table
+ Project.arel_table
+ end
+
+ def routes_table
+ Route.arel_table
+ end
+
def build_table
::CommitStatus.arel_table
end
diff --git a/lib/gitlab/cycle_analytics/permissions.rb b/lib/gitlab/cycle_analytics/permissions.rb
index 03ba98b4dfb..0da041f8950 100644
--- a/lib/gitlab/cycle_analytics/permissions.rb
+++ b/lib/gitlab/cycle_analytics/permissions.rb
@@ -23,7 +23,7 @@ module Gitlab
end
def get
- ::CycleAnalytics::Base::STAGES.each do |stage|
+ ::CycleAnalytics::BaseMethods::STAGES.each do |stage|
@stage_permission_hash[stage] = authorized_stage?(stage)
end
diff --git a/lib/gitlab/cycle_analytics/plan_event_fetcher.rb b/lib/gitlab/cycle_analytics/plan_event_fetcher.rb
index 49a6b099f34..77cc358daa9 100644
--- a/lib/gitlab/cycle_analytics/plan_event_fetcher.rb
+++ b/lib/gitlab/cycle_analytics/plan_event_fetcher.rb
@@ -10,7 +10,9 @@ module Gitlab
issue_table[:iid],
issue_table[:id],
issue_table[:created_at],
- issue_table[:author_id]]
+ issue_table[:author_id],
+ projects_table[:name],
+ routes_table[:path]]
super(*args)
end
@@ -18,7 +20,7 @@ module Gitlab
private
def serialize(event)
- AnalyticsIssueSerializer.new(project: project).represent(event)
+ AnalyticsIssueSerializer.new(serialization_context).represent(event)
end
def allowed_ids_finder_class
diff --git a/lib/gitlab/cycle_analytics/plan_helper.rb b/lib/gitlab/cycle_analytics/plan_helper.rb
index ae578d45ad5..c3f742503a9 100644
--- a/lib/gitlab/cycle_analytics/plan_helper.rb
+++ b/lib/gitlab/cycle_analytics/plan_helper.rb
@@ -5,14 +5,21 @@ module Gitlab
module PlanHelper
def stage_query(project_ids)
query = issue_table.join(issue_metrics_table).on(issue_table[:id].eq(issue_metrics_table[:issue_id]))
+ .join(projects_table).on(issue_table[:project_id].eq(projects_table[:id]))
+ .join(routes_table).on(projects_table[:namespace_id].eq(routes_table[:source_id]))
.project(issue_table[:project_id].as("project_id"))
.where(issue_table[:project_id].in(project_ids))
- .where(issue_table[:created_at].gteq(options[:from]))
- .where(issue_metrics_table[:first_added_to_board_at].not_eq(nil).or(issue_metrics_table[:first_associated_with_milestone_at].not_eq(nil)))
- .where(issue_metrics_table[:first_mentioned_in_commit_at].not_eq(nil))
+ .where(routes_table[:source_type].eq('Namespace'))
+ query = add_conditions_to_query(query)
query
end
+
+ def add_conditions_to_query(query)
+ query.where(issue_table[:created_at].gteq(options[:from]))
+ .where(issue_metrics_table[:first_added_to_board_at].not_eq(nil).or(issue_metrics_table[:first_associated_with_milestone_at].not_eq(nil)))
+ .where(issue_metrics_table[:first_mentioned_in_commit_at].not_eq(nil))
+ end
end
end
end
diff --git a/lib/gitlab/cycle_analytics/production_event_fetcher.rb b/lib/gitlab/cycle_analytics/production_event_fetcher.rb
index 949119d69a0..404b2460814 100644
--- a/lib/gitlab/cycle_analytics/production_event_fetcher.rb
+++ b/lib/gitlab/cycle_analytics/production_event_fetcher.rb
@@ -10,7 +10,9 @@ module Gitlab
issue_table[:iid],
issue_table[:id],
issue_table[:created_at],
- issue_table[:author_id]]
+ issue_table[:author_id],
+ projects_table[:name],
+ routes_table[:path]]
super(*args)
end
@@ -18,7 +20,7 @@ module Gitlab
private
def serialize(event)
- AnalyticsIssueSerializer.new(project: project).represent(event)
+ AnalyticsIssueSerializer.new(serialization_context).represent(event)
end
def allowed_ids_finder_class
diff --git a/lib/gitlab/cycle_analytics/review_event_fetcher.rb b/lib/gitlab/cycle_analytics/review_event_fetcher.rb
index d31736e755d..6acd12517fa 100644
--- a/lib/gitlab/cycle_analytics/review_event_fetcher.rb
+++ b/lib/gitlab/cycle_analytics/review_event_fetcher.rb
@@ -11,7 +11,9 @@ module Gitlab
mr_table[:id],
mr_table[:created_at],
mr_table[:state],
- mr_table[:author_id]]
+ mr_table[:author_id],
+ projects_table[:name],
+ routes_table[:path]]
super(*args)
end
@@ -19,7 +21,7 @@ module Gitlab
private
def serialize(event)
- AnalyticsMergeRequestSerializer.new(project: project).represent(event)
+ AnalyticsMergeRequestSerializer.new(serialization_context).represent(event)
end
def allowed_ids_finder_class
diff --git a/lib/gitlab/cycle_analytics/summary/group/base.rb b/lib/gitlab/cycle_analytics/summary/group/base.rb
new file mode 100644
index 00000000000..7f18b61d309
--- /dev/null
+++ b/lib/gitlab/cycle_analytics/summary/group/base.rb
@@ -0,0 +1,24 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module CycleAnalytics
+ module Summary
+ module Group
+ class Base
+ def initialize(group:, from:)
+ @group = group
+ @from = from
+ end
+
+ def title
+ raise NotImplementedError.new("Expected #{self.name} to implement title")
+ end
+
+ def value
+ raise NotImplementedError.new("Expected #{self.name} to implement value")
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/cycle_analytics/summary/group/deploy.rb b/lib/gitlab/cycle_analytics/summary/group/deploy.rb
new file mode 100644
index 00000000000..d8fcd8f2ce4
--- /dev/null
+++ b/lib/gitlab/cycle_analytics/summary/group/deploy.rb
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module CycleAnalytics
+ module Summary
+ module Group
+ class Deploy < Group::Base
+ def title
+ n_('Deploy', 'Deploys', value)
+ end
+
+ def value
+ @value ||= Deployment.joins(:project)
+ .where(projects: { id: projects })
+ .where("deployments.created_at > ?", @from)
+ .success
+ .count
+ end
+
+ private
+
+ def projects
+ Project.inside_path(@group.full_path).ids
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/cycle_analytics/summary/group/issue.rb b/lib/gitlab/cycle_analytics/summary/group/issue.rb
new file mode 100644
index 00000000000..a5188056cb7
--- /dev/null
+++ b/lib/gitlab/cycle_analytics/summary/group/issue.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module CycleAnalytics
+ module Summary
+ module Group
+ class Issue < Group::Base
+ def initialize(group:, from:, current_user:)
+ @group = group
+ @from = from
+ @current_user = current_user
+ end
+
+ def title
+ n_('New Issue', 'New Issues', value)
+ end
+
+ def value
+ @value ||= IssuesFinder.new(@current_user, group_id: @group.id, include_subgroups: true).execute.created_after(@from).count
+ end
+ end
+ end
+ end
+ end
+end