unleash 3.2.3 → 4.1.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: 70d64956aa703576336ee95064ef909655a664159b571be5417ebf073f0de224
4
- data.tar.gz: 36cff93bb8203971721e3eeace2d24d9db4075926d2c2609e5c6acd01179c2fd
3
+ metadata.gz: 14f988b84b07e45401ad61a5814c1ca44185fc9358cef33f050b1d3bae45dd4e
4
+ data.tar.gz: afda9cf356088ef976047fe58d38d3b457fb1d8797cb7f519de6bdb953f43267
5
5
  SHA512:
6
- metadata.gz: 7b8c366cc799582a672646c796858381189e9286149929bb5e37afc2404cce9ac140b0c004ba8a3a7f774b0d83c705c2c714932656121054ab920f58afa55b34
7
- data.tar.gz: 6a4f8aa92aa80e17eb2477cc77a534dcbe44b2b63b3ff7c05867392252e808ec76750094adaf476c739c2641db1ef0f8a7c3729001fd7efe8ab209a255ebe968
6
+ metadata.gz: c1ac85ea8b774a230212583b33b9fdab3110fadab2fa1652810ea0913312c1fd20abe4471761b5ccd399d66a52995c0ddb6b803ee42aa4c4432add8a5524e51d
7
+ data.tar.gz: b03da5caf2bf25683b2d61599a37f15582d26664553ef72096dfd3073aceb96224eaa46fd19c948f9f4fc143e3226ee176a4e66d762016aedf736fb903edae85
@@ -0,0 +1,73 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ pull_request:
6
+
7
+ jobs:
8
+ test:
9
+
10
+ runs-on: ${{ matrix.os }}-latest
11
+
12
+ strategy:
13
+ matrix:
14
+ os:
15
+ - ubuntu
16
+ - macos
17
+ ruby-version:
18
+ - jruby-9.2
19
+ - jruby-9.3
20
+ - 3.1
21
+ - 3.0
22
+ - 2.7
23
+ - 2.6
24
+ - 2.5
25
+
26
+ steps:
27
+ - uses: actions/checkout@v2
28
+ - name: Set up Ruby ${{ matrix.ruby-version }}
29
+ uses: ruby/setup-ruby@v1
30
+ with:
31
+ bundler-cache: true
32
+ ruby-version: ${{ matrix.ruby-version }}
33
+ - name: Install dependencies
34
+ run: bundle install
35
+ - name: Download test cases
36
+ run: git clone --depth 5 --branch v4.0.0 https://github.com/Unleash/client-specification.git client-specification
37
+ - name: rubocop
38
+ uses: reviewdog/action-rubocop@v2
39
+ with:
40
+ github_token: ${{ secrets.GITHUB_TOKEN }}
41
+ rubocop_version: gemfile
42
+ rubocop_extensions: rubocop-rspec:gemfile
43
+ reporter: github-pr-review # Default is github-pr-check
44
+ - name: Run tests
45
+ run: bundle exec rake
46
+ env:
47
+ COVERALLS_REPO_TOKEN: ${{ secrets.GITHUB_TOKEN }}
48
+ - name: Coveralls Parallel
49
+ uses: coverallsapp/github-action@master
50
+ with:
51
+ github-token: ${{ secrets.GITHUB_TOKEN }}
52
+ flag-name: run-${{ matrix.test_number }}
53
+ parallel: true
54
+ - name: Notify Slack of pipeline completion
55
+ uses: 8398a7/action-slack@v3
56
+ if: ${{ github.event.pull_request.head.repo.full_name == github.event.pull_request.base.repo.full_name }}
57
+ with:
58
+ status: ${{ job.status }}
59
+ text: Built on ${{ matrix.os }} - Ruby ${{ matrix.ruby-version }}
60
+ fields: repo,message,commit,author,action,eventName,ref,workflow,job,took
61
+ env:
62
+ SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
63
+
64
+ finish:
65
+ needs: test
66
+ runs-on: ubuntu-latest
67
+ steps:
68
+ - name: Coveralls Finished
69
+ uses: coverallsapp/github-action@master
70
+ with:
71
+ github-token: ${{ secrets.GITHUB_TOKEN }}
72
+ parallel-finished: true
73
+
data/.gitignore CHANGED
@@ -9,6 +9,9 @@
9
9
  /tmp/
