Skip to content

Commit

Permalink
Checkstyle Plugin Cleanup (#3520)
Browse files Browse the repository at this point in the history
* Set `check = true` and `stdout = true` by default since that's what
I'm guessing people will expect
* Extract out `def checkstyleHandleErrors` and `def checkstyle0` for
re-use between `CheckstyleModule` and `CheckstyleXsltModule`. This
allows `def checkstyle` to throw errors and report to console while
still generating the XSLT reports in `CheckstyleXsltModule`
* Avoid reporting `no violations` when exit code is zero, because there
may still be warnings
* Integrate the example test from @m50d's checkstyle PR
#3472, flesh it out, and
integrate it into the docsite
  • Loading branch information
lihaoyi authored Sep 12, 2024
1 parent 719146c commit 2e5b649
Show file tree
Hide file tree
Showing 18 changed files with 530 additions and 29 deletions.
1 change: 1 addition & 0 deletions build.mill
Original file line number Diff line number Diff line change
Expand Up @@ -736,6 +736,7 @@ object dist0 extends MillPublishJavaModule {
build.contrib.playlib.testDep(),
build.contrib.playlib.worker("2.8").testDep(),
build.contrib.errorprone.testDep(),
build.contrib.checkstyle.testDep(),
build.bsp.worker.testDep(),
build.testkit.testDep()
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ import mainargs.{Leftover, ParserForClass, main}
*/
@main(doc = "arguments for CheckstyleModule.checkstyle")
case class CheckstyleArgs(
check: Boolean = false,
stdout: Boolean = false,
check: Boolean = true,
stdout: Boolean = true,
sources: Leftover[String]
)
object CheckstyleArgs {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,12 @@ trait CheckstyleModule extends JavaModule {
* @note [[sources]] are processed when no [[CheckstyleArgs.sources]] are specified.
*/
def checkstyle(@mainargs.arg checkstyleArgs: CheckstyleArgs): Command[Int] = T.command {
val (output, exitCode) = checkstyle0(checkstyleArgs.stdout, checkstyleArgs.sources)()

val CheckstyleArgs(check, stdout, leftover) = checkstyleArgs
checkstyleHandleErrors(checkstyleArgs.stdout, checkstyleArgs.check, exitCode, output)
}

protected def checkstyle0(stdout: Boolean, leftover: mainargs.Leftover[String]) = T.task {

val output = checkstyleOutput().path
val args = checkstyleOptions() ++
Expand All @@ -36,17 +40,27 @@ trait CheckstyleModule extends JavaModule {
classPath = checkstyleClasspath().map(_.path),
mainArgs = args,
workingDir = millSourcePath, // allow passing relative paths for sources like src/a/b
streamOut = true,
check = false
).exitCode

(output, exitCode)
}

protected def checkstyleHandleErrors(
stdout: Boolean,
check: Boolean,
exitCode: Int,
output: os.Path
)(implicit ctx: mill.api.Ctx): Int = {

val reported = os.exists(output)
if (reported) {
T.log.info(s"checkstyle output report at $output")
}

if (exitCode == 0) {
T.log.info("checkstyle found no violation")
} else if (exitCode < 0 || !(reported || stdout)) {
if (exitCode == 0) {} // do nothing
else if (exitCode < 0 || !(reported || stdout)) {
T.log.error(
s"checkstyle exit($exitCode); please check command arguments, plugin settings or try with another version"
)
Expand All @@ -73,7 +87,7 @@ trait CheckstyleModule extends JavaModule {
* Checkstyle configuration file. Defaults to `checkstyle-config.xml`.
*/
def checkstyleConfig: T[PathRef] = T {
PathRef(millSourcePath / "checkstyle-config.xml")
PathRef(T.workspace / "checkstyle-config.xml")
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ trait CheckstyleXsltModule extends CheckstyleModule {
* Runs [[CheckstyleModule.checkstyle]] and uses [[CheckstyleModule.checkstyleOutput]] to generate [[checkstyleXsltReports]].
*/
override def checkstyle(@mainargs.arg checkstyleArgs: CheckstyleArgs): Command[Int] = T.command {
val numViolations = super.checkstyle(checkstyleArgs)()
val (output, exitCode) = checkstyle0(false, checkstyleArgs.sources)()

val checkOutput = checkstyleOutput().path

if (os.exists(checkOutput)) {
Expand All @@ -38,15 +39,13 @@ trait CheckstyleXsltModule extends CheckstyleModule {
}
}

numViolations
checkstyleHandleErrors(checkstyleArgs.stdout, checkstyleArgs.check, exitCode, output)
}

/**
* `xml`
* Necessary in order to allow XSLT transformations on the results
*/
final override def checkstyleFormat: T[String] = T {
"xml"
}
final override def checkstyleFormat: T[String] = "xml"

/**
* Set of [[CheckstyleXsltReport]]s.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,6 @@ object CheckstyleModuleTest extends TestSuite {
args: CheckstyleArgs
): Boolean = {
val eval = UnitTester(module, modulePath)

eval(module.checkstyle(args)).fold(
{
case api.Result.Exception(cause, _) => throw cause
Expand All @@ -194,12 +193,12 @@ object CheckstyleModuleTest extends TestSuite {

val Right(report) = eval(module.checkstyleOutput)

if (os.exists(report.value.path))
if (os.exists(report.value.path)) {
violations.isEmpty || {
val lines = os.read.lines(report.value.path)
violations.forall(violation => lines.exists(_.contains(violation)))
}
else
} else
args.stdout
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ object CheckstyleXsltModuleTest extends TestSuite {
def testModule(module: TestBaseModule with CheckstyleXsltModule, modulePath: os.Path): Boolean = {
val eval = UnitTester(module, modulePath)

eval(module.checkstyle(CheckstyleArgs(sources = Leftover()))).fold(
eval(module.checkstyle(CheckstyleArgs(check = false, sources = Leftover()))).fold(
{
case api.Result.Exception(cause, _) => throw cause
case failure => throw failure
Expand Down
2 changes: 2 additions & 0 deletions docs/modules/ROOT/nav.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
* xref:Java_Module_Config.adoc[]
* xref:Java_Build_Examples.adoc[]
* xref:Testing_Java_Projects.adoc[]
* xref:Linting_Java_Projects.adoc[]
// * xref:Publishing_Java_Projects.adoc[]
* xref:Java_Web_Examples.adoc[]
* xref:Case_Study_Mill_vs_Maven.adoc[]
Expand Down Expand Up @@ -56,6 +57,7 @@
** xref:contrib/codeartifact.adoc[]
** xref:contrib/docker.adoc[]
** xref:contrib/errorprone.adoc[]
** xref:contrib/checkstyle.adoc[]
** xref:contrib/flyway.adoc[]
** xref:contrib/gitlab.adoc[]
** xref:contrib/jmh.adoc[]
Expand Down
1 change: 1 addition & 0 deletions docs/modules/ROOT/pages/Contrib_Plugins.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ import $ivy.`com.lihaoyi::mill-contrib-bloop:`
* xref:contrib/codeartifact.adoc[]
* xref:contrib/docker.adoc[]
* xref:contrib/errorprone.adoc[]
* xref:contrib/checkstyle.adoc[]
* xref:contrib/flyway.adoc[]
* xref:contrib/gitlab.adoc[]
* xref:contrib/jmh.adoc[]
Expand Down
3 changes: 0 additions & 3 deletions docs/modules/ROOT/pages/Java_Module_Config.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,3 @@ If you are using millw, a more permanent solution could be to set the environmen
include::example/javalib/module/13-jni.adoc[]
== Using the ErrorProne plugin to detect code problems
include::example/javalib/module/14-error-prone.adoc[]
24 changes: 24 additions & 0 deletions docs/modules/ROOT/pages/Linting_Java_Projects.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
= Linting Java Projects

++++
<script>
gtag('config', 'AW-16649289906');
</script>
++++

This page will discuss common topics around working with test suites using the Mill build tool

== ErrorProne

include::example/javalib/linting/1-error-prone.adoc[]

== Checkstyle

include::example/javalib/linting/2-checkstyle.adoc[]

== Jacoco Code Coverage

Mill supports Java code coverage analysis via the mill-jacoco plugin. See the
plugin repository documentation for more details:

* https://github.com/lefou/mill-jacoco
37 changes: 37 additions & 0 deletions example/javalib/linting/2-checkstyle/build.mill
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package build
import mill._, javalib._
import $ivy.`com.lihaoyi::mill-contrib-checkstyle:`

import mill.contrib.checkstyle._

object `package` extends RootModule with CheckstyleModule {
def checkstyleVersion = "9.3"
}

/** Usage

> ./mill checkstyle # run checkstyle to produce a report, defaults to warning without error
...src/InputWhitespaceCharacters.java:3:23: Line contains a tab character...
...src/InputWhitespaceCharacters.java:16:3: Line contains a tab character...
...src/InputFileName1.java:2:1: Top-level class MyAnnotation1 has to reside in its own source file...
...src/InputFileName1.java:13:1: Top-level class Enum1 has to reside in its own source file...
...src/InputFileName1.java:26:1: Top-level class TestRequireThisEnum has to reside in its own source file...
Audit done.

> sed -i.bak 's/warning/error/g' checkstyle-config.xml # make checkstyle error on violations

> ./mill checkstyle
error: ...src/InputWhitespaceCharacters.java:3:23: Line contains a tab character...
...src/InputWhitespaceCharacters.java:16:3: Line contains a tab character...
...src/InputFileName1.java:2:1: Top-level class MyAnnotation1 has to reside in its own source file...
...src/InputFileName1.java:13:1: Top-level class Enum1 has to reside in its own source file...
...src/InputFileName1.java:26:1: Top-level class TestRequireThisEnum has to reside in its own source file...
Audit done.

> sed -i.bak 's/\t/ /g' src/InputWhitespaceCharacters.java

> rm src/InputFileName1.java

> ./mill checkstyle # after fixing the violations, checkstyle no longer errors
Audit done.
*/
Loading

0 comments on commit 2e5b649

Please sign in to comment.