flipper-cloud 0.23.0 → 0.24.1

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: 808e7998e34d07ad62c7e9ccf32b38bda9ba013037d8a650ab92137881a1ffd8
4
- data.tar.gz: 198d9f67b76e46a6902a67d641bb403b140ed90d4da38d8d5db9a2e50f7ac895
3
+ metadata.gz: da84cb1704e31fac9f950282867da74412c73f1cc7a0a2fdebe1cab70b1caffa
4
+ data.tar.gz: e356bef8598889a5d8905737d8201da58b1f4d8d607dd48d26a8695ce0558adc
5
5
  SHA512:
6
- metadata.gz: ca987e0d72af2621f9f9e50986e40621d06ed169cc533337f73797e51920ada87405b01d5ca74060ff04a590440ed592c4545cff54c0fd73252d443697936bfb
7
- data.tar.gz: 046f0b0d7937ba32429057b30be25ef52fd557942f6afcac7f83875129b2ccaf86cfe2f2f99c2f13876a0aa719e0c483a1644e661a548bcbd2f6f3e189e44114
6
+ metadata.gz: fa9efb9eca7fb3e058ad85cb19ddc405ac445ee2f49f1bcd368976cee7758dda4b3446baaeac4a1f1a110240d625126708fb5e85afe5706fb92a276780662151
7
+ data.tar.gz: 330335221574998e0c76452cb728881e360828fc61ff38057ba6c6d3f20a9e3e1b958452746c1104c1b4f3f40b79ea590073935cc7de918758fb0aef5b26e538
@@ -1,5 +1,7 @@
1
1
  # Usage (from the repo root):
2
2
  # env FLIPPER_CLOUD_TOKEN=<token> bundle exec ruby examples/cloud/basic.rb
3
+
4
+ require_relative "./cloud_setup"
3
5
  require 'bundler/setup'
4
6
  require 'flipper/cloud'
5
7
 
@@ -0,0 +1,4 @@
1
+ if ENV["FLIPPER_CLOUD_TOKEN"].nil? || ENV["FLIPPER_CLOUD_TOKEN"].empty?
2
+ warn "FLIPPER_CLOUD_TOKEN missing so skipping cloud example."
3
+ exit
4
+ end
@@ -1,5 +1,7 @@
1
1
  # Usage (from the repo root):
2
2
  # env FLIPPER_CLOUD_TOKEN=<token> bundle exec ruby examples/cloud/import.rb
3
+
4
+ require_relative "./cloud_setup"
3
5
  require 'bundler/setup'
4
6
  require 'flipper'
5
7
  require 'flipper/cloud'
@@ -24,4 +24,5 @@ Gem::Specification.new do |gem|
24
24
  gem.metadata = Flipper::METADATA
25
25
 
26
26
  gem.add_dependency 'flipper', "~> #{Flipper::VERSION}"
27
+ gem.add_dependency "brow", "~> 0.4.1"
27
28
  end
@@ -3,6 +3,9 @@ require "flipper/adapters/http"
3
3
  require "flipper/adapters/memory"
4
4
  require "flipper/adapters/dual_write"
5
5
  require "flipper/adapters/sync"
6
+ require "flipper/cloud/instrumenter"
7
+ require "flipper/cloud/registry"
8
+ require "brow"
6
9
 
7
10
  module Flipper
8
11
  module Cloud
@@ -75,7 +78,6 @@ module Flipper
75
78
  end
76
79
  self.sync_method = options[:sync_method] if options[:sync_method]
77
80
 
78
- @instrumenter = options.fetch(:instrumenter, Instrumenters::Noop)
79
81
  @read_timeout = options.fetch(:read_timeout) { ENV.fetch("FLIPPER_CLOUD_READ_TIMEOUT", 5).to_f }
80
82
  @open_timeout = options.fetch(:open_timeout) { ENV.fetch("FLIPPER_CLOUD_OPEN_TIMEOUT", 5).to_f }
81
83
  @write_timeout = options.fetch(:write_timeout) { ENV.fetch("FLIPPER_CLOUD_WRITE_TIMEOUT", 5).to_f }