10
10
  /vendor
11
11
 
12
+ # IntelliJ
13
+ .idea/
14
+
12
15
  # rspec failure tracking
13
16
  .rspec_status
14
17
 
data/.rubocop.yml CHANGED
@@ -14,17 +14,19 @@ Layout/LineLength:
14
14
  Metrics/MethodLength:
15
15
  Max: 20
16
16
  Metrics/BlockLength:
17
- Max: 100
17
+ Max: 110
18
18
  Exclude:
19
+ - 'spec/unleash/configuration_spec.rb'
19
20
  - 'spec/unleash/client_spec.rb'
21
+ - 'spec/unleash/context_spec.rb'
20
22
  - 'spec/unleash/feature_toggle_spec.rb'
21
23
 
22
24
  Metrics/AbcSize:
23
- Max: 25
25
+ Max: 28
24
26
  Metrics/CyclomaticComplexity:
25
27
  Max: 9
26
28
  Metrics/PerceivedComplexity:
27
- Max: 9
29
+ Max: 10
28
30
 
29
31
  Style/Documentation:
30
32
  Enabled: false
@@ -51,6 +53,12 @@ Style/HashTransformKeys:
51
53
  Enabled: true
52
54
  Style/HashTransformValues:
53
55
  Enabled: true
56
+ Style/EmptyElse:
57
+ Exclude:
58
+ - 'lib/unleash/strategy/flexible_rollout.rb'
59
+
60
+ Style/DoubleNegation:
61
+ Enabled: false
54
62
 
55
63
  Style/IfInsideElse:
56
64
  Exclude:
@@ -60,6 +68,61 @@ Style/Next:
60
68
  Exclude:
61
69
  - 'lib/unleash/scheduled_executor.rb'
62
70
 
71
+
72
+ Style/AccessorGrouping:
73
+ Enabled: true
74
+ Style/BisectedAttrAccessor:
75
+ Enabled: true
76
+ Style/CaseLikeIf:
77
+ Enabled: true
78
+ #Style/ClassEqualityComparison:
79
+ # Enabled: true
80
+ Style/CombinableLoops:
81
+ Enabled: true
82
+ Style/ExplicitBlockArgument:
83
+ Enabled: true
84
+ Style/ExponentialNotation:
85
+ Enabled: true
86
+ #Style/GlobalStdStream:
87
+ # Enabled: true
88
+ Style/HashAsLastArrayItem:
89
+ Enabled: true
90
+ Style/HashLikeCase:
91
+ Enabled: true
92
+ Style/KeywordParametersOrder:
93
+ Enabled: true
94
+ #Style/OptionalBooleanParameter:
95
+ # Enabled: false
96
+ Style/RedundantAssignment:
97
+ Enabled: true
98
+ Style/RedundantFetchBlock:
99
+ Enabled: true
100
+ Style/RedundantFileExtensionInRequire:
101
+ Enabled: true
102
+ Style/RedundantRegexpCharacterClass:
103
+ Enabled: true
104
+ Style/RedundantRegexpEscape:
105
+ Enabled: true
106
+ Style/RedundantSelfAssignment:
107
+ Enabled: true
108
+ Style/SingleArgumentDig:
109
+ Enabled: true
110
+ Style/SlicingWithRange:
111
+ Enabled: true
112
+ Style/SoleNestedConditional:
113
+ Enabled: true
114
+ Style/StringConcatenation:
115
+ Enabled: false
116
+ Style/TrailingCommaInHashLiteral:
117
+ Enabled: true
118
+ # EnforcedStyleForMultiline: consistent_comma
119
+
120
+ Layout/BeginEndAlignment:
121
+ Enabled: true
122
+ Layout/EmptyLinesAroundAttributeAccessor:
123
+ Enabled: true
124
+ Layout/SpaceAroundMethodCallOperator:
125
+ Enabled: true
63
126
  Layout/MultilineMethodCallIndentation:
