Commit 331080bc authored by Timothy Andrew's avatar Timothy Andrew

Fetch cycle analytics data for a specific date range.

1. Supported date ranges are 30 / 90 days ago. The default is 90 days
   ago.

2. All issues created before "x days ago" are filtered out, even if they
   have other related data (test runs, merge requests) within the filter
   range.
parent ce6bcdd0
class Projects::CycleAnalyticsController < Projects::ApplicationController
def show
@cycle_analytics = CycleAnalytics.new(@project)
@cycle_analytics = CycleAnalytics.new(@project, from: parse_start_date)
end
private
def parse_start_date
case cycle_analytics_params[:start_date]
when '30' then 30.days.ago
when '90' then 90.days.ago
else 90.days.ago
end
end
def cycle_analytics_params
return {} unless params[:cycle_analytics].present?
{ start_date: params[:cycle_analytics][:start_date] }
end
end
class CycleAnalytics
def initialize(project)
attr_reader :from
def initialize(project, from:)
@project = project
@from = from
end
def issue
calculate_metric(Queries::issues(@project),
calculate_metric(Queries::issues(@project, created_after: @from),
-> (data_point) { data_point[:issue].created_at },
[Queries::issue_first_associated_with_milestone_at, Queries::issue_first_added_to_list_label_at])
end
def plan
calculate_metric(Queries::issues(@project),
calculate_metric(Queries::issues(@project, created_after: @from),
[Queries::issue_first_associated_with_milestone_at, Queries::issue_first_added_to_list_label_at],
Queries::issue_closing_merge_request_opened_at)
end
def code
calculate_metric(Queries::merge_requests_closing_issues(@project),
calculate_metric(Queries::merge_requests_closing_issues(@project, created_after: @from),
-> (data_point) { data_point[:merge_request].created_at },
[Queries::merge_request_first_assigned_to_user_other_than_author_at, Queries::merge_request_wip_flag_first_removed_at])
end
def test
calculate_metric(Queries::merge_requests_closing_issues(@project),
calculate_metric(Queries::merge_requests_closing_issues(@project, created_after: @from),
Queries::merge_request_build_started_at,
Queries::merge_request_build_finished_at)
end
def review
calculate_metric(Queries::merge_requests_closing_issues(@project),
calculate_metric(Queries::merge_requests_closing_issues(@project, created_after: @from),
[Queries::merge_request_first_assigned_to_user_other_than_author_at, Queries::merge_request_wip_flag_first_removed_at],
[Queries::merge_request_first_closed_at, Queries::merge_request_merged_at])
end
def staging
calculate_metric(Queries::merge_requests_closing_issues(@project),
calculate_metric(Queries::merge_requests_closing_issues(@project, created_after: @from),
Queries::merge_request_merged_at,
Queries::merge_request_deployed_to_any_environment_at)
end
def production
calculate_metric(Queries::merge_requests_closing_issues(@project),
calculate_metric(Queries::merge_requests_closing_issues(@project, created_after: @from),
-> (data_point) { data_point[:issue].created_at },
Queries::merge_request_deployed_to_production_at)
end
......
class CycleAnalytics
module Queries
class << self
def issues(project)
project.issues.map { |issue| { issue: issue } }
def issues(project, created_after:)
project.issues.where("created_at >= ?", created_after).map { |issue| { issue: issue } }
end
def merge_requests_closing_issues(project)
issues(project).map do |data_point|
def merge_requests_closing_issues(project, options = {})
issues(project, options).map do |data_point|
merge_requests = data_point[:issue].closed_by_merge_requests(nil, check_if_open: false)
merge_requests.map { |merge_request| { issue: data_point[:issue], merge_request: merge_request } }
end.flatten
......
%h2 Cycle Analytics from #{@cycle_analytics.from} to Today
%ul.list-group
%li.list-group-item
Issue:
......
......@@ -2,7 +2,8 @@ require 'spec_helper'
describe 'CycleAnalytics#issue', models: true do
let(:project) { create(:project) }
subject { CycleAnalytics.new(project) }
let(:from_date) { 10.days.ago }
subject { CycleAnalytics.new(project, from: from_date) }
context "when calculating the median of times between:
start: issue created_at
......@@ -26,16 +27,6 @@ describe 'CycleAnalytics#issue', models: true do
median_start_time, median_end_time = start_and_end_times[2]
expect(subject.issue).to eq(median_end_time - median_start_time)
end
it "does not include issues from other projects" do
5.times do
milestone = create(:milestone, project: project)
issue = create(:issue)
issue.update(milestone: milestone)
end
expect(subject.issue).to be_nil
end
end
context "when a label is added to the issue" do
......@@ -80,6 +71,29 @@ describe 'CycleAnalytics#issue', models: true do
expect(subject.issue).to eq(milestone_add_time - start_time)
end
it "does not include issues from other projects" do
milestone = create(:milestone, project: project)
list_label = create(:label, lists: [create(:list)])
issue = create(:issue)
issue.update(milestone: milestone)
issue.update(label_ids: [list_label.id])
expect(subject.issue).to be_nil
end
it "excludes issues created before the 'from' date" do
before_from_date = from_date - 5.days
milestone = create(:milestone, project: project)
list_label = create(:label, lists: [create(:list)])
issue = Timecop.freeze(before_from_date) { create(:issue, project: project)}
issue.update(milestone: milestone)
issue.update(label_ids: [list_label.id])
expect(subject.issue).to be_nil
end
end
end
end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment