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
::Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestClosed => 105,
::Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestLastEdited => 106,
::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
EE_EVENTS = EE_ENUM_MAPPING.keys.freeze
......@@ -74,6 +75,15 @@ module EE
::Gitlab::Analytics::CycleAnalytics::StageEvents::IssueLabelAdded,
::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::MergeRequestClosed,
::Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestFirstDeployedToProduction,
......@@ -87,12 +97,14 @@ module EE
::Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestFirstDeployedToProduction,
::Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestLastEdited,
::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::MergeRequestLastEdited,
::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::MergeRequestClosed,
......@@ -100,7 +112,8 @@ module EE
::Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestLastEdited,
::Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestMerged,
::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::MergeRequestClosed,
......@@ -108,14 +121,16 @@ module EE
::Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestLastEdited,
::Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestMerged,
::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::MergeRequestClosed,
::Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestFirstDeployedToProduction,
::Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestLastEdited,
::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,
......
# 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
it_behaves_like 'custom cycle analytics stage'
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
let(:start_event_identifier) { :merge_request_last_build_started }
let(:end_event_identifier) { :merge_request_last_build_finished }
......@@ -367,39 +384,83 @@ RSpec.describe Gitlab::Analytics::CycleAnalytics::DataCollector do
it_behaves_like 'custom cycle analytics stage'
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(:end_event_identifier) { :merge_request_created }
before do
params[:label_name] = [label.name, other_label.name]
end
context 'when issue is referenced in the commit message' do
def create_data_for_start_event(example_class)
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)
issue = create(:issue, project: example_class.project)
issue.metrics.update!(first_mentioned_in_commit_at: Time.zone.now)
def create_data_for_end_event(mr, example_class)
mr.update!(created_at: Time.zone.now)
end
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
})
it_behaves_like 'custom cycle analytics stage'
end
MergeRequests::UpdateService.new(
example_class.project,
user,
label_ids: [label.id, other_label.id]
).execute(mr)
context 'when `first_commit_at` is present' do
def create_data_for_start_event(example_class)
mr = create(:merge_request, { source_project: example_class.project, target_branch: example_class.project.default_branch, allow_broken: true })
mr.metrics.update!(first_commit_at: Time.zone.now)
mr
end
mr
end
def create_data_for_end_event(mr, example_class)
mr.update!(created_at: Time.zone.now)
end
def create_data_for_end_event(mr, example_class)
mr.update!(created_at: Time.zone.now)
it_behaves_like 'custom cycle analytics stage'
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
......
# 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
end
def timestamp_projection
issue_metrics_table[:first_mentioned_in_commit_at]
Arel::Nodes::NamedFunction.new('COALESCE', column_list)
end
override :column_list
def column_list
[timestamp_projection]
[
issue_metrics_table[:first_mentioned_in_commit_at],
mr_metrics_table[:first_commit_at]
]
end
# rubocop: disable CodeReuse/ActiveRecord
def apply_query_customization(query)
issue_metrics_join = mr_closing_issues_table
.join(issue_metrics_table)
query
.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]))
.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
# rubocop: enable CodeReuse/ActiveRecord
end
end
end
......
......@@ -8207,6 +8207,9 @@ msgstr ""
msgid "CycleAnalyticsEvent|Merge request created"
msgstr ""
msgid "CycleAnalyticsEvent|Merge request first commit time"
msgstr ""
msgid "CycleAnalyticsEvent|Merge request first deployed to production"
msgstr ""
......
......@@ -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')
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).not_to include(other_merge_request)
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