Commit 1a6dd64e authored by Fabio Pitino's avatar Fabio Pitino Committed by Shinya Maeda

Allow setting feature flag for a single namespace

The `group` actor could only support Group models. With this
change it can also support `UserNamespace` types and allow
the feature flag to be set for a specific namespace.

Changelog: changed
parent 0cd5c848
......@@ -245,11 +245,11 @@ class Feature
end
def gate_specified?
%i(user project group feature_group).any? { |key| params.key?(key) }
%i(user project group feature_group namespace).any? { |key| params.key?(key) }
end
def targets
[feature_group, user, project, group].compact
[feature_group, user, project, group, namespace].compact
end
private
......@@ -279,6 +279,13 @@ class Feature
Group.find_by_full_path(params[:group])
end
def namespace
return unless params.key?(:namespace)
# We are interested in Group or UserNamespace
Namespace.without_project_namespaces.find_by_full_path(params[:namespace])
end
end
end
......
......@@ -167,29 +167,9 @@ RSpec.describe API::Features, stub_feature_flags: false do
end
end
context 'when enabling for a project by path' do
context 'when the project exists' do
let!(:project) { create(:project) }
it 'sets the feature gate' do
post api("/features/#{feature_name}", admin), params: { value: 'true', project: project.full_path }
expect(response).to have_gitlab_http_status(:created)
expect(json_response).to match(
'name' => feature_name,
'state' => 'conditional',
'gates' => [
{ 'key' => 'boolean', 'value' => false },
{ 'key' => 'actors', 'value' => ["Project:#{project.id}"] }
],
'definition' => known_feature_flag_definition_hash
)
end
end
context 'when the project does not exist' do
it 'sets no new values' do
post api("/features/#{feature_name}", admin), params: { value: 'true', project: 'mep/to/the/mep/mep' }
shared_examples 'does not enable the flag' do |actor_type, actor_path|
it 'returns the current state of the flag without changes' do
post api("/features/#{feature_name}", admin), params: { value: 'true', actor_type => actor_path }
expect(response).to have_gitlab_http_status(:created)
expect(json_response).to match(
......@@ -202,14 +182,10 @@ RSpec.describe API::Features, stub_feature_flags: false do
)
end
end
end
context 'when enabling for a group by path' do
context 'when the group exists' do
shared_examples 'enables the flag for the actor' do |actor_type|
it 'sets the feature gate' do
group = create(:group)
post api("/features/#{feature_name}", admin), params: { value: 'true', group: group.full_path }
post api("/features/#{feature_name}", admin), params: { value: 'true', actor_type => actor.full_path }
expect(response).to have_gitlab_http_status(:created)
expect(json_response).to match(
......@@ -217,26 +193,59 @@ RSpec.describe API::Features, stub_feature_flags: false do
'state' => 'conditional',
'gates' => [
{ 'key' => 'boolean', 'value' => false },
{ 'key' => 'actors', 'value' => ["Group:#{group.id}"] }
{ 'key' => 'actors', 'value' => ["#{actor.class}:#{actor.id}"] }
],
'definition' => known_feature_flag_definition_hash
)
end
end
context 'when enabling for a project by path' do
context 'when the project exists' do
it_behaves_like 'enables the flag for the actor', :project do
let(:actor) { create(:project) }
end
end
context 'when the project does not exist' do
it_behaves_like 'does not enable the flag', :project, 'mep/to/the/mep/mep'
end
end
context 'when enabling for a group by path' do
context 'when the group exists' do
it_behaves_like 'enables the flag for the actor', :group do
let(:actor) { create(:group) }
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' }
it_behaves_like 'does not enable the flag', :group, 'not/a/group'
end
end
expect(response).to have_gitlab_http_status(:created)
expect(json_response).to match(
"name" => feature_name,
"state" => "off",
"gates" => [
{ "key" => "boolean", "value" => false }
],
'definition' => known_feature_flag_definition_hash
)
context 'when enabling for a namespace by path' do
context 'when the user namespace exists' do
it_behaves_like 'enables the flag for the actor', :namespace do
let(:actor) { create(:namespace) }
end
end
context 'when the group namespace exists' do
it_behaves_like 'enables the flag for the actor', :namespace do
let(:actor) { create(:group) }
end
end
context 'when the user namespace does not exist' do
it_behaves_like 'does not enable the flag', :namespace, 'not/a/group'
end
context 'when a project namespace exists' do
let(:project_namespace) { create(:project_namespace) }
it_behaves_like 'does not enable the flag', :namespace do
let(:actor_path) { project_namespace.full_path }
end
end
end
......
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