gitlab-experiment 0.7.0 → 0.7.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b6d54c567ebebd09762fb8bbd93940efb449f99d546a62776889caebedda6387
4
- data.tar.gz: 87a37b577f0545885ce4c2d6db92f750781017c2235b4d89f0f5db977bec045c
3
+ metadata.gz: 83f13c3f8259c739163ada749acee80ecbfb48f1b94f66a4cd69e265c29df874
4
+ data.tar.gz: e70fca76e1af2f6234d888473a31cdf088bf44d0bb5dc13dbf84f40e781076bd
5
5
  SHA512:
6
- metadata.gz: ed428cb380868eb7e94e9a5b4753c7c09dd73656fa66da4bb90fc728b2e2a460cb8d7f24170e783a63c6c28f86d61b00cb99ae9065a3c02999e7518ecc79e2e2
7
- data.tar.gz: 001edc2f533b5a5c210ada04c73a335b51e0e377be05449f0ae86ba9da078655d54e860294dd8a66ea8564270345cbbd145dc789aae1eb7f76f074db1fd79be3
6
+ metadata.gz: 9d0964f78bfea29586c176cf001a335df04618e62dfd1a76952d5d12d643de6970d8eeec063b1a28255fabfad8a3fd2b47df233cea6d071b46d98d7867b97185
7
+ data.tar.gz: 172778e34c61ffe02f3d11e5538beef44ddd0f8c5e2f6029a449904264eb1365f2f013aad25648e3c1ee0fd19a015aa69a6e62de9867f87c339f8c36e4d14776
@@ -48,10 +48,8 @@ Gitlab::Experiment.configure do |config|
48
48
  # end
49
49
  #
50
50
  # Included rollout strategies:
51
- # Gitlab::Experiment::Rollout::Percent, (recommended)
52
- # Gitlab::Experiment::Rollout::RoundRobin, or
53
- # Gitlab::Experiment::Rollout::Random
54
- config.default_rollout = Gitlab::Experiment::Rollout::Percent.new(
51
+ # :percent (recommended), :round_robin, or :random
52
+ config.default_rollout = :percent, {
55
53
  include_control: true # include control in possible assignments
56
54
  )
57
55
 
@@ -132,7 +130,7 @@ Gitlab::Experiment.configure do |config|
132
130
  # level1 initiated by file_name.rb:2
133
131
  # level2 initiated by file_name.rb:3
134
132
  config.nested_behavior = lambda do |nested_experiment|
135
- raise NestingError.new(experiment: self, nested_experiment: nested_experiment)
133
+ raise Gitlab::Experiment::NestingError.new(experiment: self, nested_experiment: nested_experiment)
136
134
  end
137
135
 
138
136
  # Called at the end of every experiment run, with the result.
@@ -66,10 +66,8 @@ module Gitlab
66
66
 
67
67
  store.write(cache_key, value)
68
68
  store.delete(old_key)
69
- return value
70
- end
71
-
72
- store.fetch(cache_key, &block)
69
+ break value
70
+ end || store.fetch(cache_key, &block)
73
71
  end
74
72
  end
75
73
  end
@@ -82,7 +82,7 @@ module Gitlab
82
82
  end
83
83
 
84
84
  def build_run_callback(filters, **options)
85
- set_callback(:run, *filters, **options)
85
+ set_callback(:run, *filters.compact, **options)
86
86
  end
87
87
 
88
88
  def build_callback(chain, *filters, **options)
@@ -56,12 +56,8 @@ module Gitlab
56
56
  # end
57
57
  #
58
58
  # Included rollout strategies:
59
- # Gitlab::Experiment::Rollout::Percent, (recommended)
60
- # Gitlab::Experiment::Rollout::RoundRobin, or
61
- # Gitlab::Experiment::Rollout::Random
62
- @default_rollout = Gitlab::Experiment::Rollout::Percent.new(
63
- include_control: true # include control in possible assignments
64
- )
59
+ # :percent, (recommended), :round_robin, or :random
60
+ @default_rollout = Rollout.resolve(:percent, include_control: true)
65
61
 
66
62
  # Secret seed used in generating context keys.
67
63
  #
@@ -241,7 +237,24 @@ module Gitlab
241
237
  :publishing_behavior
242
238
  )
243
239
 
