Skip to content

Instantly share code, notes, and snippets.

@miguel-vila
Created May 28, 2024 12:42
Show Gist options
  • Save miguel-vila/e96efe3af7eaa1f687104e8c8eaabd62 to your computer and use it in GitHub Desktop.
Save miguel-vila/e96efe3af7eaa1f687104e8c8eaabd62 to your computer and use it in GitHub Desktop.
import edu.umd.cs.findbugs.{Project => SpotBugsProject}
import edu.umd.cs.findbugs.{SystemProperties => FindBugsSystemProperties}
import edu.umd.cs.findbugs.config.UserPreferences
import edu.umd.cs.findbugs.BugCollectionBugReporter
import edu.umd.cs.findbugs.DetectorFactoryCollection
import edu.umd.cs.findbugs.FindBugs2
import edu.umd.cs.findbugs.PrintingBugReporter
import edu.umd.cs.findbugs.Priorities
import sbt.Keys._
import scala.util.control.NonFatal
import _root_.sbt._
object SxmJavaSpotBugsPlugin extends AutoPlugin {
object PriorityThreshold extends Enumeration {
type PriorityThreshold = Value
val Ignore, Experimental, Low, Normal, High = Value
}
object autoImport {
lazy val spotbugs = taskKey[Unit]("Runs SpotBugs over Java code")
lazy val spotbugsExcludeFilter = settingKey[File]("SpotBugs exclude filter file")
lazy val spotbugsPriorityThreshold = settingKey[PriorityThreshold.Value]("SpotBugs priority threshold")
lazy val spotbugsRelaxed = settingKey[Boolean]("SpotBugs relaxed mode")
lazy val spotbugsSystemProperties = settingKey[Map[String, String]]("SpotBugs system properties")
}
import autoImport._
override lazy val projectSettings = Seq(
spotbugsExcludeFilter := file("exclude-filter.xml"),
spotbugsPriorityThreshold := PriorityThreshold.Normal,
spotbugsRelaxed := true,
spotbugsSystemProperties := Map.empty,
spotbugs := {
val classFiles = (Compile / classDirectory).value
val log = streams.value.log
log.info("Running SpotBugs analysis...")
val project = new SpotBugsProject()
project.addFile(classFiles.getAbsolutePath)
val classpath = (Compile / fullClasspath).value
classpath.map(_.data.getAbsolutePath).foreach(project.addAuxClasspathEntry)
// the location of this setting is important. Seems it might be better
// to set it before instantiating things that might use it.
setSystemProperties(spotbugsSystemProperties.value)
val bugReporter = new BugCollectionBugReporter(project)
bugReporter.setPriorityThreshold(priorityThresholdToSpotBugsPriority(spotbugsPriorityThreshold.value))
bugReporter.setIsRelaxed(spotbugsRelaxed.value)
val findBugs = new FindBugs2()
findBugs.setBugReporter(bugReporter)
findBugs.setProject(project)
findBugs.setDetectorFactoryCollection(new DetectorFactoryCollection())
val excludeFilterFile = spotbugsExcludeFilter.value
if (excludeFilterFile.exists()) {
findBugs.addFilter(excludeFilterFile.getAbsolutePath, false)
}
val preferences = UserPreferences.createDefaultUserPreferences()
findBugs.setUserPreferences(preferences)
try {
findBugs.execute()
log.info("SpotBugs analysis completed.")
val printingBugReporter = new PrintingBugReporter()
printingBugReporter.setPriorityThreshold(priorityThresholdToSpotBugsPriority(spotbugsPriorityThreshold.value))
printingBugReporter.setIsRelaxed(spotbugsRelaxed.value)
printingBugReporter.setUseLongBugCodes(true)
val bugCollection = bugReporter.getBugCollection()
bugCollection.forEach { bug =>
printingBugReporter.reportBug(bug)
}
if (bugCollection.getCollection().size() > 0) {
sys.error("SpotBugs found issues in the codebase.")
}
} catch {
case NonFatal(e) =>
log.error("Error running SpotBugs analysis: " + e.getMessage)
e.printStackTrace()
sys.error("SpotBugs analysis failed.")
}
},
)
private def priorityThresholdToSpotBugsPriority(priorityThreshold: PriorityThreshold.Value): Int = {
priorityThreshold match {
case PriorityThreshold.Ignore => Priorities.IGNORE_PRIORITY
case PriorityThreshold.Experimental => Priorities.EXP_PRIORITY
case PriorityThreshold.Low => Priorities.LOW_PRIORITY
case PriorityThreshold.Normal => Priorities.NORMAL_PRIORITY
case PriorityThreshold.High => Priorities.HIGH_PRIORITY
}
}
private def setSystemProperties(systemProperties: Map[String, String]): Unit = {
systemProperties.foreach { case (key, value) =>
FindBugsSystemProperties.setProperty(key, value)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment