summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMałgorzata Ksionek <mksionek@gitlab.com>2019-07-04 16:42:31 +0200
committerMałgorzata Ksionek <mksionek@gitlab.com>2019-07-15 15:06:40 +0200
commitbeaa63530669d10c7244d187fa386144bc5da7eb (patch)
treebc541f200d5a5b2c37ff50e1a75ad1b848e6c396
parent0e8af2525f16d871510c24e6e15f1bc80f133edd (diff)
downloadgitlab-ce-beaa63530669d10c7244d187fa386144bc5da7eb.tar.gz
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
-rw-r--r--app/models/cycle_analytics/base_methods.rb (renamed from app/models/cycle_analytics/base.rb)6
-rw-r--r--app/models/cycle_analytics/group_level.rb30
-rw-r--r--app/models/cycle_analytics/project_level.rb5
-rw-r--r--app/serializers/analytics_issue_entity.rb6
-rw-r--r--app/serializers/analytics_merge_request_entity.rb2
-rw-r--r--app/serializers/analytics_stage_entity.rb4
-rw-r--r--app/serializers/group_analytics_stage_entity.rb16
-rw-r--r--app/serializers/group_analytics_stage_serializer.rb5
-rw-r--r--changelogs/unreleased/adjust-cycle-analytics-to-group-level.yml5
-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
-rw-r--r--spec/lib/gitlab/cycle_analytics/base_event_fetcher_spec.rb6
-rw-r--r--spec/lib/gitlab/cycle_analytics/code_stage_spec.rb94
-rw-r--r--spec/lib/gitlab/cycle_analytics/group_stage_summary_spec.rb65
-rw-r--r--spec/lib/gitlab/cycle_analytics/issue_stage_spec.rb75
-rw-r--r--spec/lib/gitlab/cycle_analytics/plan_stage_spec.rb74
-rw-r--r--spec/lib/gitlab/cycle_analytics/review_stage_spec.rb61
-rw-r--r--spec/lib/gitlab/cycle_analytics/shared_event_spec.rb2
-rw-r--r--spec/lib/gitlab/cycle_analytics/shared_stage_spec.rb4
-rw-r--r--spec/lib/gitlab/cycle_analytics/staging_stage_spec.rb64
-rw-r--r--spec/lib/gitlab/cycle_analytics/usage_data_spec.rb2
-rw-r--r--spec/models/cycle_analytics/code_spec.rb4
-rw-r--r--spec/models/cycle_analytics/group_level_spec.rb46
-rw-r--r--spec/models/cycle_analytics/issue_spec.rb2
-rw-r--r--spec/models/cycle_analytics/plan_spec.rb2
-rw-r--r--spec/models/cycle_analytics/production_spec.rb4
-rw-r--r--spec/models/cycle_analytics/project_level_spec.rb2
-rw-r--r--spec/models/cycle_analytics/review_spec.rb2
-rw-r--r--spec/models/cycle_analytics/staging_spec.rb4
-rw-r--r--spec/models/cycle_analytics/test_spec.rb8
-rw-r--r--spec/serializers/analytics_issue_entity_spec.rb6
-rw-r--r--spec/serializers/analytics_issue_serializer_spec.rb6
-rw-r--r--spec/serializers/analytics_merge_request_serializer_spec.rb6
-rw-r--r--spec/serializers/analytics_stage_serializer_spec.rb10
-rw-r--r--spec/support/cycle_analytics_helpers/test_generation.rb12
49 files changed, 744 insertions, 113 deletions
diff --git a/app/models/cycle_analytics/base.rb b/app/models/cycle_analytics/base_methods.rb
index d7b28cd1b67..1c2a0854769 100644
--- a/app/models/cycle_analytics/base.rb
+++ b/app/models/cycle_analytics/base_methods.rb
@@ -1,12 +1,12 @@
# frozen_string_literal: true
module CycleAnalytics
- class Base
+ module BaseMethods
STAGES = %i[issue plan code test review staging production].freeze
def all_medians_by_stage
STAGES.each_with_object({}) do |stage_name, medians_per_stage|
- medians_per_stage[stage_name] = self[stage_name].median
+ medians_per_stage[stage_name] = self[stage_name].project_median
end
end
@@ -21,7 +21,7 @@ module CycleAnalytics
end
def [](stage_name)
- Gitlab::CycleAnalytics::Stage[stage_name].new(project: @project, options: @options)
+ Gitlab::CycleAnalytics::Stage[stage_name].new(options: options)
end
end
end
diff --git a/app/models/cycle_analytics/group_level.rb b/app/models/cycle_analytics/group_level.rb
new file mode 100644
index 00000000000..58bd2eb0d9a
--- /dev/null
+++ b/app/models/cycle_analytics/group_level.rb
@@ -0,0 +1,30 @@
+# frozen_string_literal: true
+
+module CycleAnalytics
+ class GroupLevel
+ include BaseMethods
+ attr_reader :options
+
+ def initialize(options:)
+ @options = options
+ end
+
+ def summary
+ @summary ||= ::Gitlab::CycleAnalytics::GroupStageSummary.new(options[:group],
+ from: options[:from],
+ current_user: options[:current_user]).data
+ end
+
+ def permissions(user: nil)
+ STAGES.each_with_object({}) do |stage, obj|
+ obj[stage] = true
+ end
+ end
+
+ def stats
+ @stats ||= STAGES.map do |stage_name|
+ self[stage_name].as_json(serializer: GroupAnalyticsStageSerializer)
+ end
+ end
+ end
+end
diff --git a/app/models/cycle_analytics/project_level.rb b/app/models/cycle_analytics/project_level.rb
index 22631cc7d41..abe1be11eae 100644
--- a/app/models/cycle_analytics/project_level.rb
+++ b/app/models/cycle_analytics/project_level.rb
@@ -1,12 +1,13 @@
# frozen_string_literal: true
module CycleAnalytics
- class ProjectLevel < Base
+ class ProjectLevel
+ include BaseMethods
attr_reader :project, :options
def initialize(project, options:)
@project = project
- @options = options
+ @options = options.merge(project: project)
end
def summary
diff --git a/app/serializers/analytics_issue_entity.rb b/app/serializers/analytics_issue_entity.rb
index ab15bd0ac7a..29d4a6ae1d0 100644
--- a/app/serializers/analytics_issue_entity.rb
+++ b/app/serializers/analytics_issue_entity.rb
@@ -20,12 +20,12 @@ class AnalyticsIssueEntity < Grape::Entity
end
expose :url do |object|
- url_to(:namespace_project_issue, id: object[:iid].to_s)
+ url_to(:namespace_project_issue, object)
end
private
- def url_to(route, id)
- public_send("#{route}_url", request.project.namespace, request.project, id) # rubocop:disable GitlabSecurity/PublicSend
+ def url_to(route, object)
+ public_send("#{route}_url", object[:path], object[:name], object[:iid].to_s) # rubocop:disable GitlabSecurity/PublicSend
end
end
diff --git a/app/serializers/analytics_merge_request_entity.rb b/app/serializers/analytics_merge_request_entity.rb
index b7134da9461..21d7eeb81b0 100644
--- a/app/serializers/analytics_merge_request_entity.rb
+++ b/app/serializers/analytics_merge_request_entity.rb
@@ -4,6 +4,6 @@ class AnalyticsMergeRequestEntity < AnalyticsIssueEntity
expose :state
expose :url do |object|
- url_to(:namespace_project_merge_request, id: object[:iid].to_s)
+ url_to(:namespace_project_merge_request, object)
end
end
diff --git a/app/serializers/analytics_stage_entity.rb b/app/serializers/analytics_stage_entity.rb
index 8bc6da5aeeb..eb38b90fb18 100644
--- a/app/serializers/analytics_stage_entity.rb
+++ b/app/serializers/analytics_stage_entity.rb
@@ -8,9 +8,9 @@ class AnalyticsStageEntity < Grape::Entity
expose :legend
expose :description
- expose :median, as: :value do |stage|
+ expose :project_median, as: :value do |stage|
# median returns a BatchLoader instance which we first have to unwrap by using to_f
# we use to_f to make sure results below 1 are presented to the end-user
- stage.median.to_f.nonzero? ? distance_of_time_in_words(stage.median) : nil
+ stage.project_median.to_f.nonzero? ? distance_of_time_in_words(stage.project_median) : nil
end
end
diff --git a/app/serializers/group_analytics_stage_entity.rb b/app/serializers/group_analytics_stage_entity.rb
new file mode 100644
index 00000000000..019a3086f68
--- /dev/null
+++ b/app/serializers/group_analytics_stage_entity.rb
@@ -0,0 +1,16 @@
+# frozen_string_literal: true
+
+class GroupAnalyticsStageEntity < Grape::Entity
+ include EntityDateHelper
+
+ expose :title
+ expose :name
+ expose :legend
+ expose :description
+
+ expose :group_median, as: :value do |stage|
+ # median returns a BatchLoader instance which we first have to unwrap by using to_f
+ # we use to_f to make sure results below 1 are presented to the end-user
+ stage.group_median.to_f.nonzero? ? distance_of_time_in_words(stage.group_median) : nil
+ end
+end
diff --git a/app/serializers/group_analytics_stage_serializer.rb b/app/serializers/group_analytics_stage_serializer.rb
new file mode 100644
index 00000000000..ec448dea602
--- /dev/null
+++ b/app/serializers/group_analytics_stage_serializer.rb
@@ -0,0 +1,5 @@
+# frozen_string_literal: true
+
+class GroupAnalyticsStageSerializer < BaseSerializer
+ entity GroupAnalyticsStageEntity
+end
diff --git a/changelogs/unreleased/adjust-cycle-analytics-to-group-level.yml b/changelogs/unreleased/adjust-cycle-analytics-to-group-level.yml
new file mode 100644
index 00000000000..49f558a6c9c
--- /dev/null
+++ b/changelogs/unreleased/adjust-cycle-analytics-to-group-level.yml
@@ -0,0 +1,5 @@
+---
+title: Adjust cycle analytics to group level
+merge_request: 30391
+author:
+type: added
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
diff --git a/spec/lib/gitlab/cycle_analytics/base_event_fetcher_spec.rb b/spec/lib/gitlab/cycle_analytics/base_event_fetcher_spec.rb
index 8b07da11c5d..b7a64adc2ff 100644
--- a/spec/lib/gitlab/cycle_analytics/base_event_fetcher_spec.rb
+++ b/spec/lib/gitlab/cycle_analytics/base_event_fetcher_spec.rb
@@ -9,12 +9,12 @@ describe Gitlab::CycleAnalytics::BaseEventFetcher do
let(:options) do
{ start_time_attrs: start_time_attrs,
end_time_attrs: end_time_attrs,
- from: 30.days.ago }
+ from: 30.days.ago,
+ project: project }
end
subject do
- described_class.new(project: project,
- stage: :issue,
+ described_class.new(stage: :issue,
options: options).fetch
end
diff --git a/spec/lib/gitlab/cycle_analytics/code_stage_spec.rb b/spec/lib/gitlab/cycle_analytics/code_stage_spec.rb
index c738cc49c1f..68f73ba3c93 100644
--- a/spec/lib/gitlab/cycle_analytics/code_stage_spec.rb
+++ b/spec/lib/gitlab/cycle_analytics/code_stage_spec.rb
@@ -5,31 +5,31 @@ describe Gitlab::CycleAnalytics::CodeStage do
let(:stage_name) { :code }
let(:project) { create(:project) }
- let!(:issue_1) { create(:issue, project: project, created_at: 90.minutes.ago) }
- let!(:issue_2) { create(:issue, project: project, created_at: 60.minutes.ago) }
- let!(:issue_3) { create(:issue, project: project, created_at: 60.minutes.ago) }
- let!(:mr_1) { create(:merge_request, source_project: project, created_at: 15.minutes.ago) }
- let!(:mr_2) { create(:merge_request, source_project: project, created_at: 10.minutes.ago, source_branch: 'A') }
- let!(:mr_3) { create(:merge_request, source_project: project, created_at: 10.minutes.ago, source_branch: 'B') }
- let(:stage) { described_class.new(project: project, options: { from: 2.days.ago, current_user: project.creator }) }
+ let(:issue_1) { create(:issue, project: project, created_at: 90.minutes.ago) }
+ let(:issue_2) { create(:issue, project: project, created_at: 60.minutes.ago) }
+ let(:issue_3) { create(:issue, project: project, created_at: 60.minutes.ago) }
+ let(:mr_1) { create(:merge_request, source_project: project, created_at: 15.minutes.ago) }
+ let(:mr_2) { create(:merge_request, source_project: project, created_at: 10.minutes.ago, source_branch: 'A') }
+ let(:stage) { described_class.new(options: { from: 2.days.ago, current_user: project.creator, project: project }) }
before do
issue_1.metrics.update!(first_associated_with_milestone_at: 60.minutes.ago, first_mentioned_in_commit_at: 45.minutes.ago)
issue_2.metrics.update!(first_added_to_board_at: 60.minutes.ago, first_mentioned_in_commit_at: 40.minutes.ago)
issue_3.metrics.update!(first_added_to_board_at: 60.minutes.ago, first_mentioned_in_commit_at: 40.minutes.ago)
+ create(:merge_request, source_project: project, created_at: 10.minutes.ago, source_branch: 'B')
create(:merge_requests_closing_issues, merge_request: mr_1, issue: issue_1)
create(:merge_requests_closing_issues, merge_request: mr_2, issue: issue_2)
end
it_behaves_like 'base stage'
- describe '#median' do
+ describe '#project_median' do
around do |example|
Timecop.freeze { example.run }
end
it 'counts median from issues with metrics' do
- expect(stage.median).to eq(ISSUES_MEDIAN)
+ expect(stage.project_median).to eq(ISSUES_MEDIAN)
end
end
@@ -41,4 +41,80 @@ describe Gitlab::CycleAnalytics::CodeStage do
expect(result.map { |event| event[:title] }).to contain_exactly(mr_1.title, mr_2.title)
end
end
+
+ context 'when group is given' do
+ let(:user) { create(:user) }
+ let(:group) { create(:group) }
+ let(:project_2) { create(:project, group: group) }
+ let(:project_3) { create(:project, group: group) }
+ let(:issue_2_1) { create(:issue, project: project_2, created_at: 90.minutes.ago) }
+ let(:issue_2_2) { create(:issue, project: project_3, created_at: 60.minutes.ago) }
+ let(:issue_2_3) { create(:issue, project: project_2, created_at: 60.minutes.ago) }
+ let(:mr_2_1) { create(:merge_request, source_project: project_2, created_at: 15.minutes.ago) }
+ let(:mr_2_2) { create(:merge_request, source_project: project_3, created_at: 10.minutes.ago, source_branch: 'A') }
+ let(:stage) { described_class.new(options: { from: 2.days.ago, current_user: user, group: group }) }
+
+ before do
+ group.add_owner(user)
+ issue_2_1.metrics.update!(first_associated_with_milestone_at: 60.minutes.ago, first_mentioned_in_commit_at: 45.minutes.ago)
+ issue_2_2.metrics.update!(first_added_to_board_at: 60.minutes.ago, first_mentioned_in_commit_at: 40.minutes.ago)
+ issue_2_3.metrics.update!(first_added_to_board_at: 60.minutes.ago, first_mentioned_in_commit_at: 40.minutes.ago)
+ create(:merge_requests_closing_issues, merge_request: mr_2_1, issue: issue_2_1)
+ create(:merge_requests_closing_issues, merge_request: mr_2_2, issue: issue_2_2)
+ end
+
+ describe '#group_median' do
+ around do |example|
+ Timecop.freeze { example.run }
+ end
+
+ it 'counts median from issues with metrics' do
+ expect(stage.group_median).to eq(ISSUES_MEDIAN)
+ end
+ end
+
+ describe '#events' do
+ it 'exposes merge requests that close issues' do
+ result = stage.events
+
+ expect(result.count).to eq(2)
+ expect(result.map { |event| event[:title] }).to contain_exactly(mr_2_1.title, mr_2_2.title)
+ end
+ end
+
+ context 'when subgroup is given' do
+ let(:subgroup) { create(:group, parent: group) }
+ let(:project_4) { create(:project, group: subgroup) }
+ let(:project_5) { create(:project, group: subgroup) }
+ let(:issue_3_1) { create(:issue, project: project_4, created_at: 90.minutes.ago) }
+ let(:issue_3_2) { create(:issue, project: project_5, created_at: 60.minutes.ago) }
+ let(:issue_3_3) { create(:issue, project: project_5, created_at: 60.minutes.ago) }
+ let(:mr_3_1) { create(:merge_request, source_project: project_4, created_at: 15.minutes.ago) }
+ let(:mr_3_2) { create(:merge_request, source_project: project_5, created_at: 10.minutes.ago, source_branch: 'A') }
+
+ before do
+ issue_3_1.metrics.update!(first_associated_with_milestone_at: 60.minutes.ago, first_mentioned_in_commit_at: 45.minutes.ago)
+ issue_3_2.metrics.update!(first_added_to_board_at: 60.minutes.ago, first_mentioned_in_commit_at: 40.minutes.ago)
+ issue_3_3.metrics.update!(first_added_to_board_at: 60.minutes.ago, first_mentioned_in_commit_at: 40.minutes.ago)
+ create(:merge_requests_closing_issues, merge_request: mr_3_1, issue: issue_3_1)
+ create(:merge_requests_closing_issues, merge_request: mr_3_2, issue: issue_3_2)
+ end
+
+ describe '#events' do
+ it 'exposes merge requests that close issues' do
+ result = stage.events
+
+ expect(result.count).to eq(4)
+ expect(result.map { |event| event[:title] }).to contain_exactly(mr_2_1.title, mr_2_2.title, mr_3_1.title, mr_3_2.title)
+ end
+
+ it 'exposes merge requests that close issues with full path for subgroup' do
+ result = stage.events
+
+ expect(result.count).to eq(4)
+ expect(result.find { |event| event[:title] == mr_3_1.title }[:url]).to include("#{subgroup.full_path}")
+ end
+ end
+ end
+ end
end
diff --git a/spec/lib/gitlab/cycle_analytics/group_stage_summary_spec.rb b/spec/lib/gitlab/cycle_analytics/group_stage_summary_spec.rb
new file mode 100644
index 00000000000..8e552b23283
--- /dev/null
+++ b/spec/lib/gitlab/cycle_analytics/group_stage_summary_spec.rb
@@ -0,0 +1,65 @@
+# frozen_string_literal: true
+require 'spec_helper'
+
+describe Gitlab::CycleAnalytics::GroupStageSummary do
+ let(:group) { create(:group) }
+ let(:project) { create(:project, :repository, namespace: group) }
+ let(:project_2) { create(:project, :repository, namespace: group) }
+ let(:from) { 1.day.ago }
+ let(:user) { create(:user, :admin) }
+ subject { described_class.new(group, from: Time.now, current_user: user).data }
+
+ describe "#new_issues" do
+ it "finds the number of issues created after the 'from date'" do
+ Timecop.freeze(5.days.ago) { create(:issue, project: project) }
+ Timecop.freeze(5.days.ago) { create(:issue, project: project_2) }
+ Timecop.freeze(5.days.from_now) { create(:issue, project: project) }
+ Timecop.freeze(5.days.from_now) { create(:issue, project: project_2) }
+
+ expect(subject.first[:value]).to eq(2)
+ end
+
+ it "doesn't find issues from other projects" do
+ Timecop.freeze(5.days.from_now) { create(:issue, project: create(:project, namespace: create(:group))) }
+ Timecop.freeze(5.days.from_now) { create(:issue, project: project) }
+ Timecop.freeze(5.days.from_now) { create(:issue, project: project_2) }
+
+ expect(subject.first[:value]).to eq(2)
+ end
+
+ it "finds issues from subgroups" do
+ Timecop.freeze(5.days.from_now) { create(:issue, project: create(:project, namespace: create(:group, parent: group))) }
+ Timecop.freeze(5.days.from_now) { create(:issue, project: project) }
+ Timecop.freeze(5.days.from_now) { create(:issue, project: project_2) }
+
+ expect(subject.first[:value]).to eq(3)
+ end
+ end
+
+ describe "#deploys" do
+ it "finds the number of deploys made created after the 'from date'" do
+ Timecop.freeze(5.days.ago) { create(:deployment, :success, project: project) }
+ Timecop.freeze(5.days.from_now) { create(:deployment, :success, project: project) }
+ Timecop.freeze(5.days.ago) { create(:deployment, :success, project: project_2) }
+ Timecop.freeze(5.days.from_now) { create(:deployment, :success, project: project_2) }
+
+ expect(subject.second[:value]).to eq(2)
+ end
+
+ it "doesn't find deploys from other projects" do
+ Timecop.freeze(5.days.from_now) do
+ create(:deployment, :success, project: create(:project, :repository, namespace: create(:group)))
+ end
+
+ expect(subject.second[:value]).to eq(0)
+ end
+
+ it "finds deploys from subgroups" do
+ Timecop.freeze(5.days.from_now) do
+ create(:deployment, :success, project: create(:project, :repository, namespace: create(:group, parent: group)))
+ end
+
+ expect(subject.second[:value]).to eq(1)
+ end
+ end
+end
diff --git a/spec/lib/gitlab/cycle_analytics/issue_stage_spec.rb b/spec/lib/gitlab/cycle_analytics/issue_stage_spec.rb
index 3b6af9cbaed..64ac9df52b2 100644
--- a/spec/lib/gitlab/cycle_analytics/issue_stage_spec.rb
+++ b/spec/lib/gitlab/cycle_analytics/issue_stage_spec.rb
@@ -4,11 +4,11 @@ require 'lib/gitlab/cycle_analytics/shared_stage_spec'
describe Gitlab::CycleAnalytics::IssueStage do
let(:stage_name) { :issue }
let(:project) { create(:project) }
- let!(:issue_1) { create(:issue, project: project, created_at: 90.minutes.ago) }
- let!(:issue_2) { create(:issue, project: project, created_at: 60.minutes.ago) }
- let!(:issue_3) { create(:issue, project: project, created_at: 30.minutes.ago) }
+ let(:issue_1) { create(:issue, project: project, created_at: 90.minutes.ago) }
+ let(:issue_2) { create(:issue, project: project, created_at: 60.minutes.ago) }
+ let(:issue_3) { create(:issue, project: project, created_at: 30.minutes.ago) }
let!(:issue_without_milestone) { create(:issue, project: project, created_at: 1.minute.ago) }
- let(:stage) { described_class.new(project: project, options: { from: 2.days.ago, current_user: project.creator }) }
+ let(:stage) { described_class.new(options: { from: 2.days.ago, current_user: project.creator, project: project }) }
before do
issue_1.metrics.update!(first_associated_with_milestone_at: 60.minutes.ago )
@@ -24,7 +24,7 @@ describe Gitlab::CycleAnalytics::IssueStage do
end
it 'counts median from issues with metrics' do
- expect(stage.median).to eq(ISSUES_MEDIAN)
+ expect(stage.project_median).to eq(ISSUES_MEDIAN)
end
end
@@ -36,4 +36,69 @@ describe Gitlab::CycleAnalytics::IssueStage do
expect(result.map { |event| event[:title] }).to contain_exactly(issue_1.title, issue_2.title, issue_3.title)
end
end
+ context 'when group is given' do
+ let(:user) { create(:user) }
+ let(:group) { create(:group) }
+ let(:project_2) { create(:project, group: group) }
+ let(:project_3) { create(:project, group: group) }
+ let(:issue_2_1) { create(:issue, project: project_2, created_at: 90.minutes.ago) }
+ let(:issue_2_2) { create(:issue, project: project_3, created_at: 60.minutes.ago) }
+ let(:issue_2_3) { create(:issue, project: project_2, created_at: 60.minutes.ago) }
+ let(:stage) { described_class.new(options: { from: 2.days.ago, current_user: user, group: group }) }
+
+ before do
+ group.add_owner(user)
+ issue_2_1.metrics.update!(first_associated_with_milestone_at: 60.minutes.ago)
+ issue_2_2.metrics.update!(first_added_to_board_at: 30.minutes.ago)
+ end
+
+ describe '#group_median' do
+ around do |example|
+ Timecop.freeze { example.run }
+ end
+
+ it 'counts median from issues with metrics' do
+ expect(stage.group_median).to eq(ISSUES_MEDIAN)
+ end
+ end
+
+ describe '#events' do
+ it 'exposes merge requests that close issues' do
+ result = stage.events
+
+ expect(result.count).to eq(2)
+ expect(result.map { |event| event[:title] }).to contain_exactly(issue_2_1.title, issue_2_2.title)
+ end
+ end
+
+ context 'when subgroup is given' do
+ let(:subgroup) { create(:group, parent: group) }
+ let(:project_4) { create(:project, group: subgroup) }
+ let(:project_5) { create(:project, group: subgroup) }
+ let(:issue_3_1) { create(:issue, project: project_4, created_at: 90.minutes.ago) }
+ let(:issue_3_2) { create(:issue, project: project_5, created_at: 60.minutes.ago) }
+ let(:issue_3_3) { create(:issue, project: project_5, created_at: 60.minutes.ago) }
+
+ before do
+ issue_3_1.metrics.update!(first_associated_with_milestone_at: 60.minutes.ago)
+ issue_3_2.metrics.update!(first_added_to_board_at: 30.minutes.ago)
+ end
+
+ describe '#events' do
+ it 'exposes merge requests that close issues' do
+ result = stage.events
+
+ expect(result.count).to eq(4)
+ expect(result.map { |event| event[:title] }).to contain_exactly(issue_2_1.title, issue_2_2.title, issue_3_1.title, issue_3_2.title)
+ end
+
+ it 'exposes merge requests that close issues with full path for subgroup' do
+ result = stage.events
+
+ expect(result.count).to eq(4)
+ expect(result.find { |event| event[:title] == issue_3_1.title }[:url]).to include("#{subgroup.full_path}")
+ end
+ end
+ end
+ end
end
diff --git a/spec/lib/gitlab/cycle_analytics/plan_stage_spec.rb b/spec/lib/gitlab/cycle_analytics/plan_stage_spec.rb
index 506a8160412..55de6192af1 100644
--- a/spec/lib/gitlab/cycle_analytics/plan_stage_spec.rb
+++ b/spec/lib/gitlab/cycle_analytics/plan_stage_spec.rb
@@ -8,7 +8,7 @@ describe Gitlab::CycleAnalytics::PlanStage do
let!(:issue_2) { create(:issue, project: project, created_at: 60.minutes.ago) }
let!(:issue_3) { create(:issue, project: project, created_at: 30.minutes.ago) }
let!(:issue_without_milestone) { create(:issue, project: project, created_at: 1.minute.ago) }
- let(:stage) { described_class.new(project: project, options: { from: 2.days.ago, current_user: project.creator }) }
+ let(:stage) { described_class.new(options: { from: 2.days.ago, current_user: project.creator, project: project }) }
before do
issue_1.metrics.update!(first_associated_with_milestone_at: 60.minutes.ago, first_mentioned_in_commit_at: 10.minutes.ago)
@@ -18,13 +18,13 @@ describe Gitlab::CycleAnalytics::PlanStage do
it_behaves_like 'base stage'
- describe '#median' do
+ describe '#project_median' do
around do |example|
Timecop.freeze { example.run }
end
it 'counts median from issues with metrics' do
- expect(stage.median).to eq(ISSUES_MEDIAN)
+ expect(stage.project_median).to eq(ISSUES_MEDIAN)
end
end
@@ -36,4 +36,72 @@ describe Gitlab::CycleAnalytics::PlanStage do
expect(result.map { |event| event[:title] }).to contain_exactly(issue_1.title, issue_2.title)
end
end
+
+ context 'when group is given' do
+ let(:user) { create(:user) }
+ let(:group) { create(:group) }
+ let(:project_2) { create(:project, group: group) }
+ let(:project_3) { create(:project, group: group) }
+ let(:issue_2_1) { create(:issue, project: project_2, created_at: 90.minutes.ago) }
+ let(:issue_2_2) { create(:issue, project: project_3, created_at: 60.minutes.ago) }
+ let(:issue_2_3) { create(:issue, project: project_2, created_at: 60.minutes.ago) }
+ let(:stage) { described_class.new(options: { from: 2.days.ago, current_user: user, group: group }) }
+
+ before do
+ group.add_owner(user)
+ issue_2_1.metrics.update!(first_associated_with_milestone_at: 60.minutes.ago, first_mentioned_in_commit_at: 10.minutes.ago)
+ issue_2_2.metrics.update!(first_added_to_board_at: 30.minutes.ago, first_mentioned_in_commit_at: 20.minutes.ago)
+ issue_2_3.metrics.update!(first_added_to_board_at: 15.minutes.ago)
+ end
+
+ describe '#group_median' do
+ around do |example|
+ Timecop.freeze { example.run }
+ end
+
+ it 'counts median from issues with metrics' do
+ expect(stage.group_median).to eq(ISSUES_MEDIAN)
+ end
+ end
+
+ describe '#events' do
+ it 'exposes merge requests that close issues' do
+ result = stage.events
+
+ expect(result.count).to eq(2)
+ expect(result.map { |event| event[:title] }).to contain_exactly(issue_2_1.title, issue_2_2.title)
+ end
+ end
+
+ context 'when subgroup is given' do
+ let(:subgroup) { create(:group, parent: group) }
+ let(:project_4) { create(:project, group: subgroup) }
+ let(:project_5) { create(:project, group: subgroup) }
+ let(:issue_3_1) { create(:issue, project: project_4, created_at: 90.minutes.ago) }
+ let(:issue_3_2) { create(:issue, project: project_5, created_at: 60.minutes.ago) }
+ let(:issue_3_3) { create(:issue, project: project_5, created_at: 60.minutes.ago) }
+
+ before do
+ issue_3_1.metrics.update!(first_associated_with_milestone_at: 60.minutes.ago, first_mentioned_in_commit_at: 10.minutes.ago)
+ issue_3_2.metrics.update!(first_added_to_board_at: 30.minutes.ago, first_mentioned_in_commit_at: 20.minutes.ago)
+ issue_3_3.metrics.update!(first_added_to_board_at: 15.minutes.ago)
+ end
+
+ describe '#events' do
+ it 'exposes merge requests that close issues' do
+ result = stage.events
+
+ expect(result.count).to eq(4)
+ expect(result.map { |event| event[:title] }).to contain_exactly(issue_2_1.title, issue_2_2.title, issue_3_1.title, issue_3_2.title)
+ end
+
+ it 'exposes merge requests that close issues with full path for subgroup' do
+ result = stage.events
+
+ expect(result.count).to eq(4)
+ expect(result.find { |event| event[:title] == issue_3_1.title }[:url]).to include("#{subgroup.full_path}")
+ end
+ end
+ end
+ end
end
diff --git a/spec/lib/gitlab/cycle_analytics/review_stage_spec.rb b/spec/lib/gitlab/cycle_analytics/review_stage_spec.rb
index f072a9644e8..9c7cb5811d0 100644
--- a/spec/lib/gitlab/cycle_analytics/review_stage_spec.rb
+++ b/spec/lib/gitlab/cycle_analytics/review_stage_spec.rb
@@ -4,14 +4,14 @@ require 'lib/gitlab/cycle_analytics/shared_stage_spec'
describe Gitlab::CycleAnalytics::ReviewStage do
let(:stage_name) { :review }
let(:project) { create(:project) }
- let!(:issue_1) { create(:issue, project: project, created_at: 90.minutes.ago) }
- let!(:issue_2) { create(:issue, project: project, created_at: 60.minutes.ago) }
- let!(:issue_3) { create(:issue, project: project, created_at: 60.minutes.ago) }
- let!(:mr_1) { create(:merge_request, :closed, source_project: project, created_at: 60.minutes.ago) }
- let!(:mr_2) { create(:merge_request, :closed, source_project: project, created_at: 40.minutes.ago, source_branch: 'A') }
- let!(:mr_3) { create(:merge_request, source_project: project, created_at: 10.minutes.ago, source_branch: 'B') }
+ let(:issue_1) { create(:issue, project: project, created_at: 90.minutes.ago) }
+ let(:issue_2) { create(:issue, project: project, created_at: 60.minutes.ago) }
+ let(:issue_3) { create(:issue, project: project, created_at: 60.minutes.ago) }
+ let(:mr_1) { create(:merge_request, :closed, source_project: project, created_at: 60.minutes.ago) }
+ let(:mr_2) { create(:merge_request, :closed, source_project: project, created_at: 40.minutes.ago, source_branch: 'A') }
+ let(:mr_3) { create(:merge_request, source_project: project, created_at: 10.minutes.ago, source_branch: 'B') }
let!(:mr_4) { create(:merge_request, source_project: project, created_at: 10.minutes.ago, source_branch: 'C') }
- let(:stage) { described_class.new(project: project, options: { from: 2.days.ago, current_user: project.creator }) }
+ let(:stage) { described_class.new(options: { from: 2.days.ago, current_user: project.creator, project: project }) }
before do
mr_1.metrics.update!(merged_at: 30.minutes.ago)
@@ -24,13 +24,13 @@ describe Gitlab::CycleAnalytics::ReviewStage do
it_behaves_like 'base stage'
- describe '#median' do
+ describe '#project_median' do
around do |example|
Timecop.freeze { example.run }
end
it 'counts median from issues with metrics' do
- expect(stage.median).to eq(ISSUES_MEDIAN)
+ expect(stage.project_median).to eq(ISSUES_MEDIAN)
end
end
@@ -42,4 +42,47 @@ describe Gitlab::CycleAnalytics::ReviewStage do
expect(result.map { |event| event[:title] }).to contain_exactly(mr_1.title, mr_2.title)
end
end
+ context 'when group is given' do
+ let(:user) { create(:user) }
+ let(:group) { create(:group) }
+ let(:project_2) { create(:project, group: group) }
+ let(:project_3) { create(:project, group: group) }
+ let(:issue_2_1) { create(:issue, project: project_2, created_at: 90.minutes.ago) }
+ let(:issue_2_2) { create(:issue, project: project_3, created_at: 60.minutes.ago) }
+ let(:issue_2_3) { create(:issue, project: project_2, created_at: 60.minutes.ago) }
+ let(:mr_2_1) { create(:merge_request, :closed, source_project: project_2, created_at: 60.minutes.ago) }
+ let(:mr_2_2) { create(:merge_request, :closed, source_project: project_3, created_at: 40.minutes.ago, source_branch: 'A') }
+ let(:mr_2_3) { create(:merge_request, source_project: project_2, created_at: 10.minutes.ago, source_branch: 'B') }
+ let!(:mr_2_4) { create(:merge_request, source_project: project_3, created_at: 10.minutes.ago, source_branch: 'C') }
+ let(:stage) { described_class.new(options: { from: 2.days.ago, current_user: user, group: group }) }
+
+ before do
+ group.add_owner(user)
+ mr_2_1.metrics.update!(merged_at: 30.minutes.ago)
+ mr_2_2.metrics.update!(merged_at: 10.minutes.ago)
+
+ create(:merge_requests_closing_issues, merge_request: mr_2_1, issue: issue_2_1)
+ create(:merge_requests_closing_issues, merge_request: mr_2_2, issue: issue_2_2)
+ create(:merge_requests_closing_issues, merge_request: mr_2_3, issue: issue_2_3)
+ end
+
+ describe '#group_median' do
+ around do |example|
+ Timecop.freeze { example.run }
+ end
+
+ it 'counts median from issues with metrics' do
+ expect(stage.group_median).to eq(ISSUES_MEDIAN)
+ end
+ end
+
+ describe '#events' do
+ it 'exposes merge requests that close issues' do
+ result = stage.events
+
+ expect(result.count).to eq(2)
+ expect(result.map { |event| event[:title] }).to contain_exactly(mr_2_1.title, mr_2_2.title)
+ end
+ end
+ end
end
diff --git a/spec/lib/gitlab/cycle_analytics/shared_event_spec.rb b/spec/lib/gitlab/cycle_analytics/shared_event_spec.rb
index c22d27f60d6..b001a46001e 100644
--- a/spec/lib/gitlab/cycle_analytics/shared_event_spec.rb
+++ b/spec/lib/gitlab/cycle_analytics/shared_event_spec.rb
@@ -2,7 +2,7 @@ require 'spec_helper'
shared_examples 'default query config' do
let(:project) { create(:project) }
- let(:event) { described_class.new(project: project, stage: stage_name, options: { from: 1.day.ago }) }
+ let(:event) { described_class.new(stage: stage_name, options: { from: 1.day.ago, project: project }) }
it 'has the stage attribute' do
expect(event.stage).not_to be_nil
diff --git a/spec/lib/gitlab/cycle_analytics/shared_stage_spec.rb b/spec/lib/gitlab/cycle_analytics/shared_stage_spec.rb
index 1a4b572cc11..c146146723f 100644
--- a/spec/lib/gitlab/cycle_analytics/shared_stage_spec.rb
+++ b/spec/lib/gitlab/cycle_analytics/shared_stage_spec.rb
@@ -3,10 +3,10 @@ require 'spec_helper'
shared_examples 'base stage' do
ISSUES_MEDIAN = 30.minutes.to_i
- let(:stage) { described_class.new(project: double, options: {}) }
+ let(:stage) { described_class.new(options: { project: double }) }
before do
- allow(stage).to receive(:median).and_return(1.12)
+ allow(stage).to receive(:project_median).and_return(1.12)
allow_any_instance_of(Gitlab::CycleAnalytics::BaseEventFetcher).to receive(:event_result).and_return({})
end
diff --git a/spec/lib/gitlab/cycle_analytics/staging_stage_spec.rb b/spec/lib/gitlab/cycle_analytics/staging_stage_spec.rb
index 17d5fbb9733..3e2d748396f 100644
--- a/spec/lib/gitlab/cycle_analytics/staging_stage_spec.rb
+++ b/spec/lib/gitlab/cycle_analytics/staging_stage_spec.rb
@@ -5,16 +5,16 @@ describe Gitlab::CycleAnalytics::StagingStage do
let(:stage_name) { :staging }
let(:project) { create(:project) }
- let!(:issue_1) { create(:issue, project: project, created_at: 90.minutes.ago) }
- let!(:issue_2) { create(:issue, project: project, created_at: 60.minutes.ago) }
- let!(:issue_3) { create(:issue, project: project, created_at: 60.minutes.ago) }
- let!(:mr_1) { create(:merge_request, :closed, source_project: project, created_at: 60.minutes.ago) }
- let!(:mr_2) { create(:merge_request, :closed, source_project: project, created_at: 40.minutes.ago, source_branch: 'A') }
- let!(:mr_3) { create(:merge_request, source_project: project, created_at: 10.minutes.ago, source_branch: 'B') }
+ let(:issue_1) { create(:issue, project: project, created_at: 90.minutes.ago) }
+ let(:issue_2) { create(:issue, project: project, created_at: 60.minutes.ago) }
+ let(:issue_3) { create(:issue, project: project, created_at: 60.minutes.ago) }
+ let(:mr_1) { create(:merge_request, :closed, source_project: project, created_at: 60.minutes.ago) }
+ let(:mr_2) { create(:merge_request, :closed, source_project: project, created_at: 40.minutes.ago, source_branch: 'A') }
+ let(:mr_3) { create(:merge_request, source_project: project, created_at: 10.minutes.ago, source_branch: 'B') }
let(:build_1) { create(:ci_build, project: project) }
let(:build_2) { create(:ci_build, project: project) }
- let(:stage) { described_class.new(project: project, options: { from: 2.days.ago, current_user: project.creator }) }
+ let(:stage) { described_class.new(options: { from: 2.days.ago, current_user: project.creator, project: project }) }
before do
mr_1.metrics.update!(merged_at: 80.minutes.ago, first_deployed_to_production_at: 50.minutes.ago, pipeline_id: build_1.commit_id)
@@ -28,13 +28,13 @@ describe Gitlab::CycleAnalytics::StagingStage do
it_behaves_like 'base stage'
- describe '#median' do
+ describe '#project_median' do
around do |example|
Timecop.freeze { example.run }
end
it 'counts median from issues with metrics' do
- expect(stage.median).to eq(ISSUES_MEDIAN)
+ expect(stage.project_median).to eq(ISSUES_MEDIAN)
end
end
@@ -46,4 +46,50 @@ describe Gitlab::CycleAnalytics::StagingStage do
expect(result.map { |event| event[:name] }).to contain_exactly(build_1.name, build_2.name)
end
end
+
+ context 'when group is given' do
+ let(:user) { create(:user) }
+ let(:group) { create(:group) }
+ let(:project_2) { create(:project, group: group) }
+ let(:project_3) { create(:project, group: group) }
+ let(:issue_2_1) { create(:issue, project: project_2, created_at: 90.minutes.ago) }
+ let(:issue_2_2) { create(:issue, project: project_3, created_at: 60.minutes.ago) }
+ let(:issue_2_3) { create(:issue, project: project_2, created_at: 60.minutes.ago) }
+ let(:mr_1) { create(:merge_request, :closed, source_project: project_2, created_at: 60.minutes.ago) }
+ let(:mr_2) { create(:merge_request, :closed, source_project: project_3, created_at: 40.minutes.ago, source_branch: 'A') }
+ let(:mr_3) { create(:merge_request, source_project: project_2, created_at: 10.minutes.ago, source_branch: 'B') }
+ let(:build_1) { create(:ci_build, project: project_2) }
+ let(:build_2) { create(:ci_build, project: project_3) }
+ let(:stage) { described_class.new(options: { from: 2.days.ago, current_user: user, group: group }) }
+
+ before do
+ group.add_owner(user)
+ mr_1.metrics.update!(merged_at: 80.minutes.ago, first_deployed_to_production_at: 50.minutes.ago, pipeline_id: build_1.commit_id)
+ mr_2.metrics.update!(merged_at: 60.minutes.ago, first_deployed_to_production_at: 30.minutes.ago, pipeline_id: build_2.commit_id)
+ mr_3.metrics.update!(merged_at: 10.minutes.ago, first_deployed_to_production_at: 3.days.ago, pipeline_id: create(:ci_build, project: project_2).commit_id)
+
+ create(:merge_requests_closing_issues, merge_request: mr_1, issue: issue_2_1)
+ create(:merge_requests_closing_issues, merge_request: mr_2, issue: issue_2_2)
+ create(:merge_requests_closing_issues, merge_request: mr_3, issue: issue_2_3)
+ end
+
+ describe '#group_median' do
+ around do |example|
+ Timecop.freeze { example.run }
+ end
+
+ it 'counts median from issues with metrics' do
+ expect(stage.group_median).to eq(ISSUES_MEDIAN)
+ end
+ end
+
+ describe '#events' do
+ it 'exposes merge requests that close issues' do
+ result = stage.events
+
+ expect(result.count).to eq(2)
+ expect(result.map { |event| event[:name] }).to contain_exactly(build_1.name, build_2.name)
+ end
+ end
+ end
end
diff --git a/spec/lib/gitlab/cycle_analytics/usage_data_spec.rb b/spec/lib/gitlab/cycle_analytics/usage_data_spec.rb
index 8122e85a981..4ef33ff6e2b 100644
--- a/spec/lib/gitlab/cycle_analytics/usage_data_spec.rb
+++ b/spec/lib/gitlab/cycle_analytics/usage_data_spec.rb
@@ -34,7 +34,7 @@ describe Gitlab::CycleAnalytics::UsageData do
expect(result).to have_key(:avg_cycle_analytics)
- CycleAnalytics::Base::STAGES.each do |stage|
+ CycleAnalytics::BaseMethods::STAGES.each do |stage|
expect(result[:avg_cycle_analytics]).to have_key(stage)
stage_values = result[:avg_cycle_analytics][stage]
diff --git a/spec/models/cycle_analytics/code_spec.rb b/spec/models/cycle_analytics/code_spec.rb
index db6e70973ae..808659552ff 100644
--- a/spec/models/cycle_analytics/code_spec.rb
+++ b/spec/models/cycle_analytics/code_spec.rb
@@ -38,7 +38,7 @@ describe 'CycleAnalytics#code' do
merge_merge_requests_closing_issue(user, project, issue)
deploy_master(user, project)
- expect(subject[:code].median).to be_nil
+ expect(subject[:code].project_median).to be_nil
end
end
end
@@ -68,7 +68,7 @@ describe 'CycleAnalytics#code' do
merge_merge_requests_closing_issue(user, project, issue)
- expect(subject[:code].median).to be_nil
+ expect(subject[:code].project_median).to be_nil
end
end
end
diff --git a/spec/models/cycle_analytics/group_level_spec.rb b/spec/models/cycle_analytics/group_level_spec.rb
new file mode 100644
index 00000000000..70c370bc39d
--- /dev/null
+++ b/spec/models/cycle_analytics/group_level_spec.rb
@@ -0,0 +1,46 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe CycleAnalytics::GroupLevel do
+ let(:group) { create(:group)}
+ let(:project) { create(:project, :repository, namespace: group) }
+ let(:from_date) { 10.days.ago }
+ let(:user) { create(:user, :admin) }
+ let(:issue) { create(:issue, project: project, created_at: 2.days.ago) }
+ let(:milestone) { create(:milestone, project: project) }
+ let(:mr) { create_merge_request_closing_issue(user, project, issue, commit_message: "References #{issue.to_reference}") }
+ let(:pipeline) { create(:ci_empty_pipeline, status: 'created', project: project, ref: mr.source_branch, sha: mr.source_branch_sha, head_pipeline_of: mr) }
+
+ subject { described_class.new(options: { from: from_date, group: group, current_user: user }) }
+
+ describe '#permissions' do
+ it 'returns permissions' do
+ expect(subject.permissions.values.uniq).to eq([true])
+ end
+ end
+
+ describe '#stats' do
+ before do
+ allow_any_instance_of(Gitlab::ReferenceExtractor).to receive(:issues).and_return([issue])
+
+ create_cycle(user, project, issue, mr, milestone, pipeline)
+ deploy_master(user, project)
+ end
+
+ it 'returns medians for each stage for a specific group' do
+ expect(subject.no_stats?).to eq(false)
+ end
+ end
+
+ describe '#summary' do
+ before do
+ create_cycle(user, project, issue, mr, milestone, pipeline)
+ deploy_master(user, project)
+ end
+
+ it 'returns medians for each stage for a specific group' do
+ expect(subject.summary.map { |summary| summary[:value] }).to contain_exactly(1, 1)
+ end
+ end
+end
diff --git a/spec/models/cycle_analytics/issue_spec.rb b/spec/models/cycle_analytics/issue_spec.rb
index 4ccbdf29df6..8cdf83b1292 100644
--- a/spec/models/cycle_analytics/issue_spec.rb
+++ b/spec/models/cycle_analytics/issue_spec.rb
@@ -43,7 +43,7 @@ describe 'CycleAnalytics#issue' do
create_merge_request_closing_issue(user, project, issue)
merge_merge_requests_closing_issue(user, project, issue)
- expect(subject[:issue].median).to be_nil
+ expect(subject[:issue].project_median).to be_nil
end
end
end
diff --git a/spec/models/cycle_analytics/plan_spec.rb b/spec/models/cycle_analytics/plan_spec.rb
index c99c38e9cf3..28ad9bd194d 100644
--- a/spec/models/cycle_analytics/plan_spec.rb
+++ b/spec/models/cycle_analytics/plan_spec.rb
@@ -47,7 +47,7 @@ describe 'CycleAnalytics#plan' do
create_merge_request_closing_issue(user, project, issue, source_branch: branch_name)
merge_merge_requests_closing_issue(user, project, issue)
- expect(subject[:issue].median).to be_nil
+ expect(subject[:issue].project_median).to be_nil
end
end
end
diff --git a/spec/models/cycle_analytics/production_spec.rb b/spec/models/cycle_analytics/production_spec.rb
index ddd199362d1..613c1786540 100644
--- a/spec/models/cycle_analytics/production_spec.rb
+++ b/spec/models/cycle_analytics/production_spec.rb
@@ -41,7 +41,7 @@ describe 'CycleAnalytics#production' do
MergeRequests::MergeService.new(project, user).execute(merge_request)
deploy_master(user, project)
- expect(subject[:production].median).to be_nil
+ expect(subject[:production].project_median).to be_nil
end
end
@@ -52,7 +52,7 @@ describe 'CycleAnalytics#production' do
MergeRequests::MergeService.new(project, user).execute(merge_request)
deploy_master(user, project, environment: 'staging')
- expect(subject[:production].median).to be_nil
+ expect(subject[:production].project_median).to be_nil
end
end
end
diff --git a/spec/models/cycle_analytics/project_level_spec.rb b/spec/models/cycle_analytics/project_level_spec.rb
index 77bd0bfeb9c..4de01b1c679 100644
--- a/spec/models/cycle_analytics/project_level_spec.rb
+++ b/spec/models/cycle_analytics/project_level_spec.rb
@@ -23,7 +23,7 @@ describe CycleAnalytics::ProjectLevel do
it 'returns every median for each stage for a specific project' do
values = described_class::STAGES.each_with_object({}) do |stage_name, hsh|
- hsh[stage_name] = subject[stage_name].median.presence
+ hsh[stage_name] = subject[stage_name].project_median.presence
end
expect(subject.all_medians_by_stage).to eq(values)
diff --git a/spec/models/cycle_analytics/review_spec.rb b/spec/models/cycle_analytics/review_spec.rb
index 63c481ed465..ef88fd86340 100644
--- a/spec/models/cycle_analytics/review_spec.rb
+++ b/spec/models/cycle_analytics/review_spec.rb
@@ -28,7 +28,7 @@ describe 'CycleAnalytics#review' do
it "returns nil" do
MergeRequests::MergeService.new(project, user).execute(create(:merge_request))
- expect(subject[:review].median).to be_nil
+ expect(subject[:review].project_median).to be_nil
end
end
end
diff --git a/spec/models/cycle_analytics/staging_spec.rb b/spec/models/cycle_analytics/staging_spec.rb
index c134b97553f..571792559d8 100644
--- a/spec/models/cycle_analytics/staging_spec.rb
+++ b/spec/models/cycle_analytics/staging_spec.rb
@@ -45,7 +45,7 @@ describe 'CycleAnalytics#staging' do
MergeRequests::MergeService.new(project, user).execute(merge_request)
deploy_master(user, project)
- expect(subject[:staging].median).to be_nil
+ expect(subject[:staging].project_median).to be_nil
end
end
@@ -56,7 +56,7 @@ describe 'CycleAnalytics#staging' do
MergeRequests::MergeService.new(project, user).execute(merge_request)
deploy_master(user, project, environment: 'staging')
- expect(subject[:staging].median).to be_nil
+ expect(subject[:staging].project_median).to be_nil
end
end
end
diff --git a/spec/models/cycle_analytics/test_spec.rb b/spec/models/cycle_analytics/test_spec.rb
index a6ea73b2699..7b3001d2bd8 100644
--- a/spec/models/cycle_analytics/test_spec.rb
+++ b/spec/models/cycle_analytics/test_spec.rb
@@ -36,7 +36,7 @@ describe 'CycleAnalytics#test' do
merge_merge_requests_closing_issue(user, project, issue)
- expect(subject[:test].median).to be_nil
+ expect(subject[:test].project_median).to be_nil
end
end
@@ -47,7 +47,7 @@ describe 'CycleAnalytics#test' do
pipeline.run!
pipeline.succeed!
- expect(subject[:test].median).to be_nil
+ expect(subject[:test].project_median).to be_nil
end
end
@@ -62,7 +62,7 @@ describe 'CycleAnalytics#test' do
merge_merge_requests_closing_issue(user, project, issue)
- expect(subject[:test].median).to be_nil
+ expect(subject[:test].project_median).to be_nil
end
end
@@ -77,7 +77,7 @@ describe 'CycleAnalytics#test' do
merge_merge_requests_closing_issue(user, project, issue)
- expect(subject[:test].median).to be_nil
+ expect(subject[:test].project_median).to be_nil
end
end
end
diff --git a/spec/serializers/analytics_issue_entity_spec.rb b/spec/serializers/analytics_issue_entity_spec.rb
index 89588b4df2b..dd5e43a4b62 100644
--- a/spec/serializers/analytics_issue_entity_spec.rb
+++ b/spec/serializers/analytics_issue_entity_spec.rb
@@ -9,12 +9,14 @@ describe AnalyticsIssueEntity do
iid: "1",
id: "1",
created_at: "2016-11-12 15:04:02.948604",
- author: user
+ author: user,
+ name: project.name,
+ path: project.namespace
}
end
let(:project) { create(:project) }
- let(:request) { EntityRequest.new(project: project, entity: :merge_request) }
+ let(:request) { EntityRequest.new(entity: :merge_request) }
let(:entity) do
described_class.new(entity_hash, request: request, project: project)
diff --git a/spec/serializers/analytics_issue_serializer_spec.rb b/spec/serializers/analytics_issue_serializer_spec.rb
index 5befc28f4fa..c9ffe1c5dad 100644
--- a/spec/serializers/analytics_issue_serializer_spec.rb
+++ b/spec/serializers/analytics_issue_serializer_spec.rb
@@ -3,7 +3,7 @@ require 'spec_helper'
describe AnalyticsIssueSerializer do
subject do
described_class
- .new(project: project, entity: :merge_request)
+ .new(entity: :merge_request)
.represent(resource)
end
@@ -16,7 +16,9 @@ describe AnalyticsIssueSerializer do
iid: "1",
id: "1",
created_at: "2016-11-12 15:04:02.948604",
- author: user
+ author: user,
+ name: project.name,
+ path: project.namespace
}
end
diff --git a/spec/serializers/analytics_merge_request_serializer_spec.rb b/spec/serializers/analytics_merge_request_serializer_spec.rb
index 62067cc0ef2..123d7d795ce 100644
--- a/spec/serializers/analytics_merge_request_serializer_spec.rb
+++ b/spec/serializers/analytics_merge_request_serializer_spec.rb
@@ -3,7 +3,7 @@ require 'spec_helper'
describe AnalyticsMergeRequestSerializer do
subject do
described_class
- .new(project: project, entity: :merge_request)
+ .new(entity: :merge_request)
.represent(resource)
end
@@ -17,7 +17,9 @@ describe AnalyticsMergeRequestSerializer do
id: "1",
state: 'open',
created_at: "2016-11-12 15:04:02.948604",
- author: user
+ author: user,
+ name: project.name,
+ path: project.namespace
}
end
diff --git a/spec/serializers/analytics_stage_serializer_spec.rb b/spec/serializers/analytics_stage_serializer_spec.rb
index 5b05c2f2ef3..86a796a2d94 100644
--- a/spec/serializers/analytics_stage_serializer_spec.rb
+++ b/spec/serializers/analytics_stage_serializer_spec.rb
@@ -6,11 +6,11 @@ describe AnalyticsStageSerializer do
end
let(:resource) do
- Gitlab::CycleAnalytics::CodeStage.new(project: double, options: {})
+ Gitlab::CycleAnalytics::CodeStage.new(options: { project: double })
end
before do
- allow_any_instance_of(Gitlab::CycleAnalytics::BaseStage).to receive(:median).and_return(1.12)
+ allow_any_instance_of(Gitlab::CycleAnalytics::BaseStage).to receive(:project_median).and_return(1.12)
allow_any_instance_of(Gitlab::CycleAnalytics::BaseEventFetcher).to receive(:event_result).and_return({})
end
@@ -24,7 +24,7 @@ describe AnalyticsStageSerializer do
context 'when median is equal 0' do
before do
- allow_any_instance_of(Gitlab::CycleAnalytics::BaseStage).to receive(:median).and_return(0)
+ allow_any_instance_of(Gitlab::CycleAnalytics::BaseStage).to receive(:project_median).and_return(0)
end
it 'sets the value to nil' do
@@ -34,7 +34,7 @@ describe AnalyticsStageSerializer do
context 'when median is below 1' do
before do
- allow_any_instance_of(Gitlab::CycleAnalytics::BaseStage).to receive(:median).and_return(0.12)
+ allow_any_instance_of(Gitlab::CycleAnalytics::BaseStage).to receive(:project_median).and_return(0.12)
end
it 'sets the value to equal to median' do
@@ -44,7 +44,7 @@ describe AnalyticsStageSerializer do
context 'when median is above 1' do
before do
- allow_any_instance_of(Gitlab::CycleAnalytics::BaseStage).to receive(:median).and_return(60.12)
+ allow_any_instance_of(Gitlab::CycleAnalytics::BaseStage).to receive(:project_median).and_return(60.12)
end
it 'sets the value to equal to median' do
diff --git a/spec/support/cycle_analytics_helpers/test_generation.rb b/spec/support/cycle_analytics_helpers/test_generation.rb
index 19b32c84d81..be1c2bc3046 100644
--- a/spec/support/cycle_analytics_helpers/test_generation.rb
+++ b/spec/support/cycle_analytics_helpers/test_generation.rb
@@ -50,7 +50,7 @@ module CycleAnalyticsHelpers
end
median_time_difference = time_differences.sort[2]
- expect(subject[phase].median).to be_within(5).of(median_time_difference)
+ expect(subject[phase].project_median).to be_within(5).of(median_time_difference)
end
context "when the data belongs to another project" do
@@ -80,7 +80,7 @@ module CycleAnalyticsHelpers
# Turn off the stub before checking assertions
allow(self).to receive(:project).and_call_original
- expect(subject[phase].median).to be_nil
+ expect(subject[phase].project_median).to be_nil
end
end
@@ -103,7 +103,7 @@ module CycleAnalyticsHelpers
Timecop.freeze(end_time + 1.day) { post_fn[self, data] } if post_fn
- expect(subject[phase].median).to be_nil
+ expect(subject[phase].project_median).to be_nil
end
end
end
@@ -121,7 +121,7 @@ module CycleAnalyticsHelpers
Timecop.freeze(end_time + 1.day) { post_fn[self, data] } if post_fn
- expect(subject[phase].median).to be_nil
+ expect(subject[phase].project_median).to be_nil
end
end
end
@@ -138,7 +138,7 @@ module CycleAnalyticsHelpers
post_fn[self, data] if post_fn
- expect(subject[phase].median).to be_nil
+ expect(subject[phase].project_median).to be_nil
end
end
end
@@ -146,7 +146,7 @@ module CycleAnalyticsHelpers
context "when none of the start / end conditions are matched" do
it "returns nil" do
- expect(subject[phase].median).to be_nil
+ expect(subject[phase].project_median).to be_nil
end
end
end