gitlab-experiment 0.5.3 → 0.5.4

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: 1c4e4a4b19b67700aab0629cd615617c4452d8b4b145ef8ff85d12443994362b
4
- data.tar.gz: 802c31143890f2431a80ed3dcb247cbf46247ce276053e8e27a4d190822650df
3
+ metadata.gz: 9d7bc7a1946d06b5188ccfe761342209779f75cf635d894bb8743519ff2830dc
4
+ data.tar.gz: 7a5c347f8b58e5caa2fe814ce013dbf1ca71f6e017148528a0ff2ca74bd562de
5
5
  SHA512:
6
- metadata.gz: 86f86cd9dd01006be9668a2ceb4d60351e943487576d236e12b40eb9405e4255fdbbffb0c5811b17a4f1c8d2784b011eb20bc783e622f4f4f05fc6fb166f0df3
7
- data.tar.gz: bca224adeaade21b59077effd1faa0d6ca95607fe02f6c7735b8c9b79b7d5a08f76675549ddbc874ce63adbe39895d7b3f6f1fb71e908ae22a76c817a1d0f88d
6
+ metadata.gz: '01927d9db97ad4b087d445db642aa39615faa68322e2bd0e0b82ae99441478bae3f1939b94956218121fe52d01f432836ba272d0b1ff052537c80f0d0ff107b3'
7
+ data.tar.gz: f53702ea5bb97fe6c73427850534b9e156744336a37029dce2b96926b70b7a5c4959708ac626f6ac0435125ad4ffe62f2ba9fd528f756af811c6ff66abc47846
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'scientist'
4
+ require 'request_store'
4
5
  require 'active_support/callbacks'
5
6
  require 'active_support/cache'
6
7
  require 'active_support/concern'
@@ -27,10 +28,10 @@ module Gitlab
27
28
  include Callbacks
28
29
 
29
30
  class << self
30
- def default_rollout(rollout = nil)
31
+ def default_rollout(rollout = nil, options = {})
31
32
  return @rollout ||= Configuration.default_rollout if rollout.blank?
32
33
 
33
- @rollout = Rollout.resolve(rollout)
34
+ @rollout = Rollout.resolve(rollout).new(options)
34
35
  end
35
36
 
36
37
  def exclude(*filter_list, **options, &block)
@@ -44,6 +45,10 @@ module Gitlab
44
45
  target.variant(variant) if target.instance_variable_get(:@variant_name).nil? && callback.call(target, nil)
45
46
  end
46
47
  end
48
+
49
+ def published_experiments
50
+ RequestStore.store[:published_gitlab_experiments] || {}
51
+ end
47
52
  end
48
53
 
49
54
  def name
@@ -85,10 +90,10 @@ module Gitlab
85
90
  @resolving_variant = false
86
91
  end
87
92
 
88
- def rollout(rollout = nil)
89
- return @rollout ||= self.class.default_rollout if rollout.blank?
93
+ def rollout(rollout = nil, options = {})
94
+ return @rollout ||= self.class.default_rollout(nil, options) if rollout.blank?
90
95
 
91
- @rollout = Rollout.resolve(rollout)
96
+ @rollout = Rollout.resolve(rollout).new(options)
92
97
  end
93
98
 
94
99
  def exclude!
@@ -101,6 +106,8 @@ module Gitlab
101
106
 
102
107
  def publish(result)
103
108
  instance_exec(result, &Configuration.publishing_behavior)
109
+
110
+ (RequestStore.store[:published_gitlab_experiments] ||= {})[name] = signature.merge(excluded: excluded?)
104
111
  end
105
112
 
106
113
  def track(action, **event_args)
@@ -131,8 +138,8 @@ module Gitlab
131
138
  { variant: variant.name, experiment: name }.merge(context.signature)
132
139
  end
133
140
 
134
- def key_for(hash)
135
- instance_exec(hash, &Configuration.context_hash_strategy)
141
+ def key_for(source, seed = name)
142
+ instance_exec(source, seed, &Configuration.context_hash_strategy)
136
143
  end
137
144
 
138
145
  protected
@@ -144,7 +151,7 @@ module Gitlab
144
151
  end
145
152
 
146
153
  def resolve_variant_name
147
- rollout.new(self).execute if experiment_group?
154
+ rollout.rollout_for(self) if experiment_group?
148
155
  end
149
156
  end
150
157
  end
@@ -26,8 +26,10 @@ module Gitlab
26
26
  # The domain to use on cookies.
27
27
  @cookie_domain = :all
28
28
 
