From 7bb6925b3446aa114ef2ee104313304cc396e3ad Mon Sep 17 00:00:00 2001 From: Akash Srivastava Date: Sun, 27 Jan 2019 21:52:19 +0530 Subject: [PATCH] Feature Flags API --- lib/gitlab/client.rb | 1 + lib/gitlab/client/features.rb | 48 ++++++++++++++++++++++ spec/fixtures/feature.json | 14 +++++++ spec/fixtures/features.json | 22 ++++++++++ spec/gitlab/client/features_spec.rb | 64 +++++++++++++++++++++++++++++ 5 files changed, 149 insertions(+) create mode 100644 lib/gitlab/client/features.rb create mode 100644 spec/fixtures/feature.json create mode 100644 spec/fixtures/features.json create mode 100644 spec/gitlab/client/features_spec.rb diff --git a/lib/gitlab/client.rb b/lib/gitlab/client.rb index a0b52f1f5..df03b4d78 100644 --- a/lib/gitlab/client.rb +++ b/lib/gitlab/client.rb @@ -17,6 +17,7 @@ class Client < API include Deployments include Environments include Events + include Features include GroupMilestones include Groups include Issues diff --git a/lib/gitlab/client/features.rb b/lib/gitlab/client/features.rb new file mode 100644 index 000000000..238d3f8d4 --- /dev/null +++ b/lib/gitlab/client/features.rb @@ -0,0 +1,48 @@ +# frozen_string_literal: true + +class Gitlab::Client + # Defines methods related to feature flags. + # https://docs.gitlab.com/ce/api/features.html + module Features + # Get a list of all persisted features, with its gate values. + # + # @example + # Gitlab.features + # + # @return [Array] + def features + get('/features') + end + + # Set a features gate value. + # If a feature with the given name does not exist yet it will be created. The value can be a boolean, or an integer to indicate percentage of time. + # + # @example + # Gitlab.set_feature('new_library', true) + # Gitlab.set_feature('new_library', 8) + # Gitlab.set_feature('new_library', true, {user: 'gitlab'}) + # + # @param [String] name(required) Name of the feature to create or update + # @param [String, Integer] value(required) true or false to enable/disable, or an integer for percentage of time + # @param [Hash] options A customizable set of options. + # @option options [String] :feature_group(optional) A Feature group name + # @option options [String] :user(optional) A GitLab username + # @option options [String] :project(optional) A projects path, for example "gitlab-org/gitlab-ce" + # @return [Gitlab::ObjectifiedHash] Information about the set/created/updated feature. + def set_feature(name, value, options = {}) + body = { value: value }.merge(options) + post("/features/#{name}", body: body) + end + + # Delete a feature. + # + # @example + # Gitlab.delete_feature('new_library') + # + # @param [String] name Name of the feature to delete + # @return [void] This API call returns an empty response body. + def delete_feature(name) + delete("/features/#{name}") + end + end +end diff --git a/spec/fixtures/feature.json b/spec/fixtures/feature.json new file mode 100644 index 000000000..d9e5b132f --- /dev/null +++ b/spec/fixtures/feature.json @@ -0,0 +1,14 @@ +{ + "name": "new_library", + "state": "conditional", + "gates": [ + { + "key": "boolean", + "value": false + }, + { + "key": "percentage_of_time", + "value": 30 + } + ] +} diff --git a/spec/fixtures/features.json b/spec/fixtures/features.json new file mode 100644 index 000000000..a1a88a080 --- /dev/null +++ b/spec/fixtures/features.json @@ -0,0 +1,22 @@ +[ + { + "name": "experimental_feature", + "state": "off", + "gates": [ + { + "key": "boolean", + "value": false + } + ] + }, + { + "name": "new_library", + "state": "on", + "gates": [ + { + "key": "boolean", + "value": true + } + ] + } +] diff --git a/spec/gitlab/client/features_spec.rb b/spec/gitlab/client/features_spec.rb new file mode 100644 index 000000000..4fec809cb --- /dev/null +++ b/spec/gitlab/client/features_spec.rb @@ -0,0 +1,64 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Gitlab::Client do + describe '.features' do + before do + stub_get('/features', 'features') + @features = Gitlab.features + end + + it 'gets the correct resource' do + expect(a_get('/features')).to have_been_made + end + + it 'returns a paginated response of features' do + expect(@features).to be_a Gitlab::PaginatedResponse + end + end + + describe '.set_feature' do + context 'when setting boolean value' do + before do + stub_post('/features/new_library', 'feature') + @feature = Gitlab.set_feature('new_library', true) + end + + it 'gets the correct resource' do + expect(a_post('/features/new_library') + .with(body: { value: true })).to have_been_made + end + + it 'returns information about the feature' do + expect(@feature).to be_a Gitlab::ObjectifiedHash + end + end + context 'when setting percentage-of-time gate value' do + before do + stub_post('/features/new_library', 'feature') + @feature = Gitlab.set_feature('new_library', 30) + end + + it 'gets the correct resource' do + expect(a_post('/features/new_library') + .with(body: { value: 30 })).to have_been_made + end + + it 'returns information about the feature' do + expect(@feature).to be_a Gitlab::ObjectifiedHash + end + end + end + + describe '.delete_feature' do + before do + stub_delete('/features/new_library', 'empty') + Gitlab.delete_feature('new_library') + end + + it 'gets the correct resource' do + expect(a_delete('/features/new_library')).to have_been_made + end + end +end