flipper-api 0.26.1 → 0.27.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a6f7a3c14843b174798472d0faeb146a680d3332d47dbd09ad9f6ec2212fcd5b
4
- data.tar.gz: b813b5c250d62b4c9a515a689b02c1ae424e2a8ebd5d17f0d82a1ef2c2715ea5
3
+ metadata.gz: 16b7564999fb4df34d901a811d675e3d0ca30f1d8577016fdb5c76bd3a3ed609
4
+ data.tar.gz: 5338a67ba725ec6ddbb3f61b30ac727faf0a2aa6a6be74d92d6c29d6e3cd0a73
5
5
  SHA512:
6
- metadata.gz: 56c6c87cf08b207eede4f1e609294a2359fae47a7b0735f399ce350cde002568255489762f25d5443e98900fae5d77cdf97e45cc478236e23cabd4dff4e514db
7
- data.tar.gz: '096bfb16a6f072e9a42a2bb5f7bf17c8f33727ca4b32f5dd7d4bd675206c3d7f688082e770166cd3669d27aa169ed26e50eb5cdfea94c88674afde14b5fd773f'
6
+ metadata.gz: 90087bf7b75e0dc5b98aa329e6350ba9c272b2e2d9b77987ede2d1edcc37ca74dcc7814dbf538ebef6d870924b1112dfdf508845945ad27a460f70244f5bc6bf
7
+ data.tar.gz: 1f76b37067421056664e19b6d74fa827d61980dc6dd16a8bedc80c16faec0fdbb62e08abee16e240f5fae54d5ad2cb0678076711ad079ba5bc704ec69219fbf5
@@ -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
@@ -23,6 +23,7 @@ module Flipper
23
23
  @action_collection.add Api::V1::Actions::Actors
24
24
  @action_collection.add Api::V1::Actions::Feature
25
25
  @action_collection.add Api::V1::Actions::Features
26
+ @action_collection.add Api::V1::Actions::Import
26
27
  end
27
28
 
28
29
  def call(env)
@@ -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(exclude_gates: exclude_gates)
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
@@ -1,3 +1,3 @@
1
1
  module Flipper
2
- VERSION = '0.26.1'.freeze
2
+ VERSION = '0.27.0'.freeze
3
3
  end
@@ -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 ' do
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['name'] == 'group' }
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['name'] == 'group' }
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['name'] == 'group' }
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['name'] == 'group' }
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['name'] == 'group' }
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['name'] == 'group' }
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['name'] == 'percentage_of_actors' }
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['name'] == 'percentage_of_actors' }
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['name'] == 'percentage_of_actors' }
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['name'] == 'percentage_of_actors' }
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['name'] == 'percentage_of_time' }
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['name'] == 'percentage_of_time' }
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['name'] == 'percentage_of_time' }
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['name'] == 'percentage_of_time' }
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.26.1
4
+ version: 0.27.0
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-15 00:00:00.000000000 Z
11
+ date: 2023-03-18 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.26.1
39
+ version: 0.27.0
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.26.1
46
+ version: 0.27.0
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