Commit 38c017a2 authored by Pavel Shutsin's avatar Pavel Shutsin

Consider first approved at in code review time

review start time should be first approved at
or first comment at whatever is earlier
parent a9bd44b2
......@@ -63,7 +63,8 @@ module EE
accepts_nested_attributes_for :approval_rules, allow_destroy: true
scope :order_review_time_desc, -> do
joins(:metrics).reorder(::Gitlab::Database.nulls_last_order('merge_request_metrics.first_comment_at'))
joins(:metrics)
.reorder(::Gitlab::Database.nulls_last_order(::MergeRequest::Metrics.review_time_field))
end
scope :with_code_review_api_entity_associations, -> do
......@@ -97,7 +98,7 @@ module EE
# Returns an array of arel columns
def grouping_columns(sort)
grouping_columns = super
grouping_columns << ::MergeRequest::Metrics.arel_table[:first_comment_at] if sort.to_s == 'review_time_desc'
grouping_columns << ::MergeRequest::Metrics.review_time_field if sort.to_s == 'review_time_desc'
grouping_columns
end
end
......
......@@ -3,6 +3,14 @@
module EE
module MergeRequest
module Metrics
extend ActiveSupport::Concern
class_methods do
def review_time_field
@review_time_field ||= Arel.sql("LEAST(merge_request_metrics.first_comment_at, merge_request_metrics.first_approved_at)")
end
end
def review_time
return unless review_start_at
......@@ -10,7 +18,7 @@ module EE
end
def review_start_at
first_comment_at
[first_comment_at, first_approved_at].compact.min
end
def review_end_at
......
---
title: Resolve Code review start time doesnt account for approvals
merge_request: 25997
author:
type: changed
......@@ -4,7 +4,7 @@ module Analytics
class RefreshApprovalsData
include MergeRequestMetricsRefresh
# Change interface to accept single MR only
# Override MergeRequestMetricsRefresh#initialize` to accept single MR only
def initialize(merge_request)
super
end
......
......@@ -3,7 +3,7 @@
require 'spec_helper'
describe Analytics::MergeRequestMetricsRefresh do
subject { calculator_class.new(merge_request_1) }
subject { calculator_class.new(merge_request) }
let(:calculator_class) do
Class.new do
......@@ -23,24 +23,24 @@ describe Analytics::MergeRequestMetricsRefresh do
end
end
let!(:merge_request_1) { create(:merge_request) }
let!(:merge_request) { create(:merge_request) }
describe '#execute' do
it 'updates metric via update_metric! method' do
expect { subject.execute }.to change { merge_request_1.metrics.first_comment_at }.to(be_like_time(Time.now))
expect { subject.execute }.to change { merge_request.metrics.first_comment_at }.to(be_like_time(Time.now))
end
context 'when metric is already present' do
before do
merge_request_1.metrics.first_comment_at = 1.day.ago
merge_request.metrics.first_comment_at = 1.day.ago
end
it 'does not update metric' do
expect { subject.execute }.not_to change { merge_request_1.metrics.first_comment_at }
expect { subject.execute }.not_to change { merge_request.metrics.first_comment_at }
end
it 'updates metric when forced' do
expect { subject.execute(force: true) }.to change { merge_request_1.metrics.first_comment_at }.to(be_like_time(Time.now))
expect { subject.execute(force: true) }.to change { merge_request.metrics.first_comment_at }.to(be_like_time(Time.now))
end
end
end
......@@ -49,7 +49,7 @@ describe Analytics::MergeRequestMetricsRefresh do
it 'schedules CodeReviewMetricsWorker with params' do
expect(Analytics::CodeReviewMetricsWorker)
.to receive(:perform_async)
.with('MyTestClass', merge_request_1.id, force: true)
.with('MyTestClass', merge_request.id, force: true)
subject.execute_async(force: true)
end
......
......@@ -4,10 +4,25 @@ require 'spec_helper'
describe MergeRequest::Metrics do
describe '#review_start_at' do
it 'is first_comment_at' do
it 'is the earliest date from first_comment_at or first_approved_at' do
subject.first_approved_at = 1.day.ago
subject.first_comment_at = 1.hour.ago
expect(subject.review_start_at).to be_like_time(1.hour.ago)
expect(subject.review_start_at).to be_like_time(1.day.ago)
end
context 'when all review start candidates are nil' do
it 'is nil' do
expect(subject.review_start_at).to eq nil
end
end
context 'when one of review start candidates is nil' do
it 'is earliest date from non-nil values' do
subject.first_approved_at = 1.day.ago
expect(subject.review_start_at).to be_like_time(1.day.ago)
end
end
end
......
......@@ -743,13 +743,19 @@ describe MergeRequest do
end
describe 'review time sorting' do
it 'orders by first_comment_at' do
merge_request_1 = create(:merge_request, :with_productivity_metrics, metrics_data: { first_comment_at: 1.day.ago })
merge_request_2 = create(:merge_request, :with_productivity_metrics, metrics_data: { first_comment_at: 3.days.ago })
merge_request_3 = create(:merge_request, :with_productivity_metrics, metrics_data: { first_comment_at: nil })
def create_mr(metrics_data = {})
create(:merge_request, :with_productivity_metrics, metrics_data: metrics_data)
end
it 'orders by first_comment_at or first_approved_at whatever is earlier' do
mr1 = create_mr(first_comment_at: 1.day.ago)
mr2 = create_mr(first_comment_at: 3.days.ago)
mr3 = create_mr(first_approved_at: 5.days.ago)
mr4 = create_mr(first_comment_at: 1.day.ago, first_approved_at: 4.days.ago)
mr5 = create_mr(first_comment_at: nil, first_approved_at: nil)
expect(described_class.order_review_time_desc).to match([merge_request_2, merge_request_1, merge_request_3])
expect(described_class.sort_by_attribute('review_time_desc')).to match([merge_request_2, merge_request_1, merge_request_3])
expect(described_class.order_review_time_desc).to match([mr3, mr4, mr2, mr1, mr5])
expect(described_class.sort_by_attribute('review_time_desc')).to match([mr3, mr4, mr2, mr1, mr5])
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