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.
This commit is contained in:
parent
ce6bcdd004
commit
331080bca6
5 changed files with 59 additions and 24 deletions
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
%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
|
||||
|
|
Loading…
Reference in a new issue