sbt-sonar is an sbt plugin, which provides an easy way to integrate Scala projects with SonarQube - a tool for continuous code inspection and quality management ✅.
Under the hood, it uses the embedded sonar-scanner API library, which allows you to run SonarQube scan without the need to have the sonar-scanner executable installed in your environment.
This plugin is particularly useful for CI when used together with e.g. sbt-release plugin for an automated release process in your project, but it can be also used on its own.
- sbt 1.x or sbt 2.x. Version
3.0.0is published for sbt 1.x (sbt-sonar_2.12_1.0) and sbt 2.x (sbt-sonar_sbt2_3). - A reachable SonarQube server.
- For Scala coverage and static-analysis reports, a SonarQube Scala plugin that understands the report properties you configure.
Add the plugin to project/plugins.sbt:
addSbtPlugin("io.github.yarosman" % "sbt-sonar" % "3.0.0")Use the same addSbtPlugin line for sbt 1 and sbt 2 projects. sbt resolves the
correct published artifact for the running sbt version.
The plugin is an auto plugin with allRequirements, so it is enabled
automatically. You only need imports when you refer to its settings or task in
build.sbt.
Define at least the SonarQube server URL in build.sbt:
import sbtsonar.SonarPlugin.autoImport.sonarProperties
sonarProperties ++= Map(
"sonar.host.url" -> "https://sonarqube.example.com"
)Run analysis from sbt:
sbt sonarScanYou can also pass Sonar properties as JVM system properties. These values
override values from sonarProperties:
sbt -Dsonar.host.url=https://sonarqube.example.com -Dsonar.token="$SONAR_TOKEN" sonarScanBy default, sonarScan uses the sonarProperties setting. sbt-sonar adds these
properties automatically:
sonar.projectNamefromnamesonar.projectKeyfromnormalizedNamesonar.projectVersionfromversionwhensonarScanrunssonar.projectBaseDirfrombaseDirectorysonar.sourceEncodingasUTF-8sonar.scala.versionfromscalaVersionsonar.sourcesfromCompile / scalaSource, relative tobaseDirectorysonar.testsfromTest / scalaSource, relative tobaseDirectory- Scala coverage and Scapegoat report paths under
Compile / crossTarget
Append your project-specific values with ++=:
import sbtsonar.SonarPlugin.autoImport.sonarProperties
sonarProperties ++= Map(
"sonar.host.url" -> "https://sonarqube.example.com",
"sonar.projectName" -> "My Scala Service",
"sonar.projectKey" -> "my-scala-service",
"sonar.sources" -> "src/main/scala",
"sonar.tests" -> "src/test/scala",
"sonar.junit.reportPaths" -> "target/test-reports"
)Replace the generated properties completely with :=:
import sbtsonar.SonarPlugin.autoImport.sonarProperties
sonarProperties := Map(
"sonar.host.url" -> "https://sonarqube.example.com",
"sonar.projectName" -> "My Scala Service",
"sonar.projectKey" -> "my-scala-service",
"sonar.projectVersion" -> version.value,
"sonar.projectBaseDir" -> baseDirectory.value.getAbsolutePath,
"sonar.sources" -> "src/main/scala",
"sonar.tests" -> "src/test/scala",
"sonar.sourceEncoding" -> "UTF-8",
"sonar.scala.version" -> scalaVersion.value
)For the official SonarScala plugin, sbt-sonar generates:
sonar.scala.coverage.reportPaths
sonar.scala.scapegoat.reportPathsIf you prefer a Sonar Scanner properties file, create
sonar-project.properties in the project root:
sonar.host.url=https://sonarqube.example.com
sonar.projectKey=my-scala-service
sonar.projectName=My Scala Service
sonar.projectVersion=0.1.0
sonar.sources=src/main/scala
sonar.tests=src/test/scala
sonar.sourceEncoding=UTF-8Enable external config in build.sbt:
import sbtsonar.SonarPlugin.autoImport.sonarUseExternalConfig
sonarUseExternalConfig := trueWhen sonarScan runs with the embedded scanner, sbt-sonar reads the file and
passes the current sbt version as sonar.projectVersion to the scanner. In
standalone scanner mode, sbt-sonar updates sonar.projectVersion in the file
before invoking sonar-scanner.
For an aggregated build, define module properties on the root project and run
sonarScan only once from that root project:
import sbtsonar.SonarPlugin.autoImport.sonarProperties
import sbtsonar.SonarPlugin.autoImport.sonarScan
lazy val commonSettings = Seq(
scalaVersion := "2.12.20",
version := "0.1.0"
)
lazy val module1 = (project in file("module1"))
.settings(commonSettings)
.settings(name := "module1")
lazy val module2 = (project in file("module2"))
.settings(commonSettings)
.settings(name := "module2")
lazy val root = (project in file("."))
.aggregate(module1, module2)
.settings(commonSettings)
.settings(
name := "multi-module",
sonarScan / aggregate := false,
sonarProperties ++= Map(
"sonar.host.url" -> "https://sonarqube.example.com",
"sonar.projectName" -> "Multi Module",
"sonar.projectKey" -> "multi-module",
"sonar.modules" -> "module1,module2",
"module1.sonar.projectName" -> "Module 1",
"module1.sonar.projectBaseDir" -> "module1",
"module2.sonar.projectName" -> "Module 2",
"module2.sonar.projectBaseDir" -> "module2"
)
)sonarScan / aggregate := false prevents sbt from running sonarScan again in
each aggregated subproject.
The default scanner mode is embedded:
sonarUseSonarScannerCli := falseUse standalone mode only when you intentionally want sbt-sonar to call an
installed sonar-scanner executable:
import sbtsonar.SonarPlugin.autoImport.sonarUseSonarScannerCli
sonarUseSonarScannerCli := trueStandalone mode requires either:
SONAR_SCANNER_HOMEin the environment, or-DsonarScanner.home=/path/to/sonar-scanner
The executable must exist at bin/sonar-scanner on Unix-like systems or
bin/sonar-scanner.bat on Windows under that directory.
Example:
SONAR_SCANNER_HOME=/opt/sonar-scanner \
sbt -Dsonar.host.url=https://sonarqube.example.com sonarScanWhen using sbt-release, run sonarScan
after tests, coverage, and other report-generating tasks:
import sbtrelease.ReleasePlugin.autoImport.ReleaseStep
import sbtrelease.ReleasePlugin.autoImport.releaseProcess
import sbtrelease.ReleasePlugin.autoImport.releaseStepCommand
import sbtrelease.ReleasePlugin.autoImport.releaseStepTask
import sbtsonar.SonarPlugin.autoImport.sonarScan
releaseProcess := Seq[ReleaseStep](
releaseStepCommand("coverageOn"),
releaseStepTask(Test / test),
releaseStepCommand("coverageOff"),
releaseStepTask(coverageReport),
releaseStepTask(scapegoat),
releaseStepTask(sonarScan)
)Adapt the release steps to the coverage and static-analysis plugins used by your build.
The repository contains scripted example builds under
src/sbt-test/sbt-sonar:
sbt-1.0- minimal sbt 1.x project.sbt-2.0- minimal sbt 2.x project.external-config- externalsonar-project.propertieswith sbt 1.x.external-config-sbt-2.0- externalsonar-project.propertieswith sbt 2.x.multi-moduleandmulti-module-sbt-2.0- aggregated multi-module builds.multi-module-not-on-root-with-correct-configandmulti-module-not-on-root-with-correct-config-sbt-2.0- module directories that need explicit
sonar.projectBaseDirvalues.
- module directories that need explicit
3.0.0removes sbt 0.13 and Scala 2.11 support.3.0.0adds sbt 2.x support and publishessbt-sonar_sbt2_3.- The current published artifacts are
io.github.yarosman:sbt-sonar_2.12_1.0:3.0.0for sbt 1.x andio.github.yarosman:sbt-sonar_sbt2_3:3.0.0for sbt 2.x. In sbt builds, useaddSbtPlugin("io.github.yarosman" % "sbt-sonar" % "3.0.0"). - The embedded scanner remains the default. Set
sonarUseSonarScannerCli := trueonly for standalone scanner mode.
The project is licensed under the Apache License v2. See the LICENSE file for more details.