- Scala Code Health Tools
scalastyle
(static analysis)]scapegoat
(static analysis)- sbt-jacoco (code coverage)
- OWASP Dependency Checker (vulnerability scan)
- Also Considered
Evaluation of code health tools for Scala project, using 'geotrellis-raster' package for evaluation.
Main focus is to produce useful code health reports. Integration with the Scala Build Tool (SBT) is a plus for ease of use.
Bulk of the implemented rules focus on consistent code style.
The plugin is easy to use and easy to integrate
- The SBT plugin is easy to configure and run
- XML report confirms to `checkstyle` format, supported by SonarQube
- Plugins for Eclipse, IntelliJ, Emacs
This is good tool that we will integrate into CI. Overall having automatic feedback on style will make it easier to accept contributions while keeping the code base visually consistent.
We will have to go through an effort of selecting rule subset and enforcing it in existing code before enabling CI.
[warn] /Users/eugene/geotrellis/raster/src/main/scala/geotrellis/raster/summary/polygonal/MeanSummary.scala:30:6: Public method must have explicit type
[warn] /Users/eugene/geotrellis/raster/src/main/scala/geotrellis/raster/summary/polygonal/MeanSummary.scala:34:6: Public method must have explicit type
[warn] /Users/eugene/geotrellis/raster/src/main/scala/geotrellis/raster/summary/polygonal/MeanSummary.scala:41:6: Public method must have explicit type
[warn] /Users/eugene/geotrellis/raster/src/main/scala/geotrellis/raster/summary/polygonal/MinSummary.scala:1: Header does not match expected text
[warn] /Users/eugene/geotrellis/raster/src/main/scala/geotrellis/raster/summary/polygonal/MinSummary.scala:45:4: If block needs braces
[warn] /Users/eugene/geotrellis/raster/src/main/scala/geotrellis/raster/summary/polygonal/MinSummary.scala:78:4: If block needs braces
[warn] /Users/eugene/geotrellis/raster/src/main/scala/geotrellis/raster/summary/polygonal/MinSummary.scala:111:4: If block needs braces
[warn] /Users/eugene/geotrellis/raster/src/main/scala/geotrellis/raster/summary/polygonal/MinSummary.scala:144:4: If block needs braces
[warn] /Users/eugene/geotrellis/raster/src/main/scala/geotrellis/raster/summary/polygonal/MultibandTilePolygonalSummaryHandler.scala:1: Header does not match expected text
[warn] /Users/eugene/geotrellis/raster/src/main/scala/geotrellis/raster/summary/polygonal/MultibandTilePolygonalSummaryHandler.scala:41:6: Public method must have explicit type
[warn] /Users/eugene/geotrellis/raster/src/main/scala/geotrellis/raster/summary/polygonal/MultibandTilePolygonalSummaryMethods.scala:1: Header does not match expected text
[warn] /Users/eugene/geotrellis/raster/src/main/scala/geotrellis/raster/summary/polygonal/SinglebandTilePolygonalSummaryMethods.scala:1: Header does not match expected text
[warn] /Users/eugene/geotrellis/raster/src/main/scala/geotrellis/raster/summary/polygonal/SumSummary.scala:1: Header does not match expected text
[warn] /Users/eugene/geotrellis/raster/src/main/scala/geotrellis/raster/summary/polygonal/SumSummary.scala:60:21: There should be a space after the plus (+) sign
[warn] /Users/eugene/geotrellis/raster/src/main/scala/geotrellis/raster/summary/polygonal/SumSummary.scala:129:22: There should be a space after the plus (+) sign
[warn] /Users/eugene/geotrellis/raster/src/main/scala/geotrellis/raster/summary/polygonal/SumSummary.scala:60:21: There should be a space before the plus (+) sign
[warn] /Users/eugene/geotrellis/raster/src/main/scala/geotrellis/raster/summary/polygonal/SumSummary.scala:129:22: There should be a space before the plus (+) sign
[warn] /Users/eugene/geotrellis/raster/src/main/scala/geotrellis/raster/summary/polygonal/SumSummary.scala:87:4: If block needs braces
[warn] /Users/eugene/geotrellis/raster/src/main/scala/geotrellis/raster/summary/polygonal/SumSummary.scala:156:4: If block needs braces
[warn] /Users/eugene/geotrellis/raster/src/main/scala/geotrellis/raster/summary/polygonal/SumSummary.scala:59:6: Public method must have explicit type
[warn] /Users/eugene/geotrellis/raster/src/main/scala/geotrellis/raster/summary/polygonal/SumSummary.scala:128:6: Public method must have explicit type
[warn] /Users/eugene/geotrellis/raster/src/main/scala/geotrellis/raster/summary/polygonal/TilePolygonalSummaryHandler.scala:1: Header does not match expected text
[warn] /Users/eugene/geotrellis/raster/src/main/scala/geotrellis/raster/summary/polygonal/TilePolygonalSummaryHandler.scala:41:6: Public method must have explicit type
[warn] /Users/eugene/geotrellis/raster/src/main/scala/geotrellis/raster/summary/SinglebandTileSummaryMethods.scala:1: Header does not match expected text
[warn] /Users/eugene/geotrellis/raster/src/main/scala/geotrellis/raster/summary/Statistics.scala:1: Header does not match expected text
[warn] /Users/eugene/geotrellis/raster/src/main/scala/geotrellis/raster/summary/Statistics.scala:46:6: Method name does not match the regular expression '^[a-z][A-Za-z0-9]*$'
[warn] /Users/eugene/geotrellis/raster/src/main/scala/geotrellis/raster/summary/Statistics.scala:61:6: Method name does not match the regular expression '^[a-z][A-Za-z0-9]*$'
scapegoat
(static analysis)
A good compliment to scalastyle
that focuses more on code safety and common pitfalls.
Number of rules dealing specifically with ill advised usage of Scala collections library.
Some more Scala oriented rules against using asInstanceOf
and null
can not be avoided when
using Java centric Hadoop API. These may be disabled in the build.
Particularly useful raised warnings on unused implicit parameters which have a tendency to proliferate when unchecked.
The plugin is easy to use and easy to integrate
- The SBT plugin is easy to configure and run
- XML report also confirms to `checkstyle` format, supported by SonarQube
We will adopt it in CI after tuning the rules and confirming existing code. Until then it is useful to be able to run it on demand.
[warning] geotrellis.spark.viewshed.IterativeViewshed.scala:131: Unused method parameter
Unused method parameter (implicit <synthetic> val evidence$2: V => geotrellis.raster.Tile = _)
[warning] geotrellis.spark.viewshed.IterativeViewshed.scala:158: Unused method parameter
Unused method parameter (implicit <synthetic> val evidence$3: K => geotrellis.spark.SpatialKey = _)
[warning] geotrellis.spark.viewshed.IterativeViewshed.scala:158: Unused method parameter
Unused method parameter (implicit <synthetic> val evidence$4: V => geotrellis.raster.Tile = _)
[warning] geotrellis.spark.viewshed.IterativeViewshed.scala:204: Unused method parameter
Unused method parameter (implicit <synthetic> val evidence$6: scala.reflect.ClassTag[K] = _)
[warning] geotrellis.spark.viewshed.RDDViewshedMethods.scala:35: Unused method parameter
Unused method parameter (implicit val sc: org.apache.spark.SparkContext = _)
[warning] org.apache.spark.rdd.FilteredCartesianRDD.scala:79: Use of asInstanceOf
asInstanceOf used near split.asInstanceOf[org.apache.spark.rdd.CartesianPartition]. Consider using pattern matching.
[warning] org.apache.spark.rdd.FilteredCartesianRDD.scala:84: Use of asInstanceOf
asInstanceOf used near split.asInstanceOf[org.apache.spark.rdd.CartesianPartition]. Consider using pattern matching.
[error] org.apache.spark.rdd.FilteredCartesianRDD.scala:54: Lonely sealed trait
Sealed trait FilteredCartesianRDD has no implementing classes
[warning] org.apache.spark.rdd.FilteredCartesianRDD.scala:122: Null assignment
Null assignment on line 122
[warning] org.apache.spark.rdd.FilteredCartesianRDD.scala:123: Null assignment
Null assignment on line 123
[warning] org.apache.spark.rdd.FilteredCartesianRDD.scala:122: Null parameter
Null is used as a method parameter: FilteredCartesianRDD.this.rdd1_=(null)
[warning] org.apache.spark.rdd.FilteredCartesianRDD.scala:123: Null parameter
Null is used as a method parameter: FilteredCartesianRDD.this.rdd2_=(null)
sbt-jacoco (code coverage)
Popular Java code coverage tool. Scala support appears to be very good.
- Has sbt plugin
- Runs fast
- Generates XML report which is understood by SonarQube
The report is easy to use and its generation does not impact test speed. Integration into CI is possible. Likely we will use this tool as part of release process initially.
[info] ------- Jacoco Coverage Report -------
[info]
[info] Lines: 75.13% (>= required 0.0%) covered, 4513 of 18148 missed, OK
[info] Instructions: 58.56% (>= required 0.0%) covered, 84774 of 204567 missed, OK
[info] Branches: 53.4% (>= required 0.0%) covered, 5300 of 11373 missed, OK
[info] Methods: 57.33% (>= required 0.0%) covered, 3869 of 9067 missed, OK
[info] Complexity: 49.23% (>= required 0.0%) covered, 7494 of 14761 missed, OK
[info] Class: 67.69% (>= required 0.0%) covered, 883 of 2733 missed, OK
SBT plugin as available https://github.com/albuch/sbt-dependency-check
Produced the desired result, checking against CVE database.
The output of the tool is extremely noisy and does not appear suitable for integration into CI. The sprawling dependency tree of provided Spark/Hadoop dependencies is source of many warnings that we do not control. Excluding those provided dependencies from the scan would likely make the report more meaningful.
Some effort will be required to write rules to filter false positives after which its usage can be included in the release process.
findbugs4sbt
https://github.com/sbt/sbt-findbugs
The rules are too Java centric and noisy in Scala project. Same function is better covered by combination of scalastyle
and scapegoat
.
Offers more detailed code coverage however is very intensive to generate. In case of GeoTrellis it does not produce output after hours of run-time. Ultimately the output of JaCoCo appears sufficient and much more easily produced.
The support for inspections is very extensive but it is very much geared towards Java, intentionally so. Ultimatly the output is has useful information but much too noise and hard to parse to be any real use for a Scala project.