Scala code quality with maven

The context : a scala project has been started but for various reasons Maven was chosen instead of sbt. At first it does seem an odd choice. Why pick such a common Java tool and not the default Scala build tool? In practice, it can make sense for a Java-centric shop making a first step towards the Scala world. The next question is then : how can the quality of the Scala code be checked while still using Maven?

Scalastyle, the scala CheckStyle

Checkstyle is well known in the Java world. Scalastyle is similar, but for Scala. Both tools help teams converge on a shared coding standard with automated control.

Scalatest should be the first stop as it provides an integration with Maven, but also common IDEs : Intellij and Eclipse. Scala IDE, based on Eclipse, is also supported as a consequence.

The configuration for Maven is composed of 4 steps.

###1) Update your pom.xml file.

<build>
  <plugins> 
    ...
    <plugin>
      <groupId>org.scalastyle</groupId>
      <artifactId>scalastyle-maven-plugin</artifactId>
      <version>0.8.0</version>
      <configuration>
        <failOnViolation>true</failOnViolation>
        <failOnWarning>false</failOnWarning>
        <verbose>false</verbose>
        <includeTestSourceDirectory>true</includeTestSourceDirectory>
        <sourceDirectory>${basedir}/src/main/scala</sourceDirectory>
        <testSourceDirectory>${basedir}/src/test/scala</testSourceDirectory>
        <configLocation>${basedir}/src/test/resources/scalastyle_config.xml</configLocation>
        <outputFile>${project.basedir}/target/scalastyle-output.xml</outputFile>
        <outputEncoding>UTF-8</outputEncoding>
      </configuration>
      <executions>
        <execution>
          <goals>
            <goal>check</goal>
          </goals>
        </execution>
      </executions>
    </plugin>
    ...
  </plugins>
</build>

###2) Download scalastyle_config.xml to ${basedir}/src/test/resources/scalastyle_config.xml.

The rule org.scalastyle.file.HeaderMatchesChecker should probably be changed or disabled (enabled="false") for a non Open Source project. The others rules can be kept without change for a first run.

<check class="org.scalastyle.file.HeaderMatchesChecker" level="warning" enabled="false">
  <parameters>
    <parameter name="header"><![CDATA[// Copyright (C) 2011-2012 the original author or authors.
// See the LICENCE.txt file distributed with this work for additional
// information regarding copyright ownership.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.]]></parameter>
    </parameters>
</check>

###3) Verify integration with Maven Build lifecyle.

mvn verify

At the end of the build, after the test, scalastyle output should be visible.

warning file=/xxx/xxx.scala message=ScalastyleWarningMessage
Saving to outputFile=/xxx/target/scalastyle-output.xml
Processed 1 file(s)
Found 0 errors
Found 1 warnings
Found 0 infos
Finished in xxxx ms
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: xx:xx min
[INFO] Finished at: xxxx-xx-xxTxx:xx:xx+xx:xx
[INFO] Final Memory: xxM/xxxM
[INFO] ------------------------------------------------------------------------

###4) Run in isolation, without all the previous Maven build lifecycle phases.

mvn scalastyle:check

With a similar end results, but quicker.

##WartRemover WartRemover is “a flexible Scala code linting tool”. Its main usage is as a sbt plugin but luckily, it is still compatible with Maven.

###1) Configure Maven to automatically copy the depency by using the maven-dependency-plugin during the validate phase.

<build>
  <plugins>
    ...
    <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-dependency-plugin</artifactId>
      <executions>
        <execution>
          <id>scala_plugins</id>
          <phase>validate</phase>
          <goals>
            <goal>copy</goal>
          </goals>
          <configuration>
            <outputDirectory>${project.basedir}/target/scala_plugins/</outputDirectory>
            <artifactItems>
              <artifactItem>
                <groupId>org.brianmckenna</groupId>
                <artifactId>wartremover_2.10</artifactId>
                <version>0.14</version>
              </artifactItem>
            </artifactItems>
          </configuration>
        </execution>
      </executions>
    </plugin>
    ...
  </plugins>
</build>

###2) Verify the configuration by running Maven.

mvn validate

The downloaded plugin (jar) should be visible from the logs.

[INFO] --- maven-dependency-plugin:2.9:copy (scala_plugins) @ xxx ---
[INFO] Configured Artifact: org.brianmckenna:wartremover_2.10:0.14:jar
[INFO] Copying wartremover_2.10-0.14.jar to /xxx/target/scala_plugins/wartremover_2.10-0.14.jar
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] ------------------------------------------------------------------------
[INFO] Total time: xx:xx min
[INFO] Finished at: xxxx-xx-xxTxx:xx:xx+xx:xx
[INFO] Final Memory: xxM/xxxM
[INFO] ------------------------------------------------------------------------

###3) Configure the compilator with this plugin.

<build>
  <plugins>
    ...
    <plugin>
      <!-- see http://davidb.github.com/scala-maven-plugin -->
      <groupId>net.alchim31.maven</groupId>
      <artifactId>scala-maven-plugin</artifactId>
      <version>3.2.1</version>
      <executions>
        <execution>
          <goals>
            <goal>compile</goal>
            <goal>testCompile</goal>
          </goals>
          <configuration>
            <args>
              <arg>-Xplugin:${project.basedir}/target/scala_plugins/wartremover_2.10-0.14.jar</arg>
              <arg>-P:wartremover:only-warn-traverser:org.brianmckenna.wartremover.warts.Unsafe</arg>
            </args>
          </configuration>
        </execution>
      </executions>
    </plugin>
    ...
  </plugins>
</build>

For more information about how to configure which rules should be actived, in error or warn, the WartRemover github should be consulted. Here, all safe checks will be displayed as warns. The build will not fail if the plugin is added and the code is warty.

###4) Compile the project.

mvn compile

And if the project is not pristine, a few warts should pop up.

[WARNING] /xxx/xxx.scala:xx: warning: Option#get is disabled - use Option#fold instead
[WARNING]     result.get
[WARNING]            ^
[WARNING] /xxx/xxx.scala:xx: warning: var is disabled
[WARNING]     var result: Option[T] = None
[WARNING]         ^
[WARNING] warning: there were x deprecation warning(s); re-run with -deprecation for details
[WARNING] x warnings found
[INFO] prepare-compile in xx s
[INFO] compile in xx s
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] ------------------------------------------------------------------------
[INFO] Total time: xx:xx min
[INFO] Finished at: xxxx-xx-xxTxx:xx:xx+xx:xx
[INFO] Final Memory: xxM/xxxM
[INFO] ------------------------------------------------------------------------

##Linter, Scapegoat, others? Linter and Scapegoat are two others well known tools in the scala community. I am open to any feedback about their usage with scala 2.10 and Maven.

Bertrand Dechoux

Bertrand Dechoux
Lead Data Engineer/Data Scientist at @Influans. Ex-xebian. Clojure fan for life.

Effective assertions, from Java to Scala

Unit testing should be part of any project. Hard to disagree. However, many complementary tools exist for various purposes. This is the c...… Continue reading

A blog in 2016!

Published on January 01, 2016