Commit d3a48fec authored by Douwe Maan's avatar Douwe Maan

Merge branch 'feature/cycle-analytics-2-backend' into 'master'

Implement second iteration of cycle analytics - Change in data measurement

Part of https://gitlab.com/gitlab-org/gitlab-ce/issues/22458

Measure everything that happened in the given time range, not only what's been pushed to production. With the exception of the staging and production stages.

- [x] [CHANGELOG](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/CHANGELOG) entry added
- [x] [Documentation created/updated](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/development/doc_styleguide.md)
- Tests
  - [x] Added for this feature/bug
  - [x] All builds are passing
- [x] Conform by the [merge request performance guides](http://docs.gitlab.com/ce/development/merge_request_performance_guidelines.html)
- [x] Conform by the [style guides](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/CONTRIBUTING.md#style-guides)
- [x] Branch has no merge conflicts with `master` (if it does - rebase it please)
- [ ] [Squashed related commits together](https://git-scm.com/book/en/Git-Tools-Rewriting-History#Squashing-Commits)

See merge request !6798
parents 88568b8c 9521736e
......@@ -83,6 +83,7 @@ v 8.13.0 (unreleased)
- Replace bootstrap caret with fontawesome caret (ClemMakesApps)
- Fix unnecessary escaping of reserved HTML characters in milestone title. !6533
- Add organization field to user profile
- Ignore deployment for statistics in Cycle Analytics, except in staging and production stages
- Fix enter key when navigating search site search dropdown. !6643 (Brennan Roberts)
- Fix deploy status responsiveness error !6633
- Make searching for commits case insensitive
......
......@@ -2,6 +2,8 @@ class CycleAnalytics
include Gitlab::Database::Median
include Gitlab::Database::DateTime
DEPLOYMENT_METRIC_STAGES = %i[production staging]
def initialize(project, from:)
@project = project
@from = from
......@@ -66,7 +68,7 @@ class CycleAnalytics
# cycle analytics stage.
interval_query = Arel::Nodes::As.new(
cte_table,
subtract_datetimes(base_query, end_time_attrs, start_time_attrs, name.to_s))
subtract_datetimes(base_query_for(name), end_time_attrs, start_time_attrs, name.to_s))
median_datetime(cte_table, interval_query, name)
end
......@@ -75,7 +77,7 @@ class CycleAnalytics
# closes the given issue) with issue and merge request metrics included. The metrics
# are loaded with an inner join, so issues / merge requests without metrics are
# automatically excluded.
def base_query
def base_query_for(name)
arel_table = MergeRequestsClosingIssues.arel_table
# Load issues
......@@ -91,7 +93,11 @@ class CycleAnalytics
join(MergeRequest::Metrics.arel_table).
on(MergeRequest.arel_table[:id].eq(MergeRequest::Metrics.arel_table[:merge_request_id]))
# Limit to merge requests that have been deployed to production after `@from`
query.where(MergeRequest::Metrics.arel_table[:first_deployed_to_production_at].gteq(@from))
if DEPLOYMENT_METRIC_STAGES.include?(name)
# Limit to merge requests that have been deployed to production after `@from`
query.where(MergeRequest::Metrics.arel_table[:first_deployed_to_production_at].gteq(@from))
end
query
end
end
......@@ -3,8 +3,8 @@
> [Introduced][ce-5986] in GitLab 8.12.
>
> **Note:**
This the first iteration of Cycle Analytics, you can follow the following issue
to track the changes that are coming to this feature: [#20975][ce-20975].
There are more changes coming to Cycle Analytics, you can follow the following
issue to track the changes to this feature: [#20975][ce-20975].
Cycle Analytics measures the time it takes to go from an [idea to production] for
each project you have. This is achieved by not only indicating the total time it
......@@ -48,13 +48,12 @@ You can see that there are seven stages in total:
## How the data is measured
Cycle Analytics records cycle time so only data on the issues that have been
deployed to production are measured. In case you just started a new project and
you have not pushed anything to production, then you will not be able to
properly see the Cycle Analytics of your project.
Cycle Analytics records cycle time and data based on the project issues with the
exception of the staging and production stages, where only data deployed to
production are measured.
Specifically, if your CI is not set up and you have not defined a `production`
[environment], then you will not have any data.
[environment], then you will not have any data for those stages.
Below you can see in more detail what the various stages of Cycle Analytics mean.
......@@ -76,9 +75,8 @@ Here's a little explanation of how this works behind the scenes:
`<issue, merge request>` pair, the merge request has the [issue closing pattern]
for the corresponding issue. All other issues and merge requests are **not**
considered.
1. Then the <issue, merge request> pairs are filtered out. Any merge request
that has **not** been deployed to production in the last XX days (specified
by the UI - default is 90 days) prohibits these pairs from being considered.
1. Then the <issue, merge request> pairs are filtered out by last XX days (specified
by the UI - default is 90 days). So it prohibits these pairs from being considered.
1. For the remaining `<issue, merge request>` pairs, we check the information that
we need for the stages, like issue creation date, merge request merge time,
etc.
......@@ -86,8 +84,8 @@ Here's a little explanation of how this works behind the scenes:
To sum up, anything that doesn't follow the [GitLab flow] won't be tracked at all.
So, if a merge request doesn't close an issue or an issue is not labeled with a
label present in the Issue Board or assigned a milestone or a project has no
`production` environment, the Cycle Analytics dashboard won't present any data
at all.
`production` environment (for staging and production stages), the Cycle Analytics
dashboard won't present any data at all.
## Example workflow
......
......@@ -8,35 +8,69 @@ describe 'CycleAnalytics#code', feature: true do
let(:user) { create(:user, :admin) }
subject { CycleAnalytics.new(project, from: from_date) }
generate_cycle_analytics_spec(
phase: :code,
data_fn: -> (context) { { issue: context.create(:issue, project: context.project) } },
start_time_conditions: [["issue mentioned in a commit",
-> (context, data) do
context.create_commit_referencing_issue(data[:issue])
end]],
end_time_conditions: [["merge request that closes issue is created",
-> (context, data) do
context.create_merge_request_closing_issue(data[:issue])
end]],
post_fn: -> (context, data) do
context.merge_merge_requests_closing_issue(data[:issue])
context.deploy_master
end)
context "when a regular merge request (that doesn't close the issue) is created" do
it "returns nil" do
5.times do
issue = create(:issue, project: project)
create_commit_referencing_issue(issue)
create_merge_request_closing_issue(issue, message: "Closes nothing")
merge_merge_requests_closing_issue(issue)
deploy_master
context 'with deployment' do
generate_cycle_analytics_spec(
phase: :code,
data_fn: -> (context) { { issue: context.create(:issue, project: context.project) } },
start_time_conditions: [["issue mentioned in a commit",
-> (context, data) do
context.create_commit_referencing_issue(data[:issue])
end]],
end_time_conditions: [["merge request that closes issue is created",
-> (context, data) do
context.create_merge_request_closing_issue(data[:issue])
end]],
post_fn: -> (context, data) do
context.merge_merge_requests_closing_issue(data[:issue])
context.deploy_master
end)
context "when a regular merge request (that doesn't close the issue) is created" do
it "returns nil" do
5.times do
issue = create(:issue, project: project)
create_commit_referencing_issue(issue)
create_merge_request_closing_issue(issue, message: "Closes nothing")
merge_merge_requests_closing_issue(issue)
deploy_master
end
expect(subject.code).to be_nil
end
end
end
expect(subject.code).to be_nil
context 'without deployment' do
generate_cycle_analytics_spec(
phase: :code,
data_fn: -> (context) { { issue: context.create(:issue, project: context.project) } },
start_time_conditions: [["issue mentioned in a commit",
-> (context, data) do
context.create_commit_referencing_issue(data[:issue])
end]],
end_time_conditions: [["merge request that closes issue is created",
-> (context, data) do
context.create_merge_request_closing_issue(data[:issue])
end]],
post_fn: -> (context, data) do
context.merge_merge_requests_closing_issue(data[:issue])
end)
context "when a regular merge request (that doesn't close the issue) is created" do
it "returns nil" do
5.times do
issue = create(:issue, project: project)
create_commit_referencing_issue(issue)
create_merge_request_closing_issue(issue, message: "Closes nothing")
merge_merge_requests_closing_issue(issue)
end
expect(subject.code).to be_nil
end
end
end
end
......@@ -28,7 +28,6 @@ describe 'CycleAnalytics#issue', models: true do
if data[:issue].persisted?
context.create_merge_request_closing_issue(data[:issue].reload)
context.merge_merge_requests_closing_issue(data[:issue])
context.deploy_master
end
end)
......@@ -41,7 +40,6 @@ describe 'CycleAnalytics#issue', models: true do
create_merge_request_closing_issue(issue)
merge_merge_requests_closing_issue(issue)
deploy_master
end
expect(subject.issue).to be_nil
......
......@@ -31,7 +31,6 @@ describe 'CycleAnalytics#plan', feature: true do
post_fn: -> (context, data) do
context.create_merge_request_closing_issue(data[:issue], source_branch: data[:branch_name])
context.merge_merge_requests_closing_issue(data[:issue])
context.deploy_master
end)
context "when a regular label (instead of a list label) is added to the issue" do
......@@ -44,7 +43,6 @@ describe 'CycleAnalytics#plan', feature: true do
create_merge_request_closing_issue(issue, source_branch: branch_name)
merge_merge_requests_closing_issue(issue)
deploy_master
expect(subject.issue).to be_nil
end
......
......@@ -19,14 +19,12 @@ describe 'CycleAnalytics#review', feature: true do
-> (context, data) do
context.merge_merge_requests_closing_issue(data[:issue])
end]],
post_fn: -> (context, data) { context.deploy_master })
post_fn: nil)
context "when a regular merge request (that doesn't close the issue) is created and merged" do
it "returns nil" do
5.times do
MergeRequests::MergeService.new(project, user).execute(create(:merge_request))
deploy_master
end
expect(subject.review).to be_nil
......
......@@ -20,7 +20,6 @@ describe 'CycleAnalytics#test', feature: true do
end_time_conditions: [["pipeline is finished", -> (context, data) { data[:pipeline].succeed! }]],
post_fn: -> (context, data) do
context.merge_merge_requests_closing_issue(data[:issue])
context.deploy_master
end)
context "when the pipeline is for a regular merge request (that doesn't close an issue)" do
......@@ -34,7 +33,6 @@ describe 'CycleAnalytics#test', feature: true do
pipeline.succeed!
merge_merge_requests_closing_issue(issue)
deploy_master
end
expect(subject.test).to be_nil
......@@ -48,8 +46,6 @@ describe 'CycleAnalytics#test', feature: true do
pipeline.run!
pipeline.succeed!
deploy_master
end
expect(subject.test).to be_nil
......@@ -67,7 +63,6 @@ describe 'CycleAnalytics#test', feature: true do
pipeline.drop!
merge_merge_requests_closing_issue(issue)
deploy_master
end
expect(subject.test).to be_nil
......@@ -85,7 +80,6 @@ describe 'CycleAnalytics#test', feature: true do
pipeline.cancel!
merge_merge_requests_closing_issue(issue)
deploy_master
end
expect(subject.test).to be_nil
......
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