244
- # Internal helpers warnings.
240
+ # Attribute method overrides.
241
+
242
+ def default_rollout=(args) # rubocop:disable Lint/DuplicateMethods
243
+ rollout, options = Array(args)
244
+ if rollout.is_a?(Rollout::Base)
245
+ options = rollout.options
246
+ rollout = rollout.class
247
+
248
+ deprecated(<<~MESSAGE, version: '0.7.0')
249
+ using a rollout instance with `default_rollout` is deprecated and will be removed from {{release}} (instead use `default_rollout = #{rollout.name}, #{options.inspect}`)
250
+ MESSAGE
251
+ end
252
+
253
+ @default_rollout = Rollout.resolve(rollout, options || {})
254
+ end
255
+
256
+ # Internal warning helpers.
257
+
245
258
  def deprecated(*args, version:, stack: 0)
246
259
  deprecator = deprecator(version)
247
260
  args << args.pop.to_s.gsub('{{release}}', "#{deprecator.gem_name} #{deprecator.deprecation_horizon}")
@@ -25,15 +25,25 @@ module Gitlab
25
25
  class Stack
26
26
  include Singleton
27
27
 
28
- @stack = []
28
+ delegate :pop, :length, :size, :[], to: :stack
29
29
 
30
30
  class << self
31
- delegate :pop, :length, :size, :[], to: :@stack
31
+ delegate :pop, :push, :length, :size, :[], to: :instance
32
+ end
33
+
34
+ def initialize
35
+ @thread_key = "#{self.class};#{object_id}".to_sym
36
+ end
37
+
38
+ def push(instance)
39
+ stack.last&.nest_experiment(instance)
40
+ stack.push(instance)
41
+ end
42
+
43
+ private
32
44
 
33
- def push(instance)
34
- @stack.last&.nest_experiment(instance)
35
- @stack.push(instance)
36
- end
45
+ def stack
46
+ Thread.current[@thread_key] ||= []
37
47
  end
38
48
  end
39
49
  end
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "zlib"
4
+
3
5
  # The percent rollout strategy is the most comprehensive included with Gitlab::Experiment. It allows specifying the
4
6
  # percentages per variant using an array, a hash, or will default to even distribution when no rules are provided.
5
7
  #
@@ -41,7 +43,7 @@ module Gitlab
41
43
  end
42
44
  end
43
45
 
44
- def execute_assigment
46
+ def execute_assignment
45
47
  crc = normalized_id
46
48
  total = 0
47
49
 
@@ -27,7 +27,7 @@ module Gitlab
27
27
  class Random < Base
28
28
  protected
29
29
 
30
- def execute_assigment
30
+ def execute_assignment
31
31
  behavior_names.sample # pick a random variant
32
32
  end
33
33
  end
@@ -31,7 +31,7 @@ module Gitlab
31
31
 
32
32
  protected
33
33
 
34
- def execute_assigment
34
+ def execute_assignment
35
35
  behavior_names[(cache.attr_inc(KEY_NAME) - 1) % behavior_names.size]
36
36
  end
37
37
  end
@@ -7,10 +7,17 @@ module Gitlab
7
7
  autoload :Random, 'gitlab/experiment/rollout/random.rb'
8
8
  autoload :RoundRobin, 'gitlab/experiment/rollout/round_robin.rb'
9
9
 
10
- def self.resolve(klass)
11
- return "#{name}::#{klass.to_s.classify}".constantize if klass.is_a?(Symbol) || klass.is_a?(String)
12
-
13
- klass
10
+ def self.resolve(klass, options = {})
11
+ case klass
12
+ when String
13
+ Strategy.new(klass.classify.constantize, options)
14
+ when Symbol
15
+ Strategy.new("#{name}::#{klass.to_s.classify}".constantize, options)
16
+ when Class
17
+ Strategy.new(klass, options)
18
+ else
19
+ raise ArgumentError, "unable to resolve rollout from #{klass.inspect}"
20
+ end
14
21
  end
15
22
 
16
23
  class Base
@@ -47,7 +54,7 @@ module Gitlab
47
54
 
48
55
  validate! # allow the rollout strategy to validate itself
49
56
 
50
- assignment = execute_assigment
57
+ assignment = execute_assignment
51
58
  assignment == :control ? nil : assignment # avoid caching control
52
59
  end
53
60
 
@@ -57,7 +64,7 @@ module Gitlab
57
64
  # base is always valid
