Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow external modules to have a defaultCommandName, simplify autoformatting and publishing docs #3545

Merged
merged 6 commits into from
Sep 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion ci/release-maven.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@ set -eu

./mill -i installLocal

./target/mill-release -i mill.scalalib.PublishModule/publishAll
./target/mill-release -i mill.scalalib.PublishModule/
3 changes: 1 addition & 2 deletions docs/modules/ROOT/nav.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
* xref:Testing_Java_Projects.adoc[]
* xref:Linting_Java_Projects.adoc[]
* xref:Publishing_Java_Projects.adoc[]
// * xref:Publishing_Java_Projects.adoc[]
* xref:Java_Web_Examples.adoc[]
* xref:Case_Study_Mill_vs_Maven.adoc[]
* xref:Case_Study_Mill_vs_Gradle.adoc[]
Expand All @@ -22,8 +21,8 @@
* xref:Scala_Module_Config.adoc[]
* xref:Scala_Build_Examples.adoc[]
* xref:Testing_Scala_Projects.adoc[]
* xref:Linting_Scala_Projects.adoc[]
* xref:Publishing_Scala_Projects.adoc[]
// * xref:Publishing_Scala_Projects.adoc[]
* xref:Scala_Web_Examples.adoc[]
* xref:Case_Study_Mill_vs_SBT.adoc[]

Expand Down
3 changes: 2 additions & 1 deletion docs/modules/ROOT/pages/Linting_Java_Projects.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ gtag('config', 'AW-16649289906');
</script>
++++

This page will discuss common topics around working with test suites using the Mill build tool
This page will discuss common topics around enforcing the code quality of Java
codebases using the Mill build tool

== ErrorProne

Expand Down
32 changes: 32 additions & 0 deletions docs/modules/ROOT/pages/Linting_Scala_Projects.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
= Linting Scala Projects

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

This page will discuss common topics around maintaining the code quality of Scala
codebases using the Mill build tool

== Autoformatting and Enforcement

include::example/scalalib/linting/1-scalafmt.adoc[]

== Scoverage Code Coverage

Mill supports Scala code coverage analysis via the Scoverage contrib plugin. See the
contrib plugin documentation for more details:

* xref:contrib/scoverage.adoc[]

== Scalafix Autofixes

Scalafix is a tool that analyzes your Scala source code, performing intelligent analyses and
code quality checks, and is often able to automatically fix the issues that it discovers.
It can also perform automated refactoring.

Mill supports Scalafix through the Mill-Scalafix third party module. See the module documentation
for more details:

* https://github.com/joan38/mill-scalafix
28 changes: 0 additions & 28 deletions docs/modules/ROOT/pages/Scala_Module_Config.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -92,34 +92,6 @@ include::example/scalalib/module/13-contrib-scoverage.adoc[]

include::example/scalalib/module/14-unidoc.adoc[]

== Reformatting your code

Mill supports code formatting via https://scalameta.org/scalafmt/[scalafmt] out of the box.

To have a formatting per-module you need to make your module extend `mill.scalalib.scalafmt.ScalafmtModule`:

.`build.mill`
[source,scala,subs="attributes,verbatim"]
----
import mill._, scalalib._, scalafmt._

object foo extends ScalaModule with ScalafmtModule {
def scalaVersion = "{example-scala-2-13-version}"
}
----

Now you can reformat code with `mill foo.reformat` command, or only check for misformatted files with `mill foo.checkFormat`.

You can also reformat your project's code globally with `+mill mill.scalalib.scalafmt.ScalafmtModule/reformatAll __.sources+` command,
or only check the code's format with `+mill mill.scalalib.scalafmt.ScalafmtModule/checkFormatAll __.sources+`.
It will reformat all sources that matches `+__.sources+` query.

If you add a `.scalafmt.conf` file at the root of you project, it will be used
to configure formatting. It can contain a `version` key to specify the scalafmt
version used to format your code. See the
https://scalameta.org/scalafmt/docs/configuration.html[scalafmt configuration documentation]
for details.


