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

Add arrow-kt example #3886

Merged
merged 10 commits into from
Nov 7, 2024
Merged

Add arrow-kt example #3886

merged 10 commits into from
Nov 7, 2024

Conversation

0xnm
Copy link
Contributor

@0xnm 0xnm commented Nov 1, 2024

This PR partially addresses #3670: it contains working example, but doesn't contain any docs.

This example contains compilation and test execution for all the modules of https://github.com/arrow-kt/arrow for the JVM and JS (Node) targets, except arrow-optics-compose module (it requires better Android support by Mill).

Full example run takes 6 minutes on my machine, so it is extracted into a dedicated CI job.

The following Gradle plugins are not added to the example build script, because their respective tooling is Gradle-dependent (no raw-jar or CLI):

There is also no publication support in this example (requires Kotlin Multiplatform publishing support, see #3867)

I faced the following issues while writing this example:

  • There is quite a lot of duplication for JVM/JS configuration, because there is no support of Kotlin Multiplatform hierarchies
  • Each Maven or Module dependency should be with JS/JVM/etc. target qualifier, which also quite explodes amount of code to be written. This is also a question of Kotlin Multiplatform hierarchies support and resolution.
  • Until KMP hierarchies and target resolution support is not implemented, adding a new compilation target will bring quite a lot of new code in the build script. And there is a lot of targets in Arrow: https://github.com/arrow-kt/arrow-gradle-config/blob/97ba7b5eab810a336cf4070eb717f05533d208a8/arrow-gradle-config-kotlin/src/main/kotlin/io.arrow-kt.arrow-gradle-config-kotlin.gradle.kts#L34-L69
  • There is no possibility to disable tests for the particular module (so I had to use a hack with overriding compile / test tasks) - this is because tests is dedicated module, but if comes as a part of the trait, we cannot add / remove it dynamically. Having such control is handy when certain multiplatform modules have a common trait for the main compilation unit, but some of them may have no tests.

Regarding docs: I think it is too early to write any comparison with Gradle, because clearly new functionality will be added to the Kotlin support in Mill which will affect overall execution time and also the comparison should be done not only for JVM targets, but for Kotlin/JS and Kotlin/Native targets as well. And ideally it should be a defined methodology for such testing (for example, certain Gradle plugins should be removed from the Arrow Gradle build script, to have the same set as Mill build script; compiler execution time should be excluded (it may be different because of the different flags passed to it under the hood)).

So I propose to open a dedicated bounty for writing such doc.

@lihaoyi
Copy link
Member

lihaoyi commented Nov 1, 2024

Thanks, will take a look.

I think splitting the bounty between example and doc is fine. Having an example gives us something to start off that we can critique and improve, and already gives a "realistic" example we can include in the documentation for educational purposes. Having it improved enough to be a meaningful comparison can come in follow ups

@0xnm 0xnm marked this pull request as ready for review November 1, 2024 23:03
@@ -0,0 +1,590 @@
package build
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CC @lefou @lolgab in case you guys want to review this as well. We've never had a realistic kotlin multiplatform build before so this will be the flagship example.

@lihaoyi
Copy link
Member

lihaoyi commented Nov 2, 2024

@0xnm I pushed a small update to tidy it up a bit; tests remain passing on my laptop, hopefully will continue passing in CI.

I'll probably take a few more passes trying to tidy this up over the next few days

@lihaoyi
Copy link
Member

lihaoyi commented Nov 2, 2024

I opened separate bounties specifically for Spotless and AnimalSniffer since those seem to keep coming up in our examples

knit and binary-compatibility-validator we can just punt on for now, unless there is repeated demand

Copy link
Member

@lefou lefou left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since KotlinModule mix-in at least JavaModule, task like languageVersion and apiVersion should be explicitly prefixing the language they refer to. Otherwise user may wonder which api is meant when they see that task. Is it Java API, or Test API or Kotlin API or domain API? There is also a risk of name clash.

kotlinlib/src/mill/kotlinlib/KotlinModule.scala Outdated Show resolved Hide resolved
kotlinlib/src/mill/kotlinlib/KotlinModule.scala Outdated Show resolved Hide resolved
kotlinlib/src/mill/kotlinlib/KotlinModule.scala Outdated Show resolved Hide resolved
Comment on lines 178 to 185
override def compile: T[CompilationResult] =
if (!modulesWithTestingEnabled.contains(multiplatformRoot))
Task { CompilationResult(T.dest, PathRef(T.dest)) }
else super.compile
override def test(args: String*): Command[(String, Seq[TestResult])] =
if (!modulesWithTestingEnabled.contains(multiplatformRoot))
Task.Command { ("", Seq.empty[TestResult]) }
else super.test(args: _*)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are a bit strange. Can we at least add a comment, what and more important why it is happening here?

Comment on lines 206 to 213
override def compile: T[CompilationResult] =
if (!modulesWithTestingEnabled.contains(multiplatformRoot))
Task { CompilationResult(T.dest, PathRef(T.dest)) }
else super.compile
override def test(args: String*): Command[(String, Seq[TestResult])] =
if (!modulesWithTestingEnabled.contains(multiplatformRoot))
Task.Command { ("", Seq.empty[TestResult]) }
else super.test(args: _*)
Copy link
Member

@lefou lefou Nov 3, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here, please add a comment why that is needed. Also, in the other places.

Comment on lines +85 to +107
val modulesWithTestingEnabled = Set[CoursierModule](
// these modules don't have hand-written tests
// `arrow-libs`.core.`arrow-annotations`,
// `arrow-libs`.core.`arrow-cache4k`,
// `arrow-libs`.core.`arrow-core-high-arity`,

`arrow-libs`.core.`arrow-atomic`,
`arrow-libs`.core.`arrow-autoclose`,
`arrow-libs`.core.`arrow-core-retrofit`,
`arrow-libs`.core.`arrow-core-serialization`,
`arrow-libs`.core.`arrow-core`,
`arrow-libs`.core.`arrow-eval`,
`arrow-libs`.core.`arrow-functions`,
`arrow-libs`.fx.`arrow-collectors`,
`arrow-libs`.fx.`arrow-fx-coroutines`,
`arrow-libs`.fx.`arrow-fx-stm`,
// Cannot test this one - it relies on the module dependency in the .jar format, while Mill provides .class files
// `arrow-libs`.optics.`arrow-optics-ksp-plugin`,
`arrow-libs`.optics.`arrow-optics-reflect`,
`arrow-libs`.optics.`arrow-optics`,

`arrow-libs`.resilience.`arrow-resilience`
)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After I better understand why that is needed at all, I'd like to move this into it's own support trait, so we can just mix in all the customized compile and test tasks, so the actual domain setup is free of these quirks.

@@ -326,15 +326,15 @@ trait KotlinModule extends JavaModule { outer =>
def kotlincOptions: T[Seq[String]] = Task {
val options = Seq.newBuilder[String]
options += "-no-stdlib"
val kotlinLanguageVersion = languageVersion()
if (!kotlinLanguageVersion.isBlank) {
val kotlinkotlinLanguageVersion = kotlinLanguageVersion()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One kotlin too much

@lihaoyi
Copy link
Member

lihaoyi commented Nov 3, 2024

I pushed some more changes to try and DRY up the build further. I'm hitting some failures that I suspect are flakiness, but not sure yet. Still looking into it

@0xnm
Copy link
Contributor Author

0xnm commented Nov 3, 2024

JS tests may be flaky, because of NPM (sometimes if fails to download the artifact) and also because some tests may time out sometimes (no idea why).

For the common part of the NPM-related JS tooling (mocha, source-map) it is probably better to use the common dest/task in the future, to avoid downloading it for every module.

@@ -133,11 +127,11 @@ object `package` extends RootModule {
s"-Xcommon-sources=${files.mkString(",")}"
}

trait ArrowPlatformModule extends KotlinModule {
trait ArrowPlatformModule extends KotlinMavenModule { outer =>
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

KotlinMavenModule implies that layout is src/main/... while for multiplatform setup it is usually src/commonMain/... + src/<target>Main/.... What is the advantage of applying it?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good question. I think it's pretty arbitrary, but it feels closer than the raw src/ folder that KotlinModule provides, and at least it puts the src/main/resources and src/test/resources in the right place. I also ended up using it in ArrowJvmModule which has the exact correct layout, and so thought it would be nice to be consistent even if it doesn't quite fit

@lihaoyi
Copy link
Member

lihaoyi commented Nov 7, 2024

I think this looks pretty good, going to merge it for now and close out the bounty. We can continue to improve upon it in master and I can try using it to do a comparative study between Mill and Gradle-Kt

@lihaoyi lihaoyi merged commit 1a5605a into com-lihaoyi:main Nov 7, 2024
25 checks passed
@lefou lefou added this to the 0.12.2 milestone Nov 7, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants