Skip to content

Commit

Permalink
Add initial support for problem events (#1296)
Browse files Browse the repository at this point in the history
* Add initial support for problem events

* Update Tooling API to GA version

* Add simple test coverage to problems API usage

* Update TAPI and fix test

* Allow opt-out from Problems API integration

* Remove whitespace
  • Loading branch information
donat authored Mar 6, 2024
1 parent 538c5f8 commit 415a78a
Show file tree
Hide file tree
Showing 31 changed files with 387 additions and 57 deletions.
5 changes: 3 additions & 2 deletions Launch Buildship.launch
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,12 @@
<listEntry value="org.eclipse.debug.ui.launchGroup.run"/>
</listAttribute>
<booleanAttribute key="org.eclipse.jdt.launching.ATTR_ATTR_USE_ARGFILE" value="false"/>
<booleanAttribute key="org.eclipse.jdt.launching.ATTR_SHOW_CODEDETAILS_IN_EXCEPTION_MESSAGES" value="true"/>
<booleanAttribute key="org.eclipse.jdt.launching.ATTR_USE_START_ON_FIRST_THREAD" value="true"/>
<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11"/>
<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-17"/>
<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-os ${target.os} -ws ${target.ws} -arch ${target.arch} -nl ${target.nl} -consoleLog"/>
<stringAttribute key="org.eclipse.jdt.launching.SOURCE_PATH_PROVIDER" value="org.eclipse.pde.ui.workbenchClasspathProvider"/>
<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-XX:MaxPermSize=128M -Dorg.eclipse.swt.internal.carbon.smallFonts -Dorg.eclipse.swt.graphics.Resource.reportNonDisposed=true"/>
<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Dorg.eclipse.swt.internal.carbon.smallFonts -Dorg.eclipse.swt.graphics.Resource.reportNonDisposed=true"/>
<stringAttribute key="pde.version" value="3.3"/>
<stringAttribute key="product" value="org.eclipse.sdk.ide"/>
<booleanAttribute key="show_selected_only" value="false"/>
Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# production library version numbers
toolingApiVersion=8.1.1
toolingApiVersion=8.6

# testing library version numbers
guavaVersion=33.0.0
Expand Down
2 changes: 1 addition & 1 deletion org.eclipse.buildship.compat/META-INF/MANIFEST.MF
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@ Bundle-Version: 3.1.10.qualifier
Bundle-Vendor: Eclipse Buildship
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
Bundle-ActivationPolicy: lazy
Require-Bundle: org.gradle.toolingapi;bundle-version="[8.1.1,8.2.0)";visibility:=reexport
Require-Bundle: org.gradle.toolingapi;bundle-version="[8.6.0,8.7.0)";visibility:=reexport
Export-Package: org.eclipse.buildship.core.internal.workspace
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ package org.eclipse.buildship.core.internal.marker

import org.gradle.tooling.BuildException

import org.eclipse.core.resources.IMarker
import org.eclipse.core.runtime.IStatus

import org.eclipse.buildship.core.GradleDistribution
import org.eclipse.buildship.core.internal.test.fixtures.ProjectSynchronizationSpecification

class GradleErrorMarkerTest extends ProjectSynchronizationSpecification {
Expand Down Expand Up @@ -120,4 +124,35 @@ class GradleErrorMarkerTest extends ProjectSynchronizationSpecification {
findProject('sub')
numOfGradleErrorMarkers == 0
}


def "Convers problem reports to error markers"() {
setup:
File projectDir = dir('error-marker-test') {
file 'build.gradle', '''
import org.gradle.api.internal.GradleInternal
import org.gradle.api.problems.Problems
import org.gradle.api.problems.Severity
def gradleInternal = gradle as GradleInternal
def problems = gradleInternal.services.get(Problems)
problems.forNamespace("buildscript").reporting {
it.label("Problem label")
.category('deprecation', 'plugin')
.severity(Severity.WARNING)
.solution("Please use 'standard-plugin-2' instead of this plugin")
}
'''
}

when:
tryImportAndWait(projectDir)

then:
numOfGradleErrorMarkers == 1
gradleErrorMarkers[0].getAttribute(IMarker.MESSAGE) == 'Problem label'
gradleErrorMarkers[0].getAttribute(GradleErrorMarker.ATTRIBUTE_PROBLEM_CATEGORY) == 'buildscript:deprecation:plugin'

}
}
2 changes: 1 addition & 1 deletion org.eclipse.buildship.core/META-INF/MANIFEST.MF
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ Require-Bundle: org.eclipse.core.expressions,
org.eclipse.jdt.junit.core,
org.eclipse.jdt.launching,
org.eclipse.debug.core,
org.gradle.toolingapi;bundle-version="[8.1.1,8.2.0)";visibility:=reexport,
org.gradle.toolingapi;bundle-version="[8.6.0,8.7.0)";visibility:=reexport,
com.google.guava;bundle-version="33.0.0",
com.google.gson;bundle-version="[2.7.0,3.0.0)",
org.eclipse.buildship.compat;visibility:=reexport
Expand Down
4 changes: 3 additions & 1 deletion org.eclipse.buildship.core/plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -104,12 +104,14 @@
<!-- Define custom marker type for Gradle-related problems -->
<extension
id="org.eclipse.buildship.core.errormarker"
name="Gradle Error Marker"
name="Gradle Problem"
point="org.eclipse.core.resources.markers">
<super type="org.eclipse.core.resources.problemmarker"/>
<persistent value="true" />
<attribute name="stacktrace" />
</extension>

<!-- Built-in Buildship project configurators -->
<extension
point="org.eclipse.buildship.core.projectconfigurators">
<configurator
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import org.gradle.tooling.GradleConnectionException;
import org.gradle.tooling.ProgressListener;
import org.gradle.tooling.ResultHandler;
import org.gradle.tooling.StreamedValueListener;
import org.gradle.tooling.events.OperationType;

import com.google.common.cache.Cache;
Expand Down Expand Up @@ -222,4 +223,9 @@ public BuildActionExecuter<T> withSystemProperties(Map<String, String> systemPro
this.delegate.withSystemProperties(systemProperties);
return this;
}

@Override
public void setStreamedValueListener(StreamedValueListener listener) {
this.delegate.setStreamedValueListener(listener);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -328,7 +328,7 @@ public GradleConnectionOperation(Function<ProjectConnection, ? extends T> action
@Override
public void runInToolingApi(CancellationTokenSource tokenSource, IProgressMonitor monitor) throws Exception {
// TODO (donat) use AutoCloseable once we update to Tooling API 5.0
ProjectConnection connection = IdeAttachedProjectConnection.newInstance(tokenSource, getGradleArguments(), monitor);
ProjectConnection connection = IdeAttachedProjectConnection.newInstance(tokenSource, getGradleArguments(), DefaultGradleBuild.this, monitor);
if (isSynchronizing()) {
connection = new CachingProjectConnection(connection, DefaultGradleBuild.this.projectConnectionCache);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,13 @@ public final class WorkspaceConfiguration {
private final boolean showConsoleView;
private final boolean showExecutionsView;
private final boolean experimentalModuleSupportEnabled;
private final boolean problemsApiSupportEnabled;

public WorkspaceConfiguration(GradleDistribution gradleDistribution, File gradleUserHome,
File javaHome, boolean gradleIsOffline, boolean buildScansEnabled,
boolean autoSync, List<String> arguments,
List<String> jvmArguments, boolean showConsoleView,
boolean showExecutionsView, boolean experimentalModuleSupportEnabled) {
boolean showExecutionsView, boolean experimentalModuleSupportEnabled, boolean problemApiSupportEnabled) {
this.gradleDistribution = gradleDistribution;
this.gradleUserHome = gradleUserHome;
this.javaHome = javaHome;
Expand All @@ -52,6 +53,7 @@ public WorkspaceConfiguration(GradleDistribution gradleDistribution, File gradle
this.showConsoleView = showConsoleView;
this.showExecutionsView = showExecutionsView;
this.experimentalModuleSupportEnabled = experimentalModuleSupportEnabled;
this.problemsApiSupportEnabled = problemApiSupportEnabled;
}

public GradleDistribution getGradleDistribution() {
Expand Down Expand Up @@ -100,6 +102,11 @@ public boolean isExperimentalModuleSupportEnabled() {
return this.experimentalModuleSupportEnabled;
}


public boolean isProblemsApiSupportEnabled() {
return this.problemsApiSupportEnabled;
}

@Override
public boolean equals(Object obj) {
if (obj instanceof WorkspaceConfiguration) {
Expand All @@ -114,13 +121,14 @@ public boolean equals(Object obj) {
&& Objects.equal(this.jvmArguments, other.jvmArguments)
&& Objects.equal(this.showConsoleView, other.showConsoleView)
&& Objects.equal(this.showExecutionsView, other.showExecutionsView)
&& Objects.equal(this.experimentalModuleSupportEnabled, other.experimentalModuleSupportEnabled);
&& Objects.equal(this.experimentalModuleSupportEnabled, other.experimentalModuleSupportEnabled)
&& Objects.equal(this.problemsApiSupportEnabled, other.problemsApiSupportEnabled);
}
return false;
}

@Override
public int hashCode() {
return Objects.hashCode(this.gradleDistribution, this.gradleUserHome, this.javaHome, this.gradleIsOffline, this.buildScansEnabled, this.autoSync, this.arguments, this.jvmArguments, this.showConsoleView, this.showExecutionsView, this.experimentalModuleSupportEnabled);
return Objects.hashCode(this.gradleDistribution, this.gradleUserHome, this.javaHome, this.gradleIsOffline, this.buildScansEnabled, this.autoSync, this.arguments, this.jvmArguments, this.showConsoleView, this.showExecutionsView, this.experimentalModuleSupportEnabled, this.problemsApiSupportEnabled);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ final class WorkspaceConfigurationPersistence {
private static final String SHOW_CONSOLE_VIEW = "show.console.view";
private static final String SHOW_EXECUTIONS_VIEW = "show.executions.view";
private static final String EXPERIMENTAL_ENABLE_MODULE_SUPPORT = "experimental.module.support";
private static final String PROBLEMS_API_SUPPORT = "problems.api.support";

public WorkspaceConfiguration readWorkspaceConfig() {
IEclipsePreferences preferences = getPreferences();
Expand Down Expand Up @@ -72,8 +73,8 @@ public WorkspaceConfiguration readWorkspaceConfig() {
boolean showConsoleView = preferences.getBoolean(SHOW_CONSOLE_VIEW, true);
boolean showExecutionsView = preferences.getBoolean(SHOW_EXECUTIONS_VIEW, true);
boolean moduleSupport = preferences.getBoolean(EXPERIMENTAL_ENABLE_MODULE_SUPPORT, false);

return new WorkspaceConfiguration(distribution, gradleUserHome, javaHome, offlineMode, buildScansEnabled, autoSyncEnabled, arguments, jvmArguments, showConsoleView, showExecutionsView, moduleSupport);
boolean problemsApiSupport = preferences.getBoolean(PROBLEMS_API_SUPPORT, true);
return new WorkspaceConfiguration(distribution, gradleUserHome, javaHome, offlineMode, buildScansEnabled, autoSyncEnabled, arguments, jvmArguments, showConsoleView, showExecutionsView, moduleSupport, problemsApiSupport);
}

public void saveWorkspaceConfiguration(WorkspaceConfiguration config) {
Expand All @@ -98,6 +99,7 @@ public void saveWorkspaceConfiguration(WorkspaceConfiguration config) {
preferences.putBoolean(SHOW_CONSOLE_VIEW, config.isShowConsoleView());
preferences.putBoolean(SHOW_EXECUTIONS_VIEW, config.isShowExecutionsView());
preferences.putBoolean(EXPERIMENTAL_ENABLE_MODULE_SUPPORT, config.isExperimentalModuleSupportEnabled());
preferences.putBoolean(PROBLEMS_API_SUPPORT, config.isProblemsApiSupportEnabled());
try {
preferences.flush();
} catch (BackingStoreException e) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,13 @@

import java.io.IOException;
import java.io.OutputStream;
import java.util.EnumSet;
import java.util.List;

import org.gradle.tooling.CancellationToken;
import org.gradle.tooling.CancellationTokenSource;
import org.gradle.tooling.LongRunningOperation;
import org.gradle.tooling.ProgressListener;
import org.gradle.tooling.events.OperationType;

import com.google.common.base.Preconditions;
import com.google.common.base.StandardSystemProperty;
Expand All @@ -32,6 +33,8 @@
import org.eclipse.buildship.core.internal.console.ProcessStreamsProvider;
import org.eclipse.buildship.core.internal.util.progress.CancellationForwardingListener;
import org.eclipse.buildship.core.internal.util.progress.DelegatingProgressListener;
import org.eclipse.buildship.core.internal.util.progress.ProblemsReportingProgressListener;
import org.eclipse.buildship.core.internal.workspace.InternalGradleBuild;

/**
* Holds attributes that are commonly used to handle progress in each Gradle invocation.
Expand Down Expand Up @@ -70,7 +73,12 @@ public void applyTo(LongRunningOperation operation) {
operation.addProgressListener(listener);
}
for (org.gradle.tooling.events.ProgressListener listener : this.progressEventListeners) {
operation.addProgressListener(listener);
if (CorePlugin.configurationManager().loadWorkspaceConfiguration().isProblemsApiSupportEnabled()) {
operation.addProgressListener(listener);
} else {
operation.addProgressListener(listener, EnumSet.complementOf(EnumSet.of(OperationType.PROBLEMS)));
}

}
operation.withCancellationToken(this.cancellationToken);
}
Expand Down Expand Up @@ -98,8 +106,8 @@ public void close() {
this.streams.close();
}

public static final GradleProgressAttributesBuilder builder(CancellationTokenSource tokenSource, IProgressMonitor monitor) {
return new GradleProgressAttributesBuilder(tokenSource, monitor);
public static final GradleProgressAttributesBuilder builder(CancellationTokenSource tokenSource, InternalGradleBuild gradleBuild, IProgressMonitor monitor) {
return new GradleProgressAttributesBuilder(tokenSource, gradleBuild, monitor);
}

/**
Expand All @@ -114,9 +122,11 @@ public static class GradleProgressAttributesBuilder {
private ProcessDescription processDescription = null;
private boolean isInteractive = true;
private ProgressListener delegatingListener = null;
private final InternalGradleBuild gradleBuild;

public GradleProgressAttributesBuilder(CancellationTokenSource tokenSource, IProgressMonitor monitor) {
public GradleProgressAttributesBuilder(CancellationTokenSource tokenSource, InternalGradleBuild gradleBuild, IProgressMonitor monitor) {
this.tokenSource = tokenSource;
this.gradleBuild = gradleBuild;
this.monitor = monitor;
}

Expand Down Expand Up @@ -158,6 +168,9 @@ public GradleProgressAttributes build() {
CancellationForwardingListener cancellationListener = new CancellationForwardingListener(this.monitor, this.tokenSource);
progressListeners.add(cancellationListener);
progressEventListeners.add(cancellationListener);
if (CorePlugin.configurationManager().loadWorkspaceConfiguration().isProblemsApiSupportEnabled()) {
progressEventListeners.add(new ProblemsReportingProgressListener(this.gradleBuild));
}

return new GradleProgressAttributes(streams, this.tokenSource.token(), progressListeners.build(), progressEventListeners.build(), this.isInteractive);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,9 @@ public final class CoreMessages extends NLS {
public static String Preference_Label_ModulePath;
public static String Preference_Label_ModulePathHover;

public static String Preference_Label_ProblemsApiSupport;
public static String Preference_Label_ProblemsApiSupportHover;

static {
// initialize resource bundle
NLS.initializeMessages(BUNDLE_NAME, CoreMessages.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import org.eclipse.buildship.core.internal.console.ProcessDescription;
import org.eclipse.buildship.core.internal.event.Event;
import org.eclipse.buildship.core.internal.gradle.GradleProgressAttributes;
import org.eclipse.buildship.core.internal.marker.GradleMarkerManager;
import org.eclipse.buildship.core.internal.operation.ToolingApiJob;
import org.eclipse.buildship.core.internal.workspace.InternalGradleBuild;

Expand Down Expand Up @@ -52,12 +53,13 @@ protected final void executeLaunch(CancellationTokenSource tokenSource, final IP
ProcessDescription processDescription = createProcessDescription();
BaseRunConfiguration runConfig = getRunConfig();
InternalGradleBuild gradleBuild = CorePlugin.internalGradleWorkspace().getGradleBuild(runConfig.getProjectConfiguration().getBuildConfiguration());
GradleProgressAttributes attributes = GradleProgressAttributes.builder(tokenSource, monitor)
GradleProgressAttributes attributes = GradleProgressAttributes.builder(tokenSource, gradleBuild, monitor)
.forDedicatedProcess(processDescription)
.withFullProgress()
.build();
T launcher = createLaunch(gradleBuild, attributes, processDescription);

GradleMarkerManager.clear(gradleBuild);
writeExtraConfigInfo(attributes);

Event event = new DefaultExecuteLaunchRequestEvent(processDescription, launcher);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
package org.eclipse.buildship.core.internal.marker;

import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.stream.Collectors;

import com.google.common.base.Throwables;

Expand All @@ -21,7 +23,7 @@
import org.eclipse.buildship.core.internal.workspace.InternalGradleBuild;

/**
* Describes Gradle error marker.
* Describes a Gradle problem marker.
*
* @author Donat Csikos
*/
Expand All @@ -30,6 +32,10 @@ public class GradleErrorMarker {
public static String ID = CorePlugin.PLUGIN_ID + ".errormarker";
public static String ATTRIBUTE_STACKTRACE = "stacktrace";
public static String ATTRIBUTE_ROOT_DIR = "rootdir";
public static String ATTRIBUTE_PROBLEM_CATEGORY = "problem.category";
public static String ATTRIBUTE_PROBLEM_SOLUTIONS = "problem.solutions";
public static String ATTRIBUTE_DOCUMENTATION_LINK = "problem.documentationlink";


private GradleErrorMarker() {
}
Expand All @@ -40,14 +46,19 @@ public static boolean belongsToBuild(IMarker marker, InternalGradleBuild build)
}

public static void createError(IResource resource, InternalGradleBuild gradleBuild, String message, Throwable exception, int lineNumber) {
createMarker(IMarker.SEVERITY_ERROR, resource, gradleBuild, message, exception,lineNumber);
createMarker(IMarker.SEVERITY_ERROR, resource, gradleBuild, message, exception, lineNumber);
}

public static void createWarning(IResource resource, InternalGradleBuild gradleBuild, String message, Throwable exception, int lineNumber) {
createMarker(IMarker.SEVERITY_WARNING, resource, gradleBuild, message, exception,lineNumber);
}

private static void createMarker(int severity, IResource resource, InternalGradleBuild gradleBuild, String message, Throwable exception, int lineNumber) {
createMarker(severity, resource, gradleBuild, message, exception, lineNumber, null, null, null);
}

public static void createMarker(int severity, IResource resource, InternalGradleBuild gradleBuild, String message, Throwable exception, int lineNumber, String category,
List<String> solutions, String documentationLink) {
try {
IMarker marker = resource.createMarker(GradleErrorMarker.ID);

Expand All @@ -63,6 +74,16 @@ private static void createMarker(int severity, IResource resource, InternalGradl
String stackTrace = Throwables.getStackTraceAsString(exception);
marker.setAttribute(GradleErrorMarker.ATTRIBUTE_STACKTRACE, trimMarkerProperty(stackTrace));
}
if (category != null) {
marker.setAttribute(ATTRIBUTE_PROBLEM_CATEGORY, category);
}
if (solutions != null) {
String solutionsString = solutions.stream().collect(Collectors.joining(System.getProperty("line.separator")));
marker.setAttribute(ATTRIBUTE_PROBLEM_SOLUTIONS, solutionsString);
}
if (documentationLink != null) {
marker.setAttribute(ATTRIBUTE_DOCUMENTATION_LINK, documentationLink);
}
} catch (CoreException e) {
CorePlugin.logger().warn("Cannot create Gradle error marker", e);
}
Expand Down
Loading

0 comments on commit 415a78a

Please sign in to comment.