64
127
  EnforcedStyle: indented
65
128
 
@@ -68,3 +131,50 @@ Layout/SpaceBeforeBlockBraces:
68
131
  Exclude:
69
132
  - 'unleash-client.gemspec'
70
133
  - 'spec/**/*.rb'
134
+
135
+ Lint/BinaryOperatorWithIdenticalOperands:
136
+ Enabled: true
137
+ Lint/ConstantDefinitionInBlock:
138
+ Enabled: false
139
+ Lint/DeprecatedOpenSSLConstant:
140
+ Enabled: true
141
+ Lint/DuplicateElsifCondition:
142
+ Enabled: true
143
+ Lint/DuplicateRequire:
144
+ Enabled: true
145
+ Lint/DuplicateRescueException:
146
+ Enabled: true
147
+ Lint/EmptyConditionalBody:
148
+ Enabled: true
149
+ Lint/EmptyFile:
150
+ Enabled: true
151
+ Lint/FloatComparison:
152
+ Enabled: true
153
+ Lint/HashCompareByIdentity:
154
+ Enabled: true
155
+ Lint/IdentityComparison:
156
+ Enabled: true
157
+ Lint/MissingSuper:
158
+ Enabled: false
159
+ Lint/MixedRegexpCaptureTypes:
160
+ Enabled: true
161
+ Lint/OutOfRangeRegexpRef:
162
+ Enabled: true
163
+ Lint/RaiseException:
164
+ Enabled: true
165
+ Lint/RedundantSafeNavigation:
166
+ Enabled: true
167
+ Lint/SelfAssignment:
168
+ Enabled: true
169
+ Lint/StructNewOverride:
170
+ Enabled: true
171
+ Lint/TopLevelReturnWithArgument:
172
+ Enabled: true
173
+ Lint/TrailingCommaInAttributeDeclaration:
174
+ Enabled: true
175
+ Lint/UnreachableLoop:
176
+ Enabled: true
177
+ Lint/UselessMethodDefinition:
178
+ Enabled: true
179
+ Lint/UselessTimes:
180
+ Enabled: true
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,18 +10,20 @@ 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
 
21
23
  Add this line to your application's Gemfile:
22
24
 
23
25
  ```ruby
24
- gem 'unleash', '~> 3.2.3'
26
+ gem 'unleash', '~> 4.0.0'
25
27
  ```
26
28
 
27
29
  And then execute:
@@ -34,22 +36,29 @@ Or install it yourself as:
34
36
 
35
37
  ## Configure
36
38
 
37
- It is **required** to configure the `url` of the unleash server and `app_name` with the name of the runninng application. Please substitute the sample `'http://unleash.herokuapp.com/api'` for the url of your own instance.
39
+ It is **required** to configure:
40
+ - `url` of the unleash server
41
+ - `app_name` with the name of the runninng application.
42
+ - `custom_http_headers` with `{'Authorization': '<API token>'}` when using Unleash v4.0.0 and later.
38
43
 
39
- It is **highly recommended** to configure the `instance_id` parameter as well.
44
+ Please substitute the example `'http://unleash.herokuapp.com/api'` for the url of your own instance.
45
+
46
+ It is **highly recommended** to configure:
47
+ - `instance_id` parameter with a unique identifier for the running instance.
40
48
 
41
49
 
42
50
  ```ruby
43
51
  Unleash.configure do |config|
44
- config.url = 'http://unleash.herokuapp.com/api'
45
- config.app_name = 'my_ruby_app'
52
+ config.app_name = 'my_ruby_app'
53
+ config.url = 'http://unleash.herokuapp.com/api'
54
+ config.custom_http_headers = {'Authorization': '<API token>'}
46
55
  end
47
56
  ```
48
57
 
49
58
  or instantiate the client with the valid configuration:
50
59
 
51
60
  ```ruby
52
- UNLEASH = Unleash::Client.new(url: 'http://unleash.herokuapp.com/api', app_name: 'my_ruby_app')
61
+ UNLEASH = Unleash::Client.new(url: 'http://unleash.herokuapp.com/api', app_name: 'my_ruby_app', custom_http_headers: {'Authorization': '<API token>'})
53
62
  ```
