flipper-api 0.26.2 → 0.27.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/flipper/api/error_response.rb +2 -2
- data/lib/flipper/api/middleware.rb +1 -0
- data/lib/flipper/api/v1/actions/features.rb +6 -1
- data/lib/flipper/api/v1/actions/import.rb +25 -0
- data/lib/flipper/api/v1/decorators/feature.rb +2 -2
- data/lib/flipper/api/v1/decorators/gate.rb +4 -3
- data/lib/flipper/version.rb +1 -1
- data/spec/flipper/api/v1/actions/features_spec.rb +25 -3
- data/spec/flipper/api/v1/actions/groups_gate_spec.rb +6 -6
- data/spec/flipper/api/v1/actions/import_spec.rb +69 -0
- data/spec/flipper/api/v1/actions/percentage_of_actors_gate_spec.rb +4 -4
- data/spec/flipper/api/v1/actions/percentage_of_time_gate_spec.rb +4 -4
- metadata +7 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e6dcd6ea7ccf9b891553566c5b845688204c4c2a2add0a9607f9d6d35f599359
|
4
|
+
data.tar.gz: 7329555251cb9b5c5ada93ec6aa5224eb6dbf0a0a27707f9d361e7c5154fd9ab
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0bc38a19b342daf3b31ca168cc08304230e83d468d5acf6658815661c002c94ad7bac947c6f9740d13c604c855c7982a1436382a9fc5fad0d04c9ab65779701b
|
7
|
+
data.tar.gz: 2cd588a44240ca5d8129d21f08d26593cb35039b3e46dd685cbbb97dff92b19340927e7d805bdc49423fbcd1c5cfa796af824fb2033f915a515987c37741190e
|
@@ -24,10 +24,10 @@ module Flipper
|
|
24
24
|
ERRORS = {
|
25
25
|
feature_not_found: Error.new(1, 'Feature not found.', 404),
|
26
26
|
group_not_registered: Error.new(2, 'Group not registered.', 404),
|
27
|
-
percentage_invalid:
|
28
|
-
Error.new(3, 'Percentage must be a positive number less than or equal to 100.', 422),
|
27
|
+
percentage_invalid: Error.new(3, 'Percentage must be a positive number less than or equal to 100.', 422),
|
29
28
|
flipper_id_invalid: Error.new(4, 'Required parameter flipper_id is missing.', 422),
|
30
29
|
name_invalid: Error.new(5, 'Required parameter name is missing.', 422),
|
30
|
+
import_invalid: Error.new(6, 'Import invalid.', 422),
|
31
31
|
}.freeze
|
32
32
|
end
|
33
33
|
end
|
@@ -11,6 +11,8 @@ module Flipper
|
|
11
11
|
def get
|
12
12
|
keys = params['keys']
|
13
13
|
exclude_gates = params['exclude_gates']&.downcase == "true"
|
14
|
+
exclude_gate_names = params['exclude_gate_names']&.downcase == "true"
|
15
|
+
|
14
16
|
features = if keys
|
15
17
|
names = keys.split(',')
|
16
18
|
if names.empty?
|
@@ -27,7 +29,10 @@ module Flipper
|
|
27
29
|
end
|
28
30
|
|
29
31
|
decorated_features = features.map do |feature|
|
30
|
-
Decorators::Feature.new(feature).as_json(
|
32
|
+
Decorators::Feature.new(feature).as_json(
|
33
|
+
exclude_gates: exclude_gates,
|
34
|
+
exclude_gate_names: exclude_gate_names
|
35
|
+
)
|
31
36
|
end
|
32
37
|
|
33
38
|
json_response(features: decorated_features)
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'flipper/exporters/json/export'
|
2
|
+
require 'flipper/api/action'
|
3
|
+
require 'flipper/api/v1/decorators/feature'
|
4
|
+
|
5
|
+
module Flipper
|
6
|
+
module Api
|
7
|
+
module V1
|
8
|
+
module Actions
|
9
|
+
class Import < Api::Action
|
10
|
+
route %r{\A/import/?\Z}
|
11
|
+
|
12
|
+
def post
|
13
|
+
body = request.body.read
|
14
|
+
request.body.rewind
|
15
|
+
export = Flipper::Exporters::Json::Export.new(contents: body)
|
16
|
+
flipper.import(export)
|
17
|
+
json_response({}, 204)
|
18
|
+
rescue Flipper::Exporters::Json::InvalidError
|
19
|
+
json_error_response(:import_invalid)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -10,7 +10,7 @@ module Flipper
|
|
10
10
|
alias_method :feature, :__getobj__
|
11
11
|
|
12
12
|
# Public: Returns instance as hash that is ready to be json dumped.
|
13
|
-
def as_json(exclude_gates: false)
|
13
|
+
def as_json(exclude_gates: false, exclude_gate_names: false)
|
14
14
|
result = {
|
15
15
|
'key' => key,
|
16
16
|
'state' => state.to_s,
|
@@ -19,7 +19,7 @@ module Flipper
|
|
19
19
|
unless exclude_gates
|
20
20
|
gate_values = feature.adapter.get(self)
|
21
21
|
result['gates'] = gates.map do |gate|
|
22
|
-
Decorators::Gate.new(gate, gate_values[gate.key]).as_json
|
22
|
+
Decorators::Gate.new(gate, gate_values[gate.key]).as_json(exclude_name: exclude_gate_names)
|
23
23
|
end
|
24
24
|
end
|
25
25
|
|
@@ -14,12 +14,13 @@ module Flipper
|
|
14
14
|
@value = value
|
15
15
|
end
|
16
16
|
|
17
|
-
def as_json
|
18
|
-
{
|
17
|
+
def as_json(exclude_name: false)
|
18
|
+
as_json = {
|
19
19
|
'key' => gate.key.to_s,
|
20
|
-
'name' => gate.name.to_s,
|
21
20
|
'value' => value_as_json,
|
22
21
|
}
|
22
|
+
as_json['name'] = gate.name.to_s unless exclude_name
|
23
|
+
as_json
|
23
24
|
end
|
24
25
|
|
25
26
|
private
|
data/lib/flipper/version.rb
CHANGED
@@ -8,10 +8,11 @@ RSpec.describe Flipper::Api::V1::Actions::Features do
|
|
8
8
|
before do
|
9
9
|
flipper[:my_feature].enable
|
10
10
|
flipper[:my_feature].enable(admin)
|
11
|
-
get '/features'
|
12
11
|
end
|
13
12
|
|
14
13
|
it 'responds with correct attributes' do
|
14
|
+
get '/features'
|
15
|
+
|
15
16
|
expected_response = {
|
16
17
|
'features' => [
|
17
18
|
{
|
@@ -50,6 +51,28 @@ RSpec.describe Flipper::Api::V1::Actions::Features do
|
|
50
51
|
expect(last_response.status).to eq(200)
|
51
52
|
expect(json_response).to eq(expected_response)
|
52
53
|
end
|
54
|
+
|
55
|
+
it 'responds without names when instructed by param' do
|
56
|
+
expected_response = {
|
57
|
+
'features' => [
|
58
|
+
{
|
59
|
+
'key' => 'my_feature',
|
60
|
+
'state' => 'on',
|
61
|
+
'gates' => [
|
62
|
+
{ 'key' => 'boolean', 'value' => 'true'},
|
63
|
+
{ 'key' => 'actors', 'value' => ['10']},
|
64
|
+
{'key' => 'percentage_of_actors', 'value' => nil},
|
65
|
+
{ 'key' => 'percentage_of_time', 'value' => nil},
|
66
|
+
{ 'key' => 'groups', 'value' => []},
|
67
|
+
],
|
68
|
+
},
|
69
|
+
],
|
70
|
+
}
|
71
|
+
|
72
|
+
get '/features', 'exclude_gate_names' => 'true'
|
73
|
+
expect(last_response.status).to eq(200)
|
74
|
+
expect(json_response).to eq(expected_response)
|
75
|
+
end
|
53
76
|
end
|
54
77
|
|
55
78
|
context 'with keys specified' do
|
@@ -103,13 +126,12 @@ RSpec.describe Flipper::Api::V1::Actions::Features do
|
|
103
126
|
post '/features', name: 'my_feature'
|
104
127
|
end
|
105
128
|
|
106
|
-
it 'responds 200
|
129
|
+
it 'responds 200' do
|
107
130
|
expect(last_response.status).to eq(200)
|
108
131
|
end
|
109
132
|
|
110
133
|
it 'returns decorated feature' do
|
111
134
|
expected_response = {
|
112
|
-
|
113
135
|
'key' => 'my_feature',
|
114
136
|
'state' => 'off',
|
115
137
|
'gates' => [
|
@@ -19,7 +19,7 @@ RSpec.describe Flipper::Api::V1::Actions::GroupsGate do
|
|
19
19
|
end
|
20
20
|
|
21
21
|
it 'returns decorated feature with group enabled' do
|
22
|
-
group_gate = json_response['gates'].find { |m| m['
|
22
|
+
group_gate = json_response['gates'].find { |m| m['key'] == 'groups' }
|
23
23
|
expect(group_gate['value']).to eq(['admins'])
|
24
24
|
end
|
25
25
|
end
|
@@ -42,7 +42,7 @@ RSpec.describe Flipper::Api::V1::Actions::GroupsGate do
|
|
42
42
|
end
|
43
43
|
|
44
44
|
it 'returns decorated feature with group enabled' do
|
45
|
-
group_gate = json_response['gates'].find { |m| m['
|
45
|
+
group_gate = json_response['gates'].find { |m| m['key'] == 'groups' }
|
46
46
|
expect(group_gate['value']).to eq(['admins'])
|
47
47
|
end
|
48
48
|
end
|
@@ -89,7 +89,7 @@ RSpec.describe Flipper::Api::V1::Actions::GroupsGate do
|
|
89
89
|
end
|
90
90
|
|
91
91
|
it 'returns decorated feature with group disabled' do
|
92
|
-
group_gate = json_response['gates'].find { |m| m['
|
92
|
+
group_gate = json_response['gates'].find { |m| m['key'] == 'groups' }
|
93
93
|
expect(group_gate['value']).to eq([])
|
94
94
|
end
|
95
95
|
end
|
@@ -111,7 +111,7 @@ RSpec.describe Flipper::Api::V1::Actions::GroupsGate do
|
|
111
111
|
end
|
112
112
|
|
113
113
|
it 'returns decorated feature with group disabled' do
|
114
|
-
group_gate = json_response['gates'].find { |m| m['
|
114
|
+
group_gate = json_response['gates'].find { |m| m['key'] == 'groups' }
|
115
115
|
expect(group_gate['value']).to eq([])
|
116
116
|
end
|
117
117
|
end
|
@@ -145,7 +145,7 @@ RSpec.describe Flipper::Api::V1::Actions::GroupsGate do
|
|
145
145
|
end
|
146
146
|
|
147
147
|
it 'returns decorated feature with group in groups set' do
|
148
|
-
group_gate = json_response['gates'].find { |m| m['
|
148
|
+
group_gate = json_response['gates'].find { |m| m['key'] == 'groups' }
|
149
149
|
expect(group_gate['value']).to eq(['admins'])
|
150
150
|
end
|
151
151
|
|
@@ -167,7 +167,7 @@ RSpec.describe Flipper::Api::V1::Actions::GroupsGate do
|
|
167
167
|
end
|
168
168
|
|
169
169
|
it 'returns decorated feature with group not in groups set' do
|
170
|
-
group_gate = json_response['gates'].find { |m| m['
|
170
|
+
group_gate = json_response['gates'].find { |m| m['key'] == 'groups' }
|
171
171
|
expect(group_gate['value']).to eq([])
|
172
172
|
end
|
173
173
|
|
@@ -0,0 +1,69 @@
|
|
1
|
+
RSpec.describe Flipper::Api::V1::Actions::Import do
|
2
|
+
let(:app) { build_api(flipper) }
|
3
|
+
|
4
|
+
describe 'post' do
|
5
|
+
context 'succesful request' do
|
6
|
+
before do
|
7
|
+
flipper.enable(:search)
|
8
|
+
flipper.disable(:adios)
|
9
|
+
|
10
|
+
source_flipper = build_flipper
|
11
|
+
source_flipper.disable(:search)
|
12
|
+
source_flipper.enable_actor(:google_analytics, Flipper::Actor.new("User;1"))
|
13
|
+
|
14
|
+
export = source_flipper.export
|
15
|
+
|
16
|
+
post '/import', export.contents, 'CONTENT_TYPE' => 'application/json'
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'responds 204' do
|
20
|
+
expect(last_response.status).to eq(204)
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'imports features' do
|
24
|
+
expect(flipper[:search].boolean_value).to be(false)
|
25
|
+
expect(flipper[:google_analytics].actors_value).to eq(Set["User;1"])
|
26
|
+
expect(flipper.features.map(&:key)).to eq(["search", "google_analytics"])
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
context 'empty request' do
|
31
|
+
before do
|
32
|
+
flipper.enable(:search)
|
33
|
+
flipper.disable(:adios)
|
34
|
+
|
35
|
+
source_flipper = build_flipper
|
36
|
+
export = source_flipper.export
|
37
|
+
|
38
|
+
post '/import', export.contents, 'CONTENT_TYPE' => 'application/json'
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'responds 204' do
|
42
|
+
expect(last_response.status).to eq(204)
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'removes all features' do
|
46
|
+
expect(flipper.features.map(&:key)).to eq([])
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
context 'bad request' do
|
51
|
+
before do
|
52
|
+
post '/import'
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'returns correct status code' do
|
56
|
+
expect(last_response.status).to eq(422)
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'returns formatted error' do
|
60
|
+
expected = {
|
61
|
+
'code' => 6,
|
62
|
+
'message' => 'Import invalid.',
|
63
|
+
'more_info' => api_error_code_reference_url,
|
64
|
+
}
|
65
|
+
expect(json_response).to eq(expected)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -8,7 +8,7 @@ RSpec.describe Flipper::Api::V1::Actions::PercentageOfActorsGate do
|
|
8
8
|
end
|
9
9
|
|
10
10
|
it 'returns decorated feature with gate enabled for a percent of actors' do
|
11
|
-
gate = json_response['gates'].find { |gate| gate['
|
11
|
+
gate = json_response['gates'].find { |gate| gate['key'] == 'percentage_of_actors' }
|
12
12
|
expect(gate['value']).to eq(percentage)
|
13
13
|
end
|
14
14
|
end
|
@@ -90,7 +90,7 @@ RSpec.describe Flipper::Api::V1::Actions::PercentageOfActorsGate do
|
|
90
90
|
end
|
91
91
|
|
92
92
|
it 'returns decorated feature with gate disabled' do
|
93
|
-
gate = json_response['gates'].find { |gate| gate['
|
93
|
+
gate = json_response['gates'].find { |gate| gate['key'] == 'percentage_of_actors' }
|
94
94
|
expect(gate['value']).to eq('0')
|
95
95
|
end
|
96
96
|
end
|
@@ -104,7 +104,7 @@ RSpec.describe Flipper::Api::V1::Actions::PercentageOfActorsGate do
|
|
104
104
|
end
|
105
105
|
|
106
106
|
it 'returns decorated feature with gate value set to 0 regardless of percentage requested' do
|
107
|
-
gate = json_response['gates'].find { |gate| gate['
|
107
|
+
gate = json_response['gates'].find { |gate| gate['key'] == 'percentage_of_actors' }
|
108
108
|
expect(gate['value']).to eq('0')
|
109
109
|
end
|
110
110
|
end
|
@@ -120,7 +120,7 @@ RSpec.describe Flipper::Api::V1::Actions::PercentageOfActorsGate do
|
|
120
120
|
|
121
121
|
it 'returns decorated feature with gate disabled' do
|
122
122
|
expect(last_response.status).to eq(200)
|
123
|
-
gate = json_response['gates'].find { |gate| gate['
|
123
|
+
gate = json_response['gates'].find { |gate| gate['key'] == 'percentage_of_actors' }
|
124
124
|
expect(gate['value']).to eq('0')
|
125
125
|
end
|
126
126
|
end
|
@@ -8,7 +8,7 @@ RSpec.describe Flipper::Api::V1::Actions::PercentageOfTimeGate do
|
|
8
8
|
end
|
9
9
|
|
10
10
|
it 'returns decorated feature with gate enabled for a percent of times' do
|
11
|
-
gate = json_response['gates'].find { |gate| gate['
|
11
|
+
gate = json_response['gates'].find { |gate| gate['key'] == 'percentage_of_time' }
|
12
12
|
expect(gate['value']).to eq(percentage)
|
13
13
|
end
|
14
14
|
end
|
@@ -90,7 +90,7 @@ RSpec.describe Flipper::Api::V1::Actions::PercentageOfTimeGate do
|
|
90
90
|
end
|
91
91
|
|
92
92
|
it 'returns decorated feature with gate disabled' do
|
93
|
-
gate = json_response['gates'].find { |gate| gate['
|
93
|
+
gate = json_response['gates'].find { |gate| gate['key'] == 'percentage_of_time' }
|
94
94
|
expect(gate['value']).to eq('0')
|
95
95
|
end
|
96
96
|
end
|
@@ -105,7 +105,7 @@ RSpec.describe Flipper::Api::V1::Actions::PercentageOfTimeGate do
|
|
105
105
|
|
106
106
|
it 'returns decorated feature with gate value set to 0 regardless of percentage requested' do
|
107
107
|
expect(last_response.status).to eq(200)
|
108
|
-
gate = json_response['gates'].find { |gate| gate['
|
108
|
+
gate = json_response['gates'].find { |gate| gate['key'] == 'percentage_of_time' }
|
109
109
|
expect(gate['value']).to eq('0')
|
110
110
|
end
|
111
111
|
end
|
@@ -120,7 +120,7 @@ RSpec.describe Flipper::Api::V1::Actions::PercentageOfTimeGate do
|
|
120
120
|
end
|
121
121
|
|
122
122
|
it 'returns decorated feature with gate disabled' do
|
123
|
-
gate = json_response['gates'].find { |gate| gate['
|
123
|
+
gate = json_response['gates'].find { |gate| gate['key'] == 'percentage_of_time' }
|
124
124
|
expect(gate['value']).to eq('0')
|
125
125
|
end
|
126
126
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: flipper-api
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.27.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- John Nunemaker
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-03-
|
11
|
+
date: 2023-03-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rack
|
@@ -36,14 +36,14 @@ dependencies:
|
|
36
36
|
requirements:
|
37
37
|
- - "~>"
|
38
38
|
- !ruby/object:Gem::Version
|
39
|
-
version: 0.
|
39
|
+
version: 0.27.1
|
40
40
|
type: :runtime
|
41
41
|
prerelease: false
|
42
42
|
version_requirements: !ruby/object:Gem::Requirement
|
43
43
|
requirements:
|
44
44
|
- - "~>"
|
45
45
|
- !ruby/object:Gem::Version
|
46
|
-
version: 0.
|
46
|
+
version: 0.27.1
|
47
47
|
description:
|
48
48
|
email:
|
49
49
|
- nunemaker@gmail.com
|
@@ -67,6 +67,7 @@ files:
|
|
67
67
|
- lib/flipper/api/v1/actions/feature.rb
|
68
68
|
- lib/flipper/api/v1/actions/features.rb
|
69
69
|
- lib/flipper/api/v1/actions/groups_gate.rb
|
70
|
+
- lib/flipper/api/v1/actions/import.rb
|
70
71
|
- lib/flipper/api/v1/actions/percentage_of_actors_gate.rb
|
71
72
|
- lib/flipper/api/v1/actions/percentage_of_time_gate.rb
|
72
73
|
- lib/flipper/api/v1/decorators/actor.rb
|
@@ -82,6 +83,7 @@ files:
|
|
82
83
|
- spec/flipper/api/v1/actions/feature_spec.rb
|
83
84
|
- spec/flipper/api/v1/actions/features_spec.rb
|
84
85
|
- spec/flipper/api/v1/actions/groups_gate_spec.rb
|
86
|
+
- spec/flipper/api/v1/actions/import_spec.rb
|
85
87
|
- spec/flipper/api/v1/actions/percentage_of_actors_gate_spec.rb
|
86
88
|
- spec/flipper/api/v1/actions/percentage_of_time_gate_spec.rb
|
87
89
|
- spec/flipper/api/v1/decorators/feature_spec.rb
|
@@ -120,6 +122,7 @@ test_files:
|
|
120
122
|
- spec/flipper/api/v1/actions/feature_spec.rb
|
121
123
|
- spec/flipper/api/v1/actions/features_spec.rb
|
122
124
|
- spec/flipper/api/v1/actions/groups_gate_spec.rb
|
125
|
+
- spec/flipper/api/v1/actions/import_spec.rb
|
123
126
|
- spec/flipper/api/v1/actions/percentage_of_actors_gate_spec.rb
|
124
127
|
- spec/flipper/api/v1/actions/percentage_of_time_gate_spec.rb
|
125
128
|
- spec/flipper/api/v1/decorators/feature_spec.rb
|