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