Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Report analysis errors #915

Merged
merged 2 commits into from
Jan 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 55 additions & 0 deletions src/main/java/org/sonar/plugins/findbugs/AnalysisResult.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
* SonarQube Findbugs Plugin
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
*/
package org.sonar.plugins.findbugs;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;

import edu.umd.cs.findbugs.AnalysisError;
import edu.umd.cs.findbugs.BugInstance;

/**
* @author gtoison
*
*/
public class AnalysisResult {
private Collection<ReportedBug> reportedBugs;
private Collection<AnalysisError> analysisErrors;

public AnalysisResult() {
this(new ArrayList<>(), new ArrayList<>());
}

public AnalysisResult(BugInstance bugInstance) {
this(Arrays.asList(new ReportedBug(bugInstance)), new ArrayList<>());
}

public AnalysisResult(Collection<ReportedBug> reportedBugs, Collection<? extends AnalysisError> errors) {
this.reportedBugs = reportedBugs;
this.analysisErrors = new ArrayList<>(errors);
}

public Collection<ReportedBug> getReportedBugs() {
return reportedBugs;
}

public Collection<AnalysisError> getAnalysisErrors() {
return analysisErrors;
}
}
16 changes: 11 additions & 5 deletions src/main/java/org/sonar/plugins/findbugs/FindbugsExecutor.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Throwables;
import com.google.common.collect.Lists;

import edu.umd.cs.findbugs.AnalysisError;
import edu.umd.cs.findbugs.BugCollection;
import edu.umd.cs.findbugs.BugInstance;
import edu.umd.cs.findbugs.DetectorFactoryCollection;
Expand All @@ -31,6 +33,7 @@
import edu.umd.cs.findbugs.PluginException;
import edu.umd.cs.findbugs.Priorities;
import edu.umd.cs.findbugs.Project;
import edu.umd.cs.findbugs.SortedBugCollection;
import edu.umd.cs.findbugs.XMLBugReporter;
import edu.umd.cs.findbugs.config.UserPreferences;
import edu.umd.cs.findbugs.plugins.DuplicatePluginIdException;
Expand Down Expand Up @@ -91,15 +94,15 @@ public FindbugsExecutor(FindbugsConfiguration configuration, FileSystem fs, Conf
}

