diff --git a/.travis.yml b/.travis.yml index d9cf945..d4159da 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,9 +4,9 @@ jdk: - openjdk8 before_install: - - wget http://apache.mirror.gtcomm.net/maven/maven-3/3.6.2/binaries/apache-maven-3.6.2-bin.tar.gz - - tar xzvf apache-maven-3.6.2-bin.tar.gz - - export PATH=`pwd`/apache-maven-3.6.2/bin:$PATH + - wget http://apache.mirror.gtcomm.net/maven/maven-3/3.6.3/binaries/apache-maven-3.6.3-bin.tar.gz + - tar xzvf apache-maven-3.6.3-bin.tar.gz + - export PATH=`pwd`/apache-maven-3.6.3/bin:$PATH install: mvn --settings .maven.xml clean test -B -V diff --git a/README.md b/README.md index 0fcd22e..9859a18 100644 --- a/README.md +++ b/README.md @@ -10,13 +10,14 @@ A wrapper that allows the use of the [Scalafmt](https://github.com/scalameta/sca Add the following snippet to your pom. -Note: `version.scala.binary` refers to major releases of scala ie. 2.11 or 2.12 (scalafmt-dynamic doesn't currently support 2.13). +Note: `version.scala.binary` refers to major releases of scala ie. 2.11, 2.12 or 2.13. + ```xml org.antipathy mvn-scalafmt_${version.scala.binary} - 1.0.1 + 1.0.3 ${project.basedir}/.scalafmt.conf false @@ -29,6 +30,8 @@ Note: `version.scala.binary` refers to major releases of scala ie. 2.11 or 2.12 ${project.basedir}/src/test/scala false + true + master diff --git a/pom.xml b/pom.xml index dd7dbc5..8eefde3 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ org.antipathy mvn-scalafmt_${version.scala.major} maven-plugin - 1.0.2 + 1.0.3 ScalaFmt Maven Plugin (${version.scala.major}) Maven plugin for ScalaFmt https://github.com/SimonJPegg/mvn_scalafmt @@ -35,7 +35,7 @@ 2.6 3.8 - 1.5.1 + 1.6 1.8 3.5.2 3.8.0 @@ -51,7 +51,7 @@ 2.13 .1 1.2.0 - 2.2.1 + 2.3.2 3.0.8 ${version.java} diff --git a/src/main/java/org/antipathy/mvn_scalafmt/FormatMojo.java b/src/main/java/org/antipathy/mvn_scalafmt/FormatMojo.java index 06e59cd..8147149 100644 --- a/src/main/java/org/antipathy/mvn_scalafmt/FormatMojo.java +++ b/src/main/java/org/antipathy/mvn_scalafmt/FormatMojo.java @@ -5,6 +5,8 @@ import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugins.annotations.Mojo; import org.apache.maven.plugins.annotations.Parameter; +import org.apache.maven.project.MavenProject; + import java.io.File; import java.util.ArrayList; import java.util.List; @@ -29,10 +31,17 @@ public class FormatMojo extends AbstractMojo { private boolean respectVersion; @Parameter(property = "format.validateOnly", defaultValue = "false") private boolean validateOnly; + @Parameter(property = "format.onlyChangedFiles", defaultValue = "false") + private boolean onlyChangedFiles; + @Parameter(property = "format.branch", defaultValue = "master") + private String branch; + @Parameter(readonly = true, defaultValue = "${project}") + private MavenProject project; + public void execute() throws MojoExecutionException { - ArrayList sources = new ArrayList<>(); + List sources = new ArrayList<>(); if (!skipSources) { sources.addAll(sourceDirectories); @@ -47,7 +56,16 @@ public void execute() throws MojoExecutionException { } if (sources.size() > 0) { try { - Summary result = ScalaFormatter.apply(configLocation,getLog(),respectVersion, validateOnly).format(sources); + + Summary result = ScalaFormatter.apply( + configLocation, + getLog(), + respectVersion, + validateOnly, + onlyChangedFiles, + branch, + project.getBasedir() + ).format(sources); getLog().info(result.toString()); if (validateOnly && result.unformattedFiles() != 0) { throw new MojoExecutionException("Scalafmt: Unformatted files found"); diff --git a/src/main/scala/org/antipathy/mvn_scalafmt/ScalaFormatter.scala b/src/main/scala/org/antipathy/mvn_scalafmt/ScalaFormatter.scala index e7d7540..83486e5 100644 --- a/src/main/scala/org/antipathy/mvn_scalafmt/ScalaFormatter.scala +++ b/src/main/scala/org/antipathy/mvn_scalafmt/ScalaFormatter.scala @@ -10,6 +10,7 @@ import org.antipathy.mvn_scalafmt.logging.MavenLogReporter import org.antipathy.mvn_scalafmt.model.{FormatResult, Summary} import org.apache.maven.plugin.logging.Log import org.scalafmt.interfaces.Scalafmt +import org.antipathy.mvn_scalafmt.builder.ChangedFilesBuilder import scala.jdk.CollectionConverters._ @@ -18,6 +19,7 @@ import scala.jdk.CollectionConverters._ */ class ScalaFormatter( sourceBuilder: Builder[Seq[File], Seq[File]], + changedFilesBuilder: Builder[Seq[File], Seq[File]], fileFormatter: Formatter[File, FormatResult], writer: Writer[Seq[FormatResult], Summary] ) extends Formatter[JList[File], Summary] { @@ -29,26 +31,49 @@ class ScalaFormatter( */ override def format(sourceDirectories: JList[File]): Summary = { val sources = sourceBuilder.build(sourceDirectories.asScala.toSeq) - val formattedSources = sources.map(fileFormatter.format) + val sourcesToFormat = changedFilesBuilder.build(sources) + val formattedSources = sourcesToFormat.map(fileFormatter.format) writer.write(formattedSources) } } object ScalaFormatter { - def apply(configLocation: String, log: Log, respectVersion: Boolean, testOnly: Boolean): ScalaFormatter = { - val config = LocalConfigBuilder(log).build(configLocation) - val sourceBuilder = new SourceFileSequenceBuilder(log) + /** + * Create a new ScalaFormatter instance + * @param configLocation The location of the scalafmt.conf + * @param log The maven logger + * @param respectVersion should we respect the version in the scalafmt.conf + * @param testOnly should files be reformatted + * @param onlyChangedFiles Should only changed files be formatted + * @param branch The branch to compare against for changed files + * @param workingDirectory The project working directory + * @return a new ScalaFormatter instance + */ + def apply( + configLocation: String, + log: Log, + respectVersion: Boolean, + testOnly: Boolean, + onlyChangedFiles: Boolean, + branch: String, + workingDirectory: File + ): ScalaFormatter = { + val config = LocalConfigBuilder(log).build(configLocation) + val sourceBuilder = new SourceFileSequenceBuilder(log) + val changedFilesBuilder = ChangedFilesBuilder(log, onlyChangedFiles, branch, workingDirectory) + val scalafmt = Scalafmt .create(this.getClass.getClassLoader) .withReporter(new MavenLogReporter(log)) .withRespectVersion(respectVersion) val sourceFormatter = new SourceFileFormatter(config, scalafmt, log) + val fileWriter = if (testOnly) { new TestResultLogWriter(log) } else { new FormattedFilesWriter(log) } - new ScalaFormatter(sourceBuilder, sourceFormatter, fileWriter) + new ScalaFormatter(sourceBuilder, changedFilesBuilder, sourceFormatter, fileWriter) } } diff --git a/src/main/scala/org/antipathy/mvn_scalafmt/builder/ChangedFilesBuilder.scala b/src/main/scala/org/antipathy/mvn_scalafmt/builder/ChangedFilesBuilder.scala new file mode 100644 index 0000000..7d90150 --- /dev/null +++ b/src/main/scala/org/antipathy/mvn_scalafmt/builder/ChangedFilesBuilder.scala @@ -0,0 +1,64 @@ +package org.antipathy.mvn_scalafmt.builder + +import java.io.File +import org.apache.maven.plugin.logging.Log +import scala.sys.process.ProcessLogger +import scala.util.{Try, Success, Failure} + +/** + * Class for building a list of files that have changed from a specified git branch + * @param log The maven logger + * @param diff Should only changed files be returned + * @param branch the git branch to compare against + * @param changeFunction Function to identify changed files + */ +class ChangedFilesBuilder(log: Log, diff: Boolean, branch: String, changeFunction: () => String) + extends Builder[Seq[File], Seq[File]] { + + /** + * Build a list of files that have changed in git from the specified input + * + * @param input The input to build from + * @return A list of changed files. + */ + override def build(input: Seq[File]): Seq[File] = + if (diff) { + log.info(s"Checking for files changed from $branch") + Try { + val names: Seq[String] = + Predef.augmentString(changeFunction()).linesIterator.toSeq + val changedFiles = names.map(new File(_).getAbsolutePath) + changedFiles.foreach { f => + log.info(s"Changed from $branch: $f") + } + changedFiles.map(new File(_)).filter { f => + val path = f.getAbsolutePath + path.endsWith("scala") || + path.endsWith("sc") || + path.endsWith("sbt") + + } + } match { + case Success(value) => value + case Failure(e) => + log.error("Could not obtain list of changed files", e) + throw e + } + } else { + input + } + +} + +object ChangedFilesBuilder { + + def apply(log: Log, diff: Boolean, branch: String, workingDirectory: File): ChangedFilesBuilder = { + + def command(branch: String): String = s"git diff --name-only --diff-filter=d $branch" + val logger: ProcessLogger = sys.process.ProcessLogger(_ => (), err => log.error(err)) + def processFunction: () => String = () => { + sys.process.Process(command(branch), workingDirectory).!!(logger) + } + new ChangedFilesBuilder(log, diff, branch, processFunction) + } +} diff --git a/src/main/scala/org/antipathy/mvn_scalafmt/builder/SourceFileSequenceBuilder.scala b/src/main/scala/org/antipathy/mvn_scalafmt/builder/SourceFileSequenceBuilder.scala index 23dd38d..e8c86bb 100644 --- a/src/main/scala/org/antipathy/mvn_scalafmt/builder/SourceFileSequenceBuilder.scala +++ b/src/main/scala/org/antipathy/mvn_scalafmt/builder/SourceFileSequenceBuilder.scala @@ -33,7 +33,6 @@ class SourceFileSequenceBuilder(log: Log) extends Builder[Seq[File], Seq[File]] None } } - files.flatMap(file => FileUtils.listFiles(file, Array("scala", "sc", "sbt"), true).asScala) } } diff --git a/src/main/scala/org/antipathy/mvn_scalafmt/io/FormattedFilesWriter.scala b/src/main/scala/org/antipathy/mvn_scalafmt/io/FormattedFilesWriter.scala index b802d1f..e96bd1d 100644 --- a/src/main/scala/org/antipathy/mvn_scalafmt/io/FormattedFilesWriter.scala +++ b/src/main/scala/org/antipathy/mvn_scalafmt/io/FormattedFilesWriter.scala @@ -24,7 +24,7 @@ class FormattedFilesWriter(log: Log) extends Writer[Seq[FormatResult], Summary] Summary( input.length, unformattedFiles.length, - build(FileSummaryRequest(input, "Correctly formatted: ", "Reformatted: ")) + build(FileSummaryRequest(input, "Correctly formatted", "Reformatted")) ) } diff --git a/src/main/scala/org/antipathy/mvn_scalafmt/model/FileSummary.scala b/src/main/scala/org/antipathy/mvn_scalafmt/model/FileSummary.scala index 5cb85ee..015287b 100644 --- a/src/main/scala/org/antipathy/mvn_scalafmt/model/FileSummary.scala +++ b/src/main/scala/org/antipathy/mvn_scalafmt/model/FileSummary.scala @@ -7,5 +7,5 @@ package org.antipathy.mvn_scalafmt.model */ case class FileSummary(name: String, details: String) { - override def toString: String = s"$name: $details" + override def toString: String = s"$details: $name" } diff --git a/src/test/scala/org/antipathy/mvn_scalafmt/builder/ChangedFilesBuilderSpec.scala b/src/test/scala/org/antipathy/mvn_scalafmt/builder/ChangedFilesBuilderSpec.scala new file mode 100644 index 0000000..d234906 --- /dev/null +++ b/src/test/scala/org/antipathy/mvn_scalafmt/builder/ChangedFilesBuilderSpec.scala @@ -0,0 +1,27 @@ +package org.antipathy.mvn_scalafmt.builder + +import org.scalatest.{FlatSpec, GivenWhenThen, Matchers} +import java.io.File +import org.apache.maven.plugin.logging.SystemStreamLog + +class ChangedFilesBuilderSpec extends FlatSpec with GivenWhenThen with Matchers { + + behavior of "ChangedFilesBuilder" + + it should "Identify files that have changed from master" in { + val log = new SystemStreamLog + val sourceDirs = Seq("src/test/scala", "src/main/scala").map(new File(_)) + val sources = new SourceFileSequenceBuilder(log).build(sourceDirs) + val changedFiles = Seq( + "/mvn_scalafmt/src/main/scala/org/antipathy/mvn_scalafmt/builder/ChangedFilesBuilder.scala", + "/mvn_scalafmt/src/main/scala/org/antipathy/mvn_scalafmt/builder/SourceFileSequenceBuilder.scala", + "/mvn_scalafmt/src/test/scala/org/antipathy/mvn_scalafmt/builder/ChangedFilesBuilderSpec.scala", + "/mvn_scalafmt/src/test/scala/org/antipathy/mvn_scalafmt/builder/LocalConfigBuilderSpec.scala" + ) + + val changeFunction = () => changedFiles.mkString(System.lineSeparator()) + + val result = new ChangedFilesBuilder(log, true, "master", changeFunction).build(sources) + result should be(changedFiles.map(new File(_))) + } +} diff --git a/src/test/scala/org/antipathy/mvn_scalafmt/builder/LocalConfigBuilderSpec.scala b/src/test/scala/org/antipathy/mvn_scalafmt/builder/LocalConfigBuilderSpec.scala index 81d1677..d1b1e44 100644 --- a/src/test/scala/org/antipathy/mvn_scalafmt/builder/LocalConfigBuilderSpec.scala +++ b/src/test/scala/org/antipathy/mvn_scalafmt/builder/LocalConfigBuilderSpec.scala @@ -28,8 +28,9 @@ class LocalConfigBuilderSpec extends FlatSpec with GivenWhenThen with Matchers { builder.build(path) - val result = scala.io.Source.fromFile(new File(".scalafmt.conf")).getLines().mkString(System.lineSeparator()) - + val source = scala.io.Source.fromFile(new File(".scalafmt.conf")) + val result = source.getLines().mkString(System.lineSeparator()) + source.close() result.trim should be(expectedContent.trim) }