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:
Diffstat (limited to 'lib/gitlab/experimentation.rb')
-rw-r--r--lib/gitlab/experimentation.rb180
1 files changed, 39 insertions, 141 deletions
diff --git a/lib/gitlab/experimentation.rb b/lib/gitlab/experimentation.rb
index 1ce3ffe4c86..6e39776bbd4 100644
--- a/lib/gitlab/experimentation.rb
+++ b/lib/gitlab/experimentation.rb
@@ -6,6 +6,7 @@
# Experiment options:
# - environment (optional, defaults to enabled for development and GitLab.com)
# - tracking_category (optional, used to set the category when tracking an experiment event)
+# - use_backwards_compatible_subject_index (optional, set this to true if you need backwards compatibility)
#
# The experiment is controlled by a Feature Flag (https://docs.gitlab.com/ee/development/feature_flags/controls.html),
# which is named "#{experiment_key}_experiment_percentage" and *must* be set with a percentage and not be used for other purposes.
@@ -30,168 +31,60 @@
module Gitlab
module Experimentation
EXPERIMENTS = {
- signup_flow: {
- tracking_category: 'Growth::Acquisition::Experiment::SignUpFlow'
- },
onboarding_issues: {
- tracking_category: 'Growth::Conversion::Experiment::OnboardingIssues'
- },
- suggest_pipeline: {
- tracking_category: 'Growth::Expansion::Experiment::SuggestPipeline'
+ tracking_category: 'Growth::Conversion::Experiment::OnboardingIssues',
+ use_backwards_compatible_subject_index: true
},
ci_notification_dot: {
- tracking_category: 'Growth::Expansion::Experiment::CiNotificationDot'
+ tracking_category: 'Growth::Expansion::Experiment::CiNotificationDot',
+ use_backwards_compatible_subject_index: true
},
upgrade_link_in_user_menu_a: {
- tracking_category: 'Growth::Expansion::Experiment::UpgradeLinkInUserMenuA'
+ tracking_category: 'Growth::Expansion::Experiment::UpgradeLinkInUserMenuA',
+ use_backwards_compatible_subject_index: true
},
invite_members_version_a: {
- tracking_category: 'Growth::Expansion::Experiment::InviteMembersVersionA'
+ tracking_category: 'Growth::Expansion::Experiment::InviteMembersVersionA',
+ use_backwards_compatible_subject_index: true
},
invite_members_version_b: {
- tracking_category: 'Growth::Expansion::Experiment::InviteMembersVersionB'
+ tracking_category: 'Growth::Expansion::Experiment::InviteMembersVersionB',
+ use_backwards_compatible_subject_index: true
+ },
+ invite_members_empty_group_version_a: {
+ tracking_category: 'Growth::Expansion::Experiment::InviteMembersEmptyGroupVersionA',
+ use_backwards_compatible_subject_index: true
},
new_create_project_ui: {
- tracking_category: 'Manage::Import::Experiment::NewCreateProjectUi'
+ tracking_category: 'Manage::Import::Experiment::NewCreateProjectUi',
+ use_backwards_compatible_subject_index: true
},
contact_sales_btn_in_app: {
- tracking_category: 'Growth::Conversion::Experiment::ContactSalesInApp'
+ tracking_category: 'Growth::Conversion::Experiment::ContactSalesInApp',
+ use_backwards_compatible_subject_index: true
},
customize_homepage: {
- tracking_category: 'Growth::Expansion::Experiment::CustomizeHomepage'
+ tracking_category: 'Growth::Expansion::Experiment::CustomizeHomepage',
+ use_backwards_compatible_subject_index: true
},
invite_email: {
- tracking_category: 'Growth::Acquisition::Experiment::InviteEmail'
+ tracking_category: 'Growth::Acquisition::Experiment::InviteEmail',
+ use_backwards_compatible_subject_index: true
},
invitation_reminders: {
- tracking_category: 'Growth::Acquisition::Experiment::InvitationReminders'
+ tracking_category: 'Growth::Acquisition::Experiment::InvitationReminders',
+ use_backwards_compatible_subject_index: true
},
group_only_trials: {
- tracking_category: 'Growth::Conversion::Experiment::GroupOnlyTrials'
+ tracking_category: 'Growth::Conversion::Experiment::GroupOnlyTrials',
+ use_backwards_compatible_subject_index: true
},
default_to_issues_board: {
- tracking_category: 'Growth::Conversion::Experiment::DefaultToIssuesBoard'
+ tracking_category: 'Growth::Conversion::Experiment::DefaultToIssuesBoard',
+ use_backwards_compatible_subject_index: true
}
}.freeze
- GROUP_CONTROL = :control
- GROUP_EXPERIMENTAL = :experimental
-
- # 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
- # to controllers and views. It returns true when the experiment is enabled and the user is selected as part
- # of the experimental group.
- #
- module ControllerConcern
- extend ActiveSupport::Concern
-
- included do
- before_action :set_experimentation_subject_id_cookie, unless: :dnt_enabled?
- helper_method :experiment_enabled?, :experiment_tracking_category_and_group
- end
-
- def set_experimentation_subject_id_cookie
- return if cookies[:experimentation_subject_id].present?
-
- cookies.permanent.signed[:experimentation_subject_id] = {
- value: SecureRandom.uuid,
- secure: ::Gitlab.config.gitlab.https,
- httponly: true
- }
- end
-
- def push_frontend_experiment(experiment_key)
- var_name = experiment_key.to_s.camelize(:lower)
- enabled = experiment_enabled?(experiment_key)
-
- gon.push({ experiments: { var_name => enabled } }, true)
- end
-
- def experiment_enabled?(experiment_key)
- return false if dnt_enabled?
-
- return true if Experimentation.enabled_for_value?(experiment_key, experimentation_subject_index)
- return true if forced_enabled?(experiment_key)
-
- false
- end
-
- def track_experiment_event(experiment_key, action, value = nil)
- return if dnt_enabled?
-
- track_experiment_event_for(experiment_key, action, value) 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)
- return if dnt_enabled?
-
- track_experiment_event_for(experiment_key, action, value) do |tracking_data|
- gon.push(tracking_data: tracking_data)
- end
- end
-
- def record_experiment_user(experiment_key)
- return if dnt_enabled?
- return unless Experimentation.enabled?(experiment_key) && current_user
-
- ::Experiment.add_user(experiment_key, tracking_group(experiment_key), current_user)
- end
-
- def experiment_tracking_category_and_group(experiment_key)
- "#{tracking_category(experiment_key)}:#{tracking_group(experiment_key, '_group')}"
- end
-
- private
-
- def dnt_enabled?
- Gitlab::Utils.to_boolean(request.headers['DNT'])
- end
-
- def experimentation_subject_id
- cookies.signed[:experimentation_subject_id]
- end
-
- def experimentation_subject_index
- return if experimentation_subject_id.blank?
-
- experimentation_subject_id.delete('-').hex % 100
- end
-
- def track_experiment_event_for(experiment_key, action, value)
- return unless Experimentation.enabled?(experiment_key)
-
- yield experimentation_tracking_data(experiment_key, action, value)
- end
-
- def experimentation_tracking_data(experiment_key, action, value)
- {
- category: tracking_category(experiment_key),
- action: action,
- property: tracking_group(experiment_key, "_group"),
- label: experimentation_subject_id,
- value: value
- }.compact
- end
-
- def tracking_category(experiment_key)
- Experimentation.experiment(experiment_key).tracking_category
- end
-
- def tracking_group(experiment_key, suffix = nil)
- return unless Experimentation.enabled?(experiment_key)
-
- group = experiment_enabled?(experiment_key) ? GROUP_EXPERIMENTAL : GROUP_CONTROL
-
- suffix ? "#{group}#{suffix}" : group
- end
-
- def forced_enabled?(experiment_key)
- params.has_key?(:force_experiment) && params[:force_experiment] == experiment_key.to_s
- end
- end
-
class << self
def experiment(key)
Experiment.new(EXPERIMENTS[key].merge(key: key))
@@ -201,7 +94,7 @@ module Gitlab
return false unless EXPERIMENTS.key?(experiment_key)
experiment = experiment(experiment_key)
- experiment.enabled? && experiment.enabled_for_environment?
+ experiment.enabled_for_environment? && experiment.enabled?
end
def enabled_for_attribute?(experiment_key, attribute)
@@ -209,13 +102,18 @@ module Gitlab
enabled_for_value?(experiment_key, index)
end
- def enabled_for_value?(experiment_key, experimentation_subject_index)
- enabled?(experiment_key) &&
- experiment(experiment_key).enabled_for_index?(experimentation_subject_index)
+ def enabled_for_value?(experiment_key, value)
+ enabled?(experiment_key) && experiment(experiment_key).enabled_for_index?(value)
end
end
- Experiment = Struct.new(:key, :environment, :tracking_category, keyword_init: true) do
+ Experiment = Struct.new(
+ :key,
+ :environment,
+ :tracking_category,
+ :use_backwards_compatible_subject_index,
+ keyword_init: true
+ ) do
def enabled?
experiment_percentage > 0
end