58
65
  end
59
66
 
60
- def execute_assigment
67
+ def execute_assignment
61
68
  behavior_names.first
62
69
  end
63
70
 
@@ -73,6 +80,12 @@ module Gitlab
73
80
  options[:include_control] ? [:control] + variant_names : variant_names
74
81
  end
75
82
  end
83
+
84
+ Strategy = Struct.new(:klass, :options) do
85
+ def for(experiment)
86
+ klass.new(options).for(experiment)
87
+ end
88
+ end
76
89
  end
77
90
  end
78
91
  end
@@ -303,7 +303,7 @@ RSpec.configure do |config|
303
303
  config.include Gitlab::Experiment::RSpecHelpers
304
304
  config.include Gitlab::Experiment::Dsl
305
305
 
306
- config.before(:each, :experiment) do
306
+ clear_cache = proc do
307
307
  RequestStore.clear!
308
308
 
309
309
  if defined?(Gitlab::Experiment::TestBehaviors::TrackedStructure)
@@ -311,9 +311,14 @@ RSpec.configure do |config|
311
311
  end
312
312
  end
313
313
 
314
+ config.before(:each, :experiment, &clear_cache)
315
+ config.before(:each, type: :experiment, &clear_cache)
316
+
314
317
  config.include Gitlab::Experiment::RSpecMatchers, :experiment
315
- config.define_derived_metadata(file_path: Regexp.new('/spec/experiments/')) do |metadata|
316
- metadata[:type] = :experiment
318
+ config.include Gitlab::Experiment::RSpecMatchers, type: :experiment
319
+
320
+ config.define_derived_metadata(file_path: Regexp.new('spec/experiments/')) do |metadata|
321
+ metadata[:type] ||= :experiment
317
322
  end
318
323
 
319
324
  # We need to monkeypatch rspec-mocks because there's an issue around stubbing class methods that impacts us here.
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Gitlab
4
4
  class Experiment
5
- VERSION = '0.7.0'
5
+ VERSION = '0.7.1'
6
6
  end
7
7
  end
@@ -3,6 +3,7 @@
3
3
  require 'request_store'
4
4
  require 'active_support'
5
5
  require 'active_support/core_ext/module/delegation'
6
+ require 'active_support/core_ext/string/inflections'
6
7
 
7
8
  require 'gitlab/experiment/errors'
8
9
  require 'gitlab/experiment/base_interface'
@@ -68,7 +69,7 @@ module Gitlab
68
69
  def default_rollout(rollout = nil, options = {})
69
70
  return @_rollout ||= Configuration.default_rollout if rollout.blank?
70
71
 
71
- @_rollout = Rollout.resolve(rollout).new(options)
72
+ @_rollout = Rollout.resolve(rollout, options)
72
73
  end
73
74
 
74
75
  # Class level accessor methods.
@@ -145,7 +146,7 @@ module Gitlab
145
146
  def rollout(rollout = nil, options = {})
146
147
  return @_rollout ||= self.class.default_rollout(nil, options).for(self) if rollout.blank?
147
148
 
148
- @_rollout = Rollout.resolve(rollout).new(options).for(self)
149
+ @_rollout = Rollout.resolve(rollout, options).for(self)
149
150
  end
150
151
 
151
152
  def exclude!
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gitlab-experiment
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.0
4
+ version: 0.7.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - GitLab
@@ -45,53 +45,54 @@ executables: []
45
45
  extensions: []
46
46
  extra_rdoc_files: []
47
47
  files:
48
- - lib/generators/test_unit
49
- - lib/generators/test_unit/experiment
50
- - lib/generators/test_unit/experiment/templates
51
- - lib/generators/test_unit/experiment/templates/experiment_test.rb.tt
52
- - lib/generators/test_unit/experiment/experiment_generator.rb
53
- - lib/generators/rspec
54
- - lib/generators/rspec/experiment
55
- - lib/generators/rspec/experiment/templates
56
- - lib/generators/rspec/experiment/templates/experiment_spec.rb.tt
57
- - lib/generators/rspec/experiment/experiment_generator.rb
58
48
  - lib/generators/gitlab
59
49
  - lib/generators/gitlab/experiment
