[ab] IJPL-186222: Drop old implementation

(cherry picked from commit 7278d60df00844be60eaf39efc278e2a1738ff6b)


(cherry picked from commit 09aeb31397b41611a0a3021fb807fd34b99ff3ea)

IJ-CR-176469

GitOrigin-RevId: 4cab7a72b9a4d6dc9c7e3c24c1fba5e71737f1bc
This commit is contained in:
Konstantin Nisht
2025-09-19 14:30:57 +02:00
committed by intellij-monorepo-bot
parent 2df6273b02
commit e930319079
17 changed files with 14 additions and 546 deletions

View File

@@ -1,25 +1,9 @@
<idea-plugin>
<extensionPoints>
<extensionPoint qualifiedName="com.intellij.experiment.abExperimentOption"
beanClass="com.intellij.platform.experiment.ab.impl.experiment.ABExperimentOptionBean"
dynamic="true">
<with attribute="implementation"
implements="com.intellij.platform.experiment.ab.impl.experiment.ABExperimentOption"/>
</extensionPoint>
</extensionPoints>
<extensions defaultExtensionNs="com.intellij">
<experiment.abExperimentOption implementation="com.intellij.platform.experiment.ab.impl.option.ABExperimentControlOption"/>
<statistics.counterUsagesCollector
implementationClass="com.intellij.platform.experiment.ab.impl.statistic.ABExperimentCountCollector"/>
<statistics.validation.customValidationRule
implementation="com.intellij.platform.experiment.ab.impl.statistic.ABExperimentOptionIdValidationRule"/>
<applicationService serviceInterface="com.intellij.platform.experiment.ab.impl.experiment.ABExperiment"
serviceImplementation="com.intellij.platform.experiment.ab.impl.experiment.ABExperimentImpl"/>
<experiment.abExperimentOption implementation="com.intellij.platform.experiment.ab.temporary.ShowTrialSurveyOption"/>
</extensions>
<actions>

View File