@@ -85,6 +87,16 @@ module Flipper
85
87
  @debug_output = options[:debug_output]
86
88
  @adapter_block = ->(adapter) { adapter }
87
89
  self.url = options.fetch(:url) { ENV.fetch("FLIPPER_CLOUD_URL", DEFAULT_URL) }
90
+
91
+ instrumenter = options.fetch(:instrumenter, Instrumenters::Noop)
92
+
93
+ # This is alpha. Don't use this unless you are me. And you are not me.
94
+ cloud_instrument = options.fetch(:cloud_instrument) { ENV["FLIPPER_CLOUD_INSTRUMENT"] == "1" }
95
+ @instrumenter = if cloud_instrument
96
+ Instrumenter.new(brow: brow, instrumenter: instrumenter)
97
+ else
98
+ instrumenter
99
+ end
88
100
  end
89
101
 
90
102
  # Public: Read or customize the http adapter. Calling without a block will
@@ -116,6 +128,24 @@ module Flipper
116
128
  }).call
117
129
  end
118
130
 
131
+ def brow
132
+ uri = URI.parse(url)
133
+ uri.path = "#{uri.path}/events".squeeze("/")
134
+ events_url = uri.to_s
135
+
136
+ Registry.default.fetch(events_url) {
137
+ Brow::Client.new({
138
+ url: events_url,
139
+ headers: {
140
+ "Accept" => "application/json",
141
+ "Content-Type" => "application/json",
142
+ "User-Agent" => "Flipper v#{VERSION} via Brow v#{Brow::VERSION}",
143
+ "Flipper-Cloud-Token" => @token,
144
+ }
145
+ })
146
+ }
147
+ end
148
+
119
149
  # Public: The method that will be used to synchronize local adapter with
120
150
  # cloud. (default: :poll, will be :webhook if sync_secret is set).
121
151
  def sync_method
@@ -157,5 +187,3 @@ module Flipper
157
187
  end
158
188
  end
159
189
  end
160
-
161
- # "FLIPPER_TIMESTAMP".freeze => Flipper::Timestamp.generate.to_s,
@@ -0,0 +1,43 @@
1
+ require "delegate"
2
+ require "flipper/instrumenters/noop"
3
+
4
+ module Flipper
5
+ module Cloud
6
+ class Instrumenter < SimpleDelegator
7
+ def initialize(options = {})
8
+ @brow = options.fetch(:brow)
9
+ @instrumenter = options.fetch(:instrumenter, Instrumenters::Noop)
10
+ super @instrumenter
11
+ end
12
+
13
+ def instrument(name, payload = {}, &block)
14
+ result = @instrumenter.instrument(name, payload, &block)
15
+ push name, payload
16
+ result
17
+ end
18
+
19
+ private
20
+
21
+ def push(name, payload)
22
+ return unless name == Flipper::Feature::InstrumentationName
23
+ return unless :enabled? == payload[:operation]
24
+
25
+ dimensions = {
26
+ "feature" => payload[:feature_name].to_s,
27
+ "result" => payload[:result].to_s,
28
+ }
29
+ if (thing = payload[:thing])
30
+ dimensions["flipper_id"] = thing.value.to_s
31
+ end
32
+
33
+ event = {
34
+ type: "enabled",
35
+ dimensions: dimensions,
36
+ measures: {},
37
+ ts: Time.now.utc,
38
+ }
39
+ @brow.push event
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,46 @@
1
+ require "thread"
2
+
3
+ module Flipper
4
+ module Cloud
5
+ class Registry
6
+ def self.default
7
+ @default ||= new
8
+ end
9
+
10
+ def initialize
11
+ @mutex = Mutex.new
12
+ @data = {}
13
+ end
14
+
15
+ def fetch(key, &block)
16
+ @mutex.synchronize do
17
+ if data = @data[key]
18
+ data
19
+ else
20
+ @data[key] = yield
21
+ end
22
+ end
23
+ end
24
+
25
+ def keys
26
+ @mutex.synchronize do
27
+ @data.keys
28
+ end
29
+ end
30
+
31
+ def each(&block)
32
+ data = @mutex.synchronize do
33
+ @data.dup
34
+ end
35
+
36
+ data.each(&block)
37
+ end
38
+
39
+ def clear
40
+ @mutex.synchronize do
41
+ @data = {}
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
data/lib/flipper/cloud.rb CHANGED
@@ -40,8 +40,9 @@ module Flipper
40
40
  builder.use Flipper::Cloud::Middleware, env_key: env_key