60
- - lib/generators/gitlab/experiment/USAGE
61
- - lib/generators/gitlab/experiment/templates
62
- - lib/generators/gitlab/experiment/templates/experiment.rb.tt
63
50
  - lib/generators/gitlab/experiment/install
51
+ - lib/generators/gitlab/experiment/install/install_generator.rb
64
52
  - lib/generators/gitlab/experiment/install/templates
65
53
  - lib/generators/gitlab/experiment/install/templates/application_experiment.rb.tt
66
54
  - lib/generators/gitlab/experiment/install/templates/initializer.rb.tt
67
55
  - lib/generators/gitlab/experiment/install/templates/POST_INSTALL
68
- - lib/generators/gitlab/experiment/install/install_generator.rb
56
+ - lib/generators/gitlab/experiment/USAGE
69
57
  - lib/generators/gitlab/experiment/experiment_generator.rb
58
+ - lib/generators/gitlab/experiment/templates
59
+ - lib/generators/gitlab/experiment/templates/experiment.rb.tt
60
+ - lib/generators/test_unit
61
+ - lib/generators/test_unit/experiment
62
+ - lib/generators/test_unit/experiment/experiment_generator.rb
63
+ - lib/generators/test_unit/experiment/templates
64
+ - lib/generators/test_unit/experiment/templates/experiment_test.rb.tt
65
+ - lib/generators/rspec
66
+ - lib/generators/rspec/experiment
67
+ - lib/generators/rspec/experiment/experiment_generator.rb
68
+ - lib/generators/rspec/experiment/templates
69
+ - lib/generators/rspec/experiment/templates/experiment_spec.rb.tt
70
+ - lib/gitlab/experiment.rb
70
71
  - lib/gitlab/experiment
71
- - lib/gitlab/experiment/dsl.rb
72
- - lib/gitlab/experiment/rspec.rb
73
- - lib/gitlab/experiment/context.rb
74
- - lib/gitlab/experiment/nestable.rb
75
- - lib/gitlab/experiment/configuration.rb
76
- - lib/gitlab/experiment/rollout.rb
72
+ - lib/gitlab/experiment/variant.rb
73
+ - lib/gitlab/experiment/middleware.rb
74
+ - lib/gitlab/experiment/test_behaviors
75
+ - lib/gitlab/experiment/test_behaviors/trackable.rb
77
76
  - lib/gitlab/experiment/cache
78
77
  - lib/gitlab/experiment/cache/redis_hash_store.rb
79
- - lib/gitlab/experiment/engine.rb
80
- - lib/gitlab/experiment/base_interface.rb
81
- - lib/gitlab/experiment/middleware.rb
82
- - lib/gitlab/experiment/version.rb
83
- - lib/gitlab/experiment/cookies.rb
84
78
  - lib/gitlab/experiment/errors.rb
85
- - lib/gitlab/experiment/cache.rb
86
- - lib/gitlab/experiment/variant.rb
79
+ - lib/gitlab/experiment/callbacks.rb
80
+ - lib/gitlab/experiment/rollout.rb
81
+ - lib/gitlab/experiment/base_interface.rb
82
+ - lib/gitlab/experiment/nestable.rb
83
+ - lib/gitlab/experiment/context.rb
84
+ - lib/gitlab/experiment/engine.rb
85
+ - lib/gitlab/experiment/rspec.rb
87
86
  - lib/gitlab/experiment/rollout
88
87
  - lib/gitlab/experiment/rollout/random.rb
89
- - lib/gitlab/experiment/rollout/percent.rb
90
88
  - lib/gitlab/experiment/rollout/round_robin.rb
91
- - lib/gitlab/experiment/callbacks.rb
92
- - lib/gitlab/experiment/test_behaviors
93
- - lib/gitlab/experiment/test_behaviors/trackable.rb
94
- - lib/gitlab/experiment.rb
89
+ - lib/gitlab/experiment/rollout/percent.rb
90
+ - lib/gitlab/experiment/rollout/concerns
91
+ - lib/gitlab/experiment/cache.rb
92
+ - lib/gitlab/experiment/version.rb
93
+ - lib/gitlab/experiment/cookies.rb
94
+ - lib/gitlab/experiment/configuration.rb
95
+ - lib/gitlab/experiment/dsl.rb
95
96
  - LICENSE.txt
96
97
  - README.md
97
98
  homepage: https://gitlab.com/gitlab-org/ruby/gems/gitlab-experiment