diff --git a/README.md b/README.md index f51675ea..99d9137f 100644 --- a/README.md +++ b/README.md @@ -32,6 +32,7 @@ pmd.ruleSets=rulesets/java/android.xml,rulesets/java/basic.xml spotbugs.enabled=true spotbugs.includeFilter= spotbugs.excludeFilter= +spotbugs.plugins.location=/opt/sputnik/SpotBugsPlugins codenarc.enabled=true codenarc.ruleSets= codenarc.excludes=**/*.java diff --git a/build.gradle b/build.gradle index 29b9c2ea..49f1c905 100644 --- a/build.gradle +++ b/build.gradle @@ -186,6 +186,10 @@ shadowJar { zip64 true } +shadowJar { + zip64 true +} + jar { manifest { attributes("Specification-Title": "Sputnik", @@ -209,7 +213,7 @@ publishing { pom { groupId = 'pl.touk' name = 'Sputnik' - description = 'Static code review for your Gerrit and Stash patchsets. Runs Checkstyle, PMD and SpotBugs for you!' + description = 'Static code review for your Gerrit and Stash patchsets. Runs Checkstyle, PMD and SpotBugs for you!' url = 'https://github.com/TouK/sputnik/' scm { url = 'scm:git@github.com:TouK/sputnik.git' diff --git a/src/main/java/pl/touk/sputnik/configuration/GeneralOption.java b/src/main/java/pl/touk/sputnik/configuration/GeneralOption.java index 4b8c26ee..891b39c2 100644 --- a/src/main/java/pl/touk/sputnik/configuration/GeneralOption.java +++ b/src/main/java/pl/touk/sputnik/configuration/GeneralOption.java @@ -53,6 +53,7 @@ public enum GeneralOption implements ConfigurationOption { SPOTBUGS_LOAD_PROPERTIES_FROM("spotbugs.loadPropertiesFrom", "SpotBugs properties file", ""), SPOTBUGS_INCLUDE_FILTER("spotbugs.includeFilter", "SpotBugs include filter file", ""), SPOTBUGS_EXCLUDE_FILTER("spotbugs.excludeFilter", "SpotBugs exclude filter file", ""), + SPOTBUGS_PLUGINS_LOCATION("spotbugs.plugins.location", "Path to catalog where SpotBugs plugins jar files are located", ""), SCALASTYLE_ENABLED("scalastyle.enabled", "ScalaStyle enabled", "false"), SCALASTYLE_CONFIGURATION_FILE("scalastyle.configurationFile", "ScalaStyle configuration file", ""), diff --git a/src/main/java/pl/touk/sputnik/processor/spotbugs/SpotBugsProcessor.java b/src/main/java/pl/touk/sputnik/processor/spotbugs/SpotBugsProcessor.java index 8366dc65..e972c7d5 100644 --- a/src/main/java/pl/touk/sputnik/processor/spotbugs/SpotBugsProcessor.java +++ b/src/main/java/pl/touk/sputnik/processor/spotbugs/SpotBugsProcessor.java @@ -9,10 +9,16 @@ import edu.umd.cs.findbugs.DetectorFactoryCollection; import edu.umd.cs.findbugs.FindBugs2; import edu.umd.cs.findbugs.IClassScreener; +import edu.umd.cs.findbugs.Plugin; +import edu.umd.cs.findbugs.PluginException; import edu.umd.cs.findbugs.Priorities; import edu.umd.cs.findbugs.Project; import edu.umd.cs.findbugs.SystemProperties; import edu.umd.cs.findbugs.config.UserPreferences; +import java.io.File; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Arrays; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.jetbrains.annotations.NotNull; @@ -29,9 +35,11 @@ @Slf4j public class SpotBugsProcessor implements ReviewProcessor { + private static final String SOURCE_NAME = "SpotBugs"; private final CollectorBugReporter collectorBugReporter; + private final Configuration config; public SpotBugsProcessor(@NotNull Configuration configuration) { @@ -70,6 +78,7 @@ public String getName() { } public FindBugs2 createFindBugs2(Review review) { + loadAllSpotbugsPlugins(config.getProperty(GeneralOption.SPOTBUGS_PLUGINS_LOCATION)); FindBugs2 findBugs = new FindBugs2(); findBugs.setProject(createProject(review)); findBugs.setBugReporter(collectorBugReporter); @@ -145,4 +154,32 @@ private String getExcludeFilterFilename() { log.info("Using SpotBugs exclude filter file {}", excludeFilterFilename); return excludeFilterFilename; } + + public void loadAllSpotbugsPlugins(String pluginsLocation) { + File[] fileList = getSpotBugsPluginFiles(pluginsLocation); + for (File file : fileList) { + loadSpotBugsPlugin(file); + } + } + + public File[] getSpotBugsPluginFiles(String pluginsLocation) { + if (!StringUtils.isBlank(pluginsLocation)) { + File[] fileList = new File(pluginsLocation).listFiles(); + if (fileList != null) { + return Arrays.stream(fileList).filter(file -> file.getName().contains(".jar")).toArray(File[]::new); + } + } + return new File[0]; + } + + private void loadSpotBugsPlugin(File pluginFile) { + log.info("SpotBugs additional plugin loading: file://{}", pluginFile.getAbsoluteFile()); + try { + Plugin.addCustomPlugin(new URI("file://" + pluginFile.getAbsoluteFile())); + } catch (PluginException e) { + log.info("Spotbugs additional plugins not loaded {} plugin not supported", e.getMessage()); + } catch (URISyntaxException e) { + log.info("Spotbugs additional plugins not loaded {} check path", e.getMessage()); + } + } } diff --git a/src/main/resources/example.properties b/src/main/resources/example.properties index 1da038b9..9189477a 100644 --- a/src/main/resources/example.properties +++ b/src/main/resources/example.properties @@ -33,6 +33,7 @@ pmd.showViolationDetails=true spotbugs.enabled=true spotbugs.includeFilter= spotbugs.excludeFilter= +spotbugs.plugins.location= scalastyle.enabled=true scalastyle.configurationFile= diff --git a/src/test/java/pl/touk/sputnik/processor/spotbugs/SpotBugsProcessorTest.java b/src/test/java/pl/touk/sputnik/processor/spotbugs/SpotBugsProcessorTest.java index 15b4fdc9..42775402 100644 --- a/src/test/java/pl/touk/sputnik/processor/spotbugs/SpotBugsProcessorTest.java +++ b/src/test/java/pl/touk/sputnik/processor/spotbugs/SpotBugsProcessorTest.java @@ -2,6 +2,8 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; +import edu.umd.cs.findbugs.Plugin; +import java.util.List; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -13,9 +15,6 @@ import pl.touk.sputnik.review.ReviewFile; import pl.touk.sputnik.review.ReviewFormatterFactory; import pl.touk.sputnik.review.ReviewResult; - -import java.util.List; - import static org.assertj.core.api.Assertions.assertThat; class SpotBugsProcessorTest extends TestEnvironment { @@ -60,6 +59,19 @@ void shouldReturnEmptyWhenNoFilesToReview() { } @Test + void shouldInstantiateIfPluginsCatalogIsPresentButEmpty() { + ReviewResult reviewResult = spotBugsProcessor.process(nonExistentReview()); + spotBugsProcessor.loadAllSpotbugsPlugins("src/test/resources/java/empty"); + assertThat(reviewResult).isNotNull(); + assertThat(reviewResult.getViolations()).isEmpty(); + } + + @Test + void pluginShouldBeLoaded() { + spotBugsProcessor.loadAllSpotbugsPlugins("src/test/resources/java"); + assertThat(Plugin.getByPluginId("com.h3xstream.findsecbugs")).isNotNull(); + } + void shouldLoadPropertiesFromExternalLocation() { ReviewResult reviewResult = spotBugsProcessor.process(nonExistentReview()); diff --git a/src/test/resources/java/empty/.gitkeep b/src/test/resources/java/empty/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/src/test/resources/java/findsecbugs-plugin-1.11.0.jar b/src/test/resources/java/findsecbugs-plugin-1.11.0.jar new file mode 100644 index 00000000..89e556f6 Binary files /dev/null and b/src/test/resources/java/findsecbugs-plugin-1.11.0.jar differ diff --git a/src/test/resources/test.properties b/src/test/resources/test.properties index c1458cea..4da2d4d5 100644 --- a/src/test/resources/test.properties +++ b/src/test/resources/test.properties @@ -11,6 +11,7 @@ pmd.ruleSets=rulesets/java/android.xml,rulesets/java/basic.xml,rulesets/java/bra spotbugs.enabled=true spotbugs.includeFilter= spotbugs.excludeFilter= +spotbugs.plugins.location= jslint.enabled=true scalastyle.configurationFile=src/test/resources/scalastyle.xml jshint.enabled=true