@VisibleForTesting
Collection<ReportedBug> execute() {
AnalysisResult execute() {
return execute(true);
}

public Collection<ReportedBug> execute(boolean useAllPlugin) {
public AnalysisResult execute(boolean useAllPlugin) {
return execute(useAllPlugin,useAllPlugin);
}

public Collection<ReportedBug> execute(boolean useFbContrib, boolean useFindSecBugs) {
public AnalysisResult execute(boolean useFbContrib, boolean useFindSecBugs) {
ClassLoader initialClassLoader = Thread.currentThread().getContextClassLoader();
Thread.currentThread().setContextClassLoader(FindBugs2.class.getClassLoader());

Expand All @@ -115,7 +118,7 @@ public Collection<ReportedBug> execute(boolean useFbContrib, boolean useFindSecB

if(project.getFileCount() == 0) {
LOG.info("Findbugs analysis skipped for this project.");
return new ArrayList<>();
return new AnalysisResult();
}

customPlugins = loadFindbugsPlugins(useFbContrib,useFindSecBugs);
Expand Down Expand Up @@ -178,7 +181,10 @@ public Collection<ReportedBug> execute(boolean useFbContrib, boolean useFindSecB
if(!foundExistingReport) { //Avoid rescanning the project if FindBugs was run already
executorService.submit(new FindbugsTask(engine)).get(configuration.getTimeout(), TimeUnit.MILLISECONDS);
}
return toReportedBugs(xmlBugReporter.getBugCollection());
Collection<ReportedBug> reportedBugs = toReportedBugs(xmlBugReporter.getBugCollection());
Collection<? extends AnalysisError> analysisErrors = ((SortedBugCollection) xmlBugReporter.getBugCollection()).getErrors();

return new AnalysisResult(reportedBugs, analysisErrors);
} catch (TimeoutException e) {
throw new IllegalStateException("Can not execute Findbugs with a timeout threshold value of " + configuration.getTimeout() + " milliseconds", e);
} catch (Exception e) {
Expand Down
36 changes: 33 additions & 3 deletions src/main/java/org/sonar/plugins/findbugs/FindbugsSensor.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
import java.io.FileOutputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.SortedSet;
Expand All @@ -38,6 +37,7 @@
import org.sonar.api.batch.sensor.Sensor;
import org.sonar.api.batch.sensor.SensorContext;
import org.sonar.api.batch.sensor.SensorDescriptor;
import org.sonar.api.batch.sensor.error.NewAnalysisError;
import org.sonar.api.batch.sensor.issue.NewIssue;
import org.sonar.api.batch.sensor.issue.NewIssueLocation;
import org.sonar.plugins.findbugs.language.Jsp;
Expand All @@ -52,6 +52,8 @@
import org.sonar.plugins.findbugs.rules.FindbugsRulesDefinition;
import org.sonar.plugins.java.api.JavaResourceLocator;

import edu.umd.cs.findbugs.AnalysisError;

public class FindbugsSensor implements Sensor {

private static final Logger LOG = LoggerFactory.getLogger(FindbugsSensor.class);
Expand Down Expand Up @@ -127,11 +129,11 @@ public void execute(SensorContext context) {
return;
}

Collection<ReportedBug> collection = executor.execute(hasActiveFbContribRules(), hasActiveFindSecBugsRules());
AnalysisResult analysisResult = executor.execute(hasActiveFbContribRules(), hasActiveFindSecBugsRules());

try {

for (ReportedBug bugInstance : collection) {
for (ReportedBug bugInstance : analysisResult.getReportedBugs()) {

try {
ActiveRule rule = null;
Expand Down Expand Up @@ -224,6 +226,9 @@ public void execute(SensorContext context) {
}
}

for (AnalysisError analysisError : analysisResult.getAnalysisErrors()) {
insertAnalysisError(context, analysisError);
}
}
finally {
if(classMappingWriter != null) {
Expand All @@ -233,6 +238,31 @@ public void execute(SensorContext context) {
}
}

public void insertAnalysisError(SensorContext context, AnalysisError analysisError) {
NewAnalysisError error = context.newAnalysisError();

StringBuilder message = buildAnalysisErrorMessage(analysisError);
error.message(message.toString());

error.save();
}

public StringBuilder buildAnalysisErrorMessage(AnalysisError analysisError) {
StringBuilder message = new StringBuilder(analysisError.getMessage());
if (analysisError.getStackTrace() != null) {
for (String trace : analysisError.getStackTrace()) {
message.append('\n');
message.append(trace);
}
}
if (analysisError.getNestedStackTrace() != null) {
for (String trace : analysisError.getNestedStackTrace()) {
message.append('\n');
message.append(trace);
}
}
return message;
}

protected void insertIssue(ActiveRule rule, InputFile resource, int line, String message, ReportedBug bugInstance) {
NewIssue newIssue = sensorContext.newIssue().forRule(rule.ruleKey());
Expand Down
17 changes: 15 additions & 2 deletions src/test/java/org/sonar/plugins/findbugs/FindbugsExecutorTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ void canGenerateXMLReport() throws Exception {
File reportFile = new File(temporaryFolder, "findbugs-report.xml");
when(conf.getTargetXMLReport()).thenReturn(reportFile);

new FindbugsExecutor(conf, fsEmpty, configEmpty).execute();
AnalysisResult analysisResult = new FindbugsExecutor(conf, fsEmpty, configEmpty).execute();

assertThat(reportFile).exists();
String report = FileUtils.readFileToString(reportFile, StandardCharsets.UTF_8);
Expand All @@ -87,6 +87,8 @@ void canGenerateXMLReport() throws Exception {
.as("Report should be generated with messages").contains("<Message>")
.contains("priority=\"1\"")
.doesNotContain("priority=\"3\"");

checkAnalysisResult(analysisResult);
}

@Test
Expand All @@ -96,7 +98,7 @@ void canGenerateXMLReportWithCustomConfidence() throws Exception {
when(conf.getTargetXMLReport()).thenReturn(reportFile);
when(conf.getConfidenceLevel()).thenReturn("low");

new FindbugsExecutor(conf, fsEmpty, configEmpty).execute();
AnalysisResult analysisResult = new FindbugsExecutor(conf, fsEmpty, configEmpty).execute();

assertThat(reportFile).exists();
String report = FileUtils.readFileToString(reportFile, StandardCharsets.UTF_8);
Expand All @@ -106,6 +108,8 @@ void canGenerateXMLReportWithCustomConfidence() throws Exception {
.as("Report should be generated with messages").contains("<Message>")
.contains("priority=\"1\"")
.contains("priority=\"3\"");

checkAnalysisResult(analysisResult);
}

public void shouldTerminateAfterTimeout() throws Exception {
Expand Down Expand Up @@ -148,4 +152,13 @@ private FindbugsConfiguration mockConf() throws Exception {
return conf;
}

/**
* Smoke test checking that no errors where reported.
* This might happen when upgrading to a new version of SpotBugs or plugins and would most likely mean that there's a regression in the new version
*
* @param analysisResult
*/
public void checkAnalysisResult(AnalysisResult analysisResult) {
assertThat(analysisResult.getAnalysisErrors()).isEmpty();
}
}
Loading