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
02d54ff3
Commit
02d54ff3
authored
Apr 17, 2020
by
Jason Goodman
Committed by
Shinya Maeda
Apr 17, 2020
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add Operations::FeatureFlags::UserList model
Add AtomicInternalId for model
parent
ea0fa636
Changes
15
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
15 changed files
with
739 additions
and
1 deletion
+739
-1
app/models/internal_id_enums.rb
app/models/internal_id_enums.rb
+1
-1
changelogs/unreleased/ff-lists-api.yml
changelogs/unreleased/ff-lists-api.yml
+5
-0
doc/api/api_resources.md
doc/api/api_resources.md
+2
-0
doc/api/feature_flag_user_lists.md
doc/api/feature_flag_user_lists.md
+140
-0
doc/user/project/operations/feature_flags.md
doc/user/project/operations/feature_flags.md
+1
-0
ee/app/models/ee/project.rb
ee/app/models/ee/project.rb
+1
-0
ee/app/models/operations/feature_flags/user_list.rb
ee/app/models/operations/feature_flags/user_list.rb
+44
-0
ee/app/policies/ee/project_policy.rb
ee/app/policies/ee/project_policy.rb
+2
-0
ee/lib/api/feature_flags_user_lists.rb
ee/lib/api/feature_flags_user_lists.rb
+98
-0
ee/lib/ee/api/api.rb
ee/lib/ee/api/api.rb
+1
-0
ee/lib/ee/api/entities/feature_flag/user_list.rb
ee/lib/ee/api/entities/feature_flag/user_list.rb
+19
-0
ee/spec/factories/operations/feature_flags/user_list.rb
ee/spec/factories/operations/feature_flags/user_list.rb
+9
-0
ee/spec/models/operations/feature_flags/user_list_spec.rb
ee/spec/models/operations/feature_flags/user_list_spec.rb
+65
-0
ee/spec/requests/api/feature_flags_user_lists_spec.rb
ee/spec/requests/api/feature_flags_user_lists_spec.rb
+350
-0
spec/lib/gitlab/import_export/all_models.yml
spec/lib/gitlab/import_export/all_models.yml
+1
-0
No files found.
app/models/internal_id_enums.rb
View file @
02d54ff3
...
@@ -3,7 +3,7 @@
...
@@ -3,7 +3,7 @@
module
InternalIdEnums
module
InternalIdEnums
def
self
.
usage_resources
def
self
.
usage_resources
# when adding new resource, make sure it doesn't conflict with EE usage_resources
# when adding new resource, make sure it doesn't conflict with EE usage_resources
{
issues:
0
,
merge_requests:
1
,
deployments:
2
,
milestones:
3
,
epics:
4
,
ci_pipelines:
5
,
operations_feature_flags:
6
}
{
issues:
0
,
merge_requests:
1
,
deployments:
2
,
milestones:
3
,
epics:
4
,
ci_pipelines:
5
,
operations_feature_flags:
6
,
operations_user_lists:
7
}
end
end
end
end
...
...
changelogs/unreleased/ff-lists-api.yml
0 → 100644
View file @
02d54ff3
---
title
:
Add public API for feature flag user lists
merge_request
:
29415
author
:
type
:
added
doc/api/api_resources.md
View file @
02d54ff3
...
@@ -31,6 +31,8 @@ The following API resources are available in the project context:
...
@@ -31,6 +31,8 @@ The following API resources are available in the project context:
|
[
Environments
](
environments.md
)
|
`/projects/:id/environments`
|
|
[
Environments
](
environments.md
)
|
`/projects/:id/environments`
|
|
[
Error Tracking
](
error_tracking.md
)
|
`/projects/:id/error_tracking/settings`
|
|
[
Error Tracking
](
error_tracking.md
)
|
`/projects/:id/error_tracking/settings`
|
|
[
Events
](
events.md
)
|
`/projects/:id/events`
(also available for users and standalone) |
|
[
Events
](
events.md
)
|
`/projects/:id/events`
(also available for users and standalone) |
|
[
Feature Flags
](
feature_flags.md
)
|
`/projects/:id/feature_flags`
|
|
[
Feature Flag User Lists
](
feature_flag_user_lists.md
)
|
`/projects/:id/feature_flags_user_lists`
|
|
[
Issues
](
issues.md
)
|
`/projects/:id/issues`
(also available for groups and standalone) |
|
[
Issues
](
issues.md
)
|
`/projects/:id/issues`
(also available for groups and standalone) |
|
[
Issues Statistics
](
issues_statistics.md
)
|
`/projects/:id/issues_statistics`
(also available for groups and standalone) |
|
[
Issues Statistics
](
issues_statistics.md
)
|
`/projects/:id/issues_statistics`
(also available for groups and standalone) |
|
[
Issue boards
](
boards.md
)
|
`/projects/:id/boards`
|
|
[
Issue boards
](
boards.md
)
|
`/projects/:id/boards`
|
...
...
doc/api/feature_flag_user_lists.md
0 → 100644
View file @
02d54ff3
# Feature Flag User Lists API **(PREMIUM)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/205409) in [GitLab Premium](https://about.gitlab.com/pricing/) 12.10.
API for accessing GitLab Feature Flag User Lists.
Users with Developer or higher
[
permissions
](
../user/permissions.md
)
can access the Feature Flag User Lists API.
NOTE:
**Note:**
`GET`
requests return twenty results at a time because the API results
are
[
paginated
](
README.md#pagination
)
. You can change this value.
## List all feature flag user lists for a project
Gets all feature flag user lists for the requested project.
```
plaintext
GET /projects/:id/feature_flags_user_lists
```
| Attribute | Type | Required | Description |
| ------------------- | ---------------- | ---------- | --------------------------------------------------------------------------------------------------------------------------- |
|
`id`
| integer/string | yes | The ID or
[
URL-encoded path of the project
](
README.md#namespaced-path-encoding
)
. |
```
shell
curl
--header
"PRIVATE-TOKEN: <your_access_token>"
https://gitlab.example.com/api/v4/projects/1/feature_flags_user_lists
```
Example response:
```
json
[
{
"name"
:
"user_list"
,
"user_xids"
:
"user1,user2"
,
"id"
:
1
,
"iid"
:
1
,
"project_id"
:
1
,
"created_at"
:
"2020-02-04T08:13:51.423Z"
,
"updated_at"
:
"2020-02-04T08:13:51.423Z"
},
{
"name"
:
"test_users"
,
"user_xids"
:
"user3,user4,user5"
,
"id"
:
2
,
"iid"
:
2
,
"project_id"
:
1
,
"created_at"
:
"2020-02-04T08:13:10.507Z"
,
"updated_at"
:
"2020-02-04T08:13:10.507Z"
}
]
```
## Create a feature flag user list
Creates a feature flag user list.
```
plaintext
POST /projects/:id/feature_flags_user_lists
```
| Attribute | Type | Required | Description |
| ------------------- | ---------------- | ---------- | ---------------------------------------------------------------------------------------|
|
`id`
| integer/string | yes | The ID or
[
URL-encoded path of the project
](
README.md#namespaced-path-encoding
)
. |
|
`name`
| string | yes | The name of the feature flag. |
|
`user_xids`
| string | yes | A comma separated list of user ids. |
```
shell
curl https://gitlab.example.com/api/v4/projects/1/feature_flags_user_lists
\
--header
"PRIVATE-TOKEN: <your_access_token>"
\
--header
"Content-type: application/json"
\
--data
@-
<<
EOF
{
"name": "my_user_list",
"user_xids": "user1,user2,user3"
}
EOF
```
Example response:
```
json
{
"name"
:
"my_user_list"
,
"user_xids"
:
"user1,user2,user3"
,
"id"
:
1
,
"iid"
:
1
,
"project_id"
:
1
,
"created_at"
:
"2020-02-04T08:32:27.288Z"
,
"updated_at"
:
"2020-02-04T08:32:27.288Z"
}
```
## Get a feature flag user list
Gets a feature flag user list.
```
plaintext
GET /projects/:id/feature_flags_user_lists/:iid
```
| Attribute | Type | Required | Description |
| ------------------- | ---------------- | ---------- | ---------------------------------------------------------------------------------------|
|
`id`
| integer/string | yes | The ID or
[
URL-encoded path of the project
](
README.md#namespaced-path-encoding
)
. |
|
`iid`
| integer/string | yes | The internal ID of the project's feature flag user list. |
```
shell
curl
--header
"PRIVATE-TOKEN: <your_access_token>"
https://gitlab.example.com/api/v4/projects/1/feature_flags_user_lists/1
```
Example response:
```
json
{
"name"
:
"my_user_list"
,
"user_xids"
:
"123,456"
,
"id"
:
1
,
"iid"
:
1
,
"project_id"
:
1
,
"created_at"
:
"2020-02-04T08:13:10.507Z"
,
"updated_at"
:
"2020-02-04T08:13:10.507Z"
,
}
```
## Delete feature flag user list
Deletes a feature flag user list.
```
plaintext
DELETE /projects/:id/feature_flags_user_lists/:iid
```
| Attribute | Type | Required | Description |
| ------------------- | ---------------- | ---------- | ---------------------------------------------------------------------------------------|
|
`id`
| integer/string | yes | The ID or
[
URL-encoded path of the project
](
README.md#namespaced-path-encoding
)
. |
|
`iid`
| integer/string | yes | The internal ID of the project's feature flag user list |
```
shell
curl
--header
"PRIVATE-TOKEN: <your_access_token>"
--request
DELETE https://gitlab.example.com/api/v4/projects/1/feature_flags_user_lists/1
```
doc/user/project/operations/feature_flags.md
View file @
02d54ff3
...
@@ -265,3 +265,4 @@ to control them in an automated flow:
...
@@ -265,3 +265,4 @@ to control them in an automated flow:
-
[
Feature Flags API
](
../../../api/feature_flags.md
)
-
[
Feature Flags API
](
../../../api/feature_flags.md
)
-
[
Feature Flag Specs API
](
../../../api/feature_flag_specs.md
)
-
[
Feature Flag Specs API
](
../../../api/feature_flag_specs.md
)
-
[
Feature Flag User Lists API
](
../../../api/feature_flag_user_lists.md
)
ee/app/models/ee/project.rb
View file @
02d54ff3
...
@@ -85,6 +85,7 @@ module EE
...
@@ -85,6 +85,7 @@ module EE
has_many
:operations_feature_flags
,
class_name:
'Operations::FeatureFlag'
has_many
:operations_feature_flags
,
class_name:
'Operations::FeatureFlag'
has_one
:operations_feature_flags_client
,
class_name:
'Operations::FeatureFlagsClient'
has_one
:operations_feature_flags_client
,
class_name:
'Operations::FeatureFlagsClient'
has_many
:operations_feature_flags_user_lists
,
class_name:
'Operations::FeatureFlags::UserList'
has_many
:project_aliases
has_many
:project_aliases
...
...
ee/app/models/operations/feature_flags/user_list.rb
0 → 100644
View file @
02d54ff3
# frozen_string_literal: true
module
Operations
module
FeatureFlags
class
UserList
<
ApplicationRecord
include
AtomicInternalId
USERXID_MAX_LENGTH
=
256
self
.
table_name
=
'operations_user_lists'
belongs_to
:project
has_internal_id
:iid
,
scope: :project
,
init:
->
(
s
)
{
s
&
.
project
&
.
operations_feature_flags_user_lists
&
.
maximum
(
:iid
)
},
presence:
true
validates
:project
,
presence:
true
validates
:name
,
presence:
true
,
uniqueness:
{
scope: :project_id
},
length:
1
..
255
validate
:user_xids_validation
private
def
user_xids_validation
unless
user_xids
.
is_a?
(
String
)
&&
!
user_xids
.
match
(
/[\n\r\t]|,,/
)
&&
valid_xids?
(
user_xids
.
split
(
","
))
errors
.
add
(
:user_xids
,
"user_xids must be a string of unique comma separated values each
#{
USERXID_MAX_LENGTH
}
characters or less"
)
end
end
def
valid_xids?
(
user_xids
)
user_xids
.
uniq
.
length
==
user_xids
.
length
&&
user_xids
.
all?
{
|
xid
|
valid_xid?
(
xid
)
}
end
def
valid_xid?
(
user_xid
)
user_xid
.
present?
&&
user_xid
.
strip
==
user_xid
&&
user_xid
.
length
<=
USERXID_MAX_LENGTH
end
end
end
end
ee/app/policies/ee/project_policy.rb
View file @
02d54ff3
...
@@ -182,6 +182,7 @@ module EE
...
@@ -182,6 +182,7 @@ module EE
enable
:update_feature_flag
enable
:update_feature_flag
enable
:destroy_feature_flag
enable
:destroy_feature_flag
enable
:admin_feature_flag
enable
:admin_feature_flag
enable
:admin_feature_flags_user_lists
enable
:create_design
enable
:create_design
enable
:destroy_design
enable
:destroy_design
end
end
...
@@ -218,6 +219,7 @@ module EE
...
@@ -218,6 +219,7 @@ module EE
rule
{
feature_flags_disabled
|
repository_disabled
}.
policy
do
rule
{
feature_flags_disabled
|
repository_disabled
}.
policy
do
prevent
(
*
create_read_update_admin_destroy
(
:feature_flag
))
prevent
(
*
create_read_update_admin_destroy
(
:feature_flag
))
prevent
(
:admin_feature_flags_user_lists
)
end
end
rule
{
can?
(
:maintainer_access
)
}.
policy
do
rule
{
can?
(
:maintainer_access
)
}.
policy
do
...
...
ee/lib/api/feature_flags_user_lists.rb
0 → 100644
View file @
02d54ff3
# frozen_string_literal: true
module
API
class
FeatureFlagsUserLists
<
Grape
::
API
include
PaginationParams
error_formatter
:json
,
->
(
message
,
_backtrace
,
_options
,
_env
,
_original_exception
)
{
message
.
is_a?
(
String
)
?
{
message:
message
}.
to_json
:
message
.
to_json
}
before
do
authorize_admin_feature_flags_user_lists!
end
params
do
requires
:id
,
type:
String
,
desc:
'The ID of a project'
end
resource
'projects/:id'
,
requirements:
API
::
NAMESPACE_OR_PROJECT_REQUIREMENTS
do
resource
:feature_flags_user_lists
do
desc
'Get all feature flags user lists of a project'
do
detail
'This feature was introduced in GitLab 12.10'
success
EE
::
API
::
Entities
::
FeatureFlag
::
UserList
end
params
do
use
:pagination
end
get
do
present
paginate
(
user_project
.
operations_feature_flags_user_lists
),
with:
EE
::
API
::
Entities
::
FeatureFlag
::
UserList
end
desc
'Create a feature flags user list for a project'
do
detail
'This feature was introduced in GitLab 12.10'
success
EE
::
API
::
Entities
::
FeatureFlag
::
UserList
end
params
do
requires
:name
,
type:
String
,
desc:
'The name of the list'
requires
:user_xids
,
type:
String
,
desc:
'A comma separated list of external user ids'
end
post
do
list
=
user_project
.
operations_feature_flags_user_lists
.
create
(
declared_params
)
if
list
.
save
present
list
,
with:
EE
::
API
::
Entities
::
FeatureFlag
::
UserList
else
render_api_error!
(
list
.
errors
.
full_messages
,
:bad_request
)
end
end
end
params
do
requires
:iid
,
type:
String
,
desc:
'The internal id of the user list'
end
resource
'feature_flags_user_lists/:iid'
do
desc
'Get a single feature flag user list belonging to a project'
do
detail
'This feature was introduced in GitLab 12.10'
success
EE
::
API
::
Entities
::
FeatureFlag
::
UserList
end
get
do
present
user_project
.
operations_feature_flags_user_lists
.
find_by_iid!
(
params
[
:iid
]),
with:
EE
::
API
::
Entities
::
FeatureFlag
::
UserList
end
desc
'Update a feature flag user list'
do
detail
'This feature was introduced in GitLab 12.10'
success
EE
::
API
::
Entities
::
FeatureFlag
::
UserList
end
params
do
optional
:name
,
type:
String
,
desc:
'The name of the list'
optional
:user_xids
,
type:
String
,
desc:
'A comma separated list of external user ids'
end
put
do
list
=
user_project
.
operations_feature_flags_user_lists
.
find_by_iid!
(
params
[
:iid
])
if
list
.
update
(
declared_params
(
include_missing:
false
))
present
list
,
with:
EE
::
API
::
Entities
::
FeatureFlag
::
UserList
else
render_api_error!
(
list
.
errors
.
full_messages
,
:bad_request
)
end
end
desc
'Delete a feature flag user list'
do
detail
'This feature was introduced in GitLab 12.10'
end
delete
do
list
=
user_project
.
operations_feature_flags_user_lists
.
find_by_iid!
(
params
[
:iid
])
list
.
destroy
end
end
end
helpers
do
def
authorize_admin_feature_flags_user_lists!
authorize!
:admin_feature_flags_user_lists
,
user_project
end
end
end
end
ee/lib/ee/api/api.rb
View file @
02d54ff3
...
@@ -21,6 +21,7 @@ module EE
...
@@ -21,6 +21,7 @@ module EE
mount
::
API
::
Epics
mount
::
API
::
Epics
mount
::
API
::
ElasticsearchIndexedNamespaces
mount
::
API
::
ElasticsearchIndexedNamespaces
mount
::
API
::
FeatureFlags
mount
::
API
::
FeatureFlags
mount
::
API
::
FeatureFlagsUserLists
mount
::
API
::
FeatureFlagScopes
mount
::
API
::
FeatureFlagScopes
mount
::
API
::
Geo
mount
::
API
::
Geo
mount
::
API
::
GeoReplication
mount
::
API
::
GeoReplication
...
...
ee/lib/ee/api/entities/feature_flag/user_list.rb
0 → 100644
View file @
02d54ff3
# frozen_string_literal: true
module
EE
module
API
module
Entities
class
FeatureFlag
<
Grape
::
Entity
class
UserList
<
Grape
::
Entity
expose
:id
expose
:iid
expose
:project_id
expose
:created_at
expose
:updated_at
expose
:name
expose
:user_xids
end
end
end
end
end
ee/spec/factories/operations/feature_flags/user_list.rb
0 → 100644
View file @
02d54ff3
# frozen_string_literal: true
FactoryBot
.
define
do
factory
:operations_feature_flag_user_list
,
class:
'Operations::FeatureFlags::UserList'
do
association
:project
,
factory: :project
name
{
'My User List'
}
user_xids
{
'user1,user2,user3'
}
end
end
ee/spec/models/operations/feature_flags/user_list_spec.rb
0 → 100644
View file @
02d54ff3
# frozen_string_literal: true
require
'spec_helper'
describe
Operations
::
FeatureFlags
::
UserList
do
subject
{
create
(
:operations_feature_flag_user_list
)
}
describe
'validations'
do
it
{
is_expected
.
to
validate_presence_of
(
:project
)
}
it
{
is_expected
.
to
validate_presence_of
(
:name
)
}
it
{
is_expected
.
to
validate_uniqueness_of
(
:name
).
scoped_to
(
:project_id
)
}
it
{
is_expected
.
to
validate_length_of
(
:name
).
is_at_least
(
1
).
is_at_most
(
255
)
}
describe
'user_xids'
do
where
(
:valid_value
)
do
[
""
,
"sam"
,
"1"
,
"a"
,
"uuid-of-some-kind"
,
"sam,fred,tom,jane,joe,mike"
,
"gitlab@example.com"
,
"123,4"
,
"UPPER,Case,charActeRS"
,
"0"
,
"$valid$email#2345#$%..{}+=-)?
\\
/@example.com"
,
"spaces allowed"
,
"a"
*
256
,
"a,
#{
'b'
*
256
}
,ccc"
,
"many spaces"
]
end
with_them
do
it
'is valid with a string of comma separated values'
do
user_list
=
described_class
.
create
(
user_xids:
valid_value
)
expect
(
user_list
.
errors
[
:user_xids
]).
to
be_empty
end
end
where
(
:typecast_value
)
do
[
1
,
2.5
,
{},
[]]
end
with_them
do
it
'automatically casts values of other types'
do
user_list
=
described_class
.
create
(
user_xids:
typecast_value
)
expect
(
user_list
.
errors
[
:user_xids
]).
to
be_empty
expect
(
user_list
.
user_xids
).
to
eq
(
typecast_value
.
to_s
)
end
end
where
(
:invalid_value
)
do
[
nil
,
"123
\n
456"
,
"1,2,3,12
\t
3"
,
"
\n
"
,
"
\n\r
"
,
"joe
\r
,sam"
,
"1,2,2"
,
"1,,2"
,
"1,2,,,,"
,
"b"
*
257
,
"1, ,2"
,
"tim, ,7"
,
" "
,
" "
,
" ,1"
,
"1, "
,
" leading,1"
,
"1,trailing "
,
"1, both ,2"
]
end
with_them
do
it
'is invalid'
do
user_list
=
described_class
.
create
(
user_xids:
invalid_value
)
expect
(
user_list
.
errors
[
:user_xids
]).
to
include
(
'user_xids must be a string of unique comma separated values each 256 characters or less'
)
end
end
end
end
it_behaves_like
'AtomicInternalId'
do
let
(
:internal_id_attribute
)
{
:iid
}
let
(
:instance
)
{
build
(
:operations_feature_flag_user_list
)
}
let
(
:scope
)
{
:project
}
let
(
:scope_attrs
)
{
{
project:
instance
.
project
}
}
let
(
:usage
)
{
:operations_user_lists
}
end
end
ee/spec/requests/api/feature_flags_user_lists_spec.rb
0 → 100644
View file @
02d54ff3
This diff is collapsed.
Click to expand it.
spec/lib/gitlab/import_export/all_models.yml
View file @
02d54ff3
...
@@ -443,6 +443,7 @@ project:
...
@@ -443,6 +443,7 @@ project:
-
vulnerability_scanners
-
vulnerability_scanners
-
operations_feature_flags
-
operations_feature_flags
-
operations_feature_flags_client
-
operations_feature_flags_client
-
operations_feature_flags_user_lists
-
prometheus_alerts
-
prometheus_alerts
-
prometheus_alert_events
-
prometheus_alert_events
-
self_managed_prometheus_alert_events
-
self_managed_prometheus_alert_events
...
...
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