@@ -1,159 +0,0 @@
// 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.experiment
import com.intellij.internal.statistic.eventLog.fus.MachineIdManager
import com.intellij.internal.statistic.utils.getPluginInfoByDescriptor
import com.intellij.openapi.application.ApplicationInfo.getInstance
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.components.service
import com.intellij.openapi.diagnostic.debug
import com.intellij.openapi.diagnostic.logger
import com.intellij.openapi.diagnostic.runAndLogException
import com.intellij.openapi.extensions.ExtensionPointName
import com.intellij.platform.experiment.ab.impl.option.ABExperimentControlOption
import com.intellij.platform.experiment.ab.impl.statistic.ABExperimentCountCollector
import com.intellij.util.MathUtil
import com.intellij.util.PlatformUtils
fun getABExperimentInstance(): ABExperiment {
return ABExperiment.getABExperimentInstance()
}
/**
* This is a multi-optional A/B experiment for all IDEs and JetBrains plugins,
* which affects IDE metrics like user retention in the IDE.
*
* Each feature is represented as an option.
* An option defines the number of user groups which will be associated with this option.
* There is a control option for default behavior.
* You need to implement `ABExperimentOption` extension point to implement an option for your feature.
*
* The number of A/B experimental groups is limited.
* It is necessary to keep a group audience enough to make statistically significant conclusions.
* So it is crucial to choose group size judiciously.
* If group capacity is exhausted for a specific IDE, there will be an error.
* In such a case, you need to communicate with related people to handle such a case and rearrange option groups accordingly.
*
* A/B experiment supports the implemented options from JetBrains plugins.
* Plugins can be installed/uninstalled or enabled/disabled.
* Accordingly, the options defined in plugins may appear when the plugin is enabled or installed,
* or disappear when the plugin is disabled or uninstalled.
* The experiment uses special storage to be able to work with such conditions correctly.
*
* @see ABExperimentControlOption
* @see ABExperimentGroupStorageService
*/
interface ABExperiment {
companion object {
fun getABExperimentInstance(): ABExperiment {
val application = ApplicationManager.getApplication() ?: return DummyABExperiment
return application.service<ABExperiment>()
}
}
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
}
private val AB_EXPERIMENTAL_OPTION_EP: ExtensionPointName<ABExperimentOptionBean> =
ExtensionPointName("com.intellij.experiment.abExperimentOption")
private val LOG = logger<ABExperiment>()
private fun getDeviceIdPurpose(): String {
return "A/B Experiment" + getInstance().shortVersion
}
private const val TOTAL_NUMBER_OF_BUCKETS = 1024
internal const val TOTAL_NUMBER_OF_GROUPS = 256
internal val OPTION_ID_FREE_GROUP = ABExperimentOptionId("free.option")
internal fun isPopularIDE(): Boolean = PlatformUtils.isIdeaUltimate() || PlatformUtils.isPyCharmPro()
internal fun getJbABExperimentOptionList(): List<ABExperimentOption> {
return getJbABExperimentOptionBeanList().map { it.instance }
}
internal fun getJbABExperimentOptionBeanList(): List<ABExperimentOptionBean> {
return AB_EXPERIMENTAL_OPTION_EP.extensionList.filter {
val pluginDescriptor = it.pluginDescriptor
val pluginInfo = getPluginInfoByDescriptor(pluginDescriptor)
pluginInfo.isDevelopedByJetBrains() && it.instance.isEnabled()
}
}
internal class ABExperimentImpl : ABExperiment {
override fun isControlExperimentOptionEnabled(): Boolean {
return isExperimentOptionEnabled(ABExperimentControlOption::class.java)
}
override fun isExperimentOptionEnabled(experimentOptionClass: Class<out ABExperimentOption>): Boolean {
return experimentOptionClass.isInstance(getUserExperimentOption())
}
internal fun getUserExperimentOption(): ABExperimentOption? {
val userOptionId = getUserExperimentOptionId()
ABExperimentCountCollector.logABExperimentOptionUsed(userOptionId, getUserGroupNumber(), getUserBucketNumber())
return getJbABExperimentOptionList().find { it.id.value == userOptionId?.value }
}
internal fun getUserExperimentOptionId(): ABExperimentOptionId? {
val manualOptionIdText = System.getProperty("platform.experiment.ab.manual.option", "")
if (manualOptionIdText.isNotBlank()) {
LOG.debug { "Use manual option id from Registry. Registry key value is: $manualOptionIdText" }
val manualOption = getJbABExperimentOptionList().find { it.id.value == manualOptionIdText }
if (manualOption != null) {
LOG.debug { "Found manual option is: $manualOption" }
return manualOption.id
}
else if (manualOptionIdText == OPTION_ID_FREE_GROUP.value) {
LOG.debug { "Found manual option is: $manualOptionIdText" }
return ABExperimentOptionId(manualOptionIdText)
}
else {
LOG.debug { "Manual option with id $manualOptionIdText not found." }
return null
}
}
val userGroupNumber = getUserGroupNumber()
val userOptionId = ABExperimentGroupStorageService.getUserExperimentOptionId(userGroupNumber)
LOG.debug { "User option id is: ${userOptionId.value}." }
return userOptionId
}
private fun getUserGroupNumber(): Int {
val bucket = getUserBucketNumber()
if (TOTAL_NUMBER_OF_BUCKETS < TOTAL_NUMBER_OF_GROUPS) {
LOG.error("Number of buckets is less than number of groups. " +
"Please revise related experiment constants and adjust them accordingly.")
}
val experimentGroup = bucket % TOTAL_NUMBER_OF_GROUPS
LOG.debug { "User group number is: $experimentGroup." }
return experimentGroup
}
private fun getUserBucketNumber(): Int {
val deviceId = LOG.runAndLogException {
MachineIdManager.getAnonymizedMachineId(getDeviceIdPurpose())
}
val bucketNumber = MathUtil.nonNegativeAbs(deviceId.hashCode()) % TOTAL_NUMBER_OF_BUCKETS
LOG.debug { "User bucket number is: $bucketNumber." }
return bucketNumber
}
}

View File