54
63
 
55
64
  #### List of Arguments
@@ -60,19 +69,25 @@ Argument | Description | Required? | Type | Default Value|
60
69
  `app_name` | Name of your program. | Y | String | N/A |
61
70
  `instance_id` | Identifier for the running instance of program. Important so you can trace back to where metrics are being collected from. **Highly recommended be be set.** | N | String | random UUID |
62
71
  `environment` | Environment the program is running on. Could be for example `prod` or `dev`. Not yet in use. | N | String | `default` |
72
+ `project_name` | Name of the project to retrieve features from. If not set, all feature flags will be retrieved. | N | String | nil |
63
73
  `refresh_interval` | How often the unleash client should check with the server for configuration changes. | N | Integer | 15 |
64
- `metrics_interval` | How often the unleash client should send metrics to server. | N | Integer | 10 |
74
+ `metrics_interval` | How often the unleash client should send metrics to server. | N | Integer | 60 |
65
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` |
66
76
  `disable_metrics` | Disables sending metrics to Unleash server. | N | Boolean | `false` |
67
- `custom_http_headers` | Custom headers to send to Unleash. | N | Hash | {} |
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 | {} |
68
78
  `timeout` | How long to wait for the connection to be established or wait in reading state (open_timeout/read_timeout) | N | Integer | 30 |
69
79
  `retry_limit` | How many consecutive failures in connecting to the Unleash server are allowed before giving up. Use `Float::INFINITY` if you would like it to never give up. | N | Numeric | 5 |
70
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` |
71
81
  `logger` | Specify a custom `Logger` class to handle logs for the Unleash client. | N | Class | `Logger.new(STDOUT)` |
72
- `log_level` | Change the log level for the `Logger` class. Constant from `Logger::Severity`. | N | Constant | `Logger::ERROR` |
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` |
73
84
 
74
- 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`.
75
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
76
91
 
77
92
  ## Usage in a plain Ruby Application
78
93
 
@@ -80,7 +95,7 @@ For in a more in depth look, please see `lib/unleash/configuration.rb`.
80
95
  require 'unleash'
81
96
  require 'unleash/context'
82
97
 
83
- @unleash = Unleash::Client.new(url: 'http://unleash.herokuapp.com/api', app_name: 'my_ruby_app')
98
+ @unleash = Unleash::Client.new(app_name: 'my_ruby_app', url: 'http://unleash.herokuapp.com/api', custom_http_headers: { 'Authorization': '<API token>' })
84
99
 
85
100
  feature_name = "AwesomeFeature"
86
101
  unleash_context = Unleash::Context.new
@@ -101,8 +116,8 @@ Put in `config/initializers/unleash.rb`:
101
116
 
102
117
  ```ruby
103
118
  Unleash.configure do |config|
104
- config.url = 'http://unleash.herokuapp.com/api'
105
119
  config.app_name = Rails.application.class.parent.to_s
120
+ config.url = 'http://unleash.herokuapp.com/api'
106
121
  # config.instance_id = "#{Socket.gethostname}"
107
122
  config.logger = Rails.logger
108
123
  config.environment = Rails.env
@@ -122,9 +137,10 @@ on_worker_boot do
122
137
  # ...
123
138
 
124
139
  Unleash.configure do |config|
125
- config.url = 'http://unleash.herokuapp.com/api'
126
- config.app_name = Rails.application.class.parent.to_s
140
+ config.app_name = Rails.application.class.parent.to_s
127
141
  config.environment = Rails.env
142
+ config.url = 'http://unleash.herokuapp.com/api'
143
+ config.custom_http_headers = {'Authorization': '<API token>'}
128
144
  end
129
145
  Rails.configuration.unleash = Unleash::Client.new
130
146
  end
@@ -132,6 +148,28 @@ end
132
148
 
133
149
  Instead of the configuration in `config/initializers/unleash.rb`.
134
150
 
151
+ #### Add Initializer if using [Phusion Passenger](https://github.com/phusion/passenger)
152
+
153
+ The unleash client needs to be configured and instantiated inside the `PhusionPassenger.on_event(:starting_worker_process)` code block due to [smart spawning](https://www.phusionpassenger.com/library/indepth/ruby/spawn_methods/#smart-spawning-caveats):
154
+
155
+ The initializer in `config/initializers/unleash.rb` should look like:
156
+
157
+ ```ruby
158
+ PhusionPassenger.on_event(:starting_worker_process) do |forked|
159
+ if forked
160
+ Unleash.configure do |config|
161
+ config.app_name = Rails.application.class.parent.to_s
162
+ # config.instance_id = "#{Socket.gethostname}"
163
+ config.logger = Rails.logger
164
+ config.environment = Rails.env
165
+ config.url = 'http://unleash.herokuapp.com/api'
166
+ config.custom_http_headers = {'Authorization': '<API token>'}
167
+ end
168
+
169
+ UNLEASH = Unleash::Client.new
170
+ end
171
+ end
172
+ ```
135
173
 
136
174
  #### Set Unleash::Context
137
175
 
@@ -180,6 +218,40 @@ if UNLEASH.is_enabled? "AwesomeFeature", @unleash_context, true
180
218
  end
181
219
  ```
