Skip to content

Cross build laika-sbt for sbt 2 - #774

Open
tanishiking wants to merge 2 commits into
typelevel:mainfrom
tanishiking:sbt2
Open

Cross build laika-sbt for sbt 2#774
tanishiking wants to merge 2 commits into
typelevel:mainfrom
tanishiking:sbt2

Conversation

@tanishiking

@tanishiking tanishiking commented Jun 25, 2026

Copy link
Copy Markdown

Depends on upstream sbt change sbt/sbt#9377, we need to wait until sbt 2.0.1 2.0.1 is released with that fix.


close #773

  • Exclude all laika-sbt tasks from sbt 2 caching with Def.uncached.
  • Adapt to sbt2 API changes using https://github.com/sbt/sbt2-compat if you don't like adding dependency, we can define small set of PluginCompat.
  • Run the plugin build and tests in CI with sbt 2, Scala 3, and Java 17.
  • Set Laika / target explicitly in each scripted project build.sbt so scripted tests work across sbt 1 and 2 target directory.

Depends on upstream sbt change sbt/sbt#9377

@tanishiking tanishiking changed the title [WIP] Cross build laika-sbt for sbt 2 Cross build laika-sbt for sbt 2 Jun 29, 2026
logLevel = MessageFilter.Warning
)

private def unapply(conf: LaikaConfig) = conf

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

unused, removed for suppress warning in Scala3.

Laika / clean := Tasks.clean.value,
laikaSite / mappings := Def.sequential(Tasks.site, Tasks.mappings).value
) :+ (cleanFiles += (Laika / target).value)
@nowarn("msg=unused import")

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

For sbtcompat.PluginCompat.* in Scala3.

@tanishiking
tanishiking marked this pull request as ready for review June 29, 2026 08:41
@armanbilge
armanbilge self-requested a review July 1, 2026 16:57

@reardonj reardonj left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

This looks pretty reasonable. I'm not familiar with the CI setup stuff enough to comment on it.


enablePlugins(LaikaPlugin)

Laika / target := baseDirectory.value / "target" / "docs"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Did this have to be added due to sbt2 changes the target directory setup?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Yes, by default, it's target/out/jvm/scala-xxx/<moduleName> for sbt 2.x, while sbt 1.x is target/.... If we didn't add this configuration, test script's $ must-mirror target/docs/site/hello.html doesn't work across sbt 1.x and 2.x.

Alternatively, we can define a custom sbt task that checks the content of generated files, but I think configuring Laika / target would be the easiest fix (smallest diff).

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

I think it's fine as is. Just was confirming my understanding.

Comment thread build.sbt Outdated
else Some(8)
},
// Scaladoc 3 cannot currently resolve some TASTy from sbt 2 transitive dependencies.
// https://github.com/scala/scala3/issues/18487

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

I see you fixed this bug. I guess we are stuck until at least 3.9 to make use of it though?

@tanishiking tanishiking Jul 23, 2026

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

When I was investigating the bug, I realized that it matters only when the plugin has a dependency to any symbols that is annotated with @datatype.data (such as https://github.com/sbt/sbt/blob/d4e8fb583c1a61733500112a2ec6dd8af2a4de4c/lm-coursier/definitions/src/main/scala/lmcoursier/CoursierConfiguration.scala#L23).

So there's no problem for laika, I'll remove this workaround 🙇

done 5c9a317

Comment thread build.sbt Outdated
// TODO: Re-enable MiMa for sbt 2 once a previous sbt 2 plugin artifact exists.
// The sbt 2 / Scala 3 plugin artifact did not exist in previous Laika releases,
// so MiMa cannot compare against a missing baseline.
mimaPreviousArtifacts := {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

I don't suppose there is a nicer way to do this @armanbilge ?

@tanishiking tanishiking Jul 23, 2026

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Oh, I learnt that there's tlVersionIntroduced in sbt-typelevel:

https://github.com/typelevel/sbt-typelevel/blob/dfb6b58df7bb55d8ac8b65658a0f4e5d6a4ca445/docs/faq.md?plain=1#L30-L34

https://github.com/typelevel/sbt-typelevel/blob/dfb6b58df7bb55d8ac8b65658a0f4e5d6a4ca445/docs/faq.md?plain=1#L30-L34

Maybe we wanna set tlVersionIntroduced := Map("3" -> "1.3.3") (where 1.3.3 is the next release version, maybe 1.4.0 ?)
Then we don't need to manually remove this mimaPreviousArtifacts when we have scala3 release.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Set tlVersionIntroduced := Map("3" -> "1.3.3"). I'm not sure the next version is either 1.3.3 or 1.4.0 though :)
e4dae94

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

I believe a new target would get a minor release, so it should be 1.4.0

@tanishiking tanishiking Jul 23, 2026

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

👍 updated to 1.4.0 9326713

Seq(
Laika / sourceDirectories := Seq(sourceDirectory.value / "docs"),
Laika / excludeFilter := HiddenFileFilter,
laikaInputs := Def.uncached(Settings.defaultInputs.value),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Do these need to be uncached or is this just for ease of migration?

@tanishiking tanishiking Jul 23, 2026

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Oops, nice catch, they're settingKey (not taskKey) and we didn't need Def.uncached. (5c9a317)

fix typelevel#773

- Exclude all laika-sbt tasks from sbt 2 caching with `Def.uncached`.
- Adapt to sbt2 API changes using https://github.com/sbt/sbt2-compat
  if you don't like adding dependency, we can define small set of
  PluginCompat.
- Run the plugin build and tests in CI with sbt 2, Scala 3, and Java 17.
- Set `Laika / target` explicitly in each scripted project `build.sbt` so
  scripted tests work across sbt 1 and 2 target directory.

Depends on upstream sbt change sbt/sbt#9377
@tanishiking
tanishiking force-pushed the sbt2 branch 2 times, most recently from e4dae94 to 6fb313f Compare July 23, 2026 12:08
@reardonj

Copy link
Copy Markdown

FYI, force pushing makes it basically impossible to review what actually changed since you destroy the history when do this. I’d have to review this whole PR from scratch now because all the commits changed so I can’t assume there are no other changes.

@tanishiking

Copy link
Copy Markdown
Author

Ah, sorry I should've used fixup commits

val mappings: Initialize[Task[Seq[(File, String)]]] = task {
sbt.Path.allSubpaths((laikaSite / target).value).toSeq
val mappings: Initialize[Task[Seq[(FileRef, String)]]] = task {
implicit val fileConverter: FileConverter = (ThisBuild / sbt.Keys.fileConverter).value

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Not given FileConverter?

streams.value.log.info(s"Packaging $zipFile ...")

sbt.IO.zip((laikaSite / sbt.Keys.mappings).value, zipFile, None)
implicit val fileConverter: FileConverter = (ThisBuild / sbt.Keys.fileConverter).value

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

ditto


enablePlugins(LaikaPlugin)

Laika / target := baseDirectory.value / "target" / "docs"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Is this something that will change in the downstream user configuration? Will we need to document these changes somewhere?

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

If I understand correctly, this is just a test file that is being forced to use an sbt 1.x output path for testing convenience. Actual users of Laika in sbt 2 would see their output follow standard sbt 2 behaviour. If the user upgrades and has other script assume the output path, they would see issues, so it would be good to note the behaviour as part of the cross-build release.

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.

sbt 2.x support for laika-sbt

3 participants