Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
1
Merge Requests
1
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
gitlab-ce
Commits
d0422e28
Commit
d0422e28
authored
Aug 01, 2019
by
Gosia Ksionek
Committed by
James Lopez
Aug 01, 2019
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add controllers changes
Add new controllers and specs
parent
cb7d9090
Changes
11
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
425 additions
and
0 deletions
+425
-0
app/controllers/concerns/cycle_analytics_params.rb
app/controllers/concerns/cycle_analytics_params.rb
+2
-0
ee/app/controllers/concerns/ee/cycle_analytics_params.rb
ee/app/controllers/concerns/ee/cycle_analytics_params.rb
+18
-0
ee/app/controllers/groups/cycle_analytics/events_controller.rb
...p/controllers/groups/cycle_analytics/events_controller.rb
+62
-0
ee/app/controllers/groups/cycle_analytics_controller.rb
ee/app/controllers/groups/cycle_analytics_controller.rb
+46
-0
ee/app/models/license.rb
ee/app/models/license.rb
+1
-0
ee/app/policies/ee/group_policy.rb
ee/app/policies/ee/group_policy.rb
+7
-0
ee/changelogs/unreleased/12077-move-cycle-analytics-to-group-level-ee.yml
...released/12077-move-cycle-analytics-to-group-level-ee.yml
+5
-0
ee/config/routes/group.rb
ee/config/routes/group.rb
+13
-0
ee/spec/controllers/groups/cycle_analytics/events_controller_spec.rb
...trollers/groups/cycle_analytics/events_controller_spec.rb
+78
-0
ee/spec/controllers/groups/cycle_analytics_controller_spec.rb
...pec/controllers/groups/cycle_analytics_controller_spec.rb
+79
-0
ee/spec/requests/groups/cycle_analytics_events_spec.rb
ee/spec/requests/groups/cycle_analytics_events_spec.rb
+114
-0
No files found.
app/controllers/concerns/cycle_analytics_params.rb
View file @
d0422e28
...
@@ -18,3 +18,5 @@ module CycleAnalyticsParams
...
@@ -18,3 +18,5 @@ module CycleAnalyticsParams
end
end
end
end
end
end
CycleAnalyticsParams
.
prepend_if_ee
(
'EE::CycleAnalyticsParams'
)
ee/app/controllers/concerns/ee/cycle_analytics_params.rb
0 → 100644
View file @
d0422e28
# frozen_string_literal: true
module
EE
module
CycleAnalyticsParams
extend
::
Gitlab
::
Utils
::
Override
include
::
Gitlab
::
Utils
::
StrongMemoize
override
:options
def
options
(
params
)
strong_memoize
(
:options
)
do
super
.
tap
do
|
options
|
options
[
:branch
]
=
params
[
:branch_name
]
options
[
:projects
]
=
params
[
:project_ids
]
if
params
[
:project_ids
]
end
end
end
end
end
ee/app/controllers/groups/cycle_analytics/events_controller.rb
0 → 100644
View file @
d0422e28
# frozen_string_literal: true
class
Groups::CycleAnalytics::EventsController
<
Groups
::
ApplicationController
include
ActionView
::
Helpers
::
DateHelper
include
ActionView
::
Helpers
::
TextHelper
include
CycleAnalyticsParams
before_action
:authorize_group_cycle_analytics!
def
issue
render_events
(
:issue
)
end
def
plan
render_events
(
:plan
)
end
def
code
render_events
(
:code
)
end
def
test
render_events
(
:test
)
end
def
review
render_events
(
:review
)
end
def
staging
render_events
(
:staging
)
end
def
production
render_events
(
:production
)
end
private
def
render_events
(
stage
)
respond_to
do
|
format
|
format
.
html
format
.
json
{
render
json:
{
events:
cycle_analytics
[
stage
].
events
}
}
end
end
def
cycle_analytics
@cycle_analytics
||=
::
CycleAnalytics
::
GroupLevel
.
new
(
group:
group
,
options:
options
(
cycle_analytics_params
))
end
def
cycle_analytics_params
return
{}
unless
params
[
:cycle_analytics
].
present?
params
[
:cycle_analytics
].
permit
(
:start_date
,
:branch_name
,
project_ids:
[])
end
def
authorize_group_cycle_analytics!
unless
can?
(
current_user
,
:read_group_cycle_analytics
,
group
)
render_403
end
end
end
ee/app/controllers/groups/cycle_analytics_controller.rb
0 → 100644
View file @
d0422e28
# frozen_string_literal: true
class
Groups::CycleAnalyticsController
<
Groups
::
ApplicationController
include
ActionView
::
Helpers
::
DateHelper
include
ActionView
::
Helpers
::
TextHelper
include
CycleAnalyticsParams
before_action
:whitelist_query_limiting
,
only:
[
:show
]
before_action
:authorize_group_cycle_analytics!
def
show
respond_to
do
|
format
|
format
.
json
{
render
json:
cycle_analytics_json
}
end
end
private
def
cycle_analytics_params
return
{}
unless
params
[
:cycle_analytics
].
present?
params
[
:cycle_analytics
].
permit
(
:start_date
,
project_ids:
[])
end
def
cycle_analytics_json
{
summary:
cycle_analytics_stats
.
summary
,
stats:
cycle_analytics_stats
.
stats
,
permissions:
cycle_analytics_stats
.
permissions
(
user:
current_user
)
}
end
def
cycle_analytics_stats
@cycle_analytics_stats
||=
::
CycleAnalytics
::
GroupLevel
.
new
(
group:
group
,
options:
options
(
cycle_analytics_params
))
end
def
whitelist_query_limiting
Gitlab
::
QueryLimiting
.
whitelist
(
'https://gitlab.com/gitlab-org/gitlab-ce/issues/42671'
)
end
def
authorize_group_cycle_analytics!
unless
can?
(
current_user
,
:read_group_cycle_analytics
,
group
)
render_403
end
end
end
ee/app/models/license.rb
View file @
d0422e28
...
@@ -89,6 +89,7 @@ class License < ApplicationRecord
...
@@ -89,6 +89,7 @@ class License < ApplicationRecord
custom_prometheus_metrics
custom_prometheus_metrics
required_ci_templates
required_ci_templates
project_aliases
project_aliases
cycle_analytics_for_groups
]
]
EEP_FEATURES
.
freeze
EEP_FEATURES
.
freeze
...
...
ee/app/policies/ee/group_policy.rb
View file @
d0422e28
...
@@ -13,6 +13,10 @@ module EE
...
@@ -13,6 +13,10 @@ module EE
@subject
.
feature_available?
(
:contribution_analytics
)
@subject
.
feature_available?
(
:contribution_analytics
)
end
end
condition
(
:cycle_analytics_available
)
do
@subject
.
feature_available?
(
:cycle_analytics_for_groups
)
end
condition
(
:can_owners_manage_ldap
,
scope: :global
)
do
condition
(
:can_owners_manage_ldap
,
scope: :global
)
do
::
Gitlab
::
CurrentSettings
.
allow_group_owners_to_manage_ldap?
::
Gitlab
::
CurrentSettings
.
allow_group_owners_to_manage_ldap?
end
end
...
@@ -49,6 +53,9 @@ module EE
...
@@ -49,6 +53,9 @@ module EE
rule
{
can?
(
:read_group
)
&
contribution_analytics_available
}
rule
{
can?
(
:read_group
)
&
contribution_analytics_available
}
.
enable
:read_group_contribution_analytics
.
enable
:read_group_contribution_analytics
rule
{
reporter
&
cycle_analytics_available
}
.
enable
:read_group_cycle_analytics
rule
{
can?
(
:read_group
)
&
dependency_proxy_available
}
rule
{
can?
(
:read_group
)
&
dependency_proxy_available
}
.
enable
:read_dependency_proxy
.
enable
:read_dependency_proxy
...
...
ee/changelogs/unreleased/12077-move-cycle-analytics-to-group-level-ee.yml
0 → 100644
View file @
d0422e28
---
title
:
Add cycle analytics on group level
merge_request
:
14627
author
:
type
:
added
ee/config/routes/group.rb
View file @
d0422e28
...
@@ -18,6 +18,19 @@ constraints(::Constraints::GroupUrlConstrainer.new) do
...
@@ -18,6 +18,19 @@ constraints(::Constraints::GroupUrlConstrainer.new) do
end
end
resource
:analytics
,
only:
[
:show
]
resource
:analytics
,
only:
[
:show
]
resource
:cycle_analytics
,
only:
[
:show
]
namespace
:cycle_analytics
do
scope
:events
,
controller:
'events'
do
get
:issue
get
:plan
get
:code
get
:test
get
:review
get
:staging
get
:production
end
end
resource
:ldap
,
only:
[]
do
resource
:ldap
,
only:
[]
do
member
do
member
do
put
:sync
put
:sync
...
...
ee/spec/controllers/groups/cycle_analytics/events_controller_spec.rb
0 → 100644
View file @
d0422e28
# frozen_string_literal: true
require
'spec_helper'
RSpec
::
Matchers
.
define
:nested_hash_including
do
|
path_to_hash
,
value
|
match
{
|
actual
|
actual
.
dig
(
*
path_to_hash
)
==
value
}
end
describe
Groups
::
CycleAnalytics
::
EventsController
do
let
(
:group
)
{
create
(
:group
)
}
let
(
:project
)
{
create
(
:project
,
namespace:
group
)
}
let
(
:user
)
{
create
(
:user
)
}
let
(
:group_service
)
{
instance_double
(
::
CycleAnalytics
::
GroupLevel
)
}
let
(
:events_service
)
{
double
}
before
do
stub_licensed_features
(
cycle_analytics_for_groups:
true
)
sign_in
(
user
)
end
describe
'cycle analytics'
do
context
'with proper permission'
do
before
do
group
.
add_owner
(
user
)
end
it
'calls service'
do
expect
(
events_service
).
to
receive
(
:events
)
expect
(
group_service
).
to
receive
(
:[]
).
and_return
(
events_service
)
expect
(
::
CycleAnalytics
::
GroupLevel
).
to
receive
(
:new
).
and_return
(
group_service
)
get
(
:issue
,
params:
{
group_id:
group
.
name
},
format: :json
)
expect
(
response
).
to
be_success
end
it
'calls service with specific params'
do
expect
(
events_service
).
to
receive
(
:events
)
expect
(
group_service
).
to
receive
(
:[]
).
and_return
(
events_service
)
expect
(
::
CycleAnalytics
::
GroupLevel
).
to
receive
(
:new
)
.
with
(
nested_hash_including
([
:options
,
:projects
],
[
project
.
id
.
to_s
]))
.
and_return
(
group_service
)
get
(
:issue
,
params:
{
group_id:
group
.
name
,
cycle_analytics:
{
project_ids:
[
project
.
id
]
}
},
format: :json
)
expect
(
response
).
to
be_success
end
end
context
'as guest'
do
before
do
group
.
add_guest
(
user
)
end
it
'returns 403'
do
get
(
:issue
,
params:
{
group_id:
group
.
name
},
format: :json
)
expect
(
response
.
status
).
to
eq
(
403
)
end
end
end
end
ee/spec/controllers/groups/cycle_analytics_controller_spec.rb
0 → 100644
View file @
d0422e28
# frozen_string_literal: true
require
'spec_helper'
RSpec
::
Matchers
.
define
:nested_hash_including
do
|
path_to_hash
,
value
|
match
{
|
actual
|
actual
.
dig
(
*
path_to_hash
)
==
value
}
end
describe
Groups
::
CycleAnalyticsController
do
let
(
:group
)
{
create
(
:group
)
}
let
(
:project
)
{
create
(
:project
,
namespace:
group
)
}
let
(
:user
)
{
create
(
:user
)
}
let
(
:group_service
)
{
instance_double
(
::
CycleAnalytics
::
GroupLevel
)
}
before
do
stub_licensed_features
(
cycle_analytics_for_groups:
true
)
sign_in
(
user
)
end
describe
'cycle analytics'
do
context
'with proper permission'
do
before
do
group
.
add_owner
(
user
)
end
it
'calls service'
do
expect
(
group_service
).
to
receive
(
:summary
)
expect
(
group_service
).
to
receive
(
:stats
)
expect
(
group_service
).
to
receive
(
:permissions
)
expect
(
::
CycleAnalytics
::
GroupLevel
).
to
receive
(
:new
).
and_return
(
group_service
)
get
(
:show
,
params:
{
group_id:
group
.
name
},
format: :json
)
expect
(
response
).
to
be_success
end
it
'calls service with specific params'
do
expect
(
group_service
).
to
receive
(
:summary
)
expect
(
group_service
).
to
receive
(
:stats
)
expect
(
group_service
).
to
receive
(
:permissions
)
expect
(
::
CycleAnalytics
::
GroupLevel
).
to
receive
(
:new
)
.
with
(
nested_hash_including
([
:options
,
:projects
],
[
project
.
id
.
to_s
]))
.
and_return
(
group_service
)
get
(
:show
,
params:
{
group_id:
group
.
name
,
cycle_analytics:
{
project_ids:
[
project
.
id
]
}
},
format: :json
)
expect
(
response
).
to
be_success
end
end
context
'as guest'
do
before
do
group
.
add_guest
(
user
)
end
it
'returns 403'
do
get
(
:show
,
params:
{
group_id:
group
.
name
},
format: :json
)
expect
(
response
.
status
).
to
eq
(
403
)
end
end
end
end
ee/spec/requests/groups/cycle_analytics_events_spec.rb
0 → 100644
View file @
d0422e28
# frozen_string_literal: true
require
'spec_helper'
describe
'cycle analytics events'
do
let
(
:user
)
{
create
(
:user
)
}
let
(
:group
)
{
create
(
:group
)}
let
(
:project
)
{
create
(
:project
,
:repository
,
namespace:
group
,
public_builds:
false
)
}
let
(
:issue
)
{
create
(
:issue
,
project:
project
,
created_at:
2
.
days
.
ago
)
}
describe
'GET /:namespace/-/cycle_analytics/events/:stage'
do
before
do
stub_licensed_features
(
cycle_analytics_for_groups:
true
)
group
.
add_developer
(
user
)
project
.
add_developer
(
user
)
3
.
times
do
|
count
|
Timecop
.
freeze
(
Time
.
now
+
count
.
days
)
do
create_cycle
end
end
deploy_master
(
user
,
project
)
login_as
(
user
)
end
it
'lists the issue events'
do
get
group_cycle_analytics_issue_path
(
group
,
format: :json
)
first_issue_iid
=
project
.
issues
.
sort_by_attribute
(
:created_desc
).
pluck
(
:iid
).
first
.
to_s
expect
(
json_response
[
'events'
]).
not_to
be_empty
expect
(
json_response
[
'events'
].
first
[
'iid'
]).
to
eq
(
first_issue_iid
)
end
it
'lists the plan events'
do
get
group_cycle_analytics_plan_path
(
group
,
format: :json
)
first_issue_iid
=
project
.
issues
.
sort_by_attribute
(
:created_desc
).
pluck
(
:iid
).
first
.
to_s
expect
(
json_response
[
'events'
]).
not_to
be_empty
expect
(
json_response
[
'events'
].
first
[
'iid'
]).
to
eq
(
first_issue_iid
)
end
it
'lists the code events'
do
get
group_cycle_analytics_code_path
(
group
,
format: :json
)
expect
(
json_response
[
'events'
]).
not_to
be_empty
first_mr_iid
=
project
.
merge_requests
.
sort_by_attribute
(
:created_desc
).
pluck
(
:iid
).
first
.
to_s
expect
(
json_response
[
'events'
].
first
[
'iid'
]).
to
eq
(
first_mr_iid
)
end
it
'lists the test events'
do
get
group_cycle_analytics_test_path
(
group
,
format: :json
)
expect
(
json_response
[
'events'
]).
not_to
be_empty
expect
(
json_response
[
'events'
].
first
[
'date'
]).
not_to
be_empty
end
it
'lists the review events'
do
get
group_cycle_analytics_review_path
(
group
,
format: :json
)
first_mr_iid
=
project
.
merge_requests
.
sort_by_attribute
(
:created_desc
).
pluck
(
:iid
).
first
.
to_s
expect
(
json_response
[
'events'
]).
not_to
be_empty
expect
(
json_response
[
'events'
].
first
[
'iid'
]).
to
eq
(
first_mr_iid
)
end
it
'lists the staging events'
do
get
group_cycle_analytics_staging_path
(
group
,
format: :json
)
expect
(
json_response
[
'events'
]).
not_to
be_empty
expect
(
json_response
[
'events'
].
first
[
'date'
]).
not_to
be_empty
end
it
'lists the production events'
do
get
group_cycle_analytics_production_path
(
group
,
format: :json
)
first_issue_iid
=
project
.
issues
.
sort_by_attribute
(
:created_desc
).
pluck
(
:iid
).
first
.
to_s
expect
(
json_response
[
'events'
]).
not_to
be_empty
expect
(
json_response
[
'events'
].
first
[
'iid'
]).
to
eq
(
first_issue_iid
)
end
context
'specific branch'
do
it
'lists the test events'
do
branch
=
project
.
merge_requests
.
first
.
source_branch
get
group_cycle_analytics_test_path
(
group
,
format: :json
,
branch:
branch
)
expect
(
json_response
[
'events'
]).
not_to
be_empty
expect
(
json_response
[
'events'
].
first
[
'date'
]).
not_to
be_empty
end
end
end
def
create_cycle
milestone
=
create
(
:milestone
,
project:
project
)
issue
.
update
(
milestone:
milestone
)
mr
=
create_merge_request_closing_issue
(
user
,
project
,
issue
,
commit_message:
"References
#{
issue
.
to_reference
}
"
)
pipeline
=
create
(
:ci_empty_pipeline
,
status:
'created'
,
project:
project
,
ref:
mr
.
source_branch
,
sha:
mr
.
source_branch_sha
,
head_pipeline_of:
mr
)
pipeline
.
run
create
(
:ci_build
,
pipeline:
pipeline
,
status: :success
,
author:
user
)
create
(
:ci_build
,
pipeline:
pipeline
,
status: :success
,
author:
user
)
merge_merge_requests_closing_issue
(
user
,
project
,
issue
)
ProcessCommitWorker
.
new
.
perform
(
project
.
id
,
user
.
id
,
mr
.
commits
.
last
.
to_hash
)
end
end
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment