Report statistics for actions invoked from build tool windows (FUS-171)

This commit is contained in:
Vladislav.Soroka
2018-11-07 19:43:35 +03:00
parent 9eca38c983
commit c0802407e4
15 changed files with 234 additions and 42 deletions
@@ -43,12 +43,16 @@ import java.util.*;
public class ExternalSystemActionUtil {
public static void executeAction(final String actionId, final InputEvent e) {
executeAction(actionId, "", e);
}
public static void executeAction(final String actionId, @NotNull final String place, final InputEvent e) {
final ActionManager actionManager = ActionManager.getInstance();
final AnAction action = actionManager.getAction(actionId);
if (action != null) {
final Presentation presentation = new Presentation();
final AnActionEvent event =
new AnActionEvent(e, DataManager.getInstance().getDataContext(e.getComponent()), "", presentation, actionManager, 0);
new AnActionEvent(e, DataManager.getInstance().getDataContext(e.getComponent()), place, presentation, actionManager, 0);
action.update(event);
if (presentation.isEnabled()) {
action.actionPerformed(event);
@@ -0,0 +1,64 @@
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.openapi.externalSystem.action.task
import com.intellij.execution.Executor
import com.intellij.execution.ExecutorRegistry
import com.intellij.execution.actions.RunContextAction
import com.intellij.openapi.actionSystem.*
import com.intellij.openapi.externalSystem.model.ExternalSystemDataKeys
import com.intellij.openapi.externalSystem.statistics.ExternalSystemActionsCollector
import com.intellij.openapi.project.DumbAware
class ExternalSystemTaskMenu : DefaultActionGroup(), DumbAware {
override fun update(e: AnActionEvent) {
val project = AnAction.getEventProject(e) ?: return
childActionsOrStubs
.filter { it is MyDelegatingAction }
.forEach { remove(it) }
ExecutorRegistry.getInstance().registeredExecutors
.filter { it.isApplicable(project) }
.reversed()
.forEach { add(wrap(RunContextAction(it), it), Constraints.FIRST) }
}
private interface MyDelegatingAction
private class DelegatingActionGroup internal constructor(action: ActionGroup, private val executor: Executor) :
EmptyAction.MyDelegatingActionGroup(action), MyDelegatingAction {
override fun getChildren(e: AnActionEvent?): Array<AnAction> {
val children = super.getChildren(e)
return children.map { wrap(it, executor) }.toTypedArray()
}
override fun actionPerformed(e: AnActionEvent) {
reportUsage(e, executor)
super.actionPerformed(e)
}
}
private class DelegatingAction internal constructor(action: AnAction, private val executor: Executor) :
EmptyAction.MyDelegatingAction(action), MyDelegatingAction {
override fun actionPerformed(e: AnActionEvent) {
reportUsage(e, executor)
super.actionPerformed(e)
}
}
companion object {
private fun wrap(action: AnAction, executor: Executor): AnAction = if (action is ActionGroup) DelegatingActionGroup(action, executor)
else DelegatingAction(action, executor)
private fun reportUsage(e: AnActionEvent, executor: Executor) {
val project = e.project
val systemId = ExternalSystemDataKeys.EXTERNAL_SYSTEM_ID.getData(e.dataContext)
ExternalSystemActionsCollector.trigger(project, systemId, "RunExternalSystemTaskAction", e, executor.id)
}
}
}
@@ -9,6 +9,7 @@ import com.intellij.openapi.actionSystem.AnAction
import com.intellij.openapi.actionSystem.AnActionEvent
import com.intellij.openapi.externalSystem.model.ProjectSystemId
import com.intellij.openapi.project.Project
import com.intellij.util.text.nullize
class ExternalSystemActionsCollector : ProjectUsageTriggerCollector() {
override fun getGroupId(): String {
@@ -18,21 +19,52 @@ class ExternalSystemActionsCollector : ProjectUsageTriggerCollector() {
companion object {
@JvmStatic
fun trigger(project: Project?,
fusClass: Class<out ProjectUsageTriggerCollector>,
systemId: ProjectSystemId?,
action: AnAction,
event: AnActionEvent?) {
featureId: String,
place: String?,
isFromContextMenu: Boolean,
vararg additionalContextData: String) {
if (project == null) return
// preserve context data ordering
val context = FUSUsageContext.create(
"from.${event?.place ?: "undefined.place"}",
"fromContextMenu.${event?.isFromContextMenu?.toString() ?: "false"}",
systemId?.let { escapeSystemId(it) } ?: "undefined.system"
place.nullize() ?: "undefined place",
"fromContextMenu.$isFromContextMenu",
systemId?.let { escapeSystemId(it) } ?: "undefined.system",
*additionalContextData
)
FUSProjectUsageTrigger.getInstance(project).trigger(
ExternalSystemActionsCollector::class.java,
UsageDescriptorKeyValidator.ensureProperKey(action.javaClass.simpleName), context)
FUSProjectUsageTrigger.getInstance(project).trigger(fusClass, UsageDescriptorKeyValidator.ensureProperKey(featureId), context)
}
@JvmStatic
fun trigger(project: Project?,
systemId: ProjectSystemId?,
featureId: String,
place: String?,
isFromContextMenu: Boolean,
vararg additionalContextData: String) {
trigger(project, ExternalSystemActionsCollector::class.java, systemId, featureId, place, isFromContextMenu, *additionalContextData)
}
@JvmStatic
fun trigger(project: Project?,
systemId: ProjectSystemId?,
action: AnAction,
event: AnActionEvent?,
vararg additionalContextData: String) {
trigger(project, systemId, action.javaClass.simpleName, event, *additionalContextData)
}
@JvmStatic
fun trigger(project: Project?,
systemId: ProjectSystemId?,
featureId: String,
event: AnActionEvent?,
vararg additionalContextData: String) {
trigger(project, systemId, featureId, event?.place, event?.isFromContextMenu ?: false, *additionalContextData)
}
}
}
@@ -53,8 +53,8 @@ import org.jetbrains.annotations.Nullable;
import javax.swing.tree.TreeSelectionModel;
import java.awt.*;
import java.awt.event.InputEvent;
import java.util.*;
import java.util.List;
import java.util.*;
import java.util.stream.Collectors;
/**
@@ -103,6 +103,8 @@ public class ExternalProjectsViewImpl extends SimpleToolWindowPanel implements D
.filter(c -> ProjectSystemId.IDE.equals(c.getSystemId()) ||
myExternalSystemId.equals(c.getSystemId()))
.collect(Collectors.toList());
setName(myExternalSystemId.getReadableName() + " tool window");
}
@Nullable
@@ -257,7 +259,7 @@ public class ExternalProjectsViewImpl extends SimpleToolWindowPanel implements D
@Override
public void handleDoubleClickOrEnter(@NotNull ExternalSystemNode node, @Nullable String actionId, InputEvent inputEvent) {
if (actionId != null) {
ExternalSystemActionUtil.executeAction(actionId, inputEvent);
ExternalSystemActionUtil.executeAction(actionId, getName(), inputEvent);
}
for (Listener listener : listeners) {
listener.onDoubleClickOrEnter(node, inputEvent);
@@ -315,7 +317,7 @@ public class ExternalProjectsViewImpl extends SimpleToolWindowPanel implements D
if (id != null) {
final ActionGroup actionGroup = (ActionGroup)actionManager.getAction(id);
if (actionGroup != null) {
actionManager.createActionPopupMenu("", actionGroup).getComponent().show(comp, x, y);
actionManager.createActionPopupMenu(ExternalProjectsViewImpl.this.getName(), actionGroup).getComponent().show(comp, x, y);
}
}
}
@@ -23,12 +23,14 @@ import com.intellij.execution.impl.EditConfigurationsDialog;
import com.intellij.ide.projectView.PresentationData;
import com.intellij.openapi.externalSystem.model.execution.ExternalSystemTaskExecutionSettings;
import com.intellij.openapi.externalSystem.service.execution.ExternalSystemRunConfiguration;
import com.intellij.openapi.externalSystem.statistics.ExternalSystemActionsCollector;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.pom.Navigatable;
import com.intellij.ui.treeStructure.SimpleTree;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.awt.*;
import java.awt.event.InputEvent;
import static com.intellij.openapi.externalSystem.service.project.manage.ExternalSystemTaskActivator.getRunConfigurationActivationTaskName;
@@ -98,6 +100,10 @@ public class RunConfigurationNode extends ExternalSystemNode {
@Override
public void handleDoubleClickOrEnter(SimpleTree tree, InputEvent inputEvent) {
ExternalProjectsView projectsView = getExternalProjectsView();
String place = projectsView instanceof Component ? ((Component)projectsView).getName() : "unknown";
ExternalSystemActionsCollector.trigger(myProject, projectsView.getSystemId(),
"ExecuteExternalSystemRunConfigurationAction", place, false);
ProgramRunnerUtil.executeConfiguration(mySettings, DefaultRunExecutor.getRunExecutorInstance());
RunManager.getInstance(mySettings.getConfiguration().getProject()).setSelectedConfiguration(mySettings);
}
@@ -158,8 +158,9 @@
<reference id="ExternalSystem.ShowSettings"/>
</group>
<group id="ExternalSystemView.TaskMenu" popup="true">
<reference ref="RunContextGroup"/>
<group id="ExternalSystemView.TaskMenu" popup="true" class="com.intellij.openapi.externalSystem.action.task.ExternalSystemTaskMenu">
<separator/>
<action id="ExternalSystem.CreateRunConfiguration" class="com.intellij.execution.actions.CreateAction"/>
<separator/>
<reference id="EditSource"/>
<separator/>
@@ -19,7 +19,7 @@ class GradleActionsUsagesCollector : ProjectUsageTriggerCollector() {
// preserve context data ordering
val context = FUSUsageContext.create(
"from.${event?.place ?: "undefined.place"}",
event?.place ?: "undefined.place",
"fromContextMenu.${event?.isFromContextMenu?.toString() ?: "false"}"
)
@@ -27,7 +27,7 @@ class GradleSettingsCollector : ProjectUsagesCollector() {
// project settings
for (setting in gradleSettings.linkedProjectsSettings) {
usages.add(getBooleanUsage("useCompositeBuilds", setting.compositeBuild != null))
usages.add(getYesNoUsage("isCompositeBuilds", setting.compositeBuild != null))
usages.add(getEnumUsage("distributionType", setting.distributionType))
usages.add(getEnumUsage("storeProjectFilesExternally", setting.storeProjectFilesExternally))
usages.add(getBooleanUsage("disableWrapperSourceDistributionNotification", setting.isDisableWrapperSourceDistributionNotification))
@@ -42,4 +42,8 @@ class GradleSettingsCollector : ProjectUsagesCollector() {
usages.add(getEnumUsage("preferredTestRunner", runningSettings.preferredTestRunner))
return usages
}
private fun getYesNoUsage(key: String, value: Boolean): UsageDescriptor {
return UsageDescriptor(key + if (value) ".yes" else ".no", 1)
}
}
@@ -49,6 +49,7 @@ import java.util.List;
public class MavenProjectsNavigator extends MavenSimpleProjectComponent implements PersistentStateComponent<MavenProjectsNavigatorState>,
Disposable, ProjectComponent {
public static final String TOOL_WINDOW_ID = "Maven";
public static final String TOOL_WINDOW_PLACE_ID = "Maven tool window";
private MavenProjectsNavigatorState myState = new MavenProjectsNavigatorState();
@@ -53,6 +53,8 @@ import java.io.File;
import java.util.List;
import java.util.*;
import static org.jetbrains.idea.maven.navigator.MavenProjectsNavigator.TOOL_WINDOW_PLACE_ID;
public class MavenProjectsNavigatorPanel extends SimpleToolWindowPanel implements DataProvider {
private final Project myProject;
private final SimpleTree myTree;
@@ -103,7 +105,7 @@ public class MavenProjectsNavigatorPanel extends SimpleToolWindowPanel implement
if (id != null) {
final ActionGroup actionGroup = (ActionGroup)actionManager.getAction(id);
if (actionGroup != null) {
actionManager.createActionPopupMenu("", actionGroup).getComponent().show(comp, x, y);
actionManager.createActionPopupMenu(TOOL_WINDOW_PLACE_ID, actionGroup).getComponent().show(comp, x, y);
}
}
}
@@ -44,6 +44,7 @@ import org.jetbrains.idea.maven.execution.MavenRunner;
import org.jetbrains.idea.maven.model.*;
import org.jetbrains.idea.maven.project.MavenProject;
import org.jetbrains.idea.maven.project.MavenProjectsManager;
import org.jetbrains.idea.maven.statistics.MavenActionsUsagesCollector;
import org.jetbrains.idea.maven.tasks.MavenShortcutsManager;
import org.jetbrains.idea.maven.tasks.MavenTasksManager;
import org.jetbrains.idea.maven.utils.*;
@@ -57,6 +58,7 @@ import java.net.URL;
import java.util.List;
import java.util.*;
import static org.jetbrains.idea.maven.navigator.MavenProjectsNavigator.TOOL_WINDOW_PLACE_ID;
import static org.jetbrains.idea.maven.project.ProjectBundle.message;
public class MavenProjectsStructure extends SimpleTreeStructure {
@@ -495,7 +497,7 @@ public class MavenProjectsStructure extends SimpleTreeStructure {
public void handleDoubleClickOrEnter(SimpleTree tree, InputEvent inputEvent) {
String actionId = getActionId();
if (actionId != null) {
MavenUIUtil.executeAction(actionId, inputEvent);
MavenUIUtil.executeAction(actionId, TOOL_WINDOW_PLACE_ID, inputEvent);
}
}
}
@@ -1524,6 +1526,7 @@ public class MavenProjectsStructure extends SimpleTreeStructure {
@Override
public void handleDoubleClickOrEnter(SimpleTree tree, InputEvent inputEvent) {
MavenActionsUsagesCollector.trigger(myProject, "ExecuteMavenRunConfigurationAction", TOOL_WINDOW_PLACE_ID, false);
ProgramRunnerUtil.executeConfiguration(mySettings, DefaultRunExecutor.getRunExecutorInstance());
}
}
@@ -0,0 +1,66 @@
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.idea.maven.navigator.actions
import com.intellij.execution.Executor
import com.intellij.execution.ExecutorRegistry
import com.intellij.execution.actions.RunContextAction
import com.intellij.openapi.actionSystem.*
import com.intellij.openapi.project.DumbAware
import org.jetbrains.idea.maven.project.actions.RunBuildAction
import org.jetbrains.idea.maven.statistics.MavenActionsUsagesCollector
class MavenBuildMenu : DefaultActionGroup(), DumbAware {
override fun update(e: AnActionEvent) {
val project = AnAction.getEventProject(e) ?: return
childActionsOrStubs
.filter { it is MyDelegatingAction || it is RunBuildAction }
.forEach { remove(it) }
ExecutorRegistry.getInstance().registeredExecutors
.filter { it.isApplicable(project) }
.reversed()
.forEach { add(wrap(RunContextAction(it), it), Constraints.FIRST) }
ActionManager.getInstance().getAction("Maven.RunBuild")?.let {
add(it, Constraints.FIRST)
}
}
private interface MyDelegatingAction
private class DelegatingActionGroup internal constructor(action: ActionGroup, private val executor: Executor) :
EmptyAction.MyDelegatingActionGroup(action), MyDelegatingAction {
override fun getChildren(e: AnActionEvent?): Array<AnAction> {
val children = super.getChildren(e)
return children.map { wrap(it, executor) }.toTypedArray()
}
override fun actionPerformed(e: AnActionEvent) {
reportUsage(e, executor)
super.actionPerformed(e)
}
}
private class DelegatingAction internal constructor(action: AnAction, private val executor: Executor) :
EmptyAction.MyDelegatingAction(action), MyDelegatingAction {
override fun actionPerformed(e: AnActionEvent) {
reportUsage(e, executor)
super.actionPerformed(e)
}
}
companion object {
private fun wrap(action: AnAction, executor: Executor): AnAction = if (action is ActionGroup) DelegatingActionGroup(action, executor)
else DelegatingAction(action, executor)
private fun reportUsage(e: AnActionEvent, executor: Executor) {
MavenActionsUsagesCollector.trigger(e.project, "RunBuildAction", e, executor.id)
}
}
}
@@ -8,22 +8,40 @@ import com.intellij.internal.statistic.service.fus.collectors.UsageDescriptorKey
import com.intellij.openapi.actionSystem.AnAction
import com.intellij.openapi.actionSystem.AnActionEvent
import com.intellij.openapi.project.Project
import com.intellij.util.text.nullize
class MavenActionsUsagesCollector : ProjectUsageTriggerCollector() {
override fun getGroupId() = "statistics.build.maven.actions"
companion object {
@JvmStatic
fun trigger(project: Project?, action: AnAction, event: AnActionEvent?) {
fun trigger(project: Project?,
featureId: String,
place: String?,
isFromContextMenu: Boolean,
vararg additionalContextData: String) {
if (project == null) return
// preserve context data ordering
val context = FUSUsageContext.create(
"from.${event?.place ?: "undefined.place"}",
"fromContextMenu.${event?.isFromContextMenu?.toString() ?: "false"}"
place.nullize() ?: "undefined place",
"fromContextMenu.$isFromContextMenu",
*additionalContextData
)
val actionClassName = UsageDescriptorKeyValidator.ensureProperKey(action.javaClass.simpleName)
FUSProjectUsageTrigger.getInstance(project).trigger(MavenActionsUsagesCollector::class.java, actionClassName, context)
FUSProjectUsageTrigger.getInstance(project).trigger(MavenActionsUsagesCollector::class.java,
UsageDescriptorKeyValidator.ensureProperKey(featureId), context)
}
@JvmStatic
fun trigger(project: Project?, action: AnAction, event: AnActionEvent?, vararg additionalContextData: String) {
trigger(project, action.javaClass.simpleName, event?.place, event?.isFromContextMenu ?: false, *additionalContextData)
}
@JvmStatic
fun trigger(project: Project?, featureId: String, event: AnActionEvent?, vararg additionalContextData: String) {
trigger(project, featureId, event?.place, event?.isFromContextMenu ?: false, *additionalContextData)
}
@JvmStatic
@@ -15,12 +15,8 @@
*/
package org.jetbrains.idea.maven.utils;
import com.intellij.ide.DataManager;
import com.intellij.ide.util.ElementsChooser;
import com.intellij.openapi.actionSystem.ActionManager;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.Presentation;
import com.intellij.openapi.externalSystem.action.ExternalSystemActionUtil;
import com.intellij.ui.treeStructure.SimpleTree;
import com.intellij.util.ui.UIUtil;
@@ -37,17 +33,11 @@ import java.util.TreeSet;
public class MavenUIUtil {
public static void executeAction(final String actionId, final InputEvent e) {
final ActionManager actionManager = ActionManager.getInstance();
final AnAction action = actionManager.getAction(actionId);
if (action != null) {
final Presentation presentation = new Presentation();
final AnActionEvent event =
new AnActionEvent(e, DataManager.getInstance().getDataContext(e.getComponent()), "", presentation, actionManager, 0);
action.update(event);
if (presentation.isEnabled()) {
action.actionPerformed(event);
}
}
executeAction(actionId, "", e);
}
public static void executeAction(final String actionId, final String place, final InputEvent e) {
ExternalSystemActionUtil.executeAction(actionId, place, e);
}
public static <E> void setElements(ElementsChooser<E> chooser, Collection<? extends E> all, Collection<? extends E> selected, Comparator<? super E> comparator) {
@@ -602,9 +602,8 @@
<reference id="EditSource"/>
</group>
<group id="Maven.BuildMenu" popup="true">
<reference id="Maven.RunBuild"/>
<reference ref="RunContextGroup"/>
<group id="Maven.BuildMenu" popup="true" class="org.jetbrains.idea.maven.navigator.actions.MavenBuildMenu">
<action id="Maven.CreateRunConfiguration" class="com.intellij.execution.actions.CreateAction"/>
<separator/>
<reference ref="Maven.TasksGroup"/>
</group>