gitlab-experiment 0.5.3 → 0.5.4

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: 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