Commit 5ff775fd authored by James Lopez's avatar James Lopez

Merge branch 'jej/feature-gates-can-be-set-by-group-path' into 'master'

Allow setting feature flags per GitLab group

See merge request gitlab-org/gitlab-ce!25022
parents 50306121 46f66c7f
---
title: Allow setting feature flags per GitLab group through the API
merge_request: 25022
author:
type: added
...@@ -60,10 +60,11 @@ POST /features/:name ...@@ -60,10 +60,11 @@ POST /features/:name
| `value` | integer/string | yes | `true` or `false` to enable/disable, or an integer for percentage of time | | `value` | integer/string | yes | `true` or `false` to enable/disable, or an integer for percentage of time |
| `feature_group` | string | no | A Feature group name | | `feature_group` | string | no | A Feature group name |
| `user` | string | no | A GitLab username | | `user` | string | no | A GitLab username |
| `group` | string | no | A GitLab group's path, for example 'gitlab-org' |
| `project` | string | no | A projects path, for example 'gitlab-org/gitlab-ce' | | `project` | string | no | A projects path, for example 'gitlab-org/gitlab-ce' |
Note that you can enable or disable a feature for a `feature_group`, a `user`, Note that you can enable or disable a feature for a `feature_group`, a `user`,
and a `project` in a single API call. a `group`, and a `project` in a single API call.
```bash ```bash
curl --data "value=30" --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/features/new_library curl --data "value=30" --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/features/new_library
......
...@@ -42,6 +42,7 @@ module API ...@@ -42,6 +42,7 @@ module API
requires :value, type: String, desc: '`true` or `false` to enable/disable, an integer for percentage of time' requires :value, type: String, desc: '`true` or `false` to enable/disable, an integer for percentage of time'
optional :feature_group, type: String, desc: 'A Feature group name' optional :feature_group, type: String, desc: 'A Feature group name'
optional :user, type: String, desc: 'A GitLab username' optional :user, type: String, desc: 'A GitLab username'
optional :group, type: String, desc: "A GitLab group's path, such as 'gitlab-org'"
optional :project, type: String, desc: 'A projects path, like gitlab-org/gitlab-ce' optional :project, type: String, desc: 'A projects path, like gitlab-org/gitlab-ce'
end end
post ':name' do post ':name' do
......
...@@ -111,11 +111,11 @@ class Feature ...@@ -111,11 +111,11 @@ class Feature
end end
def gate_specified? def gate_specified?
%i(user project feature_group).any? { |key| params.key?(key) } %i(user project group feature_group).any? { |key| params.key?(key) }
end end
def targets def targets
[feature_group, user, project].compact [feature_group, user, project, group].compact
end end
private private
...@@ -139,5 +139,11 @@ class Feature ...@@ -139,5 +139,11 @@ class Feature
Project.find_by_full_path(params[:project]) Project.find_by_full_path(params[:project])
end end
def group
return unless params.key?(:group)
Group.find_by_full_path(params[:group])
end
end end
end end
...@@ -186,13 +186,14 @@ describe Feature do ...@@ -186,13 +186,14 @@ describe Feature do
describe Feature::Target do describe Feature::Target do
describe '#targets' do describe '#targets' do
let(:project) { create(:project) } let(:project) { create(:project) }
let(:group) { create(:group) }
let(:user_name) { project.owner.username } let(:user_name) { project.owner.username }
subject { described_class.new(user: user_name, project: project.full_path) } subject { described_class.new(user: user_name, project: project.full_path, group: group.full_path) }
it 'returns all found targets' do it 'returns all found targets' do
expect(subject.targets).to be_an(Array) expect(subject.targets).to be_an(Array)
expect(subject.targets).to eq([project.owner, project]) expect(subject.targets).to eq([project.owner, project, group])
end end
end end
end end
......
...@@ -163,6 +163,40 @@ describe API::Features do ...@@ -163,6 +163,40 @@ describe API::Features do
end end
end end
context 'when enabling for a group by path' do
context 'when the group exists' do
it 'sets the feature gate' do
group = create(:group)
post api("/features/#{feature_name}", admin), params: { value: 'true', group: group.full_path }
expect(response).to have_gitlab_http_status(201)
expect(json_response).to eq(
'name' => 'my_feature',
'state' => 'conditional',
'gates' => [
{ 'key' => 'boolean', 'value' => false },
{ 'key' => 'actors', 'value' => ["Group:#{group.id}"] }
])
end
end
context 'when the group does not exist' do
it 'sets no new values and keeps the feature disabled' do
post api("/features/#{feature_name}", admin), params: { value: 'true', group: 'not/a/group' }
expect(response).to have_gitlab_http_status(201)
expect(json_response).to eq(
"name" => "my_feature",
"state" => "off",
"gates" => [
{ "key" => "boolean", "value" => false }
]
)
end
end
end
it 'creates a feature with the given percentage if passed an integer' do it 'creates a feature with the given percentage if passed an integer' do
post api("/features/#{feature_name}", admin), params: { value: '50' } post api("/features/#{feature_name}", admin), params: { value: '50' }
......
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