29
- # The default rollout strategy that works for single and multi-variants.
30
- @default_rollout = Rollout::First
29
+ # The default rollout strategy only works for single variant experiments.
30
+ # It's expected that you use a more advanced rollout for multiple variant
31
+ # experiments.
32
+ @default_rollout = Rollout::Base.new
31
33
 
32
34
  # Logic this project uses to determine inclusion in a given experiment.
33
35
  # Expected to return a boolean value.
@@ -45,10 +47,11 @@ module Gitlab
45
47
  track(:assignment)
46
48
  end
47
49
 
48
- # Algorithm that consistently generates a hash key for a given hash map.
49
- @context_hash_strategy = lambda do |hash_map|
50
- values = hash_map.values.map { |v| (v.respond_to?(:to_global_id) ? v.to_global_id : v).to_s }
51
- Digest::MD5.hexdigest(([name] + hash_map.keys + values).join('|'))
50
+ # Algorithm that consistently generates a hash key for a given source.
51
+ @context_hash_strategy = lambda do |source, seed|
52
+ source = source.keys + source.values if source.is_a?(Hash)
53
+ data = Array(source).map { |v| (v.respond_to?(:to_global_id) ? v.to_global_id : v).to_s }
54
+ Digest::MD5.hexdigest(data.unshift(seed).join('|'))
52
55
  end
53
56
 
54
57
  class << self
@@ -3,7 +3,6 @@
3
3
  module Gitlab
4
4
  class Experiment
5
5
  module Rollout
6
- autoload :First, 'gitlab/experiment/rollout/first.rb' # default strategy
7
6
  autoload :Random, 'gitlab/experiment/rollout/random.rb'
8
7
  autoload :RoundRobin, 'gitlab/experiment/rollout/round_robin.rb'
9
8
 
@@ -18,8 +17,17 @@ module Gitlab
18
17
 
19
18
  delegate :variant_names, :cache, to: :experiment
20
19
 
21
- def initialize(experiment)
20
+ def initialize(options = {})
21
+ @options = options
22
+ end
23
+
24
+ def rollout_for(experiment)
22
25
  @experiment = experiment
26
+ execute
27
+ end
28
+
29
+ def execute
30
+ variant_names.first
23
31
  end
24
32
  end
25
33
  end
@@ -232,6 +232,10 @@ RSpec.configure do |config|
232
232
  config.include Gitlab::Experiment::RSpecHelpers
233
233
  config.include Gitlab::Experiment::Dsl
234
234
 
235
+ config.before(:each, :experiment) do
236
+ RequestStore.clear!
237
+ end
238
+
235
239
  config.include Gitlab::Experiment::RSpecMatchers, :experiment
236
240
  config.define_derived_metadata(file_path: Regexp.new('/spec/experiments/')) do |metadata|
237
241
  metadata[:type] = :experiment
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Gitlab
4
4
  class Experiment
5
- VERSION = '0.5.3'
5
+ VERSION = '0.5.4'
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gitlab-experiment
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.3
4
+ version: 0.5.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - GitLab
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-04-06 00:00:00.000000000 Z
11
+ date: 2021-05-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -24,6 +24,20 @@ dependencies:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: '3.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: request_store
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '1.0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '1.0'
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: scientist
29
43
  requirement: !ruby/object:Gem::Requirement
@@ -75,7 +89,6 @@ files:
75
89
  - lib/gitlab/experiment/dsl.rb
76
90
  - lib/gitlab/experiment/engine.rb
77
91
  - lib/gitlab/experiment/rollout.rb
78
- - lib/gitlab/experiment/rollout/first.rb
79
92
  - lib/gitlab/experiment/rollout/random.rb
80
93
  - lib/gitlab/experiment/rollout/round_robin.rb
81
94
  - lib/gitlab/experiment/rspec.rb
@@ -100,7 +113,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
100
113
  - !ruby/object:Gem::Version
101
114
  version: '0'
102
115
  requirements: []
103
- rubygems_version: 3.1.4
116
+ rubygems_version: 3.2.17
104
117
  signing_key:
105
118
  specification_version: 4
106
119
  summary: GitLab experiment library built on top of scientist.
@@ -1,16 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Gitlab
4
- class Experiment
5
- module Rollout
6
- class First < Base
7
- # This rollout strategy just picks the first variant name. It's the
8
- # default resolver as it assumes a single variant. You should consider
9
- # using a more advanced rollout if you have multiple variants.
10
- def execute
11
- variant_names.first
12
- end
13
- end
14
- end
15
- end
16
- end