Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2020-12-17 14:59:07 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2020-12-17 14:59:07 +0300
commit8b573c94895dc0ac0e1d9d59cf3e8745e8b539ca (patch)
tree544930fb309b30317ae9797a9683768705d664c4 /lib/gitlab/experimentation
parent4b1de649d0168371549608993deac953eb692019 (diff)
Add latest changes from gitlab-org/gitlab@13-7-stable-eev13.7.0-rc42
Diffstat (limited to 'lib/gitlab/experimentation')
-rw-r--r--lib/gitlab/experimentation/controller_concern.rb80
-rw-r--r--lib/gitlab/experimentation/experiment.rb31
2 files changed, 81 insertions, 30 deletions
diff --git a/lib/gitlab/experimentation/controller_concern.rb b/lib/gitlab/experimentation/controller_concern.rb
index c6d15d7d82d..c85d3f4eee6 100644
--- a/lib/gitlab/experimentation/controller_concern.rb
+++ b/lib/gitlab/experimentation/controller_concern.rb
@@ -3,7 +3,7 @@
require 'zlib'
# Controller concern that checks if an `experimentation_subject_id cookie` is present and sets it if absent.
-# Used for A/B testing of experimental features. Exposes the `experiment_enabled?(experiment_name)` method
+# Used for A/B testing of experimental features. Exposes the `experiment_enabled?(experiment_name, subject: nil)` method
# to controllers and views. It returns true when the experiment is enabled and the user is selected as part
# of the experimental group.
#
@@ -28,47 +28,56 @@ module Gitlab
}
end
- def push_frontend_experiment(experiment_key)
+ def push_frontend_experiment(experiment_key, subject: nil)
var_name = experiment_key.to_s.camelize(:lower)
- enabled = experiment_enabled?(experiment_key)
+
+ enabled = experiment_enabled?(experiment_key, subject: subject)
gon.push({ experiments: { var_name => enabled } }, true)
end
- def experiment_enabled?(experiment_key)
+ def experiment_enabled?(experiment_key, subject: nil)
+ return true if forced_enabled?(experiment_key)
return false if dnt_enabled?
- return true if Experimentation.enabled_for_value?(experiment_key, experimentation_subject_index(experiment_key))
- return true if forced_enabled?(experiment_key)
+ subject ||= fallback_experimentation_subject_index(experiment_key)
- false
+ Experimentation.in_experiment_group?(experiment_key, subject: subject)
end
- def track_experiment_event(experiment_key, action, value = nil)
+ def track_experiment_event(experiment_key, action, value = nil, subject: nil)
return if dnt_enabled?
- track_experiment_event_for(experiment_key, action, value) do |tracking_data|
+ track_experiment_event_for(experiment_key, action, value, subject: subject) do |tracking_data|
::Gitlab::Tracking.event(tracking_data.delete(:category), tracking_data.delete(:action), **tracking_data)
end
end
- def frontend_experimentation_tracking_data(experiment_key, action, value = nil)
+ def frontend_experimentation_tracking_data(experiment_key, action, value = nil, subject: nil)
return if dnt_enabled?
- track_experiment_event_for(experiment_key, action, value) do |tracking_data|
+ track_experiment_event_for(experiment_key, action, value, subject: subject) do |tracking_data|
gon.push(tracking_data: tracking_data)
end
end
- def record_experiment_user(experiment_key)
+ def record_experiment_user(experiment_key, context = {})
+ return if dnt_enabled?
+ return unless Experimentation.active?(experiment_key) && current_user
+
+ ::Experiment.add_user(experiment_key, tracking_group(experiment_key, nil, subject: current_user), current_user, context)
+ end
+
+ def record_experiment_conversion_event(experiment_key)
return if dnt_enabled?
- return unless Experimentation.enabled?(experiment_key) && current_user
+ return unless current_user
+ return unless Experimentation.active?(experiment_key)
- ::Experiment.add_user(experiment_key, tracking_group(experiment_key), current_user)
+ ::Experiment.record_conversion_event(experiment_key, current_user)
end
- def experiment_tracking_category_and_group(experiment_key)
- "#{tracking_category(experiment_key)}:#{tracking_group(experiment_key, '_group')}"
+ def experiment_tracking_category_and_group(experiment_key, subject: nil)
+ "#{tracking_category(experiment_key)}:#{tracking_group(experiment_key, '_group', subject: subject)}"
end
private
@@ -81,40 +90,41 @@ module Gitlab
cookies.signed[:experimentation_subject_id]
end
- def experimentation_subject_index(experiment_key)
+ def fallback_experimentation_subject_index(experiment_key)
return if experimentation_subject_id.blank?
- if Experimentation.experiment(experiment_key).use_backwards_compatible_subject_index
- experimentation_subject_id.delete('-').hex % 100
+ if Experimentation.get_experiment(experiment_key).use_backwards_compatible_subject_index
+ experimentation_subject_id.delete('-')
else
- Zlib.crc32("#{experiment_key}#{experimentation_subject_id}") % 100
+ experimentation_subject_id
end
end
- def track_experiment_event_for(experiment_key, action, value)
- return unless Experimentation.enabled?(experiment_key)
+ def track_experiment_event_for(experiment_key, action, value, subject: nil)
+ return unless Experimentation.active?(experiment_key)
- yield experimentation_tracking_data(experiment_key, action, value)
+ yield experimentation_tracking_data(experiment_key, action, value, subject: subject)
end
- def experimentation_tracking_data(experiment_key, action, value)
+ def experimentation_tracking_data(experiment_key, action, value, subject: nil)
{
category: tracking_category(experiment_key),
action: action,
- property: tracking_group(experiment_key, "_group"),
- label: experimentation_subject_id,
+ property: tracking_group(experiment_key, "_group", subject: subject),
+ label: tracking_label(subject),
value: value
}.compact
end
def tracking_category(experiment_key)
- Experimentation.experiment(experiment_key).tracking_category
+ Experimentation.get_experiment(experiment_key).tracking_category
end
- def tracking_group(experiment_key, suffix = nil)
- return unless Experimentation.enabled?(experiment_key)
+ def tracking_group(experiment_key, suffix = nil, subject: nil)
+ return unless Experimentation.active?(experiment_key)
- group = experiment_enabled?(experiment_key) ? GROUP_EXPERIMENTAL : GROUP_CONTROL
+ subject ||= fallback_experimentation_subject_index(experiment_key)
+ group = experiment_enabled?(experiment_key, subject: subject) ? GROUP_EXPERIMENTAL : GROUP_CONTROL
suffix ? "#{group}#{suffix}" : group
end
@@ -122,6 +132,16 @@ module Gitlab
def forced_enabled?(experiment_key)
params.has_key?(:force_experiment) && params[:force_experiment] == experiment_key.to_s
end
+
+ def tracking_label(subject)
+ return experimentation_subject_id if subject.blank?
+
+ if subject.respond_to?(:to_global_id)
+ Digest::MD5.hexdigest(subject.to_global_id.to_s)
+ else
+ Digest::MD5.hexdigest(subject.to_s)
+ end
+ end
end
end
end
diff --git a/lib/gitlab/experimentation/experiment.rb b/lib/gitlab/experimentation/experiment.rb
new file mode 100644
index 00000000000..e594c3bedeb
--- /dev/null
+++ b/lib/gitlab/experimentation/experiment.rb
@@ -0,0 +1,31 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Experimentation
+ class Experiment
+ attr_reader :key, :tracking_category, :use_backwards_compatible_subject_index
+
+ def initialize(key, **params)
+ @key = key
+ @tracking_category = params[:tracking_category]
+ @use_backwards_compatible_subject_index = params[:use_backwards_compatible_subject_index]
+
+ @experiment_percentage = Feature.get(:"#{key}_experiment_percentage").percentage_of_time_value # rubocop:disable Gitlab/AvoidFeatureGet
+ end
+
+ def active?
+ ::Gitlab.dev_env_or_com? && experiment_percentage > 0
+ end
+
+ def enabled_for_index?(index)
+ return false if index.blank?
+
+ index <= experiment_percentage
+ end
+
+ private
+
+ attr_reader :experiment_percentage
+ end
+ end
+end