AB Experiment - allow without Application

(cherry picked from commit ea9fcbc3e22889ce853bb03126498534c5ee2c81)

IJ-CR-149437

GitOrigin-RevId: 6793cb58363fd34ccded57bf8010a3e4f60c6d35
This commit is contained in:
Sergey Pak
2024-11-13 17:30:36 +01:00
committed by intellij-monorepo-bot
parent bbb3b32bcb
commit 9ed3ab009e
6 changed files with 44 additions and 17 deletions

View File

@@ -4,12 +4,15 @@ package com.intellij.platform.experiment.ab.demo
import com.intellij.openapi.actionSystem.ActionUpdateThread
import com.intellij.openapi.actionSystem.AnAction
import com.intellij.openapi.actionSystem.AnActionEvent
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.components.service
import com.intellij.platform.experiment.ab.impl.bundle.ABExperimentBundle
import com.intellij.platform.experiment.ab.impl.experiment.ABExperimentImpl
import com.intellij.platform.experiment.ab.impl.experiment.getABExperimentInstance
internal class ABExperimentDemoAction : AnAction(ABExperimentBundle.message("experiment.ab.demo.action.name")) {
override fun actionPerformed(e: AnActionEvent) {
val service = getABExperimentInstance()
val service = ApplicationManager.getApplication().service<ABExperimentImpl>()
println("User experiment option is: " + service.getUserExperimentOption())
println("User experiment option id is: " + service.getUserExperimentOptionId())

View File

@@ -17,7 +17,7 @@ import com.intellij.util.MathUtil
import com.intellij.util.PlatformUtils
fun getABExperimentInstance(): ABExperiment {
return ApplicationManager.getApplication().service<ABExperiment>()
return ABExperiment.getABExperimentInstance()
}
/**
@@ -44,9 +44,29 @@ fun getABExperimentInstance(): ABExperiment {
* @see com.intellij.platform.experiment.ab.impl.option.ABExperimentControlOption
* @see com.intellij.platform.experiment.ab.impl.experiment.ABExperimentGroupStorageService
*/
@Service
class ABExperiment {
interface ABExperiment {
companion object {
fun getABExperimentInstance(): ABExperiment {
val application = ApplicationManager.getApplication() ?: return DummyABExperiment
return application.service<ABExperimentImpl>()
}
}
fun isControlExperimentOptionEnabled() : Boolean
fun isExperimentOptionEnabled(experimentOptionClass: Class<out ABExperimentOption>): Boolean
}
internal object DummyABExperiment : ABExperiment {
// is never a control group
override fun isControlExperimentOptionEnabled(): Boolean = false
// always turned on
override fun isExperimentOptionEnabled(experimentOptionClass: Class<out ABExperimentOption>): Boolean = true
}
@Service
internal class ABExperimentImpl : ABExperiment {
companion object {
private val AB_EXPERIMENTAL_OPTION_EP = ExtensionPointName<ABExperimentOptionBean>("com.intellij.experiment.abExperimentOption")
private val LOG = logger<ABExperiment>()
@@ -71,11 +91,11 @@ class ABExperiment {
internal fun isPopularIDE() = PlatformUtils.isIdeaUltimate() || PlatformUtils.isPyCharmPro()
}
fun isControlExperimentOptionEnabled(): Boolean {
override fun isControlExperimentOptionEnabled(): Boolean {
return isExperimentOptionEnabled(ABExperimentControlOption::class.java)
}
fun isExperimentOptionEnabled(experimentOptionClass: Class<out ABExperimentOption>): Boolean {
override fun isExperimentOptionEnabled(experimentOptionClass: Class<out ABExperimentOption>): Boolean {
return experimentOptionClass.isInstance(getUserExperimentOption())
}

View File

@@ -6,8 +6,8 @@ import com.intellij.ide.plugins.PluginStateManager
import com.intellij.openapi.components.*
import com.intellij.openapi.diagnostic.debug
import com.intellij.openapi.diagnostic.logger
import com.intellij.platform.experiment.ab.impl.experiment.ABExperiment.Companion.OPTION_ID_FREE_GROUP
import com.intellij.platform.experiment.ab.impl.experiment.ABExperiment.Companion.TOTAL_NUMBER_OF_GROUPS
import com.intellij.platform.experiment.ab.impl.experiment.ABExperimentImpl.Companion.OPTION_ID_FREE_GROUP
import com.intellij.platform.experiment.ab.impl.experiment.ABExperimentImpl.Companion.TOTAL_NUMBER_OF_GROUPS
/**
* This storage is used to ensure that option groups are assigned properly.
@@ -65,7 +65,7 @@ internal class ABExperimentGroupStorageService : PersistentStateComponent<ABExpe
val groupNumberToExperimentOptionId = myState.groupNumberToExperimentOptionId
LOG.debug { "State BEFORE update is: $groupNumberToExperimentOptionId" }
val optionBeans = ABExperiment.getJbABExperimentOptionBeanList()
val optionBeans = ABExperimentImpl.getJbABExperimentOptionBeanList()
val usedOptionIds = groupNumberToExperimentOptionId.values.toSet()
val newOptionBeans = optionBeans.filter { it.instance.id.value !in usedOptionIds }
@@ -73,7 +73,7 @@ internal class ABExperimentGroupStorageService : PersistentStateComponent<ABExpe
return
}
val isPopularIDE = ABExperiment.isPopularIDE()
val isPopularIDE = ABExperimentImpl.isPopularIDE()
for (newOptionBean in newOptionBeans) {
val newOption = newOptionBean.instance
@@ -102,8 +102,8 @@ internal class ABExperimentGroupStorageService : PersistentStateComponent<ABExpe
OPTION_ID_FREE_GROUP.value
}).toMutableMap()
val isPopularIDE = ABExperiment.isPopularIDE()
val options = ABExperiment.getJbABExperimentOptionList().sortedBy { it.id.value }
val isPopularIDE = ABExperimentImpl.isPopularIDE()
val options = ABExperimentImpl.getJbABExperimentOptionList().sortedBy { it.id.value }
var counter = 0

View File

@@ -1,13 +1,15 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.platform.experiment.ab.impl.option
import com.intellij.platform.experiment.ab.impl.experiment.ABExperimentImpl
import com.intellij.platform.experiment.ab.impl.experiment.ABExperimentOption
import com.intellij.platform.experiment.ab.impl.experiment.ABExperimentOptionId
import com.intellij.platform.experiment.ab.impl.experiment.getABExperimentInstance
fun isControlOptionEnabled(): Boolean {
return getABExperimentInstance().getUserExperimentOption() is ABExperimentControlOption
val abImpl = getABExperimentInstance() as? ABExperimentImpl ?: return false
return abImpl.getUserExperimentOption() is ABExperimentControlOption
}
internal class ABExperimentControlOption : ABExperimentOption {

View File

@@ -5,6 +5,7 @@ import com.intellij.internal.statistic.eventLog.EventLogGroup
import com.intellij.internal.statistic.eventLog.events.EventFields
import com.intellij.internal.statistic.service.fus.collectors.CounterUsagesCollector
import com.intellij.platform.experiment.ab.impl.experiment.ABExperiment
import com.intellij.platform.experiment.ab.impl.experiment.ABExperimentImpl
import com.intellij.platform.experiment.ab.impl.experiment.ABExperimentOptionId
object ABExperimentCountCollector : CounterUsagesCollector() {
@@ -32,12 +33,12 @@ object ABExperimentCountCollector : CounterUsagesCollector() {
return
}
if (userOptionId == ABExperiment.OPTION_ID_FREE_GROUP) {
if (userOptionId == ABExperimentImpl.OPTION_ID_FREE_GROUP) {
AB_EXPERIMENT_OPTION_USED.log(userOptionId.value, userGroupNumber, userBucketNumber)
return
}
val option = ABExperiment.getJbABExperimentOptionList().find { it.id.value == userOptionId.value }
val option = ABExperimentImpl.getJbABExperimentOptionList().find { it.id.value == userOptionId.value }
if (option != null) {
AB_EXPERIMENT_OPTION_USED.log(option.id.value, userGroupNumber, userBucketNumber)
return

View File

@@ -5,14 +5,15 @@ import com.intellij.internal.statistic.eventLog.validator.ValidationResultType
import com.intellij.internal.statistic.eventLog.validator.rules.EventContext
import com.intellij.internal.statistic.eventLog.validator.rules.impl.CustomValidationRule
import com.intellij.platform.experiment.ab.impl.experiment.ABExperiment
import com.intellij.platform.experiment.ab.impl.experiment.ABExperiment.Companion.OPTION_ID_FREE_GROUP
import com.intellij.platform.experiment.ab.impl.experiment.ABExperimentImpl
import com.intellij.platform.experiment.ab.impl.experiment.ABExperimentImpl.Companion.OPTION_ID_FREE_GROUP
import com.intellij.platform.experiment.ab.impl.statistic.ABExperimentCountCollector.OPTION_ID_MISSING
class ABExperimentOptionIdValidationRule : CustomValidationRule() {
override fun getRuleId(): String = "ab_experiment_option_id"
override fun doValidate(data: String, context: EventContext): ValidationResultType {
return if (ABExperiment.getJbABExperimentOptionList().any { it.id.value == data } ||
return if (ABExperimentImpl.getJbABExperimentOptionList().any { it.id.value == data } ||
data == OPTION_ID_FREE_GROUP.value ||
data == OPTION_ID_MISSING.value)
ValidationResultType.ACCEPTED