@@ -1,122 +0,0 @@
// 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.experiment
import com.intellij.ide.plugins.DynamicPluginEnabler
import com.intellij.ide.plugins.PluginStateManager
import com.intellij.openapi.components.*
import com.intellij.openapi.diagnostic.debug
import com.intellij.openapi.diagnostic.logger
/**
* This storage is used to ensure that option groups are assigned properly.
* It maintains a map from a group's number to an assigned option id.
* It uses a special id to mark free groups.
*
* At the start, the map is initialized with available options.
* After that, for each event of plugin enabling/disabling/installing/uninstalling and after startup,
* it checks new available options and puts its id into the map.
* Ids of options that become not available are not removed from the map.
* This is to avoid mixing different options with the user and
* handle a case when a user enables and disables a plugin several times.
*
* @see com.intellij.platform.experiment.ab.impl.experiment.OPTION_ID_FREE_GROUP
*/
@Service(Service.Level.APP)
@State(
name = "ABExperimentGroupStorageService",
storages = [Storage("ABExperimentGroupStorageService.xml", roamingType = RoamingType.DISABLED)]
)
internal class ABExperimentGroupStorageService : PersistentStateComponent<ABExperimentGroupStorage> {
companion object {
private val LOG = logger<ABExperimentGroupStorageService>()
fun getUserExperimentOptionId(userGroupNumber: Int): ABExperimentOptionId {
val experimentOptionIdText = service<ABExperimentGroupStorageService>().state.groupNumberToExperimentOptionId[userGroupNumber]!!
return ABExperimentOptionId(experimentOptionIdText)
}
}
private lateinit var myState: ABExperimentGroupStorage
override fun getState(): ABExperimentGroupStorage {
return myState
}
override fun loadState(state: ABExperimentGroupStorage) {
myState = state
}
override fun noStateLoaded() {
myState = ABExperimentGroupStorage(getInitialGroupToOptionState())
}
override fun initializeComponent() {
val tracker = ABExperimentPluginTracker()
PluginStateManager.addStateListener(tracker)
DynamicPluginEnabler.addPluginStateChangedListener(tracker)
setupNewPluginABExperimentOptions()
}
internal fun setupNewPluginABExperimentOptions() {
val groupNumberToExperimentOptionId = myState.groupNumberToExperimentOptionId
LOG.debug { "State BEFORE update is: $groupNumberToExperimentOptionId" }
val optionBeans = getJbABExperimentOptionBeanList()
val usedOptionIds = groupNumberToExperimentOptionId.values.toSet()
val newOptionBeans = optionBeans.filter { it.instance.id.value !in usedOptionIds }
if (newOptionBeans.isEmpty()) {
return
}
val isPopularIDE = isPopularIDE()
for (newOptionBean in newOptionBeans) {
val newOption = newOptionBean.instance
val groupCount = newOption.getGroupSizeForIde(isPopularIDE).groupCount
for (i in 0 until groupCount) {
val freeGroupKey = groupNumberToExperimentOptionId.entries.find { entry ->
entry.value == OPTION_ID_FREE_GROUP.value
}?.key
if (freeGroupKey == null) {
LOG.error("There is no available groups for option ${newOption.id} from plugin " +
newOptionBean.pluginDescriptor.pluginId.idString)
return
}
LOG.debug { "Assign experiment option ${newOption.id} to group $freeGroupKey." }
groupNumberToExperimentOptionId[freeGroupKey] = newOption.id.value
}
}
LOG.debug { "State AFTER update is: $groupNumberToExperimentOptionId" }
}
private fun getInitialGroupToOptionState(): MutableMap<Int, String> {
val initialGroupNumberToExperimentOptionId = (0.rangeUntil(TOTAL_NUMBER_OF_GROUPS).associateWith {
OPTION_ID_FREE_GROUP.value
}).toMutableMap()
val isPopularIDE = isPopularIDE()
val options = getJbABExperimentOptionList().sortedBy { it.id.value }
var counter = 0
for (option in options) {
val optionGroupsCount = option.getGroupSizeForIde(isPopularIDE).groupCount
for (groupNumber in counter.rangeUntil(counter + optionGroupsCount)) {
LOG.debug { "Assign experiment option ${option.id} to group $groupNumber." }
initialGroupNumberToExperimentOptionId[groupNumber] = option.id.value
}
counter += optionGroupsCount
}
LOG.debug { "Initial state of group to option map is: $initialGroupNumberToExperimentOptionId" }
return initialGroupNumberToExperimentOptionId
}
}
internal data class ABExperimentGroupStorage(val groupNumberToExperimentOptionId: MutableMap<Int, String>)

