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
90879740
Commit
90879740
authored
Jun 17, 2020
by
Jason Goodman
Committed by
Shinya Maeda
Jun 17, 2020
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add feature flag issues controller with GET index route
Add feature flag issues list service
parent
dd2cf5cf
Changes
13
Hide whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
326 additions
and
1 deletion
+326
-1
ee/app/controllers/projects/feature_flag_issues_controller.rb
...pp/controllers/projects/feature_flag_issues_controller.rb
+24
-0
ee/app/models/ee/issue.rb
ee/app/models/ee/issue.rb
+3
-0
ee/app/models/feature_flag_issue.rb
ee/app/models/feature_flag_issue.rb
+8
-0
ee/app/models/operations/feature_flag.rb
ee/app/models/operations/feature_flag.rb
+13
-0
ee/app/serializers/linked_feature_flag_issue_entity.rb
ee/app/serializers/linked_feature_flag_issue_entity.rb
+11
-0
ee/app/serializers/linked_feature_flag_issue_serializer.rb
ee/app/serializers/linked_feature_flag_issue_serializer.rb
+5
-0
ee/app/services/feature_flag_issues/list_service.rb
ee/app/services/feature_flag_issues/list_service.rb
+18
-0
ee/config/routes/project.rb
ee/config/routes/project.rb
+3
-1
ee/spec/controllers/projects/feature_flag_issues_controller_spec.rb
...ntrollers/projects/feature_flag_issues_controller_spec.rb
+190
-0
ee/spec/controllers/projects/feature_flags_controller_spec.rb
...pec/controllers/projects/feature_flags_controller_spec.rb
+8
-0
ee/spec/factories/feature_flag_issue.rb
ee/spec/factories/feature_flag_issue.rb
+8
-0
ee/spec/serializers/linked_feature_flag_issue_entity_spec.rb
ee/spec/serializers/linked_feature_flag_issue_entity_spec.rb
+30
-0
spec/lib/gitlab/import_export/all_models.yml
spec/lib/gitlab/import_export/all_models.yml
+5
-0
No files found.
ee/app/controllers/projects/feature_flag_issues_controller.rb
0 → 100644
View file @
90879740
# frozen_string_literal: true
module
Projects
class
FeatureFlagIssuesController
<
Projects
::
ApplicationController
include
IssuableLinks
before_action
:ensure_feature_enabled!
before_action
:authorize_admin_feature_flag!
private
def
list_service
::
FeatureFlagIssues
::
ListService
.
new
(
feature_flag
,
current_user
)
end
def
feature_flag
project
.
operations_feature_flags
.
find_by_iid
(
params
[
:feature_flag_iid
])
end
def
ensure_feature_enabled!
render_404
unless
Feature
.
enabled?
(
:feature_flags_issue_links
,
project
)
end
end
end
ee/app/models/ee/issue.rb
View file @
90879740
...
...
@@ -44,6 +44,9 @@ module EE
has_many
:vulnerability_links
,
class_name:
'Vulnerabilities::IssueLink'
,
inverse_of: :issue
has_many
:related_vulnerabilities
,
through: :vulnerability_links
,
source: :vulnerability
has_many
:feature_flag_issues
has_many
:feature_flags
,
through: :feature_flag_issues
,
class_name:
'::Operations::FeatureFlag'
validates
:weight
,
allow_nil:
true
,
numericality:
{
greater_than_or_equal_to:
0
}
validate
:validate_confidential_epic
...
...
ee/app/models/feature_flag_issue.rb
0 → 100644
View file @
90879740
# frozen_string_literal: true
class
FeatureFlagIssue
<
ApplicationRecord
self
.
table_name
=
'operations_feature_flags_issues'
belongs_to
:feature_flag
,
class_name:
'::Operations::FeatureFlag'
belongs_to
:issue
end
ee/app/models/operations/feature_flag.rb
View file @
90879740
...
...
@@ -17,6 +17,8 @@ module Operations
has_many
:scopes
,
class_name:
'Operations::FeatureFlagScope'
# strategies exists only for the second version
has_many
:strategies
,
class_name:
'Operations::FeatureFlags::Strategy'
has_many
:feature_flag_issues
has_many
:issues
,
through: :feature_flag_issues
has_one
:default_scope
,
->
{
where
(
environment_scope:
'*'
)
},
class_name:
'Operations::FeatureFlagScope'
validates
:project
,
presence:
true
...
...
@@ -61,6 +63,17 @@ module Operations
end
end
def
related_issues
(
current_user
,
preload
:)
issues
=
::
Issue
.
select
(
'issues.*, operations_feature_flags_issues.id AS link_id'
)
.
joins
(
:feature_flag_issues
)
.
where
(
'operations_feature_flags_issues.feature_flag_id = ?'
,
id
)
.
order
(
'operations_feature_flags_issues.id ASC'
)
.
includes
(
preload
)
Ability
.
issues_readable_by_user
(
issues
,
current_user
)
end
private
def
version_associations
...
...
ee/app/serializers/linked_feature_flag_issue_entity.rb
0 → 100644
View file @
90879740
# frozen_string_literal: true
class
LinkedFeatureFlagIssueEntity
<
LinkedIssueEntity
expose
:relation_path
,
override:
true
do
|
issue
|
project_feature_flag_issue_path
(
issuable
.
project
,
issuable
,
issue
.
link_id
)
end
expose
:link_type
do
|
_issue
|
'relates_to'
end
end
ee/app/serializers/linked_feature_flag_issue_serializer.rb
0 → 100644
View file @
90879740
# frozen_string_literal: true
class
LinkedFeatureFlagIssueSerializer
<
BaseSerializer
entity
LinkedFeatureFlagIssueEntity
end
ee/app/services/feature_flag_issues/list_service.rb
0 → 100644
View file @
90879740
# frozen_string_literal: true
module
FeatureFlagIssues
class
ListService
<
IssuableLinks
::
ListService
extend
::
Gitlab
::
Utils
::
Override
private
def
child_issuables
issuable
.
related_issues
(
current_user
,
preload:
preload_for_collection
)
end
override
:serializer
def
serializer
LinkedFeatureFlagIssueSerializer
end
end
end
ee/config/routes/project.rb
View file @
90879740
...
...
@@ -22,7 +22,9 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do
end
end
resources
:feature_flags
,
param: :iid
resources
:feature_flags
,
param: :iid
do
resources
:feature_flag_issues
,
only:
[
:index
,
:destroy
],
as:
'issues'
,
path:
'issues'
end
resource
:feature_flags_client
,
only:
[]
do
post
:reset_token
end
...
...
ee/spec/controllers/projects/feature_flag_issues_controller_spec.rb
0 → 100644
View file @
90879740
# frozen_string_literal: true
require
'spec_helper'
describe
Projects
::
FeatureFlagIssuesController
do
let_it_be
(
:project
)
{
create
(
:project
)
}
let_it_be
(
:developer
)
{
create
(
:user
)
}
let_it_be
(
:reporter
)
{
create
(
:user
)
}
before_all
do
project
.
add_developer
(
developer
)
project
.
add_reporter
(
reporter
)
end
before
do
stub_licensed_features
(
feature_flags:
true
)
end
describe
'GET #index'
do
def
setup
feature_flag
=
create
(
:operations_feature_flag
,
project:
project
)
issue
=
create
(
:issue
,
project:
project
)
link
=
create
(
:feature_flag_issue
,
feature_flag:
feature_flag
,
issue:
issue
)
[
feature_flag
,
issue
,
link
]
end
def
get_request
(
project
,
feature_flag
)
params
=
{
namespace_id:
project
.
namespace
,
project_id:
project
,
feature_flag_iid:
feature_flag
}
get
:index
,
params:
params
,
format: :json
end
it
'returns linked issues'
do
feature_flag
,
issue
=
setup
sign_in
(
developer
)
get_request
(
project
,
feature_flag
)
expect
(
response
).
to
have_gitlab_http_status
(
:ok
)
expect
(
json_response
).
to
match
([
a_hash_including
({
'id'
=>
issue
.
id
})])
end
it
'does not return linked issues for a reporter'
do
feature_flag
,
_
,
_
=
setup
sign_in
(
reporter
)
get_request
(
project
,
feature_flag
)
expect
(
response
).
to
have_gitlab_http_status
(
:not_found
)
end
it
'orders by feature_flag_issue id'
do
feature_flag
=
create
(
:operations_feature_flag
,
project:
project
)
issue_a
=
create
(
:issue
,
project:
project
)
issue_b
=
create
(
:issue
,
project:
project
)
create
(
:feature_flag_issue
,
feature_flag:
feature_flag
,
issue:
issue_b
)
create
(
:feature_flag_issue
,
feature_flag:
feature_flag
,
issue:
issue_a
)
sign_in
(
developer
)
get_request
(
project
,
feature_flag
)
expect
(
response
).
to
have_gitlab_http_status
(
:ok
)
expect
(
json_response
.
map
{
|
issue
|
issue
[
'id'
]
}).
to
eq
([
issue_b
.
id
,
issue_a
.
id
])
end
it
'returns the correct relation_path when the feature flag is linked to multiple issues'
do
feature_flag
,
issue_a
,
link_a
=
setup
issue_b
=
create
(
:issue
,
project:
project
)
link_b
=
create
(
:feature_flag_issue
,
feature_flag:
feature_flag
,
issue:
issue_b
)
sign_in
(
developer
)
get_request
(
project
,
feature_flag
)
expect
(
response
).
to
have_gitlab_http_status
(
:ok
)
actual
=
json_response
.
sort_by
{
|
issue
|
issue
[
'id'
]
}.
map
{
|
issue
|
issue
.
slice
(
'id'
,
'relation_path'
)
}
expect
(
actual
).
to
eq
([{
'id'
=>
issue_a
.
id
,
'relation_path'
=>
"/
#{
project
.
full_path
}
/-/feature_flags/
#{
feature_flag
.
iid
}
/issues/
#{
link_a
.
id
}
"
},
{
'id'
=>
issue_b
.
id
,
'relation_path'
=>
"/
#{
project
.
full_path
}
/-/feature_flags/
#{
feature_flag
.
iid
}
/issues/
#{
link_b
.
id
}
"
}])
end
it
'returns the correct relation_path when multiple feature flags are linked to an issue'
do
feature_flag_a
,
issue
,
link
=
setup
feature_flag_b
=
create
(
:operations_feature_flag
,
project:
project
)
create
(
:feature_flag_issue
,
feature_flag:
feature_flag_b
,
issue:
issue
)
sign_in
(
developer
)
get_request
(
project
,
feature_flag_a
)
expect
(
response
).
to
have_gitlab_http_status
(
:ok
)
actual
=
json_response
.
map
{
|
issue
|
issue
.
slice
(
'id'
,
'relation_path'
)
}
expect
(
actual
).
to
eq
([{
'id'
=>
issue
.
id
,
'relation_path'
=>
"/
#{
project
.
full_path
}
/-/feature_flags/
#{
feature_flag_a
.
iid
}
/issues/
#{
link
.
id
}
"
}])
end
it
'returns the correct relation_path when there are multiple linked feature flags and issues'
do
feature_flag_a
,
issue_a
,
_
=
setup
feature_flag_b
,
issue_b
,
link_b
=
setup
feature_flag_c
,
issue_c
,
_
=
setup
link_a
=
create
(
:feature_flag_issue
,
feature_flag:
feature_flag_b
,
issue:
issue_a
)
link_c
=
create
(
:feature_flag_issue
,
feature_flag:
feature_flag_b
,
issue:
issue_c
)
create
(
:feature_flag_issue
,
feature_flag:
feature_flag_a
,
issue:
issue_b
)
create
(
:feature_flag_issue
,
feature_flag:
feature_flag_a
,
issue:
issue_c
)
create
(
:feature_flag_issue
,
feature_flag:
feature_flag_c
,
issue:
issue_a
)
create
(
:feature_flag_issue
,
feature_flag:
feature_flag_c
,
issue:
issue_b
)
sign_in
(
developer
)
get_request
(
project
,
feature_flag_b
)
expect
(
response
).
to
have_gitlab_http_status
(
:ok
)
actual
=
json_response
.
sort_by
{
|
issue
|
issue
[
'id'
]
}.
map
{
|
issue
|
issue
.
slice
(
'id'
,
'relation_path'
)
}
expect
(
actual
).
to
eq
([{
'id'
=>
issue_a
.
id
,
'relation_path'
=>
"/
#{
project
.
full_path
}
/-/feature_flags/
#{
feature_flag_b
.
iid
}
/issues/
#{
link_a
.
id
}
"
},
{
'id'
=>
issue_b
.
id
,
'relation_path'
=>
"/
#{
project
.
full_path
}
/-/feature_flags/
#{
feature_flag_b
.
iid
}
/issues/
#{
link_b
.
id
}
"
},
{
'id'
=>
issue_c
.
id
,
'relation_path'
=>
"/
#{
project
.
full_path
}
/-/feature_flags/
#{
feature_flag_b
.
iid
}
/issues/
#{
link_c
.
id
}
"
}])
end
it
'does not make N+1 queries'
do
feature_flag
,
_
,
_
=
setup
sign_in
(
developer
)
control_count
=
ActiveRecord
::
QueryRecorder
.
new
{
get_request
(
project
,
feature_flag
)
}.
count
issue_b
=
create
(
:issue
,
project:
project
)
issue_c
=
create
(
:issue
,
project:
project
)
create
(
:feature_flag_issue
,
feature_flag:
feature_flag
,
issue:
issue_b
)
create
(
:feature_flag_issue
,
feature_flag:
feature_flag
,
issue:
issue_c
)
expect
{
get_request
(
project
,
feature_flag
)
}.
not_to
exceed_query_limit
(
control_count
)
end
it
'returns only issues readable by the user'
do
feature_flag
,
_
,
_
=
setup
issue_b
=
create
(
:issue
,
project:
project
,
author:
developer
)
create
(
:feature_flag_issue
,
feature_flag:
feature_flag
,
issue:
issue_b
)
allow
(
Ability
).
to
receive
(
:issues_readable_by_user
)
do
|
issues
,
user
,
_filters
|
issues
.
where
(
author:
user
)
end
sign_in
(
developer
)
get_request
(
project
,
feature_flag
)
expect
(
response
).
to
have_gitlab_http_status
(
:ok
)
expect
(
json_response
.
map
{
|
issue
|
issue
[
'id'
]
}).
to
eq
([
issue_b
.
id
])
end
it
'returns not found when the feature is off'
do
stub_feature_flags
(
feature_flags_issue_links:
false
)
feature_flag
,
_
,
_
=
setup
sign_in
(
developer
)
get_request
(
project
,
feature_flag
)
expect
(
response
).
to
have_gitlab_http_status
(
:not_found
)
end
context
'when feature flags are unlicensed'
do
before
do
stub_licensed_features
(
feature_flags:
false
)
end
it
'does not return linked issues'
do
feature_flag
,
_
,
_
=
setup
sign_in
(
developer
)
get_request
(
project
,
feature_flag
)
expect
(
response
).
to
have_gitlab_http_status
(
:not_found
)
end
end
end
end
ee/spec/controllers/projects/feature_flags_controller_spec.rb
View file @
90879740
...
...
@@ -48,6 +48,14 @@ RSpec.describe Projects::FeatureFlagsController do
is_expected
.
to
have_gitlab_http_status
(
:not_found
)
end
end
context
'when the user is a reporter'
do
let
(
:user
)
{
reporter
}
it
'responds with not found'
do
is_expected
.
to
have_gitlab_http_status
(
:not_found
)
end
end
end
describe
'GET #index.json'
do
...
...
ee/spec/factories/feature_flag_issue.rb
0 → 100644
View file @
90879740
# frozen_string_literal: true
FactoryBot
.
define
do
factory
:feature_flag_issue
do
feature_flag
factory: :operations_feature_flag
issue
end
end
ee/spec/serializers/linked_feature_flag_issue_entity_spec.rb
0 → 100644
View file @
90879740
# frozen_string_literal: true
require
'spec_helper'
RSpec
.
describe
LinkedFeatureFlagIssueEntity
do
let_it_be
(
:project
)
{
create
(
:project
)
}
let_it_be
(
:developer
)
{
create
(
:user
)
}
before_all
do
project
.
add_developer
(
developer
)
end
describe
'#as_json'
do
it
'returns json'
do
issue
=
create
(
:issue
,
project:
project
)
feature_flag
=
create
(
:operations_feature_flag
,
project:
project
)
link
=
create
(
:feature_flag_issue
,
feature_flag:
feature_flag
,
issue:
issue
)
allow
(
issue
).
to
receive
(
:link_id
).
and_return
(
link
.
id
)
request
=
double
(
'request'
)
allow
(
request
).
to
receive
(
:current_user
).
and_return
(
developer
)
allow
(
request
).
to
receive
(
:issuable
).
and_return
(
feature_flag
)
entity
=
described_class
.
new
(
issue
,
request:
request
,
current_user:
developer
)
expect
(
entity
.
as_json
.
slice
(
:link_type
,
:relation_path
)).
to
eq
({
link_type:
'relates_to'
,
relation_path:
"/
#{
project
.
full_path
}
/-/feature_flags/
#{
feature_flag
.
iid
}
/issues/
#{
link
.
id
}
"
})
end
end
end
spec/lib/gitlab/import_export/all_models.yml
View file @
90879740
...
...
@@ -31,6 +31,8 @@ issues:
-
closed_by
-
epic_issue
-
epic
-
feature_flag_issues
-
feature_flags
-
designs
-
design_versions
-
description_versions
...
...
@@ -569,6 +571,9 @@ self_managed_prometheus_alert_events:
epic_issues
:
-
issue
-
epic
feature_flag_issues
:
-
issue
-
feature_flag
tracing_setting
:
-
project
reviews
:
...
...
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