== Using the Ammonite Repl / Scala console

Expand Down
10 changes: 5 additions & 5 deletions docs/modules/ROOT/partials/Publishing_Footer.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -48,14 +48,14 @@ You can publish all eligible modules in your Mill project as follows:

[source,bash]
----
mill mill.scalalib.PublishModule/publishAll
mill mill.scalalib.PublishModule/
----

You can also specify individual modules you want to publish via a selector:

[source,bash]
----
mill mill.scalalib.PublishModule/publishAll foo.publishArtifacts
mill mill.scalalib.PublishModule/ foo.publishArtifacts
----

The default URL for publishing to sonatype's Maven Central is `oss.sonatype.org`.
Expand All @@ -64,7 +64,7 @@ In that case, you can pass in a `--sonatypeUri`:

[source,bash]
----
mill mill.scalalib.PublishModule/publishAll \
mill mill.scalalib.PublishModule/ \
--sonatypeUri https://s01.oss.sonatype.org/service/local
----

Expand Down Expand Up @@ -108,7 +108,7 @@ jobs:
with:
distribution: 'temurin'
java-version: '17'
- run: ./mill mill.scalalib.PublishModule/publishAll
- run: ./mill mill.scalalib.PublishModule/
env:
MILL_PGP_PASSPHRASE: ${{ secrets.MILL_PGP_PASSPHRASE }}
MILL_PGP_SECRET_BASE64: ${{ secrets.MILL_PGP_SECRET_BASE64 }}
Expand All @@ -131,7 +131,7 @@ maven path under `sonatypeUri` instead of staging path.

[source,bash]
----
mill mill.scalalib.PublishModule/publishAll \
mill mill.scalalib.PublishModule/ \
foo.publishArtifacts \
lihaoyi:$SONATYPE_PASSWORD \
--sonatypeUri http://example.company.com/release \
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,6 @@ Publishing Artifact(com.lihaoyi,myplugin_2.13,0.0.2) to ivy repo...
// Mill plugins are JVM libraries like any other library written in Java or Scala. Thus they
// are published the same way: by extending `PublishModule` and defining the module's `publishVersion`
// and `pomSettings`. Once done, you can publish the plugin locally via `publishLocal` below,
// or to Maven Central via `mill.scalalib.public.PublishModule/publishAll`for other developers to
// or to Maven Central via `mill.scalalib.public.PublishModule/`for other developers to
// use.

1 change: 1 addition & 0 deletions example/package.mill
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ object `package` extends RootModule with Module {
object basic extends Cross[ExampleCrossModule](build.listIn(millSourcePath / "basic"))
object builds extends Cross[ExampleCrossModule](build.listIn(millSourcePath / "builds"))
object testing extends Cross[ExampleCrossModule](build.listIn(millSourcePath / "testing"))
object linting extends Cross[ExampleCrossModule](build.listIn(millSourcePath / "linting"))
object publishing extends Cross[ExampleCrossModule](build.listIn(millSourcePath / "publishing"))
object module extends Cross[ExampleCrossModule](build.listIn(millSourcePath / "module"))
object web extends Cross[ExampleCrossModule](build.listIn(millSourcePath / "web"))
Expand Down
3 changes: 3 additions & 0 deletions example/scalalib/linting/1-scalafmt/.scalafmt.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Newer versions won't work with Java 8!
version = "3.7.15"
runner.dialect = scala213
60 changes: 60 additions & 0 deletions example/scalalib/linting/1-scalafmt/build.mill
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package build
import mill._, scalalib._

object `package` extends RootModule with ScalaModule {
def scalaVersion = "2.13.11"
}

/** See Also .scalafmt.conf */

// Mill supports code formatting via https://scalameta.org/scalafmt/[scalafmt] out of the box.
// You can reformat your project's code globally with `mill mill.scalalib.scalafmt.ScalafmtModule/` command,
// specific modules via `mill mill.scalalib.scalafmt.ScalafmtModule/ '{foo,bar}.sources`
// or only check the code's format with `+mill mill.scalalib.scalafmt.ScalafmtModule/checkFormatAll`.
// By default, ScalaFmt checks for a `.scalafmt.conf` file at the root of repository.

/** Usage

> cat src/Foo.scala # initial poorly formatted source code
package foo
object Foo{
def main(args:
Array[String
]
):Unit=
{println("hello world")
}
}


> mill mill.scalalib.scalafmt.ScalafmtModule/checkFormatAll
error: ...Found 1 misformatted files

> mill mill.scalalib.scalafmt.ScalafmtModule/

> cat src/Foo.scala
package foo
object Foo {
def main(args: Array[String]): Unit = { println("hello world") }
}

> mill mill.scalalib.scalafmt.ScalafmtModule/checkFormatAll
Everything is formatted already

*/

// You can modify `.scalafmt.conf` to adjust the formatting as desired:

/** Usage
> echo "maxColumn: 50" >> .scalafmt.conf

> mill mill.scalalib.scalafmt.ScalafmtModule/

> cat src/Foo.scala
package foo
object Foo {
def main(args: Array[String]): Unit = {
println("hello world")
}
}
*/
9 changes: 9 additions & 0 deletions example/scalalib/linting/1-scalafmt/src/Foo.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package foo
object Foo{
def main(args:
Array[String
]
):Unit=
{println("hello world")
}
}
30 changes: 19 additions & 11 deletions main/eval/test/src/mill/eval/ModuleTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,26 @@ import mill.define.Discover

import utest._

object ModuleTests extends TestSuite {
object ExternalModule extends mill.define.ExternalModule {
def x = T { 13 }
object inner extends mill.Module {
def y = T { 17 }
}
lazy val millDiscover = Discover[this.type]
object TestExternalModule extends mill.define.ExternalModule with mill.define.TaskModule {
def defaultCommandName = "x"
def x = T { 13 }
object inner extends mill.Module {
def y = T { 17 }
}
lazy val millDiscover = Discover[this.type]
}
object ModuleTests extends TestSuite {
object Build extends TestBaseModule {
def z = T { ExternalModule.x() + ExternalModule.inner.y() }
def z = T { TestExternalModule.x() + TestExternalModule.inner.y() }
}
val tests = Tests {
test("externalModuleCalls") {
val check = UnitTester(Build, null)
val result = check.apply("mill.eval.TestExternalModule/x")
assert(result == Right(Result(Vector(13), 0)))
val result2 = check.apply("mill.eval.TestExternalModule/")
assert(result2 == Right(Result(Vector(13), 0)))
}
test("externalModuleTargetsAreNamespacedByModulePackagePath") {
val check = UnitTester(Build, null)
os.remove.all(check.outPath)
Expand All @@ -28,18 +36,18 @@ object ModuleTests extends TestSuite {
zresult == Right(Result(30, 1)),
os.read(check.evaluator.outPath / "z.json").contains("30"),
os.read(
check.outPath / "mill/eval/ModuleTests/ExternalModule/x.json"
check.outPath / "mill/eval/TestExternalModule/x.json"
).contains("13"),
os.read(
check.outPath / "mill/eval/ModuleTests/ExternalModule/inner/y.json"
check.outPath / "mill/eval/TestExternalModule/inner/y.json"
).contains("17")
)
}
test("externalModuleMustBeGlobalStatic") {

object Build extends mill.define.ExternalModule {

def z = T { ExternalModule.x() + ExternalModule.inner.y() }
def z = T { TestExternalModule.x() + TestExternalModule.inner.y() }
lazy val millDiscover = Discover[this.type]
}

Expand Down
11 changes: 6 additions & 5 deletions main/resolve/src/mill/resolve/ParseArgs.scala
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import scala.annotation.tailrec

object ParseArgs {

type TargetsWithParams = (Seq[(Option[Segments], Segments)], Seq[String])
type TargetsWithParams = (Seq[(Option[Segments], Option[Segments])], Seq[String])

/** Separator used in multiSelect-mode to separate targets from their args. */
val MultiArgsSeparator = "--"
Expand Down Expand Up @@ -86,13 +86,14 @@ object ParseArgs {
else Right(())
}

def extractSegments(selectorString: String): Either[String, (Option[Segments], Segments)] =
def extractSegments(selectorString: String)
: Either[String, (Option[Segments], Option[Segments])] =
parse(selectorString, selector(_)) match {
case f: Parsed.Failure => Left(s"Parsing exception ${f.msg}")
case Parsed.Success(selector, _) => Right(selector)
}

private def selector[_p: P]: P[(Option[Segments], Segments)] = {
private def selector[_p: P]: P[(Option[Segments], Option[Segments])] = {
def wildcard = P("__" | "_")
def label = mill.define.Reflect.ident

Expand All @@ -114,8 +115,8 @@ object ParseArgs {
case (h, rest) => Segments(h +: rest)
}

P(simpleQuery ~ ("/" ~/ simpleQuery).? ~ End).map {
case (q, None) => (None, q)
P(simpleQuery ~ ("/" ~ simpleQuery.?).? ~ End).map {
case (q, None) => (None, Some(q))
case (q, Some(q2)) => (Some(q), q2)
}
}
Expand Down
2 changes: 1 addition & 1 deletion main/resolve/src/mill/resolve/Resolve.scala
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,7 @@ trait Resolve[T] {
resolveNonEmptyAndHandle(
args,
rootModuleSels,
sel,
sel.getOrElse(Segments()),
nullCommandDefaults,
allowPositionalCommandArgs
)
Expand Down
12 changes: 6 additions & 6 deletions main/resolve/test/src/mill/main/ParseArgsTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,8 @@ object ParseArgsTests extends TestSuite {
ParseArgs(input, if (multiSelect) SelectMode.Multi else SelectMode.Separated)

val selectors = selectors0.map {
case (Some(v1), v2) => (Some(v1.value), v2.value)
case (None, v2) => (None, v2.value)
case (Some(v1), Some(v2)) => (Some(v1.value), v2.value)
case (None, Some(v2)) => (None, v2.value)
}
assert(
selectors == expectedSelectors,
Expand Down Expand Up @@ -201,8 +201,8 @@ object ParseArgsTests extends TestSuite {
List(
(
List(
None -> Segments(Seq(Label("core"), Label("compile"))),
None -> Segments(Seq(Label("application"), Label("compile")))
None -> Some(Segments(Seq(Label("core"), Label("compile")))),
None -> Some(Segments(Seq(Label("application"), Label("compile"))))
),
Nil
)
Expand Down Expand Up @@ -237,8 +237,8 @@ object ParseArgsTests extends TestSuite {
val actual = parsed.map {
case (selectors0, args) =>
val selectors = selectors0.map {
case (Some(v1), v2) => (Some(v1.value), v2.value)
case (None, v2) => (None, v2.value)
case (Some(v1), Some(v2)) => (Some(v1.value), v2.value)
case (None, Some(v2)) => (None, v2.value)
}
(selectors, args)
}
Expand Down
7 changes: 6 additions & 1 deletion main/src/mill/main/TokenReaders.scala
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,13 @@ import mill.resolve.SimpleTaskTokenReader
case class Tasks[T](value: Seq[mill.define.NamedTask[T]])

object Tasks {
def resolveMainDefault[T](tokens: String*): Tasks[T] = {
new Tasks.TokenReader[T]()
.read(tokens)
.getOrElse(sys.error("Unable to resolve: " + tokens.mkString(" ")))
}
private[mill] class TokenReader[T]() extends mainargs.TokensReader.Simple[Tasks[T]] {
def shortName = "<tasks>"
def shortName = "tasks"
def read(s: Seq[String]): Either[String, Tasks[T]] = {
Resolve.Tasks.resolve(
Evaluator.currentEvaluator.value.rootModule,
Expand Down
Loading
Loading