diff --git a/README.md b/README.md
index 4c0073b..3750701 100644
--- a/README.md
+++ b/README.md
@@ -22,6 +22,7 @@ The plugin supports various static analysis tools for Java, Kotlin and Android p
* [`Checkstyle`](docs/tools/checkstyle.md)
* [`PMD`](docs/tools/pmd.md)
* [`FindBugs`](docs/tools/findbugs.md)
+ * [`SpotBugs`](docs/tools/spotbugs.md)
* [`Detekt`](docs/tools/detekt.md)
* [`Android Lint`](docs/tools/android_lint.md)
* [`KtLint`](docs/tools/ktlint.md)
@@ -31,7 +32,6 @@ Please note that the tools availability depends on the project the plugin is app
### Tools in-consideration
- * `Spotbugs` [#142](https://github.com/novoda/gradle-static-analysis-plugin/issues/142)
* `CPD (Duplicate Code Detection) ` [#150](https://github.com/novoda/gradle-static-analysis-plugin/issues/150)
* `error-prone` [#151](https://github.com/novoda/gradle-static-analysis-plugin/issues/151)
* `Jetbrains IDEA Inspections` [#152](https://github.com/novoda/gradle-static-analysis-plugin/issues/152)
@@ -80,6 +80,7 @@ staticAnalysis {
checkstyle { }
pmd { }
findbugs { }
+ spotbugs { }
detekt { }
lintOptions { }
}
@@ -89,7 +90,7 @@ This will enable all the tools with their default settings and create `evaluateV
[advanced usage](docs/advanced-usage.md) and to the [supported tools](docs/supported-tools.md) pages.
## Sample app
-There are two sample Android projects available, one consisting of a regular app - available [here](https://github.com/novoda/gradle-static-analysis-plugin/tree/master/sample) - and the other comprising a multi-module setup available [here](https://github.com/novoda/gradle-static-analysis-plugin/tree/master/sample-multi-module). Both sample projects showcase a setup featuring Checkstyle, FindBugs, PMD, Lint and Detekt.
+There are two sample Android projects available, one consisting of a regular app - available [here](https://github.com/novoda/gradle-static-analysis-plugin/tree/master/sample) - and the other comprising a multi-module setup available [here](https://github.com/novoda/gradle-static-analysis-plugin/tree/master/sample-multi-module). Both sample projects showcase a setup featuring Checkstyle, FindBugs, SpotBugs, PMD, Lint, Ktlint and Detekt.
## Snapshots
[![CI status](https://ci.novoda.com/buildStatus/icon?job=gradle-static-analysis-plugin-snapshot)](https://ci.novoda.com/job/gradle-static-analysis-plugin-snapshot/lastBuild/console) [![Download from Bintray](https://api.bintray.com/packages/novoda-oss/snapshots/gradle-static-analysis-plugin/images/download.svg)](https://bintray.com/novoda-oss/snapshots/gradle-static-analysis-plugin/_latestVersion)
diff --git a/docs/supported-tools.md b/docs/supported-tools.md
index 40905bd..8cff379 100644
--- a/docs/supported-tools.md
+++ b/docs/supported-tools.md
@@ -8,6 +8,7 @@ Tool | Java | Android
(Java) | Kotlin | Android
(Kotlin)
[`Checkstyle`](https://checkstyle.sourceforge.net) | :white_check_mark: | :white_check_mark: | — | —
[`PMD`](https://pmd.github.io) | :white_check_mark: | :white_check_mark: | — | —
[`FindBugs`](http://findbugs.sourceforge.net/) | :white_check_mark: | :white_check_mark: | — | —
+[`SpotBugs`](https://spotbugs.github.io/) | :white_check_mark: | :white_check_mark: | — | —
[`Detekt`](https://github.com/arturbosch/detekt) | — | — | :white_check_mark: | :white_check_mark:
[`Android Lint`](https://developer.android.com/studio/write/lint.html) | — | :white_check_mark:️ | — | :white_check_mark:️
[`KtLint`](https://github.com/shyiko/ktlint) | — | — | :white_check_mark:️ | :white_check_mark:️
@@ -22,6 +23,7 @@ For additional informations and tips on how to obtain advanced behaviours with t
* [Checkstyle](tools/checkstyle.md)
* [PMD](tools/pmd.md)
* [Findbugs](tools/findbugs.md)
+ * [SpotBugs](tools/spotbugs.md)
* [Android Lint](tools/android_lint.md)
* [KtLint](tools/ktlint.md)
* [Example configurations](#example-configurations)
@@ -40,6 +42,7 @@ staticAnalysis {
checkstyle {}
pmd {}
findbugs {}
+ spotbugs {}
lintOptions {}
detekt {}
ktlint {}
diff --git a/docs/tools/spotbugs.md b/docs/tools/spotbugs.md
new file mode 100644
index 0000000..2303074
--- /dev/null
+++ b/docs/tools/spotbugs.md
@@ -0,0 +1,29 @@
+# SpotBugs
+[SpotBugs](https://spotbugs.github.io/) is a static analysis tool that looks for potential bugs in Java code. It does not support Kotlin.
+It can be used in both pure Java, and Android Java projects. It then only makes sense to have SpotBugs enabled if you have Java code in your project.
+The plugin only runs SpotBugs on projects that contain the Java or the Android plugin.
+
+## Table of contents
+ * [Configure SpotBugs](#configure-spotbugs)
+ * [SpotBugs in mixed-language projects](#spotbugs-in-mixed-language-projects)
+
+---
+
+## Configure SpotBugs
+Enabling and configuring SpotBugs for a project is done through the `spotbugs` closure:
+
+```gradle
+spotbugs {
+ toolVersion // Optional string, the latest SpotBugs release (currently 4.0.0-beta4)
+ excludeFilter // A file containing the SpotBugs exclusions, e.g., teamPropsFile('static-analysis/spotbugs-excludes.xml')
+ htmlReportEnabled true // Control whether html report generation should be enabled. `true` by default.
+ includeVariants { variant -> ... } // A closure to determine which variants (only for Android) to include
+}
+```
+
+(assuming you're using the Novoda scaffolding system, see [Example configurations](#example-configurations) for more details)
+
+For more information about SpotBugs rules, refer to the [official website](https://spotbugs.readthedocs.io/en/latest/bugDescriptions.html).
+
+## SpotBugs in mixed-language projects
+If your project mixes Java and Kotlin code, you will need to exclude your Kotlin files by using `excludeFilter`
diff --git a/plugin/src/main/groovy/com/novoda/staticanalysis/StaticAnalysisPlugin.groovy b/plugin/src/main/groovy/com/novoda/staticanalysis/StaticAnalysisPlugin.groovy
index 2e3de10..36f1719 100644
--- a/plugin/src/main/groovy/com/novoda/staticanalysis/StaticAnalysisPlugin.groovy
+++ b/plugin/src/main/groovy/com/novoda/staticanalysis/StaticAnalysisPlugin.groovy
@@ -7,6 +7,7 @@ import com.novoda.staticanalysis.internal.findbugs.FindbugsConfigurator
import com.novoda.staticanalysis.internal.ktlint.KtlintConfigurator
import com.novoda.staticanalysis.internal.lint.LintConfigurator
import com.novoda.staticanalysis.internal.pmd.PmdConfigurator
+import com.novoda.staticanalysis.internal.spotbugs.SpotBugsConfigurator
import org.gradle.api.NamedDomainObjectContainer
import org.gradle.api.Plugin
import org.gradle.api.Project
@@ -42,6 +43,7 @@ class StaticAnalysisPlugin implements Plugin {
CheckstyleConfigurator.create(project, violationsContainer, evaluateViolations),
PmdConfigurator.create(project, violationsContainer, evaluateViolations),
FindbugsConfigurator.create(project, violationsContainer, evaluateViolations),
+ SpotBugsConfigurator.create(project, violationsContainer, evaluateViolations),
DetektConfigurator.create(project, violationsContainer, evaluateViolations),
KtlintConfigurator.create(project, violationsContainer, evaluateViolations),
LintConfigurator.create(project, violationsContainer, evaluateViolations)
diff --git a/plugin/src/main/groovy/com/novoda/staticanalysis/internal/spotbugs/SpotBugsConfigurator.groovy b/plugin/src/main/groovy/com/novoda/staticanalysis/internal/spotbugs/SpotBugsConfigurator.groovy
new file mode 100644
index 0000000..75b199d
--- /dev/null
+++ b/plugin/src/main/groovy/com/novoda/staticanalysis/internal/spotbugs/SpotBugsConfigurator.groovy
@@ -0,0 +1,171 @@
+package com.novoda.staticanalysis.internal.spotbugs
+
+import com.novoda.staticanalysis.StaticAnalysisExtension
+import com.novoda.staticanalysis.Violations
+import com.novoda.staticanalysis.internal.Configurator
+import com.novoda.staticanalysis.internal.VariantFilter
+import com.novoda.staticanalysis.internal.findbugs.CollectFindbugsViolationsTask
+import com.novoda.staticanalysis.internal.findbugs.GenerateFindBugsHtmlReport
+import org.gradle.api.*
+import org.gradle.api.tasks.SourceTask
+
+import static com.novoda.staticanalysis.internal.Exceptions.handleException
+import static com.novoda.staticanalysis.internal.TasksCompat.createTask
+
+class SpotBugsConfigurator implements Configurator {
+
+ private static final String SPOTBUGS_PLUGIN = 'com.github.spotbugs'
+ private static final String SPOTBUGS_NOT_APPLIED = "The SpotBugs plugin is configured but not applied. Please apply the plugin: $SPOTBUGS_PLUGIN in your build script."
+ private static final String SPOTBUGS_CONFIGURATION_ERROR = "A problem occurred while configuring SpotBugs."
+
+ private final Project project
+ private final Violations violations
+ private final Task evaluateViolations
+ private final VariantFilter variantFilter
+ protected boolean htmlReportEnabled = true
+ protected boolean configured = false
+
+ static SpotBugsConfigurator create(Project project,
+ NamedDomainObjectContainer violationsContainer,
+ Task evaluateViolations) {
+ Violations violations = violationsContainer.maybeCreate('SpotBugs')
+ return new SpotBugsConfigurator(project, violations, evaluateViolations)
+ }
+
+ SpotBugsConfigurator(Project project, Violations violations, Task evaluateViolations) {
+ this.project = project
+ this.violations = violations
+ this.evaluateViolations = evaluateViolations
+ this.variantFilter = new VariantFilter(project)
+ }
+
+ @Override
+ void execute() {
+ project.extensions.findByType(StaticAnalysisExtension).ext.spotbugs = { Closure config ->
+ if (!project.plugins.hasPlugin(SPOTBUGS_PLUGIN)) {
+ throw new GradleException(SPOTBUGS_NOT_APPLIED)
+ }
+
+ configureSpotBugsExtension(config)
+
+ project.plugins.withId('com.android.application') {
+ configureAndroidWithVariants(variantFilter.filteredApplicationVariants)
+ }
+ project.plugins.withId('com.android.library') {
+ configureAndroidWithVariants(variantFilter.filteredLibraryVariants)
+ }
+ project.plugins.withId('java') {
+ configureJavaProject()
+ }
+ }
+ }
+
+ private void configureSpotBugsExtension(Closure config) {
+ try {
+ def spotbugs = project.spotbugs
+ spotbugs.ext.includeVariants = { Closure filter ->
+ variantFilter.includeVariantsFilter = filter
+ }
+ spotbugs.ext.htmlReportEnabled = { boolean enabled -> this.htmlReportEnabled = enabled }
+ config.delegate = spotbugs
+ config.resolveStrategy = Closure.DELEGATE_FIRST
+ config()
+ } catch (Exception exception) {
+ handleException(SPOTBUGS_CONFIGURATION_ERROR, exception)
+ }
+ }
+
+ protected void configureAndroidWithVariants(DomainObjectSet variants) {
+ if (configured) return
+
+ variants.all { configureVariant(it) }
+ variantFilter.filteredTestVariants.all { configureVariant(it) }
+ variantFilter.filteredUnitTestVariants.all { configureVariant(it) }
+ configured = true
+ }
+
+ private void configureVariant(variant) {
+ createToolTaskForAndroid(variant)
+ def collectViolations = createCollectViolations(getToolTaskNameFor(variant), violations)
+ evaluateViolations.dependsOn collectViolations
+ }
+
+ private void createToolTaskForAndroid(variant) {
+ createTask(project, getToolTaskNameFor(variant), Class.forName('com.github.spotbugs.SpotBugsTask')) { SourceTask task ->
+ def javaCompile = javaCompile(variant)
+ def androidSourceDirs = variant.sourceSets.collect {
+ it.javaDirectories
+ }.flatten()
+ task.description = "Run SpotBugs analysis for ${variant.name} classes"
+ task.setSource(androidSourceDirs)
+ task.classpath = javaCompile.classpath
+ task.extraArgs '-auxclasspath', androidJar
+ task.conventionMapping.map("classes") {
+ project.fileTree(javaCompile.destinationDir)
+ }
+ task.dependsOn javaCompile
+ }
+ }
+
+ private void configureJavaProject() {
+ if (configured) return
+
+ project.sourceSets.all { sourceSet ->
+ def collectViolations = createCollectViolations(getToolTaskNameFor(sourceSet), violations)
+ evaluateViolations.dependsOn collectViolations
+ }
+ configured = true
+ }
+
+ private def createCollectViolations(String taskName, Violations violations) {
+ if (htmlReportEnabled) {
+ createHtmlReportTask(taskName)
+ }
+ createTask(project, "collect${taskName.capitalize()}Violations", CollectFindbugsViolationsTask) { task ->
+ def spotbugs = project.tasks[taskName] as SourceTask
+ configureToolTask(spotbugs)
+ task.xmlReportFile = spotbugs.reports.xml.destination
+ task.violations = violations
+
+ if (htmlReportEnabled) {
+ task.dependsOn project.tasks["generate${taskName.capitalize()}HtmlReport"]
+ } else {
+ task.dependsOn spotbugs
+ }
+ }
+ }
+
+ private void createHtmlReportTask(String taskName) {
+ createTask(project, "generate${taskName.capitalize()}HtmlReport", GenerateFindBugsHtmlReport) { GenerateFindBugsHtmlReport task ->
+ def spotbugs = project.tasks[taskName]
+ task.xmlReportFile = spotbugs.reports.xml.destination
+ task.htmlReportFile = new File(task.xmlReportFile.absolutePath - '.xml' + '.html')
+ task.classpath = spotbugs.spotbugsClasspath
+ task.dependsOn spotbugs
+ }
+ }
+
+ private static void configureToolTask(SourceTask task) {
+ task.group = 'verification'
+ task.exclude '**/*.kt'
+ task.ignoreFailures = true
+ task.reports.xml.enabled = true
+ task.reports.html.enabled = false
+ }
+
+ private static String getToolTaskNameFor(named) {
+ "spotbugs${named.name.capitalize()}"
+ }
+
+ private static def javaCompile(variant) {
+ if (variant.hasProperty('javaCompileProvider')) {
+ variant.javaCompileProvider.get()
+ } else {
+ variant.javaCompile
+ }
+ }
+
+ private def getAndroidJar() {
+ "${project.android.sdkDirectory}/platforms/${project.android.compileSdkVersion}/android.jar"
+ }
+}
diff --git a/plugin/src/test/groovy/com/novoda/staticanalysis/internal/spotbugs/SpotBugsIntegrationTest.groovy b/plugin/src/test/groovy/com/novoda/staticanalysis/internal/spotbugs/SpotBugsIntegrationTest.groovy
new file mode 100644
index 0000000..b3df238
--- /dev/null
+++ b/plugin/src/test/groovy/com/novoda/staticanalysis/internal/spotbugs/SpotBugsIntegrationTest.groovy
@@ -0,0 +1,195 @@
+package com.novoda.staticanalysis.internal.spotbugs
+
+import com.google.common.truth.Truth
+import com.novoda.test.TestProject
+import com.novoda.test.TestProjectRule
+import org.gradle.testkit.runner.TaskOutcome
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+
+import static com.novoda.test.Fixtures.Findbugs.*
+import static com.novoda.test.LogsSubject.assertThat
+
+@RunWith(Parameterized.class)
+class SpotBugsIntegrationTest {
+
+ @Parameterized.Parameters(name = "{0}")
+ static Iterable rules() {
+ return [TestProjectRule.forJavaProject(), TestProjectRule.forAndroidProject()]
+ }
+
+ @Rule
+ public final TestProjectRule projectRule
+
+ SpotBugsIntegrationTest(TestProjectRule projectRule) {
+ this.projectRule = projectRule
+ }
+
+ @Test
+ void shouldFailBuildWhenSpotBugsWarningsOverTheThreshold() {
+ TestProject.Result result = createProjectWith()
+ .withSourceSet('debug', SOURCES_WITH_LOW_VIOLATION, SOURCES_WITH_MEDIUM_VIOLATION)
+ .withPenalty('''{
+ maxErrors = 0
+ maxWarnings = 1
+ }''')
+ .withToolsConfig('spotbugs {}')
+ .buildAndFail('check')
+
+ assertThat(result.logs).containsLimitExceeded(0, 1)
+ assertThat(result.logs).containsSpotBugsViolations(0, 2,
+ result.buildFileUrl('reports/spotbugs/debug.html'))
+ }
+
+ @Test
+ void shouldFailBuildAfterSecondRunWhenSpotBugsWarningsStillOverTheThreshold() {
+ def project = createProjectWith()
+ .withSourceSet('debug', SOURCES_WITH_LOW_VIOLATION, SOURCES_WITH_MEDIUM_VIOLATION)
+ .withPenalty('''{
+ maxErrors = 0
+ maxWarnings = 1
+ }''')
+ .withToolsConfig('spotbugs {}')
+
+ TestProject.Result result = project.buildAndFail('check')
+
+ assertThat(result.logs).containsLimitExceeded(0, 1)
+ assertThat(result.logs).containsSpotBugsViolations(0, 2,
+ result.buildFileUrl('reports/spotbugs/debug.html'))
+
+ result = project.buildAndFail('check')
+
+ assertThat(result.logs).containsLimitExceeded(0, 1)
+ assertThat(result.logs).containsSpotBugsViolations(0, 2,
+ result.buildFileUrl('reports/spotbugs/debug.html'))
+ }
+
+ @Test
+ void shouldDetectMoreWarningsWhenEffortIsMaxAndReportLevelIsLow() {
+ TestProject.Result result = createProjectWith()
+ .withSourceSet('debug', SOURCES_WITH_LOW_VIOLATION, SOURCES_WITH_MEDIUM_VIOLATION)
+ .withPenalty('''{
+ maxErrors = 0
+ maxWarnings = 1
+ }''')
+ .withToolsConfig("spotbugs { effort = 'max' \n reportLevel = 'low'}")
+ .buildAndFail('check')
+
+ assertThat(result.logs).containsLimitExceeded(0, 2)
+ assertThat(result.logs).containsSpotBugsViolations(0, 3,
+ result.buildFileUrl('reports/spotbugs/debug.html'))
+ }
+
+ @Test
+ void shouldFailBuildWhenSpotBugsErrorsOverTheThreshold() {
+ TestProject.Result result = createProjectWith()
+ .withSourceSet('debug', SOURCES_WITH_HIGH_VIOLATION)
+ .withPenalty('''{
+ maxErrors = 0
+ maxWarnings = 0
+ }''')
+ .withToolsConfig('spotbugs {}')
+ .buildAndFail('check')
+
+ assertThat(result.logs).containsLimitExceeded(1, 0)
+ assertThat(result.logs).containsSpotBugsViolations(1, 0,
+ result.buildFileUrl('reports/spotbugs/debug.html'))
+ }
+
+ @Test
+ void shouldNotFailBuildWhenNoSpotBugsWarningsOrErrorsEncounteredAndNoThresholdTrespassed() {
+ TestProject.Result result = createProjectWith()
+ .withPenalty('''{
+ maxErrors = 0
+ maxWarnings = 0
+ }''')
+ .withToolsConfig('spotbugs {}')
+ .build('check')
+
+ assertThat(result.logs).doesNotContainLimitExceeded()
+ assertThat(result.logs).doesNotContainSpotBugsViolations()
+ }
+
+ @Test
+ void shouldNotFailBuildWhenSpotBugsWarningsAndErrorsEncounteredAndNoThresholdTrespassed() {
+ TestProject.Result result = createProjectWith()
+ .withSourceSet('debug', SOURCES_WITH_LOW_VIOLATION, SOURCES_WITH_MEDIUM_VIOLATION)
+ .withSourceSet('release', SOURCES_WITH_HIGH_VIOLATION)
+ .withPenalty('''{
+ maxErrors = 10
+ maxWarnings = 10
+ }''')
+ .withToolsConfig('spotbugs {}')
+ .build('check')
+
+ assertThat(result.logs).doesNotContainLimitExceeded()
+ assertThat(result.logs).containsSpotBugsViolations(1, 2,
+ result.buildFileUrl('reports/spotbugs/debug.html'),
+ result.buildFileUrl('reports/spotbugs/release.html'))
+ }
+
+ @Test
+ void shouldNotFailBuildWhenSpotBugsConfiguredToNotIgnoreFailures() {
+ createProjectWith()
+ .withSourceSet('debug', SOURCES_WITH_LOW_VIOLATION, SOURCES_WITH_MEDIUM_VIOLATION)
+ .withSourceSet('release', SOURCES_WITH_HIGH_VIOLATION)
+ .withPenalty('''{
+ maxErrors = 10
+ maxWarnings = 10
+ }''')
+ .withToolsConfig('spotbugs { ignoreFailures = false }')
+ .build('check')
+ }
+
+ @Test
+ void shouldNotFailBuildWhenSpotBugsIsConfiguredMultipleTimes() {
+ createProjectWith()
+ .withSourceSet('main', SOURCES_WITH_LOW_VIOLATION)
+ .withPenalty('none')
+ .withToolsConfig("""
+ spotbugs { }
+ spotbugs {
+ effort = "max"
+ }
+ """)
+ .build('check')
+ }
+
+ @Test
+ void shouldBeUpToDateWhenCheckTaskRunsAgain() {
+ def project = createProjectWith()
+ .withSourceSet('debug', SOURCES_WITH_LOW_VIOLATION, SOURCES_WITH_MEDIUM_VIOLATION)
+ .withSourceSet('release', SOURCES_WITH_HIGH_VIOLATION)
+ .withPenalty('''{
+ maxErrors = 10
+ maxWarnings = 10
+ }''')
+ .withToolsConfig('spotbugs {}')
+
+ project.build('check')
+
+ def result = project.build('check')
+
+ Truth.assertThat(result.outcome(':spotbugsDebug')).isEqualTo(TaskOutcome.UP_TO_DATE)
+ Truth.assertThat(result.outcome(':generateSpotbugsDebugHtmlReport')).isEqualTo(TaskOutcome.UP_TO_DATE)
+ }
+
+ @Test
+ void shouldNotGenerateHtmlWhenDisabled() {
+ def result = createProjectWith()
+ .withSourceSet('main', SOURCES_WITH_LOW_VIOLATION)
+ .withToolsConfig('''spotbugs {
+ htmlReportEnabled false
+ }''')
+ .build('check')
+
+ Truth.assertThat(result.tasksPaths).doesNotContain(':generateSpotBugsDebugHtmlReport')
+ }
+
+ private TestProject createProjectWith() {
+ projectRule.newProject()
+ .withPlugin('com.github.spotbugs', "2.0.0")
+ }
+}
diff --git a/plugin/src/test/groovy/com/novoda/test/LogsSubject.groovy b/plugin/src/test/groovy/com/novoda/test/LogsSubject.groovy
index 35fb1e9..9f56360 100644
--- a/plugin/src/test/groovy/com/novoda/test/LogsSubject.groovy
+++ b/plugin/src/test/groovy/com/novoda/test/LogsSubject.groovy
@@ -17,6 +17,7 @@ class LogsSubject extends Subject {
private static final String CHECKSTYLE_VIOLATIONS_FOUND = 'Checkstyle violations found'
private static final String PMD_VIOLATIONS_FOUND = 'PMD violations found'
private static final String FINDBUGS_VIOLATIONS_FOUND = 'Findbugs violations found'
+ private static final String SPOTBUGS_VIOLATIONS_FOUND = 'SpotBugs violations found'
private static final String DETEKT_VIOLATIONS_FOUND = 'Detekt violations found'
private static final String KTLINT_VIOLATIONS_FOUND = 'ktlint violations found'
private static final String LINT_VIOLATIONS_FOUND = 'Lint violations found'
@@ -68,6 +69,10 @@ class LogsSubject extends Subject {
outputSubject.doesNotContain(FINDBUGS_VIOLATIONS_FOUND)
}
+ public void doesNotContainSpotBugsViolations() {
+ outputSubject.doesNotContain(SPOTBUGS_VIOLATIONS_FOUND)
+ }
+
public void doesNotContainDetektViolations() {
outputSubject.doesNotContain(DETEKT_VIOLATIONS_FOUND)
}
@@ -92,6 +97,10 @@ class LogsSubject extends Subject {
containsToolViolations(FINDBUGS_VIOLATIONS_FOUND, errors, warnings, reportUrls)
}
+ public void containsSpotBugsViolations(int errors, int warnings, String... reportUrls) {
+ containsToolViolations(SPOTBUGS_VIOLATIONS_FOUND, errors, warnings, reportUrls)
+ }
+
public void containsDetektViolations(int errors, int warnings, String... reportUrls) {
containsToolViolations(DETEKT_VIOLATIONS_FOUND, errors, warnings, reportUrls)
}
diff --git a/sample-multi-module/build.gradle b/sample-multi-module/build.gradle
index 73afee0..61e4532 100644
--- a/sample-multi-module/build.gradle
+++ b/sample-multi-module/build.gradle
@@ -11,6 +11,7 @@ buildscript {
classpath 'com.novoda:gradle-static-analysis-plugin:local'
classpath 'io.gitlab.arturbosch.detekt:detekt-gradle-plugin:1.0.0-RC14'
classpath 'org.jlleitschuh.gradle:ktlint-gradle:9.0.0'
+ classpath "gradle.plugin.com.github.spotbugs:spotbugs-gradle-plugin:2.0.0"
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
diff --git a/sample-multi-module/core/src/main/java/com/novoda/staticanalysisplugin/sample/SomeJavaClass.java b/sample-multi-module/core/src/main/java/com/novoda/staticanalysisplugin/sample/SomeJavaClass.java
index 2fd1406..28bd695 100644
--- a/sample-multi-module/core/src/main/java/com/novoda/staticanalysisplugin/sample/SomeJavaClass.java
+++ b/sample-multi-module/core/src/main/java/com/novoda/staticanalysisplugin/sample/SomeJavaClass.java
@@ -1,4 +1,18 @@
package com.novoda.staticanalysisplugin.sample;
public class SomeJavaClass {
+
+ private void THIS_IS_A_VERY_VERY_VERY_LONG_NAME_FOR_A_METHOD_IT_IS_IN_FACT_VERY_LONG_INDEED_NO_NEED_TO_COUNT_THE_NUMBER_OF_CHARACTERS_YOU_CAN_CLEARLY_SEE_THIS_IS_WAY_LONGER_THAN_IT_SHOULD(int duration) {
+ // no-op
+ }
+
+ public static class Internal {
+
+ public void impossibleCast() {
+ final Object doubleValue = Double.valueOf(1.0);
+ final Long value = (Long) doubleValue;
+ System.out.println(" - " + value);
+ }
+
+ }
}
diff --git a/sample-multi-module/team-props/static-analysis.gradle b/sample-multi-module/team-props/static-analysis.gradle
index 3d7b7c7..aefa67f 100644
--- a/sample-multi-module/team-props/static-analysis.gradle
+++ b/sample-multi-module/team-props/static-analysis.gradle
@@ -1,6 +1,7 @@
apply plugin: 'com.novoda.static-analysis'
apply plugin: 'io.gitlab.arturbosch.detekt'
apply plugin: 'org.jlleitschuh.gradle.ktlint'
+apply plugin: 'com.github.spotbugs'
staticAnalysis {
@@ -27,6 +28,11 @@ staticAnalysis {
includeVariants { variant -> variant.name.contains('debug') }
}
+ spotbugs {
+ excludeFilter rootProject.file('team-props/findbugs-excludes.xml')
+ includeVariants { variant -> variant.name.contains('debug') }
+ }
+
lintOptions {
lintConfig rootProject.file('team-props/lint-config.xml')
checkReleaseBuilds false
diff --git a/sample/app/build.gradle b/sample/app/build.gradle
index a49ab7f..320a155 100755
--- a/sample/app/build.gradle
+++ b/sample/app/build.gradle
@@ -1,6 +1,7 @@
plugins {
id 'io.gitlab.arturbosch.detekt'
- id "org.jlleitschuh.gradle.ktlint"
+ id 'org.jlleitschuh.gradle.ktlint'
+ id 'com.github.spotbugs'
}
apply plugin: 'com.android.application'
@@ -51,6 +52,11 @@ staticAnalysis {
includeVariants { variant -> variant.name.contains('debug') }
}
+ spotbugs {
+ excludeFilter rootProject.file('team-props/findbugs-excludes.xml')
+ includeVariants { variant -> variant.name.contains('debug') }
+ }
+
lintOptions {
lintConfig rootProject.file('team-props/lint-config.xml')
checkReleaseBuilds false
diff --git a/sample/build.gradle b/sample/build.gradle
index a784b83..a2f6efa 100755
--- a/sample/build.gradle
+++ b/sample/build.gradle
@@ -11,6 +11,7 @@ buildscript {
classpath 'com.novoda:gradle-static-analysis-plugin:local'
classpath 'io.gitlab.arturbosch.detekt:detekt-gradle-plugin:1.0.0-RC14'
classpath 'org.jlleitschuh.gradle:ktlint-gradle:9.0.0'
+ classpath "gradle.plugin.com.github.spotbugs:spotbugs-gradle-plugin:2.0.0"
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}