From 331080bca683fdab73520f68c53f6a5367d17f22 Mon Sep 17 00:00:00 2001 From: Timothy Andrew Date: Fri, 26 Aug 2016 16:18:52 +0530 Subject: [PATCH] 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. --- .../projects/cycle_analytics_controller.rb | 18 +++++++++- app/models/cycle_analytics.rb | 19 +++++----- app/models/cycle_analytics/queries.rb | 8 ++--- .../projects/cycle_analytics/show.html.haml | 2 ++ spec/models/cycle_analytics/issue_spec.rb | 36 +++++++++++++------ 5 files changed, 59 insertions(+), 24 deletions(-) diff --git a/app/controllers/projects/cycle_analytics_controller.rb b/app/controllers/projects/cycle_analytics_controller.rb index 85c81cba511..002a71b593d 100644 --- a/app/controllers/projects/cycle_analytics_controller.rb +++ b/app/controllers/projects/cycle_analytics_controller.rb @@ -1,5 +1,21 @@ 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 diff --git a/app/models/cycle_analytics.rb b/app/models/cycle_analytics.rb index 331bb450e08..d6a0b5fcc7a 100644 --- a/app/models/cycle_analytics.rb +++ b/app/models/cycle_analytics.rb @@ -1,46 +1,49 @@ 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 diff --git a/app/models/cycle_analytics/queries.rb b/app/models/cycle_analytics/queries.rb index 122b2599bd3..1a9a1daa2b0 100644 --- a/app/models/cycle_analytics/queries.rb +++ b/app/models/cycle_analytics/queries.rb @@ -1,12 +1,12 @@ 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 diff --git a/app/views/projects/cycle_analytics/show.html.haml b/app/views/projects/cycle_analytics/show.html.haml index 160c8eaca72..50ac9904445 100644 --- a/app/views/projects/cycle_analytics/show.html.haml +++ b/app/views/projects/cycle_analytics/show.html.haml @@ -1,3 +1,5 @@ +%h2 Cycle Analytics from #{@cycle_analytics.from} to Today + %ul.list-group %li.list-group-item Issue: diff --git a/spec/models/cycle_analytics/issue_spec.rb b/spec/models/cycle_analytics/issue_spec.rb index 6fdce020642..4dc7f62af98 100644 --- a/spec/models/cycle_analytics/issue_spec.rb +++ b/spec/models/cycle_analytics/issue_spec.rb @@ -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