unleash 4.0.0 → 4.1.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4ce69a2f4588a0d5e459e76aa8d78894497736f484ae20f5d987d50b34aced50
4
- data.tar.gz: 24222c2c023197dc4f283ee4e09316f233245b2e82ca4c9ad934fe5519de75d5
3
+ metadata.gz: 14f988b84b07e45401ad61a5814c1ca44185fc9358cef33f050b1d3bae45dd4e
4
+ data.tar.gz: afda9cf356088ef976047fe58d38d3b457fb1d8797cb7f519de6bdb953f43267
5
5
  SHA512:
6
- metadata.gz: 6e056f24c5f840b211f04bc3c605ccf0846d1ff8717cc824d1e50307e636f28c50f91a8fe85f648de9f16377d5441d5feea459a15ad1eae00c35a6238ebb0355
7
- data.tar.gz: 51b49947d4aea7d1901bf0083ef366604b5d1cd7859cab1cfaceacc420fb056c4188dd4512c1a7feddc5f9711e0c5ad2660e91c1e681cd57e47307f29948790c
6
+ metadata.gz: c1ac85ea8b774a230212583b33b9fdab3110fadab2fa1652810ea0913312c1fd20abe4471761b5ccd399d66a52995c0ddb6b803ee42aa4c4432add8a5524e51d
7
+ data.tar.gz: b03da5caf2bf25683b2d61599a37f15582d26664553ef72096dfd3073aceb96224eaa46fd19c948f9f4fc143e3226ee176a4e66d762016aedf736fb903edae85
@@ -15,7 +15,9 @@ jobs:
15
15
  - ubuntu
16
16
  - macos
17
17
  ruby-version:
18
- - jruby
18
+ - jruby-9.2
19
+ - jruby-9.3
20
+ - 3.1
19
21
  - 3.0
20
22
  - 2.7
21
23
  - 2.6
data/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # Unleash::Client
2
2
 
