Commit 31974a55 authored by Doug Stull's avatar Doug Stull Committed by Alper Akgun

Implement experiments endpoint for experiment statuses

- for exposure through api.
parent a525107c
---
stage: Growth
group: Expansion
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#designated-technical-writers
---
# Experiments API
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/262725) in GitLab 13.5.
This API is for listing Experiments [experiment use in development of GitLab](../development/experiment_guide/index.md).
All methods require user be a [GitLab team member](https://gitlab.com/groups/gitlab-com/-/group_members) for authorization.
## List all experiments
Get a list of all experiments, with its enabled status.
```plaintext
GET /experiments
```
```shell
curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/experiments"
```
Example response:
```json
[
{
"key": "experiment_1",
"enabled": true
},
{
"key": "experiment_2",
"enabled": false
}
]
```
...@@ -333,11 +333,13 @@ module EE ...@@ -333,11 +333,13 @@ module EE
def gitlab_employee? def gitlab_employee?
strong_memoize(:gitlab_employee) do strong_memoize(:gitlab_employee) do
if ::Gitlab.com? && ::Feature.enabled?(:gitlab_employee_badge) ::Gitlab.com? && ::Feature.enabled?(:gitlab_employee_badge) && gitlab_team_member?
human? && ::Gitlab::Com.gitlab_com_group_member_id?(id) end
else end
false
end def gitlab_team_member?
strong_memoize(:gitlab_team_member) do
::Gitlab::Com.gitlab_com_group_member?(id) && human?
end end
end end
......
---
title: API endpoint to return defined experiments
merge_request: 44498
author:
type: added
# frozen_string_literal: true
module API
class Experiments < ::API::Base
before { authorize_read_experiments! }
resource :experiments do
desc 'Get a list of all experiments' do
success EE::API::Entities::Experiment
end
get do
experiments = Gitlab::Experimentation::EXPERIMENTS.keys.map do |experiment_key|
{ key: experiment_key, enabled: Gitlab::Experimentation.enabled?(experiment_key) }
end
present experiments, with: EE::API::Entities::Experiment, current_user: current_user
end
end
helpers do
def authorize_read_experiments!
authenticate!
forbidden! unless current_user.gitlab_team_member?
end
end
end
end
...@@ -19,6 +19,7 @@ module EE ...@@ -19,6 +19,7 @@ module EE
mount ::API::EpicLinks mount ::API::EpicLinks
mount ::API::Epics mount ::API::Epics
mount ::API::ElasticsearchIndexedNamespaces mount ::API::ElasticsearchIndexedNamespaces
mount ::API::Experiments
mount ::API::Geo mount ::API::Geo
mount ::API::GeoReplication mount ::API::GeoReplication
mount ::API::GeoNodes mount ::API::GeoNodes
......
# frozen_string_literal: true
module EE
module API
module Entities
class Experiment < Grape::Entity
expose :key
expose :enabled
end
end
end
end
...@@ -8,9 +8,13 @@ module Gitlab ...@@ -8,9 +8,13 @@ module Gitlab
GITLAB_COM_GROUP = 'gitlab-com' GITLAB_COM_GROUP = 'gitlab-com'
def self.gitlab_com_group_member_id?(user_id = nil) def self.gitlab_com_group_member_id?(user_id = nil)
return false unless Gitlab.com? && user_id && ::Feature.enabled?(:gitlab_employee_badge) ::Feature.enabled?(:gitlab_employee_badge) && gitlab_com_group_member?(user_id)
end
def self.gitlab_com_group_member?(user_id)
return false unless user_id
gitlab_com_user_ids.include?(user_id) Gitlab.dev_env_or_com? && gitlab_com_user_ids.include?(user_id)
end end
# rubocop: disable CodeReuse/ActiveRecord # rubocop: disable CodeReuse/ActiveRecord
......
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe EE::API::Entities::Experiment do
describe '#as_json' do
let(:experiment) { { key: 'experiment_1', enabled: true } }
let(:entity) { described_class.new(experiment) }
subject { entity.as_json }
it { is_expected.to match({ key: experiment[:key], enabled: experiment[:enabled] }) }
end
end
...@@ -6,7 +6,7 @@ RSpec.describe Gitlab::Com do ...@@ -6,7 +6,7 @@ RSpec.describe Gitlab::Com do
it { expect(described_class.l1_cache_backend).to eq(Gitlab::ProcessMemoryCache.cache_backend) } it { expect(described_class.l1_cache_backend).to eq(Gitlab::ProcessMemoryCache.cache_backend) }
it { expect(described_class.l2_cache_backend).to eq(Rails.cache) } it { expect(described_class.l2_cache_backend).to eq(Rails.cache) }
describe '.gitlab_team_member?' do describe '.gitlab_com_group_member_id?' do
subject { described_class.gitlab_com_group_member_id?(user&.id) } subject { described_class.gitlab_com_group_member_id?(user&.id) }
let(:user) { create(:user) } let(:user) { create(:user) }
......
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe API::Experiments do
let_it_be(:user) { create(:user) }
let_it_be(:group) { create(:group, name: 'gitlab-com') }
describe 'GET /experiments' do
context 'when on .com' do
let(:experiments) do
{
experiment_1: {
tracking_category: 'something',
environment: true
},
experiment_2: {
tracking_category: 'something_else'
}
}
end
before do
stub_const('Gitlab::Experimentation::EXPERIMENTS', experiments)
Feature.enable_percentage_of_time('experiment_1_experiment_percentage', 10)
Feature.disable('experiment_2_experiment_percentage')
allow(Gitlab).to receive(:com?).and_return(true)
end
it 'returns a 401 for anonymous users' do
get api('/experiments')
expect(response).to have_gitlab_http_status(:unauthorized)
end
it 'returns a 403 for users' do
get api('/experiments', user)
expect(response).to have_gitlab_http_status(:forbidden)
end
it 'returns a 403 for non human users' do
bot = create(:user, :bot)
group.add_developer(bot)
get api('/experiments', bot)
expect(response).to have_gitlab_http_status(:forbidden)
end
it 'returns the feature list for gitlab team members' do
expected_experiments = [
{
'key' => 'experiment_1',
'enabled' => true
},
{
'key' => 'experiment_2',
'enabled' => false
}
]
group.add_developer(user)
get api('/experiments', user)
expect(response).to have_gitlab_http_status(:ok)
expect(json_response).to match_array(expected_experiments)
end
end
context 'when not .com' do
before do
allow(Gitlab).to receive(:com?).and_return(false)
end
it 'returns a 403 for users' do
group.add_developer(user)
get api('/experiments', user)
expect(response).to have_gitlab_http_status(:forbidden)
end
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