View File

@@ -1,55 +0,0 @@
// 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.experiment
import com.intellij.platform.experiment.ab.impl.option.ABExperimentOptionGroupSize
/**
* A/B Experiment option interface.
*
* Implement and register an option for your feature.
*/
interface ABExperimentOption {
val id: ABExperimentOptionId
/**
* Returns the size of an audience group for the option.
*
* The number of A/B experimental groups is limited.
* The group size must be agreed with the analysts so that the result of the experiment is statistically significant.
*
* If group capacity is exhausted for a specific IDE, there will be an error in runtime.
* In such a case, you need to communicate with related persons with other options
* to handle such a case and rearrange option groups accordingly.
*
* @param isPopularIde true if the current IDE is popular.
* It can be used to adjust the group size of the option accordingly.
* Popular IDEs have more users, and the group size should be smaller than it is in other IDEs.
*
* @see com.intellij.platform.experiment.ab.impl.experiment.TOTAL_NUMBER_OF_GROUPS
*/
fun getGroupSizeForIde(isPopularIde: Boolean): ABExperimentOptionGroupSize
/**
* Check if the option should be enabled in a certain IDE.
*
* Mostly useful for options in Intellij Platform to enable option only in certain IDEs.
*/
fun checkIdeIsSuitable(): Boolean
/**
* Check if the option should be enabled in a certain IDE version.
*
* Must be agreed with analytics to do not spoil an experiment.
*
* Mostly useful for plugins that potentially can be installed to a different version of a certain IDE.
* In this case, the plugin must specify the target version so as not to spoil the experiment
* by overflowing the maximum number of user groups.
*
* For IDEs, it allows to control in what version of IDE what options are enabled.
*/
fun checkIdeVersionIsSuitable(): Boolean
}
fun ABExperimentOption.isEnabled(): Boolean {
return checkIdeIsSuitable() && checkIdeVersionIsSuitable()
}

View File

@@ -1,17 +0,0 @@
// 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.experiment
import com.intellij.openapi.extensions.RequiredElement
import com.intellij.serviceContainer.BaseKeyedLazyInstance
import com.intellij.util.xmlb.annotations.Attribute
class ABExperimentOptionBean : BaseKeyedLazyInstance<ABExperimentOption>() {
@Attribute("implementation")
@JvmField
@RequiredElement
var implementationClass: String? = null
override fun getImplementationClassName(): String? {
return implementationClass
}
}

View File

@@ -1,5 +0,0 @@
// 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.experiment
@JvmInline
value class ABExperimentOptionId(val value: String)

View File

@@ -1,25 +0,0 @@
// 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.experiment
import com.intellij.ide.plugins.IdeaPluginDescriptor
import com.intellij.ide.plugins.PluginEnableStateChangedListener
import com.intellij.ide.plugins.PluginStateListener
import com.intellij.openapi.components.service
internal class ABExperimentPluginTracker : PluginStateListener, PluginEnableStateChangedListener {
override fun stateChanged(pluginDescriptors: Collection<IdeaPluginDescriptor>, enable: Boolean) {
if (!enable) {
return
}
service<ABExperimentGroupStorageService>().setupNewPluginABExperimentOptions()
}
override fun install(descriptor: IdeaPluginDescriptor) {
service<ABExperimentGroupStorageService>().setupNewPluginABExperimentOptions()
}
override fun uninstall(descriptor: IdeaPluginDescriptor) {
service<ABExperimentGroupStorageService>().setupNewPluginABExperimentOptions()
}
}

View File

@@ -1,5 +0,0 @@
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
@ApiStatus.Internal
package com.intellij.platform.experiment.ab.impl.experiment;
import org.jetbrains.annotations.ApiStatus;

View File