3
- [![Build Status](https://travis-ci.org/Unleash/unleash-client-ruby.svg?branch=master)](https://travis-ci.org/Unleash/unleash-client-ruby)
4
- [![Coverage Status](https://coveralls.io/repos/github/Unleash/unleash-client-ruby/badge.svg?branch=master)](https://coveralls.io/github/Unleash/unleash-client-ruby?branch=master)
3
+ ![Build Status](https://github.com/Unleash/unleash-client-ruby/actions/workflows/pull_request.yml/badge.svg?branch=main)
4
+ [![Coverage Status](https://coveralls.io/repos/github/Unleash/unleash-client-ruby/badge.svg?branch=main)](https://coveralls.io/github/Unleash/unleash-client-ruby?branch=main)
5
5
  [![Gem Version](https://badge.fury.io/rb/unleash.svg)](https://badge.fury.io/rb/unleash)
6
6
 
7
7
  Unleash client so you can roll out your features with confidence.
@@ -10,11 +10,13 @@ Leverage the [Unleash Server](https://github.com/Unleash/unleash) for powerful f
10
10
 
11
11
  ## Supported Ruby Interpreters
12
12
 
13
+ * MRI 3.1
13
14
  * MRI 3.0
14
15
  * MRI 2.7
15
16
  * MRI 2.6
16
17
  * MRI 2.5
17
- * jruby
18
+ * jruby 9.3
19
+ * jruby 9.2
18
20
 
19
21
  ## Installation
20
22
 
@@ -69,7 +71,7 @@ Argument | Description | Required? | Type | Default Value|
69
71
  `environment` | Environment the program is running on. Could be for example `prod` or `dev`. Not yet in use. | N | String | `default` |
70
72
  `project_name` | Name of the project to retrieve features from. If not set, all feature flags will be retrieved. | N | String | nil |
71
73
  `refresh_interval` | How often the unleash client should check with the server for configuration changes. | N | Integer | 15 |
72
- `metrics_interval` | How often the unleash client should send metrics to server. | N | Integer | 30 |
74
+ `metrics_interval` | How often the unleash client should send metrics to server. | N | Integer | 60 |
73
75
  `disable_client` | Disables all communication with the Unleash server, effectively taking it *offline*. If set, `is_enabled?` will always answer with the `default_value` and configuration validation is skipped. Defeats the entire purpose of using unleash, but can be useful in when running tests. | N | Boolean | `false` |
74
76
  `disable_metrics` | Disables sending metrics to Unleash server. | N | Boolean | `false` |
75
77
  `custom_http_headers` | Custom headers to send to Unleash. As of Unleash v4.0.0, the `Authorization` header is required. For example: `{'Authorization': '<API token>'}` | N | Hash | {} |
@@ -78,9 +80,14 @@ Argument | Description | Required? | Type | Default Value|
78
80
  `backup_file` | Filename to store the last known state from the Unleash server. Best to not change this from the default. | N | String | `Dir.tmpdir + "/unleash-#{app_name}-repo.json` |
79
81
  `logger` | Specify a custom `Logger` class to handle logs for the Unleash client. | N | Class | `Logger.new(STDOUT)` |
80
82
  `log_level` | Change the log level for the `Logger` class. Constant from `Logger::Severity`. | N | Constant | `Logger::WARN` |
83
+ `bootstrap_config` | Bootstrap config on how to loaded data on start-up. This is useful for loading large states on startup without (or before) hitting the network. | N | Unleash::Bootstrap::Configuration | `nil` |
81
84
 
82
- For in a more in depth look, please see `lib/unleash/configuration.rb`.
85
+ For a more in-depth look, please see `lib/unleash/configuration.rb`.
83
86
 
87
+ Environment Variable | Description
88
+ ---------|---------
89
+ `UNLEASH_BOOTSTRAP_FILE` | File to read bootstrap data from
90
+ `UNLEASH_BOOTSTRAP_URL` | URL to read bootstrap data from
84
91
 
85
92
  ## Usage in a plain Ruby Application
86
93
 
@@ -88,7 +95,7 @@ For in a more in depth look, please see `lib/unleash/configuration.rb`.
88
95
  require 'unleash'
89
96
  require 'unleash/context'
90
97
 
91
- @unleash = Unleash::Client.new(app_name: 'my_ruby_app', url: 'http://unleash.herokuapp.com/api', custom_http_headers: {'Authorization': '<API token>'})
98
+ @unleash = Unleash::Client.new(app_name: 'my_ruby_app', url: 'http://unleash.herokuapp.com/api', custom_http_headers: { 'Authorization': '<API token>' })
92
99
 
93
100
  feature_name = "AwesomeFeature"
94
101
  unleash_context = Unleash::Context.new
@@ -266,6 +273,62 @@ variant = UNLEASH.get_variant "ColorVariants", @unleash_context, fallback_varian
266
273
  puts "variant color is: #{variant.payload.fetch('color')}"
267
274
  ```
268
275
 
276
+ ## Bootstrapping
277
+
278
+ Bootstrap configuration allows the client to be initialized with a predefined set of toggle states. Bootstrapping can be configured by providing a bootstrap configuration when initializing the client.
279
+ ```ruby
280
+ @unleash = Unleash::Client.new(
281
+ url: 'http://unleash.herokuapp.com/api',
282
+ app_name: 'my_ruby_app',
283
+ custom_http_headers: { 'Authorization': '<API token>' },
284
+ bootstrap_config: Unleash::Bootstrap::Configuration.new({
285
+ url: "http://unleash.herokuapp.com/api/client/features",
286
+ url_headers: {'Authorization': '<API token>'}
287
+ })
288
+ )
289
+ ```
290
+ The `Bootstrap::Configuration` initializer takes a hash with one of the following options specified:
291
+
292
+ * `file_path` - An absolute or relative path to a file containing a JSON string of the response body from the Unleash server. This can also be set though the `UNLEASH_BOOTSTRAP_FILE` environment variable.
293
+ * `url` - A url pointing to an Unleash server's features endpoint, the code sample above is illustrative. This can also be set though the `UNLEASH_BOOTSTRAP_URL` environment variable.
294
+ * `url_headers` - Headers for the GET http request to the `url` above. Only used if the `url` parameter is also set. If this option isn't set then the bootstrapper will use the same url headers as the Unleash client.
295
+ * `data` - A raw JSON string as returned by the Unleash server.
296
+ * `block` - A lambda containing custom logic if you need it, an example is provided below.
297
+
298
+ You should only specify one type of bootstrapping since only one will be invoked and the others will be ignored. The order of preference is as follows:
299
+
300
+ - Select a data bootstrapper if it exists.
301
+ - If no data bootstrapper exists, select the block bootstrapper.
302
+ - If no block bootstrapper exists, select the file bootstrapper from either parameters or the specified environment variable.
303
+ - If no file bootstrapper exists, then check for a URL bootstrapper from either the parameters or the specified environment variable.
304
+
305
+
306
+ Example usage:
307
+
308
+ First saving the toggles locally:
309
+ ```shell
310
+ curl -H 'Authorization: <API token>' -XGET 'http://unleash.herokuapp.com/api' > ./default-toggles.json
311
+ ```
312
+
313
+ Now using them on start up:
314
+
315
+ ```ruby
316
+
317
+ custom_boostrapper = lambda {
318
+ File.read('./default-toggles.json')
319
+ }
320
+
321
+ @unleash = Unleash::Client.new(
322
+ app_name: 'my_ruby_app',
323
+ url: 'http://unleash.herokuapp.com/api',
324
+ custom_http_headers: { 'Authorization': '<API token>' },
325
+ bootstrap_config: Unleash::Bootstrap::Configuration.new({
326
+ block: custom_boostrapper
327
+ }
328
+ )
329
+ ```
330
+
331
+ This example could be easily achieved with a file bootstrapper, this is just to illustrate the usage of custom bootstrapping. Be aware that the client initializer will block until bootstrapping is complete.
269
332
 
270
333
  #### Client methods
271
334
 
@@ -304,7 +367,6 @@ This client comes with the all the required strategies out of the box:
304
367
  * UnknownStrategy
305
368
  * UserWithIdStrategy
306
369
 
307
-
308
370
  ## Development
309
371
 
310
372
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
@@ -0,0 +1,51 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'unleash'
4
+ require 'unleash/context'
5
+ require 'unleash/bootstrap/configuration'
6
+
7
+ puts ">> START bootstrap.rb"
8
+
9
+ @unleash = Unleash::Client.new(
10
+ url: 'http://unleash.herokuapp.com/api',
11
+ custom_http_headers: { 'Authorization': '943ca9171e2c884c545c5d82417a655fb77cec970cc3b78a8ff87f4406b495d0' },
12
+ app_name: 'bootstrap-test',
13
+ instance_id: 'local-test-cli',
14
+ refresh_interval: 2,
15
+ disable_client: true,
16
+ disable_metrics: true,
17
+ metrics_interval: 2,
18
+ retry_limit: 2,
19
+ bootstrap_config: Unleash::Bootstrap::Configuration.new(file_path: "examples/default-toggles.json")
20
+ )
21
+
22
+ feature_name = "featureX"
23
+ unleash_context = Unleash::Context.new
24
+ unleash_context.user_id = 123
25
+
26
+ sleep 1
27
+ 3.times do
28
+ if @unleash.is_enabled?(feature_name, unleash_context)
29
+ puts "> #{feature_name} is enabled"
30
+ else
31
+ puts "> #{feature_name} is not enabled"
32
+ end
33
+ sleep 1
34
+ puts "---"
35
+ puts ""
36
+ puts ""
37
+ end
38
+
39
+ sleep 3
40
+ feature_name = "foobar"
41
+ if @unleash.is_enabled?(feature_name, unleash_context, true)
42
+ puts "> #{feature_name} is enabled"
43
+ else
44
+ puts "> #{feature_name} is not enabled"
45
+ end
46
+
47
+ puts "> shutting down client..."
48
+
49
+ @unleash.shutdown
50
+
51
+ puts ">> END bootstrap.rb"
@@ -0,0 +1,42 @@
1
+ {
2
+ "version": 1,
3
+ "features": [
4
+ {
5
+ "name": "featureX",
6
+ "enabled": true,
7
+ "strategies": [
8
+ {
9
+ "name": "default"
10
+ }
11
+ ]
12
+ },
13
+ {
14
+ "name": "featureY",
15
+ "enabled": false,
16
+ "strategies": [
17
+ {
18
+ "name": "baz",
19
+ "parameters": {
20
+ "foo": "bar"
21
+ }
22
+ }
23
+ ]
24
+ },
25
+ {
26
+ "name": "featureZ",
27
+ "enabled": true,
28
+ "strategies": [
29
+ {
30
+ "name": "default"
31
+ },
32
+ {
33
+ "name": "hola",
34
+ "parameters": {
35
+ "name": "val"
36
+ }
37
+ }
38
+ ]
39
+ }
40
+ ]
41
+ }
42
+
@@ -0,0 +1,25 @@
1
+ module Unleash
2
+ module Bootstrap
3
+ class Configuration
4
+ attr_accessor :data, :file_path, :url, :url_headers, :block
5
+
6
+ def initialize(opts = {})
7
+ self.file_path = resolve_value_indifferently(opts, 'file_path') || ENV['UNLEASH_BOOTSTRAP_FILE'] || nil
8
+ self.url = resolve_value_indifferently(opts, 'url') || ENV['UNLEASH_BOOTSTRAP_URL'] || nil
9
+ self.url_headers = resolve_value_indifferently(opts, 'url_headers')
10
+ self.data = resolve_value_indifferently(opts, 'data')
11
+ self.block = resolve_value_indifferently(opts, 'block')
12
+ end
13
+
14
+ def valid?
15
+ ![self.data, self.file_path, self.url, self.block].all?(&:nil?)
16
+ end
17
+
18
+ private
19
+
20
+ def resolve_value_indifferently(opts, key)
21
+ opts[key] || opts[key.to_sym]
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,22 @@
1
+ require 'unleash/bootstrap/provider/from_url'
2
+ require 'unleash/bootstrap/provider/from_file'
3
+
4
+ module Unleash
5
+ module Bootstrap
6
+ class Handler
7
+ attr_accessor :configuration
8
+
9
+ def initialize(configuration)
10
+ self.configuration = configuration
11
+ end
12
+
13
+ # @return [String] JSON string representing data returned from an Unleash server
14
+ def retrieve_toggles
15
+ return configuration.data unless self.configuration.data.nil?
16
+ return configuration.block.call if self.configuration.block.is_a?(Proc)
17
+ return Provider::FromFile.read(configuration.file_path) unless self.configuration.file_path.nil?
18
+ return Provider::FromUrl.read(configuration.url, configuration.url_headers) unless self.configuration.url.nil?
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,14 @@
1
+ module Unleash
2
+ module Bootstrap
3
+ module Provider
4
+ class NotImplemented < RuntimeError
5
+ end
6
+
7
+ class Base
8
+ def read
9
+ raise NotImplemented, "Bootstrap is not implemented"
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,14 @@
1
+ require 'unleash/bootstrap/provider/base'
2
+
3
+ module Unleash
4
+ module Bootstrap
5
+ module Provider
6
+ class FromFile < Base
7
+ # @param file_path [String]
8
+ def self.read(file_path)
9
+ File.read(file_path)
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,19 @@
1
+ require 'unleash/bootstrap/provider/base'
2
+
3
+ module Unleash
4
+ module Bootstrap
5
+ module Provider
6
+ class FromUrl < Base
7
+ # @param url [String]
8
+ # @param headers [Hash, nil] HTTP headers to use. If not set, the unleash client SDK ones will be used.
9
+ def self.read(url, headers = nil)
10
+ response = Unleash::Util::Http.get(URI.parse(url), nil, headers)
11
+
12
+ return nil if response.code != '200'
13
+
14
+ response.body
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -18,8 +18,9 @@ module Unleash
18
18
  Unleash.logger = Unleash.configuration.logger.clone
19
19
  Unleash.logger.level = Unleash.configuration.log_level
20
20
 
21
+ Unleash.toggle_fetcher = Unleash::ToggleFetcher.new
21
22
  if Unleash.configuration.disable_client
22
- Unleash.logger.warn "Unleash::Client is disabled! Will only return default results!"
23
+ Unleash.logger.warn "Unleash::Client is disabled! Will only return default (or bootstrapped if available) results!"
23
24
  return
24
25
  end
25
26
 
@@ -37,11 +38,6 @@ module Unleash
37
38
  default_value_param
38
39
  end
39
40
 
40
- if Unleash.configuration.disable_client
41
- Unleash.logger.warn "unleash_client is disabled! Always returning #{default_value} for feature #{feature}!"
42
- return default_value
43
- end
44
-
45
41
  toggle_as_hash = Unleash&.toggles&.select{ |toggle| toggle['name'] == feature }&.first
46
42
 
47
43
  if toggle_as_hash.nil?
@@ -121,11 +117,11 @@ module Unleash
121
117
  end
122
118
 
123
119
  def start_toggle_fetcher
124
- Unleash.toggle_fetcher = Unleash::ToggleFetcher.new
125
120
  self.fetcher_scheduled_executor = Unleash::ScheduledExecutor.new(
126
121
  'ToggleFetcher',
127
122
  Unleash.configuration.refresh_interval,
128
- Unleash.configuration.retry_limit
123
+ Unleash.configuration.retry_limit,
124
+ first_fetch_is_eager
129
125
  )
130
126
  self.fetcher_scheduled_executor.run do
131
127
  Unleash.toggle_fetcher.fetch
@@ -161,5 +157,9 @@ module Unleash
161
157
  def disabled_variant
162
158
  @disabled_variant ||= Unleash::FeatureToggle.disabled_variant
163
159
  end
160
+
161
+ def first_fetch_is_eager
162
+ Unleash.configuration.use_bootstrap?
163
+ end
164
164
  end
165
165
  end
@@ -1,5 +1,6 @@
1
1
  require 'securerandom'
2
2
  require 'tmpdir'
3
+ require 'unleash/bootstrap/configuration'
3
4
 
4
5
  module Unleash
5
6
  class Configuration
@@ -18,7 +19,8 @@ module Unleash
18
19
  :metrics_interval,
19
20
  :backup_file,
20
21
  :logger,
21
- :log_level
22
+ :log_level,
23
+ :bootstrap_config
22
24
 
23
25
  def initialize(opts = {})
24
26
  ensure_valid_opts(opts)
@@ -70,6 +72,10 @@ module Unleash
70
72
  self.url.delete_suffix '/'
71
73
  end
72
74
 
75
+ def use_bootstrap?
76
+ self.bootstrap_config&.valid?
77
+ end
78
+
73
79
  private
74
80
 
75
81
  def ensure_valid_opts(opts)
@@ -87,11 +93,12 @@ module Unleash
87
93
  self.disable_client = false
88
94
  self.disable_metrics = false
89
95
  self.refresh_interval = 10
90
- self.metrics_interval = 30
96
+ self.metrics_interval = 60
91
97
  self.timeout = 30
92
- self.retry_limit = 1
98
+ self.retry_limit = 5
93
99
  self.backup_file = nil
94
100
  self.log_level = Logger::WARN
101
+ self.bootstrap_config = nil
95
102
 
96
103
  self.custom_http_headers = {}
97
104
  end
@@ -1,19 +1,22 @@
1
1
  module Unleash
2
2
  class ScheduledExecutor
3
- attr_accessor :name, :interval, :max_exceptions, :retry_count, :thread
3
+ attr_accessor :name, :interval, :max_exceptions, :retry_count, :thread, :immediate_execution
4
4
 
5
- def initialize(name, interval, max_exceptions = 5)
5
+ def initialize(name, interval, max_exceptions = 5, immediate_execution = false)
6
6
  self.name = name || ''
7
7
  self.interval = interval
8
8
  self.max_exceptions = max_exceptions
9
9
  self.retry_count = 0
10
10
  self.thread = nil
11
+ self.immediate_execution = immediate_execution
11
12
  end
12
13
 
13
14
  def run(&blk)
14
15
  self.thread = Thread.new do
15
16
  Thread.current[:name] = self.name
16
17
 
18
+ run_blk{ blk.call } if self.immediate_execution
19
+
17
20
  Unleash.logger.debug "thread #{name} loop starting"
18
21
  loop do
19
22
  Unleash.logger.debug "thread #{name} sleeping for #{interval} seconds"
@@ -13,7 +13,23 @@ module Unleash
13
13
  return false unless params.fetch(PARAM, nil).is_a? String
14
14
  return false unless context.class.name == 'Unleash::Context'
15
15
 
16
- params[PARAM].split(',').map(&:strip).include?(context.remote_address)
16
+ remote_address = ipaddr_or_nil_from_str(context.remote_address)
17
+
18
+ params[PARAM]
19
+ .split(',')
20
+ .map(&:strip)
21
+ .map{ |ipblock| ipaddr_or_nil_from_str(ipblock) }
22
+ .compact
23
+ .map{ |ipb| ipb.include? remote_address }
24
+ .any?
25
+ end
26
+
27
+ private
28
+
29
+ def ipaddr_or_nil_from_str(ip)
30
+ IPAddr.new(ip)
31
+ rescue StandardError
32
+ nil
17
33
  end
18
34
  end
19
35
  end
@@ -1,4 +1,5 @@
1
1
  require 'unleash/configuration'
2
+ require 'unleash/bootstrap/handler'
2
3
  require 'net/http'
3
4
  require 'json'
4
5
 
@@ -13,10 +14,15 @@ module Unleash
13
14
  self.toggle_resource = ConditionVariable.new
14
15
  self.retry_count = 0
15
16
 
16
- # start by fetching synchronously, and failing back to reading the backup file.
17
17
  begin
18
- fetch
18
+ # if bootstrap configuration is available, initialize. An immediate API read is also triggered
19
+ if Unleash.configuration.use_bootstrap?
20
+ bootstrap
21
+ else
22
+ fetch
23
+ end
19
24
  rescue StandardError => e
25
+ # fail back to reading the backup file
20
26
  Unleash.logger.warn "ToggleFetcher was unable to fetch from the network, attempting to read from backup file."
21
27
  Unleash.logger.debug "Exception Caught: #{e}"
22
28
  read!
@@ -36,6 +42,8 @@ module Unleash
36
42
  # rename to refresh_from_server! ??
37
43
  def fetch
38
44
  Unleash.logger.debug "fetch()"
45
+ return if Unleash.configuration.disable_client
46
+
39
47
  response = Unleash::Util::Http.get(Unleash.configuration.fetch_toggles_uri, etag)
40
48
 
41
49
  if response.code == '304'
@@ -46,14 +54,7 @@ module Unleash
46
54
  end
47
55
 
48
56
  self.etag = response['ETag']
49
- response_hash = JSON.parse(response.body)
50
-
51
- if response_hash['version'] >= 1
52
- features = response_hash['features']
53
- else
54
- raise NotImplemented, "Version of features provided by unleash server" \
55
- " is unsupported by this client."
56
- end
57
+ features = get_features(response.body)
57
58
 
58
59
  # always synchronize with the local cache when fetching:
59
60
  synchronize_with_local_cache!(features)
@@ -126,5 +127,23 @@ module Unleash
126
127
  file&.close
127
128
  end
128
129
  end
130
+
131
+ def bootstrap
132
+ bootstrap_payload = Unleash::Bootstrap::Handler.new(Unleash.configuration.bootstrap_config).retrieve_toggles
133
+ synchronize_with_local_cache! get_features bootstrap_payload
134
+ update_running_client!
135
+
136
+ # reset Unleash.configuration.bootstrap_data to free up memory, as we will never use it again
137
+ Unleash.configuration.bootstrap_config = nil
138
+ end
139
+
140
+ # @param response_body [String]
141
+ def get_features(response_body)
142
+ response_hash = JSON.parse(response_body)
143
+ return response_hash['features'] if response_hash['version'] >= 1
144
+
145
+ raise NotImplemented, "Version of features provided by unleash server" \
146
+ " is unsupported by this client."
147
+ end
129
148
  end
130
149
  end
@@ -4,10 +4,10 @@ require 'uri'
4
4
  module Unleash
5
5
  module Util
6
6
  module Http
7
- def self.get(uri, etag = nil)
7
+ def self.get(uri, etag = nil, headers_override = nil)
8
8
  http = http_connection(uri)
9
9
 
10
- request = Net::HTTP::Get.new(uri.request_uri, http_headers(etag))
10
+ request = Net::HTTP::Get.new(uri.request_uri, http_headers(etag, headers_override))
11
11
 
12
12
  http.request(request)
13
13
  end
@@ -30,10 +30,13 @@ module Unleash
30
30
  http
31
31
  end
32
32
 
33
- def self.http_headers(etag = nil)
33
+ # @param etag [String, nil]
34
+ # @param headers_override [Hash, nil]
35
+ def self.http_headers(etag = nil, headers_override = nil)
34
36
  Unleash.logger.debug "ETag: #{etag}" unless etag.nil?
35
37
 
36
38
  headers = (Unleash.configuration.http_headers || {}).dup
39
+ headers = headers_override if headers_override.is_a?(Hash)
37
40
  headers['Content-Type'] = 'application/json'
38
41
  headers['If-None-Match'] = etag unless etag.nil?
39
42
 
@@ -1,3 +1,3 @@
1
1
  module Unleash
2
- VERSION = "4.0.0".freeze
2
+ VERSION = "4.1.0".freeze
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: unleash
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.0.0
4
+ version: 4.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Renato Arruda
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-12-16 00:00:00.000000000 Z
11
+ date: 2022-02-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: murmurhash3
@@ -157,9 +157,16 @@ files:
157
157
  - bin/console
158
158
  - bin/setup
159
159
  - bin/unleash-client
160
+ - examples/bootstrap.rb
161
+ - examples/default-toggles.json
160
162
  - examples/simple.rb
161
163
  - lib/unleash.rb
162
164
  - lib/unleash/activation_strategy.rb
165
+ - lib/unleash/bootstrap/configuration.rb
166
+ - lib/unleash/bootstrap/handler.rb
167
+ - lib/unleash/bootstrap/provider/base.rb
168
+ - lib/unleash/bootstrap/provider/from_file.rb
169
+ - lib/unleash/bootstrap/provider/from_url.rb
163
170
  - lib/unleash/client.rb
164
171
  - lib/unleash/configuration.rb
165
172
  - lib/unleash/constraint.rb
@@ -204,7 +211,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
204
211
  - !ruby/object:Gem::Version
205
212
  version: '0'
206
213
  requirements: []
207
- rubygems_version: 3.2.3
214
+ rubygems_version: 3.3.6
208
215
  signing_key:
209
216
  specification_version: 4
210
217
  summary: Unleash feature toggle client.