41
41
  builder.run app
42
42
  klass = self
43
- builder.define_singleton_method(:inspect) { klass.inspect } # pretty rake routes output
44
- builder
43
+ app = builder.to_app
44
+ app.define_singleton_method(:inspect) { klass.inspect } # pretty rake routes output
45
+ app
45
46
  end
46
47
 
47
48
  # Private: Configure Flipper to use Cloud by default
@@ -1,3 +1,3 @@
1
1
  module Flipper
2
- VERSION = '0.23.0'.freeze
2
+ VERSION = '0.24.1'.freeze
3
3
  end
@@ -240,4 +240,21 @@ RSpec.describe Flipper::Cloud::Configuration do
240
240
  expect(all["search"][:boolean]).to eq("true")
241
241
  expect(all["history"][:boolean]).to eq(nil)
242
242
  end
243
+
244
+ it "can setup brow to report events to cloud" do
245
+ # skip logging brow
246
+ Brow.logger = Logger.new(File::NULL)
247
+ brow = described_class.new(required_options).brow
248
+
249
+ stub = stub_request(:post, "https://www.flippercloud.io/adapter/events")
250
+ .with { |request|
251
+ data = JSON.parse(request.body)
252
+ data.keys == ["uuid", "messages"] && data["messages"] == [{"n" => 1}]
253
+ }
254
+ .to_return(status: 201, body: "{}", headers: {})
255
+
256
+ brow.push({"n" => 1})
257
+ brow.worker.stop
258
+ expect(stub).to have_been_requested.times(1)
259
+ end
243
260
  end
@@ -267,7 +267,7 @@ RSpec.describe Flipper::Cloud::Middleware do
267
267
 
268
268
  describe 'Inspecting the built Rack app' do
269
269
  it 'returns a String' do
270
- expect(Flipper::Cloud.app(flipper).inspect).to be_a(String)
270
+ expect(Flipper::Cloud.app(flipper).inspect).to eq("Flipper::Cloud")
271
271
  end
272
272
  end
273
273
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: flipper-cloud
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.23.0
4
+ version: 0.24.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: 2021-12-24 00:00:00.000000000 Z
11
+ date: 2022-04-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: flipper
@@ -16,14 +16,28 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: 0.23.0
19
+ version: 0.24.1
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: 0.23.0
26
+ version: 0.24.1
27
+ - !ruby/object:Gem::Dependency
28
+ name: brow
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 0.4.1
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 0.4.1
27
41
  description:
28
42
  email:
29
43
  - nunemaker@gmail.com
@@ -34,6 +48,7 @@ files:
34
48
  - docs/images/flipper_cloud.png
35
49
  - examples/cloud/app.ru
36
50
  - examples/cloud/basic.rb
51
+ - examples/cloud/cloud_setup.rb
37
52
  - examples/cloud/import.rb
38
53
  - flipper-cloud.gemspec
39
54
  - lib/flipper-cloud.rb
@@ -41,8 +56,10 @@ files:
41
56
  - lib/flipper/cloud/configuration.rb
42
57
  - lib/flipper/cloud/dsl.rb
43
58
  - lib/flipper/cloud/engine.rb
59
+ - lib/flipper/cloud/instrumenter.rb
44
60
  - lib/flipper/cloud/message_verifier.rb
45
61
  - lib/flipper/cloud/middleware.rb
62
+ - lib/flipper/cloud/registry.rb
46
63
  - lib/flipper/cloud/routes.rb
47
64
  - lib/flipper/version.rb
48
65
  - spec/flipper/cloud/configuration_spec.rb