Commit 8343b553 authored by Adam Hegyi's avatar Adam Hegyi Committed by Peter Leitzen

Update code stage calculation in VSA

This change updates the calculation in value stream analytics. For the
code stage, the start event timestamp can be first_commit_at (new) or
first_mentioned_in_commit_at.

The change also introduces a separate stage where only the
first_commit_at is used.
parent a5b9c068
---
title: Include first commit date in code stage calculation in Value Stream Analytics
merge_request: 47215
author:
type: changed
...@@ -22,7 +22,8 @@ module EE ...@@ -22,7 +22,8 @@ module EE
::Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestClosed => 105, ::Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestClosed => 105,
::Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestLastEdited => 106, ::Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestLastEdited => 106,
::Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestLabelAdded => 107, ::Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestLabelAdded => 107,
::Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestLabelRemoved => 108 ::Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestLabelRemoved => 108,
::Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestFirstCommitAt => 109
}.freeze }.freeze
EE_EVENTS = EE_ENUM_MAPPING.keys.freeze EE_EVENTS = EE_ENUM_MAPPING.keys.freeze
...@@ -74,6 +75,15 @@ module EE ...@@ -74,6 +75,15 @@ module EE
::Gitlab::Analytics::CycleAnalytics::StageEvents::IssueLabelAdded, ::Gitlab::Analytics::CycleAnalytics::StageEvents::IssueLabelAdded,
::Gitlab::Analytics::CycleAnalytics::StageEvents::IssueLabelRemoved ::Gitlab::Analytics::CycleAnalytics::StageEvents::IssueLabelRemoved
], ],
::Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestFirstCommitAt => [
::Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestClosed,
::Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestFirstDeployedToProduction,
::Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestLastBuildStarted,
::Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestLastBuildFinished,
::Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestLastEdited,
::Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestLabelAdded,
::Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestLabelRemoved
],
::Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestCreated => [ ::Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestCreated => [
::Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestClosed, ::Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestClosed,
::Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestFirstDeployedToProduction, ::Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestFirstDeployedToProduction,
...@@ -87,12 +97,14 @@ module EE ...@@ -87,12 +97,14 @@ module EE
::Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestFirstDeployedToProduction, ::Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestFirstDeployedToProduction,
::Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestLastEdited, ::Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestLastEdited,
::Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestLabelAdded, ::Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestLabelAdded,
::Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestLabelRemoved ::Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestLabelRemoved,
::Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestFirstCommitAt
], ],
::Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestFirstDeployedToProduction => [ ::Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestFirstDeployedToProduction => [
::Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestLastEdited, ::Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestLastEdited,
::Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestLabelAdded, ::Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestLabelAdded,
::Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestLabelRemoved ::Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestLabelRemoved,
::Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestFirstCommitAt
], ],
::Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestLastBuildStarted => [ ::Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestLastBuildStarted => [
::Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestClosed, ::Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestClosed,
...@@ -100,7 +112,8 @@ module EE ...@@ -100,7 +112,8 @@ module EE
::Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestLastEdited, ::Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestLastEdited,
::Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestMerged, ::Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestMerged,
::Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestLabelAdded, ::Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestLabelAdded,
::Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestLabelRemoved ::Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestLabelRemoved,
::Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestFirstCommitAt
], ],
::Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestLastBuildFinished => [ ::Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestLastBuildFinished => [
::Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestClosed, ::Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestClosed,
...@@ -108,14 +121,16 @@ module EE ...@@ -108,14 +121,16 @@ module EE
::Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestLastEdited, ::Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestLastEdited,
::Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestMerged, ::Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestMerged,
::Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestLabelAdded, ::Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestLabelAdded,
::Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestLabelRemoved ::Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestLabelRemoved,
::Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestFirstCommitAt
], ],
::Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestMerged => [ ::Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestMerged => [
::Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestClosed, ::Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestClosed,
::Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestFirstDeployedToProduction, ::Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestFirstDeployedToProduction,
::Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestLastEdited, ::Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestLastEdited,
::Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestLabelAdded, ::Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestLabelAdded,
::Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestLabelRemoved ::Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestLabelRemoved,
::Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestFirstCommitAt
], ],
::Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestLabelAdded => [ ::Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestLabelAdded => [
::Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestLabelAdded, ::Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestLabelAdded,
......
# frozen_string_literal: true
module Gitlab
module Analytics
module CycleAnalytics
module StageEvents
class MergeRequestFirstCommitAt < MetricsBasedStageEvent
def self.name
s_("CycleAnalyticsEvent|Merge request first commit time")
end
def self.identifier
:merge_request_first_commit_at
end
def object_type
MergeRequest
end
def timestamp_projection
mr_metrics_table[:first_commit_at]
end
end
end
end
end
end
...@@ -288,6 +288,23 @@ RSpec.describe Gitlab::Analytics::CycleAnalytics::DataCollector do ...@@ -288,6 +288,23 @@ RSpec.describe Gitlab::Analytics::CycleAnalytics::DataCollector do
it_behaves_like 'custom cycle analytics stage' it_behaves_like 'custom cycle analytics stage'
end end
context 'between first commit at and merge request merged time' do
let(:start_event_identifier) { :merge_request_first_commit_at }
let(:end_event_identifier) { :merge_request_merged }
def create_data_for_start_event(example_class)
create(:merge_request, :merged, source_project: example_class.project).tap do |mr|
mr.metrics.update!(first_commit_at: Time.now)
end
end
def create_data_for_end_event(mr, example_class)
mr.metrics.update!(merged_at: Time.now)
end
it_behaves_like 'custom cycle analytics stage'
end
context 'between merge request build started time and build finished time' do context 'between merge request build started time and build finished time' do
let(:start_event_identifier) { :merge_request_last_build_started } let(:start_event_identifier) { :merge_request_last_build_started }
let(:end_event_identifier) { :merge_request_last_build_finished } let(:end_event_identifier) { :merge_request_last_build_finished }
...@@ -367,39 +384,83 @@ RSpec.describe Gitlab::Analytics::CycleAnalytics::DataCollector do ...@@ -367,39 +384,83 @@ RSpec.describe Gitlab::Analytics::CycleAnalytics::DataCollector do
it_behaves_like 'custom cycle analytics stage' it_behaves_like 'custom cycle analytics stage'
end end
context 'between code stage start time and merge request created time with label filter' do context 'between code stage start time and merge request created time' do
let(:start_event_identifier) { :code_stage_start } let(:start_event_identifier) { :code_stage_start }
let(:end_event_identifier) { :merge_request_created } let(:end_event_identifier) { :merge_request_created }
before do context 'when issue is referenced in the commit message' do
params[:label_name] = [label.name, other_label.name] def create_data_for_start_event(example_class)
end issue = create(:issue, project: example_class.project)
mr = create(:merge_request, {
source_project: example_class.project,
target_branch: example_class.project.default_branch,
description: "Description\n\nclosing #{issue.to_reference}",
allow_broken: true
})
MergeRequests::UpdateService.new(
example_class.project,
user,
assignees: [user]
).execute(mr)
mr.metrics.update!(first_commit_at: Time.zone.now)
mr
end
def create_data_for_start_event(example_class) def create_data_for_end_event(mr, example_class)
issue = create(:issue, project: example_class.project) mr.update!(created_at: Time.zone.now)
issue.metrics.update!(first_mentioned_in_commit_at: Time.zone.now) end
mr = create(:merge_request, { it_behaves_like 'custom cycle analytics stage'
source_project: example_class.project, end
target_branch: example_class.project.default_branch,
description: "Description\n\nclosing #{issue.to_reference}",
allow_broken: true
})
MergeRequests::UpdateService.new( context 'when `first_commit_at` is present' do
example_class.project, def create_data_for_start_event(example_class)
user, mr = create(:merge_request, { source_project: example_class.project, target_branch: example_class.project.default_branch, allow_broken: true })
label_ids: [label.id, other_label.id] mr.metrics.update!(first_commit_at: Time.zone.now)
).execute(mr) mr
end
mr def create_data_for_end_event(mr, example_class)
end mr.update!(created_at: Time.zone.now)
end
def create_data_for_end_event(mr, example_class) it_behaves_like 'custom cycle analytics stage'
mr.update!(created_at: Time.zone.now)
end end
it_behaves_like 'custom cycle analytics stage' context 'label filter' do
before do
params[:label_name] = [label.name, other_label.name]
end
def create_data_for_start_event(example_class)
issue = create(:issue, project: example_class.project)
issue.metrics.update!(first_mentioned_in_commit_at: Time.zone.now)
mr = create(:merge_request, {
source_project: example_class.project,
target_branch: example_class.project.default_branch,
description: "Description\n\nclosing #{issue.to_reference}",
allow_broken: true
})
MergeRequests::UpdateService.new(
example_class.project,
user,
label_ids: [label.id, other_label.id]
).execute(mr)
mr
end
def create_data_for_end_event(mr, example_class)
mr.update!(created_at: Time.zone.now)
end
it_behaves_like 'custom cycle analytics stage'
end
end end
end end
end end
......
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestFirstCommitAt do
it_behaves_like 'cycle analytics event'
end
...@@ -18,24 +18,46 @@ module Gitlab ...@@ -18,24 +18,46 @@ module Gitlab
end end
def timestamp_projection def timestamp_projection
issue_metrics_table[:first_mentioned_in_commit_at] Arel::Nodes::NamedFunction.new('COALESCE', column_list)
end end
override :column_list override :column_list
def column_list def column_list
[timestamp_projection] [
issue_metrics_table[:first_mentioned_in_commit_at],
mr_metrics_table[:first_commit_at]
]
end end
# rubocop: disable CodeReuse/ActiveRecord # rubocop: disable CodeReuse/ActiveRecord
def apply_query_customization(query) def apply_query_customization(query)
issue_metrics_join = mr_closing_issues_table query
.join(issue_metrics_table) .joins(merge_requests_closing_issues_join)
.joins(issue_metrics_join)
.joins(mr_metrics_join)
end
# rubocop: enable CodeReuse/ActiveRecord
def issue_metrics_join
mr_closing_issues_table
.join(issue_metrics_table, Arel::Nodes::OuterJoin)
.on(mr_closing_issues_table[:issue_id].eq(issue_metrics_table[:issue_id])) .on(mr_closing_issues_table[:issue_id].eq(issue_metrics_table[:issue_id]))
.join_sources .join_sources
end
query.joins(:merge_requests_closing_issues).joins(issue_metrics_join) def merge_requests_closing_issues_join
mr_table
.join(mr_closing_issues_table, Arel::Nodes::OuterJoin)
.on(mr_table[:id].eq(mr_closing_issues_table[:merge_request_id]))
.join_sources
end
def mr_metrics_join
mr_metrics_table
.join(mr_metrics_table, Arel::Nodes::OuterJoin)
.on(mr_metrics_table[:merge_request_id].eq(mr_table[:id]))
.join_sources
end end
# rubocop: enable CodeReuse/ActiveRecord
end end
end end
end end
......
...@@ -8207,6 +8207,9 @@ msgstr "" ...@@ -8207,6 +8207,9 @@ msgstr ""
msgid "CycleAnalyticsEvent|Merge request created" msgid "CycleAnalyticsEvent|Merge request created"
msgstr "" msgstr ""
msgid "CycleAnalyticsEvent|Merge request first commit time"
msgstr ""
msgid "CycleAnalyticsEvent|Merge request first deployed to production" msgid "CycleAnalyticsEvent|Merge request first deployed to production"
msgstr "" msgstr ""
......
...@@ -15,7 +15,7 @@ RSpec.describe Gitlab::Analytics::CycleAnalytics::StageEvents::CodeStageStart do ...@@ -15,7 +15,7 @@ RSpec.describe Gitlab::Analytics::CycleAnalytics::StageEvents::CodeStageStart do
other_merge_request = create(:merge_request, source_project: project, source_branch: 'a', target_branch: 'master') other_merge_request = create(:merge_request, source_project: project, source_branch: 'a', target_branch: 'master')
records = subject.apply_query_customization(MergeRequest.all) records = subject.apply_query_customization(MergeRequest.all).where('merge_requests_closing_issues.issue_id IS NOT NULL')
expect(records).to eq([merge_request]) expect(records).to eq([merge_request])
expect(records).not_to include(other_merge_request) expect(records).not_to include(other_merge_request)
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