@@ -17,9 +17,10 @@ import kotlin.math.absoluteValue
* The plugins are welcome to use [ABExperimentOption.isEnabled] to check whether the experiment is enabled on the user's machine
*/
enum class ABExperimentOption {
EXPERIMENT_1,
EXPERIMENT_2,
EXPERIMENT_3,
KUBERNETES_SEPARATE_SERVICE_VIEW,
FUZZY_FILE_SEARCH,
SHOW_TRIAL_SURVEY,
NEW_USERS_ONBOARDING,
/**
* A group for users which are not assigned to any experiment.
@@ -49,10 +50,9 @@ internal const val NUMBER_OF_BUCKETS: Int = 1024
*/
@VisibleForTesting
internal val experimentsPartition: List<ExperimentAssignment> = listOf(
ExperimentAssignment(experiment = EXPERIMENT_1, experimentBuckets = (0 until 180).toSet(), controlBuckets = (180 until 256).toSet()),
ExperimentAssignment(experiment = EXPERIMENT_2, experimentBuckets = (256 until 384).toSet(), controlBuckets = (384 until 512).toSet()),
ExperimentAssignment(experiment = EXPERIMENT_3, experimentBuckets = (512 until 640).toSet(), controlBuckets = (640 until 768).toSet()),
// the rest belongs to the unassigned experiment
ExperimentAssignment(experiment = KUBERNETES_SEPARATE_SERVICE_VIEW, experimentBuckets = (0 until 128).toSet(), controlBuckets = (128 until 256).toSet()),
ExperimentAssignment(experiment = FUZZY_FILE_SEARCH, experimentBuckets = (256 until 512).toSet(), controlBuckets = (512 until 768).toSet()),
// the rest belongs to the "unassigned" experiment
)
/**

View File

@@ -1,30 +0,0 @@
// 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 {
val abImpl = getABExperimentInstance() as? ABExperimentImpl ?: return false
return abImpl.getUserExperimentOption() is ABExperimentControlOption
}
internal class ABExperimentControlOption : ABExperimentOption {
override val id: ABExperimentOptionId = ABExperimentOptionId("control.option")
override fun getGroupSizeForIde(isPopularIde: Boolean): ABExperimentOptionGroupSize {
return ABExperimentOptionGroupSize(32)
}
override fun checkIdeIsSuitable(): Boolean {
return true
}
override fun checkIdeVersionIsSuitable(): Boolean {
return true
}
}

View File

@@ -1,20 +0,0 @@
// 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
/**
* Represent experiment option user group size.
*
* Must be greater than 0 and less than the total number of user groups.
*
* The group size must be agreed with the analysts so that the result of the experiment is statistically significant.
*
* @see com.intellij.platform.experiment.ab.impl.experiment.TOTAL_NUMBER_OF_GROUPS
*/
@JvmInline
value class ABExperimentOptionGroupSize(val groupCount: Int) {
init {
if (groupCount <= 0) {
error("Size of option group should be greater then 0.")
}
}
}

View File

@@ -1,5 +0,0 @@
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
@ApiStatus.Internal
package com.intellij.platform.experiment.ab.impl.option;
import org.jetbrains.annotations.ApiStatus;

View File

@@ -1,36 +1,15 @@
// Copyright 2000-2025 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.temporary
import com.intellij.openapi.application.ApplicationInfo
import com.intellij.platform.experiment.ab.impl.experiment.ABExperiment
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.option.ABExperimentOptionGroupSize
import com.intellij.util.PlatformUtils
import com.intellij.platform.experiment.ab.impl.ABExperimentOption
import org.jetbrains.annotations.ApiStatus
@ApiStatus.Internal
class ShowTrialSurveyOption : ABExperimentOption {
override val id: ABExperimentOptionId = ABExperimentOptionId("showTrialSurvey")
override fun getGroupSizeForIde(isPopularIde: Boolean): ABExperimentOptionGroupSize {
return ABExperimentOptionGroupSize(192)
}
override fun checkIdeIsSuitable(): Boolean = PlatformUtils.isIdeaUltimate()
/**
* Experiment should be available only in 2024.3.5
*/
override fun checkIdeVersionIsSuitable(): Boolean {
val appInfo = ApplicationInfo.getInstance()
return appInfo.majorVersion == "2024" && appInfo.minorVersion.startsWith("3.5")
}
class ShowTrialSurveyOption {
@Suppress("CompanionObjectInExtension")
companion object {
@JvmStatic
val isTrialSurveyEnabled: Boolean get() = System.getProperty("test.ide.trial.survey", "false").toBoolean() ||
ABExperiment.getABExperimentInstance().isExperimentOptionEnabled(ShowTrialSurveyOption::class.java)
ABExperimentOption.SHOW_TRIAL_SURVEY.isEnabled()
}
}

View File

@@ -1,36 +1,11 @@
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.ide.util.gotoByName
import com.intellij.openapi.application.ApplicationInfo
import com.intellij.openapi.util.registry.Registry.Companion.`is`
import com.intellij.platform.experiment.ab.impl.experiment.ABExperiment
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.option.ABExperimentOptionGroupSize
import com.intellij.platform.experiment.ab.impl.ABExperimentOption
import org.jetbrains.annotations.ApiStatus
@ApiStatus.Internal
internal fun isFuzzyFileSearchEnabled(): Boolean {
return `is`("search.everywhere.fuzzy.file.search.ab.experiment.enabled", false) &&
ABExperiment.getABExperimentInstance().isExperimentOptionEnabled(FuzzyFileSearchExperimentOption::class.java)
}
@ApiStatus.Internal
internal class FuzzyFileSearchExperimentOption : ABExperimentOption {
override val id: ABExperimentOptionId = ABExperimentOptionId(FUZZY_FILE_SEARCH_EXPERIMENT_OPTION_ID)
override fun getGroupSizeForIde(isPopularIde: Boolean): ABExperimentOptionGroupSize {
return ABExperimentOptionGroupSize(128)
}
override fun checkIdeIsSuitable(): Boolean = true
override fun checkIdeVersionIsSuitable(): Boolean {
val appInfo = ApplicationInfo.getInstance()
return appInfo.isEAP && appInfo.majorVersion == "2025" && appInfo.minorVersionMainPart == "2"
}
companion object {
const val FUZZY_FILE_SEARCH_EXPERIMENT_OPTION_ID = "fuzzyFileSearch"
}
return `is`("search.everywhere.fuzzy.file.search.enabled", false) || ABExperimentOption.FUZZY_FILE_SEARCH.isEnabled()
}

View File

@@ -17,8 +17,6 @@
<notificationGroup displayType="BALLOON" id="newUsersOnboarding" bundle="messages.NewUsersOnboardingBundle"
key="notification.group"/>
<experiment.abExperimentOption implementation="com.intellij.platform.ide.newUsersOnboarding.NewUsersOnboardingExperimentOption"/>
<statistics.counterUsagesCollector implementationClass="com.intellij.platform.ide.newUsersOnboarding.NewUsersOnboardingStatistics"/>
</extensions>

View File

@@ -7,7 +7,7 @@ import com.intellij.openapi.components.Service
import com.intellij.openapi.components.serviceAsync
import com.intellij.openapi.extensions.ExtensionNotApplicableException
import com.intellij.openapi.util.registry.Registry
import com.intellij.platform.experiment.ab.impl.experiment.getABExperimentInstance
import com.intellij.platform.experiment.ab.impl.ABExperimentOption
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import org.jetbrains.annotations.ApiStatus
@@ -20,7 +20,7 @@ class NewUsersOnboardingExperiment {
* Since it is not changed during IDE session, better to calculate it once.
*/
private val isExperimentEnabled: Boolean by lazy {
getABExperimentInstance().isExperimentOptionEnabled(NewUsersOnboardingExperimentOption::class.java)
ABExperimentOption.NEW_USERS_ONBOARDING.isEnabled()
}
fun isEnabled(): Boolean {

View File

@@ -1,25 +0,0 @@
// 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.ide.newUsersOnboarding
import com.intellij.openapi.application.ApplicationInfo
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.option.ABExperimentOptionGroupSize
internal class NewUsersOnboardingExperimentOption : ABExperimentOption {
override val id: ABExperimentOptionId = ABExperimentOptionId("newUsersOnboarding")
override fun getGroupSizeForIde(isPopularIde: Boolean): ABExperimentOptionGroupSize {
return ABExperimentOptionGroupSize(128)
}
override fun checkIdeIsSuitable(): Boolean = true
/**
* Experiment should be available only in 2024.2.1
*/
override fun checkIdeVersionIsSuitable(): Boolean {
val appInfo = ApplicationInfo.getInstance()
return appInfo.majorVersion == "2024" && appInfo.minorVersion == "2.1"
}
}