diff options
Diffstat (limited to 'lib/gitlab/cycle_analytics/usage_data.rb')
-rw-r--r-- | lib/gitlab/cycle_analytics/usage_data.rb | 72 |
1 files changed, 72 insertions, 0 deletions
diff --git a/lib/gitlab/cycle_analytics/usage_data.rb b/lib/gitlab/cycle_analytics/usage_data.rb new file mode 100644 index 00000000000..5122e3417ca --- /dev/null +++ b/lib/gitlab/cycle_analytics/usage_data.rb @@ -0,0 +1,72 @@ +module Gitlab + module CycleAnalytics + class UsageData + PROJECTS_LIMIT = 10 + + attr_reader :projects, :options + + def initialize + @projects = Project.sorted_by_activity.limit(PROJECTS_LIMIT) + @options = { from: 7.days.ago } + end + + def to_json + total = 0 + + values = + medians_per_stage.each_with_object({}) do |(stage_name, medians), hsh| + calculations = stage_values(medians) + + total += calculations.values.compact.sum + hsh[stage_name] = calculations + end + + values[:total] = total + + { avg_cycle_analytics: values } + end + + private + + def medians_per_stage + projects.each_with_object({}) do |project, hsh| + ::CycleAnalytics.new(project, options).all_medians_per_stage.each do |stage_name, median| + hsh[stage_name] ||= [] + hsh[stage_name] << median + end + end + end + + def stage_values(medians) + medians = medians.map(&:presence).compact + average = calc_average(medians) + + { + average: average, + sd: standard_deviation(medians, average), + missing: projects.length - medians.length + } + end + + def calc_average(values) + return if values.empty? + + (values.sum / values.length).to_i + end + + def standard_deviation(values, average) + Math.sqrt(sample_variance(values, average)).to_i + end + + def sample_variance(values, average) + return 0 if values.length <= 1 + + sum = values.inject(0) do |acc, val| + acc + (val - average)**2 + end + + sum / (values.length - 1) + end + end + end +end |