182
220
 
221
+ Another possibility is to send a block, [Lambda](https://ruby-doc.org/core-3.0.1/Kernel.html#method-i-lambda) or [Proc](https://ruby-doc.org/core-3.0.1/Proc.html#method-i-yield)
222
+ to evaluate the default value:
223
+
224
+ ```ruby
225
+ net_check_proc = proc do |feature_name, context|
226
+ context.remote_address.starts_with?("10.0.0.")
227
+ end
228
+
229
+ if UNLEASH.is_enabled?("AwesomeFeature", @unleash_context, &net_check_proc)
230
+ puts "AwesomeFeature is enabled by default if you are in the 10.0.0.* network."
231
+ end
232
+ ```
233
+
234
+ or
235
+
236
+ ```ruby
237
+ awesomeness = 10
238
+ @unleash_context.properties[:coolness] = 10
239
+
240
+ if UNLEASH.is_enabled?("AwesomeFeature", @unleash_context) { |feat, ctx| awesomeness >= 6 && ctx.properties[:coolness] >= 8 }
241
+ puts "AwesomeFeature is enabled by default if both the user has a high enought coolness and the application has a high enough awesomeness"
242
+ end
243
+ ```
244
+
245
+ Note:
246
+ - The block/lambda/proc can use feature name and context as an arguments.
247
+ - The client will evaluate the fallback function once per call of `is_enabled()`.
248
+ Please keep this in mind when creating your fallback function!
249
+ - The returned value of the block should be a boolean.
250
+ However the client will coerce the result to boolean via `!!`.
251
+ - If both a `default_value` and `fallback_function` are supplied,
252
+ the client will define the default value by `OR`ing the default value and the output of the fallback function.
253
+
254
+
183
255
  Alternatively by using `if_enabled` you can send a code block to be executed as a parameter:
184
256
 
185
257
  ```ruby
@@ -188,6 +260,8 @@ UNLEASH.if_enabled "AwesomeFeature", @unleash_context, true do
188
260
  end
189
261
  ```
190
262
 
263
+ Note: `if_enabled` only supports `default_value`, but not `fallback_function`.
264
+
191
265
  ##### Variations
192
266
 
193
267
  If no variant is found in the server, use the fallback variant.
@@ -199,6 +273,62 @@ variant = UNLEASH.get_variant "ColorVariants", @unleash_context, fallback_varian
199
273
  puts "variant color is: #{variant.payload.fetch('color')}"
200
274
  ```
201
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.
202
332
 
203
333
  #### Client methods
204
334
 
@@ -211,6 +341,7 @@ Method Name | Description | Return Type |
211
341
  `shutdown` | Save metrics to disk, flush metrics to server, and then kill ToggleFetcher and MetricsReporter threads. A safe shutdown. Not really useful in long running applications, like web applications. | nil |
212
342
  `shutdown!` | Kill ToggleFetcher and MetricsReporter threads immediately. | nil |
213
343
 
344
+ For the full method signatures, please see [client.rb](lib/unleash/client.rb)
214
345
 
215
346
  ## Local test client
216
347
 
@@ -228,6 +359,7 @@ This client comes with the all the required strategies out of the box:
228
359
 
229
360
  * ApplicationHostnameStrategy
230
361
  * DefaultStrategy
362
+ * FlexibleRolloutStrategy
231
363
  * GradualRolloutRandomStrategy
232
364
  * GradualRolloutSessionIdStrategy
233
365
  * GradualRolloutUserIdStrategy
@@ -235,7 +367,6 @@ This client comes with the all the required strategies out of the box:
235
367
  * UnknownStrategy
236
368
  * UserWithIdStrategy
237
369
 
238
-
239
370
  ## Development
240
371
 
241
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.
data/bin/unleash-client CHANGED
@@ -12,11 +12,13 @@ options = {
12
12
  url: 'http://localhost:4242',
13
13
  demo: false,
14
14
  disable_metrics: true,
15
+ custom_http_headers: {},
15
16
  sleep: 0.1
16
17
  }
17
18
 
18
19
  OptionParser.new do |opts|
19
- opts.banner = "Usage: #{__FILE__} [options] feature [key1=val1] [key2=val2]"
20
+ opts.banner = "Usage: #{__FILE__} [options] feature [contextKey1=val1] [contextKey2=val2] \n\n" \
21
+ "Where contextKey1 could be user_id, session_id, remote_address or any field in the Context class (or any property within it).\n"
20
22
 
21
23
  opts.on("-V", "--variant", "Fetch variant for feature") do |v|
22
24
  options[:variant] = v
@@ -46,6 +48,13 @@ OptionParser.new do |opts|
46
48
  options[:sleep] = s
47
49
  end
48
50
 
51
+ opts.on("-H", "--http-headers='Authorization: *:developement.secretstring'",
52
+ "Adds http headers to all requests on the unleash server. Use multiple times for multiple headers.") do |h|
53
+ http_header_as_hash = [h].to_h{ |l| l.split(": ") }.transform_keys(&:to_sym)
54
+
55
+ options[:custom_http_headers].merge!(http_header_as_hash)
56
+ end
57
+
49
58
  opts.on("-h", "--help", "Prints this help") do
50
59
  puts opts
51
60
  exit
@@ -70,10 +79,11 @@ log_level = \
70
79
  url: options[:url],
71
80
  app_name: 'unleash-client-ruby-cli',
72
81
  disable_metrics: options[:metrics],
82
+ custom_http_headers: options[:custom_http_headers],
73
83
  log_level: log_level
74
84
  )
75
85
 
76
- context_params = ARGV.map{ |e| e.split("=") }.map{ |k, v| [k.to_sym, v] }.to_h
86
+ context_params = ARGV.to_h{ |l| l.split("=") }.transform_keys(&:to_sym)
77
87
  context_properties = context_params.reject{ |k, _v| [:user_id, :session_id, :remote_address].include? k }
78
88
  context_params.select!{ |k, _v| [:user_id, :session_id, :remote_address].include? k }
79
89
  context_params.merge!(properties: context_properties) unless context_properties.nil?
@@ -97,12 +107,12 @@ if options[:demo]
97
107
  end
98
108
  elsif options[:variant]
99
109
  variant = @unleash.get_variant(feature_name, unleash_context)
100
- puts " For feature \'#{feature_name}\' got variant \'#{variant}\'"
110
+ puts " For feature '#{feature_name}' got variant '#{variant}'"
101
111
  else
102
112
  if @unleash.is_enabled?(feature_name, unleash_context)
103
- puts " \'#{feature_name}\' is enabled according to unleash"
113
+ puts " '#{feature_name}' is enabled according to unleash"
104
114
  else
105
- puts " \'#{feature_name}\' is disabled according to unleash"
115
+ puts " '#{feature_name}' is disabled according to unleash"
106
116
  end
107
117
  end
108
118
 
@@ -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
+