From 3d5729a7008f4ae62190a7862873fc6f28f33425 Mon Sep 17 00:00:00 2001 From: Timothy Andrew Date: Thu, 25 Aug 2016 14:36:01 +0530 Subject: [PATCH] Add the "Production" cycle analytics section. 1. Rewrite the `Queries` module to work off a `data_point` hash, with `issue` and `merge_request` as keys. The "production" query needs both an issue and a merge request to make it's calculation, so it makes sense to keep things consistent and provide the same data (issue + merge request) for all queries. --- app/models/cycle_analytics.rb | 27 ++++++------ app/models/cycle_analytics/queries.rb | 41 +++++++++++++++---- .../projects/cycle_analytics/show.html.haml | 7 ++++ 3 files changed, 54 insertions(+), 21 deletions(-) diff --git a/app/models/cycle_analytics.rb b/app/models/cycle_analytics.rb index 8ba275dd13a..2caccdce9a2 100644 --- a/app/models/cycle_analytics.rb +++ b/app/models/cycle_analytics.rb @@ -1,39 +1,40 @@ class CycleAnalytics def issue - issues = Issue.includes(:metrics).where("issue_metrics.id IS NOT NULL").references(:issue_metrics).to_a - start_time_fn = -> (issue) { issue.created_at } - calculate_metric(issues, start_time_fn, Queries::issue_first_associated_with_milestone_or_first_added_to_list_label_time) + calculate_metric(Queries::issues, + -> (data_point) { data_point[:issue].created_at }, + Queries::issue_first_associated_with_milestone_or_first_added_to_list_label_time) end def plan - issues = Issue.includes(:metrics).where("issue_metrics.id IS NOT NULL").references(:issue_metrics).to_a - calculate_metric(issues, + calculate_metric(Queries::issues, Queries::issue_first_associated_with_milestone_or_first_added_to_list_label_time, Queries::issue_closing_merge_request_opened_time) end def code - issues = Issue.all.to_a - start_time_fn = -> (merge_request) { merge_request.created_at } - calculate_metric(Queries::merge_requests_closing_issues(issues), - start_time_fn, + calculate_metric(Queries::merge_requests_closing_issues, + -> (data_point) { data_point[:merge_request].created_at }, Queries::mr_wip_flag_removed_or_assigned_to_user_other_than_author_time) end def review - issues = Issue.all.to_a - calculate_metric(Queries::merge_requests_closing_issues(issues), + calculate_metric(Queries::merge_requests_closing_issues, Queries::mr_wip_flag_removed_or_assigned_to_user_other_than_author_time, Queries::mr_first_closed_or_merged_at) end def staging - issues = Issue.all.to_a - calculate_metric(Queries::merge_requests_closing_issues(issues), + calculate_metric(Queries::merge_requests_closing_issues, Queries::mr_merged_at, Queries::mr_deployed_to_any_environment_at) end + def production + calculate_metric(Queries::merge_requests_closing_issues, + -> (data_point) { data_point[:issue].created_at }, + Queries::mr_deployed_to_production_at) + end + private def calculate_metric(data, start_time_fn, end_time_fn) diff --git a/app/models/cycle_analytics/queries.rb b/app/models/cycle_analytics/queries.rb index 9970941837d..f14f44c3876 100644 --- a/app/models/cycle_analytics/queries.rb +++ b/app/models/cycle_analytics/queries.rb @@ -1,12 +1,20 @@ class CycleAnalytics module Queries class << self - def merge_requests_closing_issues(issues) - issues.map { |issue| issue.closed_by_merge_requests(nil, check_if_open: false) }.flatten + def issues + Issue.all.to_a.map { |issue| { issue: issue } } + end + + def merge_requests_closing_issues + issues.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 end def issue_first_associated_with_milestone_or_first_added_to_list_label_time - lambda do |issue| + lambda do |data_point| + issue = data_point[:issue] if issue.metrics.present? issue.metrics.first_associated_with_milestone_at.presence || issue.metrics.first_added_to_board_at.presence @@ -15,7 +23,8 @@ class CycleAnalytics end def mr_first_closed_or_merged_at - lambda do |merge_request| + lambda do |data_point| + merge_request = data_point[:merge_request] if merge_request.metrics.present? merge_request.metrics.merged_at.presence || merge_request.metrics.first_closed_at.presence end @@ -23,7 +32,8 @@ class CycleAnalytics end def mr_merged_at - lambda do |merge_request| + lambda do |data_point| + merge_request = data_point[:merge_request] if merge_request.metrics.present? merge_request.metrics.merged_at end @@ -31,7 +41,8 @@ class CycleAnalytics end def mr_deployed_to_any_environment_at - lambda do |merge_request| + lambda do |data_point| + merge_request = data_point[:merge_request] if merge_request.metrics.present? deployments = Deployment.where(ref: merge_request.target_branch).where("created_at > ?", merge_request.metrics.merged_at) deployment = deployments.order(:created_at).first @@ -40,15 +51,29 @@ class CycleAnalytics end end + def mr_deployed_to_production_at + lambda do |data_point| + merge_request = data_point[:merge_request] + if merge_request.metrics.present? + deployments = Deployment.joins(:environment).where(ref: merge_request.target_branch, "environments.name" => "production"). + where("deployments.created_at > ?", merge_request.metrics.merged_at) + deployment = deployments.order(:created_at).first + deployment.created_at if deployment + end + end + end + def issue_closing_merge_request_opened_time - lambda do |issue| + lambda do |data_point| + issue = data_point[:issue] merge_requests = issue.closed_by_merge_requests(nil, check_if_open: false) merge_requests.map(&:created_at).min if merge_requests.present? end end def mr_wip_flag_removed_or_assigned_to_user_other_than_author_time - lambda do |merge_request| + lambda do |data_point| + merge_request = data_point[:merge_request] if merge_request.metrics.present? merge_request.metrics.wip_flag_first_removed_at.presence || merge_request.metrics.first_assigned_to_user_other_than_author.presence diff --git a/app/views/projects/cycle_analytics/show.html.haml b/app/views/projects/cycle_analytics/show.html.haml index e1c13b3c7a5..b4f875f00db 100644 --- a/app/views/projects/cycle_analytics/show.html.haml +++ b/app/views/projects/cycle_analytics/show.html.haml @@ -33,3 +33,10 @@ = distance_of_time_in_words staging - else = "" + + %li.list-group-item + Production: + - if production = @cycle_analytics.production.presence + = distance_of_time_in_words production + - else + = ""