null

Scala codestyle checker на коленке

Однажды я столкнулся с задачей автоматической проверки соответсвия кода принятому стилю, заданному в конфигурации Scalariform плагина для IDE.

Поискав в интернетах, я нашёл плагин, выполняющий форматирование кода с помощью Scalariform - вот он https://github.com/mdr/scalariform-maven-plugin. Давайте посмотрим, как заставить этот плагин делать то, что нам нужно.

Первым делом откроем файл org.scalariform.ScalariformMojo, в котором находится описание нашего плагина, в частности параметры и фаза исполнения.

Изменим 

@goal format

на что-то, более подходящее по смыслу, например

@goal checkstyle

Далее добавим параметр, который позволит нам решать, останавливать ли сборку проекта при обнаружении стилистических ошибок или нет

/**
 *  @parameter default-value=false
 */
    protected boolean failOnWarnings;

Так же передадим этот параметр в 

MojoFormatter.format(...
                     ...
                     failOnWarnings);

Далее переходим в org.scalariform.MojoFormatter

В функцию format добавляем еще один, переданный ранее аргумент и модифицируем её следующим образом:

files.foreach { file ⇒
      try {
        val original = Source.fromFile(file).mkString
        val formatted = ScalaFormatter.format(original, preferences)
        if (original != formatted) {
          writeText(file, formatted)
          log.warn("Modified " +  file.getName)
          count += 1
        }
      } catch {
        case ex: ScalaParserException ⇒
          log.error("Error parsing Scala " + file + ": " + ex.getMessage)
          if(failOnWarnings){
            throw new MojoFailureException("Build failed")
          }
        case ex: Exception ⇒
          log.error("Error formatting " + file + ": " + ex)
          if(failOnWarnings){
            throw new MojoFailureException("Build failed")
          }
      }
    }
    log.info("Modified " + count + " of " + files.size + " .scala files")
    if(count>0 && failOnWarnings){
      throw new MojoFailureException("Build failed")
    }

Где throw new MojoFailureException("Build failed") позволяет нам прервать сборку проекта при необходимости.

Далее открываем pom.xml и изменяем groupId и, при желании, остальные атрибуты.

Переходим в консоль, набираем mvn clean install и .... если у вас установлена java-8, получаем следующие ошибки

[ERROR] error: error while loading CharSequence, class file '/usr/lib/jvm/java-8-oracle/jre/lib/rt.jar(java/lang/CharSequence.class)' is broken

[ERROR] scalariform-maven-plugin/src/main/scala/org/scalariform/MojoFormatter.scala:97: error: overloaded method value warn with alternatives:
[INFO]   (Throwable)Unit <and>
[INFO]   (CharSequence)Unit
[INFO]  cannot be applied to (String)

Чтобы этого избежать, изменяем версию зависимости scala-library на 2.10.3 или выше и пробуем снова.

Видим заветное BUILD SUCCESS и переходим к проверке работоспособности.

Для этого создадим проект, подключим в него наш плагин и зададим несколько параметров

<build>
    <plugins>
      <plugin>
        <groupId>my.custom</groupId>
        <artifactId>scalariform-maven-plugin</artifactId>
        <version>0.1.5</version>
        <executions>
          <execution>
            <phase>process-sources</phase>
            <goals>
              <goal>checkstyle</goal>
            </goals>
            <configuration>
              <alignParameters>true</alignParameters>
              <failOnWarnings>true</failOnWarnings>
              <indentSpaces>4</indentSpaces>
            </configuration>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>

Создадим несколько файлов .scala с кодом и запустим mvn clean package

[INFO] --- scalariform-maven-plugin:0.1.5:checkstyle (default) @ Scalackeck ---
[WARNING] Modified Test2.scala
[WARNING] Modified Test.scala
[WARNING] Modified Test3.scala
[INFO] Modified 3 of 3 .scala files
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE

Как видим, наш плагин сработал отлично и прервал сборку проекта. 

Таким образом можно легко расширить функционал плагина и использовать его в последующих проектах.