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 ...@@ -63,7 +63,8 @@ module EE
accepts_nested_attributes_for :approval_rules, allow_destroy: true accepts_nested_attributes_for :approval_rules, allow_destroy: true
scope :order_review_time_desc, -> do 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 end
scope :with_code_review_api_entity_associations, -> do scope :with_code_review_api_entity_associations, -> do
...@@ -97,7 +98,7 @@ module EE ...@@ -97,7 +98,7 @@ module EE
# Returns an array of arel columns # Returns an array of arel columns
def grouping_columns(sort) def grouping_columns(sort)
grouping_columns = super 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 grouping_columns
end end
end end
......
...@@ -3,6 +3,14 @@ ...@@ -3,6 +3,14 @@
module EE module EE
module MergeRequest module MergeRequest
module Metrics 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 def review_time
return unless review_start_at return unless review_start_at
...@@ -10,7 +18,7 @@ module EE ...@@ -10,7 +18,7 @@ module EE
end end
def review_start_at def review_start_at
first_comment_at [first_comment_at, first_approved_at].compact.min
end end
def review_end_at 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 ...@@ -4,7 +4,7 @@ module Analytics
class RefreshApprovalsData class RefreshApprovalsData
include MergeRequestMetricsRefresh include MergeRequestMetricsRefresh
# Change interface to accept single MR only # Override MergeRequestMetricsRefresh#initialize` to accept single MR only
def initialize(merge_request) def initialize(merge_request)
super super
end end
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
require 'spec_helper' require 'spec_helper'
describe Analytics::MergeRequestMetricsRefresh do describe Analytics::MergeRequestMetricsRefresh do
subject { calculator_class.new(merge_request_1) } subject { calculator_class.new(merge_request) }
let(:calculator_class) do let(:calculator_class) do
Class.new do Class.new do
...@@ -23,24 +23,24 @@ describe Analytics::MergeRequestMetricsRefresh do ...@@ -23,24 +23,24 @@ describe Analytics::MergeRequestMetricsRefresh do
end end
end end
let!(:merge_request_1) { create(:merge_request) } let!(:merge_request) { create(:merge_request) }
describe '#execute' do describe '#execute' do
it 'updates metric via update_metric! method' 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 end
context 'when metric is already present' do context 'when metric is already present' do
before do before do
merge_request_1.metrics.first_comment_at = 1.day.ago merge_request.metrics.first_comment_at = 1.day.ago
end end
it 'does not update metric' do 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 end
it 'updates metric when forced' do 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 end
end end
...@@ -49,7 +49,7 @@ describe Analytics::MergeRequestMetricsRefresh do ...@@ -49,7 +49,7 @@ describe Analytics::MergeRequestMetricsRefresh do
it 'schedules CodeReviewMetricsWorker with params' do it 'schedules CodeReviewMetricsWorker with params' do
expect(Analytics::CodeReviewMetricsWorker) expect(Analytics::CodeReviewMetricsWorker)
.to receive(:perform_async) .to receive(:perform_async)
.with('MyTestClass', merge_request_1.id, force: true) .with('MyTestClass', merge_request.id, force: true)
subject.execute_async(force: true) subject.execute_async(force: true)
end end
......
...@@ -4,10 +4,25 @@ require 'spec_helper' ...@@ -4,10 +4,25 @@ require 'spec_helper'
describe MergeRequest::Metrics do describe MergeRequest::Metrics do
describe '#review_start_at' 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 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
end end
......
...@@ -743,13 +743,19 @@ describe MergeRequest do ...@@ -743,13 +743,19 @@ describe MergeRequest do
end end
describe 'review time sorting' do describe 'review time sorting' do
it 'orders by first_comment_at' do def create_mr(metrics_data = {})
merge_request_1 = create(:merge_request, :with_productivity_metrics, metrics_data: { first_comment_at: 1.day.ago }) create(:merge_request, :with_productivity_metrics, metrics_data: metrics_data)
merge_request_2 = create(:merge_request, :with_productivity_metrics, metrics_data: { first_comment_at: 3.days.ago }) end
merge_request_3 = create(:merge_request, :with_productivity_metrics, metrics_data: { first_comment_at: nil })
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.order_review_time_desc).to match([mr3, mr4, mr2, mr1, mr5])
expect(described_class.sort_by_attribute('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([mr3, mr4, mr2, mr1, mr5])
end end
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