summaryrefslogtreecommitdiff
path: root/doc/development/cycle_analytics.md
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2020-02-07 21:08:39 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2020-02-07 21:08:39 +0000
commit0c6bc5443aa6c8f3e4becccb89fc0f135b4c64c8 (patch)
tree55f13e752e9061c1800cce510a52fc78b13282ca /doc/development/cycle_analytics.md
parentd7ce7307dca551759ffa972015875f8ebe476927 (diff)
downloadgitlab-ce-0c6bc5443aa6c8f3e4becccb89fc0f135b4c64c8.tar.gz
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'doc/development/cycle_analytics.md')
-rw-r--r--doc/development/cycle_analytics.md249
1 files changed, 4 insertions, 245 deletions
diff --git a/doc/development/cycle_analytics.md b/doc/development/cycle_analytics.md
index 90abafb3e03..3947a012bd5 100644
--- a/doc/development/cycle_analytics.md
+++ b/doc/development/cycle_analytics.md
@@ -1,246 +1,5 @@
-# Cycle Analytics development guide
+---
+redirect_to: 'value_stream_analytics.md'
+---
-Cycle analytics calculates the time between two arbitrary events recorded on domain objects and provides aggregated statistics about the duration.
-
-## Stage
-
-During development, events occur that move issues and merge requests through different stages of progress until they are considered finished. These stages can be expressed with the `Stage` model.
-
-Example stage:
-
-- Name: Development
-- Start event: Issue created
-- End event: Issue first mentioned in commit
-- Parent: `Group: gitlab-org`
-
-### Events
-
-Events are the smallest building blocks of the cycle analytics feature. A stage consists of two events:
-
-- Start
-- End
-
-These events play a key role in the duration calculation.
-
-Formula: `duration = end_event_time - start_event_time`
-
-To make the duration calculation flexible, each `Event` is implemented as a separate class. They're responsible for defining a timestamp expression that will be used in the calculation query.
-
-#### Implementing an `Event` class
-
-There are a few methods that are required to be implemented, the `StageEvent` base class describes them in great detail. The most important ones are:
-
-- `object_type`
-- `timestamp_projection`
-
-The `object_type` method defines which domain object will be queried for the calculation. Currently two models are allowed:
-
-- `Issue`
-- `MergeRequest`
-
-For the duration calculation the `timestamp_projection` method will be used.
-
-```ruby
-def timestamp_projection
- # your timestamp expression comes here
-end
-
-# event will use the issue creation time in the duration calculation
-def timestamp_projection
- Issue.arel_table[:created_at]
-end
-```
-
-NOTE: **Note:**
-More complex expressions are also possible (e.g. using `COALESCE`). Look at the existing event classes for examples.
-
-In some cases, defining the `timestamp_projection` method is not enough. The calculation query should know which table contains the timestamp expression. Each `Event` class is responsible for making modifications to the calculation query to make the `timestamp_projection` work. This usually means joining an additional table.
-
-Example for joining the `issue_metrics` table and using the `first_mentioned_in_commit_at` column as the timestamp expression:
-
-```ruby
-def object_type
- Issue
-end
-
-def timestamp_projection
- IssueMetrics.arel_table[:first_mentioned_in_commit_at]
-end
-
-def apply_query_customization(query)
- # in this case the query attribute will be based on the Issue model: `Issue.where(...)`
- query.joins(:metrics)
-end
-```
-
-### Validating start and end events
-
-Some start/end event pairs are not "compatible" with each other. For example:
-
-- "Issue created" to "Merge Request created": The event classes are defined on different domain models, the `object_type` method is different.
-- "Issue closed" to "Issue created": Issue must be created first before it can be closed.
-- "Issue closed" to "Issue closed": Duration is always 0.
-
-The `StageEvents` module describes the allowed `start_event` and `end_event` pairings (`PAIRING_RULES` constant). If a new event is added, it needs to be registered in this module.
-​To add a new event:​
-
-1. Add an entry in `ENUM_MAPPING` with a unique number, it'll be used in the `Stage` model as `enum`.
-1. Define which events are compatible with the event in the `PAIRING_RULES` hash.
-
-Supported start/end event pairings:
-
-```mermaid
-graph LR;
- IssueCreated --> IssueClosed;
- IssueCreated --> IssueFirstAddedToBoard;
- IssueCreated --> IssueFirstAssociatedWithMilestone;
- IssueCreated --> IssueFirstMentionedInCommit;
- IssueCreated --> IssueLastEdited;
- IssueCreated --> IssueLabelAdded;
- IssueCreated --> IssueLabelRemoved;
- MergeRequestCreated --> MergeRequestMerged;
- MergeRequestCreated --> MergeRequestClosed;
- MergeRequestCreated --> MergeRequestFirstDeployedToProduction;
- MergeRequestCreated --> MergeRequestLastBuildStarted;
- MergeRequestCreated --> MergeRequestLastBuildFinished;
- MergeRequestCreated --> MergeRequestLastEdited;
- MergeRequestCreated --> MergeRequestLabelAdded;
- MergeRequestCreated --> MergeRequestLabelRemoved;
- MergeRequestLastBuildStarted --> MergeRequestLastBuildFinished;
- MergeRequestLastBuildStarted --> MergeRequestClosed;
- MergeRequestLastBuildStarted --> MergeRequestFirstDeployedToProduction;
- MergeRequestLastBuildStarted --> MergeRequestLastEdited;
- MergeRequestLastBuildStarted --> MergeRequestMerged;
- MergeRequestLastBuildStarted --> MergeRequestLabelAdded;
- MergeRequestLastBuildStarted --> MergeRequestLabelRemoved;
- MergeRequestMerged --> MergeRequestFirstDeployedToProduction;
- MergeRequestMerged --> MergeRequestClosed;
- MergeRequestMerged --> MergeRequestFirstDeployedToProduction;
- MergeRequestMerged --> MergeRequestLastEdited;
- MergeRequestMerged --> MergeRequestLabelAdded;
- MergeRequestMerged --> MergeRequestLabelRemoved;
- IssueLabelAdded --> IssueLabelAdded;
- IssueLabelAdded --> IssueLabelRemoved;
- IssueLabelAdded --> IssueClosed;
- IssueLabelRemoved --> IssueClosed;
- IssueFirstAddedToBoard --> IssueClosed;
- IssueFirstAddedToBoard --> IssueFirstAssociatedWithMilestone;
- IssueFirstAddedToBoard --> IssueFirstMentionedInCommit;
- IssueFirstAddedToBoard --> IssueLastEdited;
- IssueFirstAddedToBoard --> IssueLabelAdded;
- IssueFirstAddedToBoard --> IssueLabelRemoved;
- IssueFirstAssociatedWithMilestone --> IssueClosed;
- IssueFirstAssociatedWithMilestone --> IssueFirstAddedToBoard;
- IssueFirstAssociatedWithMilestone --> IssueFirstMentionedInCommit;
- IssueFirstAssociatedWithMilestone --> IssueLastEdited;
- IssueFirstAssociatedWithMilestone --> IssueLabelAdded;
- IssueFirstAssociatedWithMilestone --> IssueLabelRemoved;
- IssueFirstMentionedInCommit --> IssueClosed;
- IssueFirstMentionedInCommit --> IssueFirstAssociatedWithMilestone;
- IssueFirstMentionedInCommit --> IssueFirstAddedToBoard;
- IssueFirstMentionedInCommit --> IssueLastEdited;
- IssueFirstMentionedInCommit --> IssueLabelAdded;
- IssueFirstMentionedInCommit --> IssueLabelRemoved;
- IssueClosed --> IssueLastEdited;
- IssueClosed --> IssueLabelAdded;
- IssueClosed --> IssueLabelRemoved;
- MergeRequestClosed --> MergeRequestFirstDeployedToProduction;
- MergeRequestClosed --> MergeRequestLastEdited;
- MergeRequestClosed --> MergeRequestLabelAdded;
- MergeRequestClosed --> MergeRequestLabelRemoved;
- MergeRequestFirstDeployedToProduction --> MergeRequestLastEdited;
- MergeRequestFirstDeployedToProduction --> MergeRequestLabelAdded;
- MergeRequestFirstDeployedToProduction --> MergeRequestLabelRemoved;
- MergeRequestLastBuildFinished --> MergeRequestClosed;
- MergeRequestLastBuildFinished --> MergeRequestFirstDeployedToProduction;
- MergeRequestLastBuildFinished --> MergeRequestLastEdited;
- MergeRequestLastBuildFinished --> MergeRequestMerged;
- MergeRequestLastBuildFinished --> MergeRequestLabelAdded;
- MergeRequestLastBuildFinished --> MergeRequestLabelRemoved;
- MergeRequestLabelAdded --> MergeRequestLabelAdded;
- MergeRequestLabelAdded --> MergeRequestLabelRemoved;
- MergeRequestLabelRemoved --> MergeRequestLabelAdded;
- MergeRequestLabelRemoved --> MergeRequestLabelRemoved;
-```
-
-### Parent
-
-Teams and organizations might define their own way of building software, thus stages can be completely different. For each stage, a parent object needs to be defined.
-
-Currently supported parents:
-
-- `Project`
-- `Group`
-
-#### How parent relationship it work
-
-1. User navigates to the cycle analytics page.
-1. User selects a group.
-1. Backend loads the defined stages for the selected group.
-1. Additions and modifications to the stages will be persisted within the selected group only.
-
-### Default stages
-
-The [original implementation](https://gitlab.com/gitlab-org/gitlab/issues/847) of cycle analytics defined 7 stages. These stages are always available for each parent, however altering these stages is not possible.
-​
-To make things efficient and reduce the number of records created, the default stages are expressed as in-memory objects (not persisted). When the user creates a custom stage for the first time, all the stages will be persisted. This behaviour is implemented in the cycle analytics service objects.
-​
-The reason for this was that we'd like to add the abilities to hide and order stages later on.
-
-## Data Collector
-
-`DataCollector` is the central point where the data will be queried from the database. The class always operates on a single stage and consists of the following components:
-
-- `BaseQueryBuilder`:
- - Responsible for composing the initial query.
- - Deals with `Stage` specific configuration: events and their query customizations.
- - Parameters coming from the UI: date ranges.
-- `Median`: Calculates the median duration for a stage using the query from `BaseQueryBuilder`.
-- `RecordsFetcher`: Loads relevant records for a stage using the query from `BaseQueryBuilder` and specific `Finder` classes to apply visibility rules.
-- `DataForDurationChart`: Loads calculated durations with the finish time (end event timestamp) for the scatterplot chart.
-
-For a new calculation or a query, implement it as a new method call in the `DataCollector` class.
-
-## Database query
-
-Structure of the database query:
-
-```sql
-SELECT (customized by: Median or RecordsFetcher or DataForDurationChart)
-FROM OBJECT_TYPE (Issue or MergeRequest)
-INNER JOIN (several JOIN statements, depending on the events)
-WHERE
- (Filter by the PARENT model, example: filter Issues from Project A)
- (Date range filter based on the OBJECT_TYPE.created_at)
- (Check if the START_EVENT is earlier than END_EVENT, preventing negative duration)
-```
-
-Structure of the `SELECT` statement for `Median`:
-
-```sql
-SELECT (calculate median from START_EVENT_TIME-END_EVENT_TIME)
-```
-
-Structure of the `SELECT` statement for `DataForDurationChart`:
-
-```sql
-SELECT (START_EVENT_TIME-END_EVENT_TIME) as duration, END_EVENT.timestamp
-```
-
-## High-level overview
-
-- Rails Controller (`Analytics::CycleAnalytics` module): Cycle analytics exposes its data via JSON endpoints, implemented within the `analytics` workspace. Configuring the stages are also implements JSON endpoints (CRUD).
-- Services (`Analytics::CycleAnalytics` module): All `Stage` related actions will be delegated to respective service objects.
-- Models (`Analytics::CycleAnalytics` module): Models are used to persist the `Stage` objects `ProjectStage` and `GroupStage`.
-- Feature classes (`Gitlab::Analytics::CycleAnalytics` module):
- - Responsible for composing queries and define feature specific busines logic.
- - `DataCollector`, `Event`, `StageEvents`, etc.
-
-## Testing
-
-Since we have a lots of events and possible pairings, testing each pairing is not possible. The rule is to have at least one test case using an `Event` class.
-
-Writing a test case for a stage using a new `Event` can be challenging since data must be created for both events. To make this a bit simpler, each test case must be implemented in the `data_collector_spec.rb` where the stage is tested through the `DataCollector`. Each test case will be turned into multiple tests, covering the following cases:
-
-- Different parents: `Group` or `Project`
-- Different calculations: `Median`, `RecordsFetcher` or `DataForDurationChart`
+This document was moved to [another location](value_stream_analytics.md)