Skip to content

Support Bzlmod and add rules_scala to bazel-central-registry #1482

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

Open
sfc-gh-pbennes opened this issue Mar 16, 2023 · 85 comments · Fixed by #1619 or #1722
Open

Support Bzlmod and add rules_scala to bazel-central-registry #1482

sfc-gh-pbennes opened this issue Mar 16, 2023 · 85 comments · Fixed by #1619 or #1722

Comments

@sfc-gh-pbennes
Copy link

sfc-gh-pbennes commented Mar 16, 2023

Greetings!

It looks like rules_scala isn't part of the Bzlmod effort or added to bazel-central-registry yet. I've opened an issue both here and in https://github.com/bazelbuild/bazel-central-registry to request it: bazelbuild/bazel-central-registry#522

@chrislovecnm
Copy link

Just a note to anyone that starts the work native.register_toolchains is not supported when using bzlmod.

@sluongng
Copy link

@chrislovecnm
Copy link

chrislovecnm commented Jul 11, 2023

@sluongng
Copy link

Yeah you would only want to prepare the toolchain (as a new repository) inside the extension I think. Registering it must be called from the MODULE.bazel file.

So native.register_toolchains call from the extension's starlark does not work, but having the extension create @pythons_hub//:all and then MODULE.bazel calling register_toolchains("@pythons_hub//:all") worked. 👍

@mateuszkuta256
Copy link
Contributor

I prepared a minimal bzlmod support here and gonna split it into a few PRs
TODOs after merging it:

  • write documentation on how to use rules_scala with bzlmod (some properties like SCALA_VERSION will probably be configurable via repo-env)
  • prepare release notes
  • contribute repo to the Bazel Central Registry
  • add tests that the project builds using both WORKSPACE and MODULE.bazel
  • migrate test/external workspaces to blzmod too

@pcj
Copy link

pcj commented Jun 30, 2024

@mateuszkuta256 thanks for getting this started! Any progress updates or blockers?

@mateuszkuta256
Copy link
Contributor

@mateuszkuta256 thanks for getting this started! Any progress updates or blockers?

hi, unfortunately I'm working on other things now and won't continue with this PR in the foreseeable future
I remember this migration was on hold because interfered with 'cross compilation support'
It looks like great progress was done it this area, so maybe someone can already take over the PR

@mbland
Copy link
Contributor

mbland commented Oct 2, 2024

I'd like to take on the task of Bzlmodifying this repo through a series of pull requests.

I've already created a (mostly) working branch in my own fork. Though I saw a couple draft pull requests here, I ended up taking a different approach and got it mostly working. In fact, I did exactly what @sluongng suggested in #1482 (comment). (I didn't notice this comment before just now—I might've read it, but not understood it at the time—but I did study rules_python and rules_go, and ended up doing exactly that.)

There are still issues I need help to address (recorded in some of the commit messages), I didn't strictly maintain WORKSPACE compatibility (fixable), and I only tested against Scala 2.13. But I can start teasing chunks out of it in a methodical fashion, to ensure that I maintain WORKSPACE and cross-version compatibility.

For an example of what it looks like from a client perspective, here's what the MODULE.bazel stanza from my local EngFlow/example repo looks like (as opposed to the current stanza, explanatory comment notwithstanding):

bazel_dep(name = "rules_scala", repo_name = "io_bazel_rules_scala")
local_path_override(
    module_name = "rules_scala",
    path = "../../bazelbuild/rules_scala"
)   

scala_dev_deps = use_extension(
    "@io_bazel_rules_scala//scala/extensions:deps.bzl",
    "scala_deps",
    dev_dependency = True,
)   
scala_dev_deps.toolchains(
    scalatest = True,
)

So if folks are game for me to do this, I'll start carving off pieces as separate pull requests, and we can resolve any outstanding problems in the process.

cc: @BillyAutrey @jayconrod @benjaminp @TheGrizzlyDev

mbland added a commit to mbland/rules_scala that referenced this issue Oct 3, 2024
This begins the Bzlmod compatibility migration by updating Bazel to
version 7.3.2 and adding initial `MODULE.bazel` and `WORKSPACE.bzlmod`
files.

Part of: bazel-contrib#1482

Though Bzlmod remains disabled, updating to Bazel 7.3.2 requred updating
or adding the following packages to maintain `WORKSPACE` compatibility.

In `rules_scala_setup()`:

- bazel_skylib: 1.4.1 => 1.7.1
- rules_cc: 0.0.6 => 0.0.10
- rules_java: 5.4.1 => 7.9.0
- rules_proto: 5.3.0-21.7 => 6.0.2

Dev dependencies in `WORKSPACE`:

- com_google_protobuf: 28.2
- rules_pkg: 1.0.1
- rules_jvm_external: 6.4
- com_google_absl: abseil-cpp-20240722.0
- zlib: 1.3.1

Of all of the new, explicit dev dependencies, only `com_google_protobuf`
will be necessary to include in `MODULE.bazel`. The Bzlmod mechanism
will discover these other transitive dev dependencies automatically.

Also removed the `rules_java_extra` repo from `WORKSPACE`, which
appeared unused.

---

Though the current `rules_java` version is 7.12.1, and largely works
with this repo, it requires a few temporary workarounds. Rather than
commit the workarounds, upgrading only to 7.9.0 now seems less crufty.

What follows is a very detailed explanation of what happens with 7.12.1
with Bazel 7.3.2, just to have it on the record.

---

The workaround is to change a few toolchain and macro file targets from
`@bazel_tools//tools/jdk:` to `@rules_java//toolchains:`. This isn't a
terribly bad or invasive workaround, but `@bazel_tools//tools/jdk:` is
clearly the canonical path. Best to keep it that way, lest we build up
technical debt.

Without the workaround, these targets would fail:

- //test/src/main/resources/java_sources:CompiledWithJava11
- //test/src/main/resources/java_sources:CompiledWithJava8
- //test/toolchains:java21_toolchain
- //test:JunitRuntimePlatform
- //test:JunitRuntimePlatform_test_runner
- //test:scala_binary_jdk_11

with this error:

```txt
ERROR: .../external/rules_java_builtin/toolchains/BUILD:254:14:

While resolving toolchains for target
@@rules_java_builtin//toolchains:platformclasspath (096dcc8):

No matching toolchains found for types
@@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type.
```

This appears to be a consequence of both upgrading the Bazel version
from 6.3.0 to 7.3.2 and updating `rules_java` to 7.12.1. The
`rules_java_builtin` repo is part of the `WORKSPACE` prefix that adds
implicit dependencies:

- https://bazel.build/external/migration#builtin-default-deps

This repo was added to 7.0.0-pre.20231011.2 in the following change,
mapped to `@rules_java` within the scope of the `@bazel_tools` repo:

- bazelbuild/bazel: Add rules_java_builtin to the users of Java modules
  bazelbuild/bazel@ff1abb2

This change tried to ensure `rules_java` remained compatible with
earlier Bazel versions. However, it changed all instances of
`@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type` to
`//toolchains:bootstrap_runtime_toolchain_type`:

- bazelbuild/rules_java: Make rules_java backwards compatible with Bazel
  6.3.0
  bazelbuild/rules_java@30ecf3f

Bazel has bumped `rules_java` in its `workspace_deps.bzl` from 7.9.0 to
7.11.0, but it's only available as of 8.0.0-pre.20240911.1.

- bazelbuild/bazel: Update rules_java 7.11.1 / java_tools 13.8
  bazelbuild/bazel#23571
  bazelbuild/bazel@f92124a

---

What I believe is happening is, under Bazel 7.3.2 and `rules_java`
7.12.1:

- Bazel creates `rules_java` 7.9.0 as `@rules_java_builtin` in the
  `WORKSPACE` prefix.

- `@bazel_tools` has `@rules_java` mapped to `@rules_java_builtin` when
  initialized during the `WORKSPACE` prefix, during which
  `@bazel_tools//tools/jdk` registers `alias()` targets to
  `@rules_java` toolchain targets. These aliased toolchains specify
  `@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type` in their
  `toolchains` attribute.

- `WORKSPACE` loads `@rules_java` 7.12.1 and registers all its
  toolchains with type
  `@rules_java//toolchains:bootstrap_runtime_toolchain_type`.

- Some `@rules_java` rules explicitly specifying toolchains from
  `@bazel_tools//tools/jdk` can't find them, because the
  `@bazel_tools//tools/jdk` toolchain aliases expect toolchains of type
  `@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type`.

This has broken other projects in the same way:

- bazelbuild/bazel: [Bazel CI] Downstream project broken by rules_java
  upgrade #23619
  bazelbuild/bazel#23619

These problems don't appear under Bzlmod, and `@rules_java_builtin` was
never required. This is because `WORKSPACE` executes its statements
sequentially, while Bzlmod builds the module dependency graph _before_
instantiating repositories (within module extensions).

It seems a fix is on the way that removes `@rules_java_builtin` from the
`WORKSPACE` prefix, and adds `@rules_java` to the suffix. At this
moment, though, it's not even in a prerelase:

- bazelbuild/bazel: Remove rules_java_builtin in WORKSPACE prefix
  bazelbuild/bazel@7506690

---

Note that the error message matches that from the following resolved
issue, but that issue was for non-Bzlmod child repos when `WORKSPACE`
was disabled.

- bazelbuild/bazel: Undefined @@rules_java_builtin repository with
  --noenable_workspace option
  bazelbuild/bazel#22754
mbland added a commit to mbland/rules_scala that referenced this issue Oct 5, 2024
Related to bazel-contrib#1482, bazel-contrib#1618, and bazel-contrib#1619. Results from the investigation
documented at:

- bazel-contrib#1619 (comment)

Updates `_import_paths()` in `scala_proto_aspect.bzl` to handle
differences `ProtoInfo.proto_source_root` and `ProtoInfo.direct_sources`
values between Bazel 6 and Bazel 7.

Without this change, `_import_paths()` emits incorrect values under
Bazel 7, causing targets containing generated `.proto` inputs to fail,
e.g.  `//test/proto3:test_generated_proto`.

See also:

- Fix paths for sibling repository setup and generated .proto files
  bazelbuild/bazel@6c6c196

- The docstring for `ProtoInfo.proto_source_root` in the Bazel sources:
  https://github.com/bazelbuild/bazel/blob/7.3.2/src/main/starlark/builtins_bzl/common/proto/proto_info.bzl#L155-L172

- Remove incompatible_generated_protos_in_virtual_imports
  bazelbuild/bazel@3efaa32

- Comment from: Generated Protos are no longer considered as
  virtual_imports in Bazel 7
  bazelbuild/bazel#21075 (comment)

---

I cherrypicked this commit into bazel-contrib#1618. While it fixed the
`//test/proto3` build failure, it does _not_ fix the hanging
scalapb_workers from the ProtoScalaPBRule aspect.

I'll have to investiate further whether than hang is related to Bazel,
rules_proto, com_google_protobuf, or some mixture thereof. Still,
progress!
mbland added a commit to mbland/rules_scala that referenced this issue Oct 5, 2024
Related to bazel-contrib#1482, bazel-contrib#1618, and bazel-contrib#1619. Results from the investigation
documented at:

- bazel-contrib#1619 (comment)

Updates `_import_paths()` in `scala_proto_aspect.bzl` to handle
differences `ProtoInfo.proto_source_root` and `ProtoInfo.direct_sources`
values between Bazel 6 and Bazel 7.

Without this change, `_import_paths()` emits incorrect values under
Bazel 7, causing targets containing generated `.proto` inputs to fail,
e.g.  `//test/proto3:test_generated_proto`.

See also:

- Fix paths for sibling repository setup and generated .proto files
  bazelbuild/bazel@6c6c196

- The docstring for `ProtoInfo.proto_source_root` in the Bazel sources:
  https://github.com/bazelbuild/bazel/blob/7.3.2/src/main/starlark/builtins_bzl/common/proto/proto_info.bzl#L155-L172

- Remove incompatible_generated_protos_in_virtual_imports
  bazelbuild/bazel@3efaa32

- Comment from: Generated Protos are no longer considered as
  virtual_imports in Bazel 7
  bazelbuild/bazel#21075 (comment)

---

I cherrypicked this commit into bazel-contrib#1618. While it fixed the
`//test/proto3` build failure, it does _not_ fix the hanging
scalapb_workers from the ProtoScalaPBRule aspect.

I'll have to investiate further whether than hang is related to Bazel,
rules_proto, com_google_protobuf, or some mixture thereof. Still,
progress!
mbland added a commit to mbland/rules_scala that referenced this issue Oct 6, 2024
Related to bazel-contrib#1482, bazel-contrib#1618, and bazel-contrib#1619. Results from the investigation
documented at:

- bazel-contrib#1619 (comment)

Updates `_import_paths()` in `scala_proto_aspect.bzl` to handle
differences `ProtoInfo.proto_source_root` and `ProtoInfo.direct_sources`
values between Bazel 6 and Bazel 7.

Without this change, `_import_paths()` emits incorrect values under
Bazel 7, causing targets containing generated `.proto` inputs to fail,
e.g.  `//test/proto3:test_generated_proto`.

See also:

- Fix paths for sibling repository setup and generated .proto files
  bazelbuild/bazel@6c6c196

- The docstring for `ProtoInfo.proto_source_root` in the Bazel sources:
  https://github.com/bazelbuild/bazel/blob/7.3.2/src/main/starlark/builtins_bzl/common/proto/proto_info.bzl#L155-L172

- Remove incompatible_generated_protos_in_virtual_imports
  bazelbuild/bazel@3efaa32

- Comment from: Generated Protos are no longer considered as
  virtual_imports in Bazel 7
  bazelbuild/bazel#21075 (comment)

---

I cherrypicked this commit into bazel-contrib#1618. While it fixed the
`//test/proto3` build failure, it does _not_ fix the hanging
scalapb_workers from the ProtoScalaPBRule aspect.

I'll have to investiate further whether than hang is related to Bazel,
rules_proto, com_google_protobuf, or some mixture thereof. Still,
progress!
mbland added a commit to mbland/rules_scala that referenced this issue Oct 7, 2024
Related to bazel-contrib#1482, bazel-contrib#1618, and bazel-contrib#1619. Results from the investigation
documented at:

- bazel-contrib#1619 (comment)

Updates `_import_paths()` in `scala_proto_aspect.bzl` to handle
differences `ProtoInfo.proto_source_root` and `ProtoInfo.direct_sources`
values between Bazel 6 and Bazel 7.

Without this change, `_import_paths()` emits incorrect values under
Bazel 7, causing targets containing generated `.proto` inputs to fail,
e.g.  `//test/proto3:test_generated_proto`.

See also:

- Fix paths for sibling repository setup and generated .proto files
  bazelbuild/bazel@6c6c196

- The docstring for `ProtoInfo.proto_source_root` in the Bazel sources:
  https://github.com/bazelbuild/bazel/blob/7.3.2/src/main/starlark/builtins_bzl/common/proto/proto_info.bzl#L155-L172

- Remove incompatible_generated_protos_in_virtual_imports
  bazelbuild/bazel@3efaa32

- Comment from: Generated Protos are no longer considered as
  virtual_imports in Bazel 7
  bazelbuild/bazel#21075 (comment)

---

I cherrypicked this commit into bazel-contrib#1618. While it fixed the
`//test/proto3` build failure, it does _not_ fix the hanging
scalapb_workers from the ProtoScalaPBRule aspect.

I'll have to investiate further whether than hang is related to Bazel,
rules_proto, com_google_protobuf, or some mixture thereof. Still,
progress!
mbland added a commit to mbland/rules_scala that referenced this issue Oct 7, 2024
Part of bazel-contrib#1482.

Splits the last component off of canonical repo names to produce the
expected repo name.

Without Bzlmod, it returns the original name. With Bzlmod enabled, it
avoids generating output like:

    scala_import(
        name = "_main~scala_deps~io_bazel_rules_scala_scala_compiler",
        jars = ["scala-compiler-2.12.18.jar"],
    )

resulting in errors like:

```
ERROR: .../_main~_repo_rules~io_bazel_rules_scala/scala/BUILD:
no such target '@@_main~scala_deps~io_bazel_rules_scala_scala_compiler//:io_bazel_rules_scala_scala_compiler':
target 'io_bazel_rules_scala_scala_compiler' not declared in package ''
defined by .../_main~scala_deps~io_bazel_rules_scala_scala_compiler/BUILD
and referenced by '@@_main~_repo_rules~io_bazel_rules_scala//scala:default_toolchain_scala_compile_classpath_provider'
```

Also fixes the following error when attaching resources from custom repos to
targets under Bzlmod:

```txt
$ bazel test //test/src/main/scala/scalarules/test/resources:all

1) Scala library depending on resources from external resource-only
  jar::allow to load resources(scalarules.test.resources.ScalaLibResourcesFromExternalDepTest)
  java.lang.NullPointerException
    at scalarules.test.resources.ScalaLibResourcesFromExternalDepTest.get(ScalaLibResourcesFromExternalDepTest.scala:17)
    at scalarules.test.resources.ScalaLibResourcesFromExternalDepTest.$anonfun$new$3(ScalaLibResourcesFromExternalDepTest.scala:11)
    at scalarules.test.resources.ScalaLibResourcesFromExternalDepTest.$anonfun$new$2(ScalaLibResourcesFromExternalDepTest.scala:11)
```

Can be replaced with a future bazel-skylib implementation, if accepted
into that repo.

---

We can't rely on the specific canonical repository name format:

> Repos generated by extensions have canonical names in the form of
> `module_repo_canonical_name+extension_name+repo_name`. For extensions
> hosted in the root module, the `module_repo_canonical_name` part is
> replaced with the string `_main`. Note that the canonical name format is
> not an API you should depend on — it's subject to change at any time.
>
> - https://bazel.build/external/extension#repository_names_and_visibility

The change to no longer encode module versions in canonical repo names in
Bazel 7.1.0 is a recent example of Bazel maintainers altering the format:

- bazelbuild/bazel#21316

And the maintainers recently replaced the `~` delimiter with `+` in the
upcoming Bazel 8 release due to build performance issues on Windows:

- bazelbuild/bazel#22865

This function assumes the only valid `repo_name` characters are letters,
numbers, '_', '-', and '.'. It finds the last character not in this set, and
returns the contents of `name` following this character. This is valid so
long as this condition holds:

- https://github.com/bazelbuild/bazel/blob/7.3.2/src/main/java/com/google/devtools/build/lib/cmdline/RepositoryName.java#L159-L162
mbland added a commit to mbland/rules_scala that referenced this issue Oct 7, 2024
Part of bazel-contrib#1482.

Splits the last component off of canonical repo names to produce the
expected repo name.

Without Bzlmod, it returns the original name. With Bzlmod enabled, it
avoids generating output like:

    scala_import(
        name = "_main~scala_deps~io_bazel_rules_scala_scala_compiler",
        jars = ["scala-compiler-2.12.18.jar"],
    )

resulting in errors like:

```
ERROR: .../_main~_repo_rules~io_bazel_rules_scala/scala/BUILD:
no such target '@@_main~scala_deps~io_bazel_rules_scala_scala_compiler//:io_bazel_rules_scala_scala_compiler':
target 'io_bazel_rules_scala_scala_compiler' not declared in package ''
defined by .../_main~scala_deps~io_bazel_rules_scala_scala_compiler/BUILD
and referenced by '@@_main~_repo_rules~io_bazel_rules_scala//scala:default_toolchain_scala_compile_classpath_provider'
```

Also fixes the following error when attaching resources from custom repos to
targets under Bzlmod:

```txt
$ bazel test //test/src/main/scala/scalarules/test/resources:all

1) Scala library depending on resources from external resource-only
  jar::allow to load resources(scalarules.test.resources.ScalaLibResourcesFromExternalDepTest)
  java.lang.NullPointerException
    at scalarules.test.resources.ScalaLibResourcesFromExternalDepTest.get(ScalaLibResourcesFromExternalDepTest.scala:17)
    at scalarules.test.resources.ScalaLibResourcesFromExternalDepTest.$anonfun$new$3(ScalaLibResourcesFromExternalDepTest.scala:11)
    at scalarules.test.resources.ScalaLibResourcesFromExternalDepTest.$anonfun$new$2(ScalaLibResourcesFromExternalDepTest.scala:11)
```

Can be replaced with a future bazel-skylib implementation, if accepted
into that repo.

---

We can't rely on the specific canonical repository name format:

> Repos generated by extensions have canonical names in the form of
> `module_repo_canonical_name+extension_name+repo_name`. For extensions
> hosted in the root module, the `module_repo_canonical_name` part is
> replaced with the string `_main`. Note that the canonical name format is
> not an API you should depend on — it's subject to change at any time.
>
> - https://bazel.build/external/extension#repository_names_and_visibility

The change to no longer encode module versions in canonical repo names in
Bazel 7.1.0 is a recent example of Bazel maintainers altering the format:

- bazelbuild/bazel#21316

And the maintainers recently replaced the `~` delimiter with `+` in the
upcoming Bazel 8 release due to build performance issues on Windows:

- bazelbuild/bazel#22865

This function assumes the only valid `repo_name` characters are letters,
numbers, '_', '-', and '.'. It finds the last character not in this set, and
returns the contents of `name` following this character. This is valid so
long as this condition holds:

- https://github.com/bazelbuild/bazel/blob/7.3.2/src/main/java/com/google/devtools/build/lib/cmdline/RepositoryName.java#L159-L162
liucijus pushed a commit that referenced this issue Oct 8, 2024
Related to #1482, #1618, and #1619. Results from the investigation
documented at:

- #1619 (comment)

Updates `_import_paths()` in `scala_proto_aspect.bzl` to handle
differences `ProtoInfo.proto_source_root` and `ProtoInfo.direct_sources`
values between Bazel 6 and Bazel 7.

Without this change, `_import_paths()` emits incorrect values under
Bazel 7, causing targets containing generated `.proto` inputs to fail,
e.g.  `//test/proto3:test_generated_proto`.

See also:

- Fix paths for sibling repository setup and generated .proto files
  bazelbuild/bazel@6c6c196

- The docstring for `ProtoInfo.proto_source_root` in the Bazel sources:
  https://github.com/bazelbuild/bazel/blob/7.3.2/src/main/starlark/builtins_bzl/common/proto/proto_info.bzl#L155-L172

- Remove incompatible_generated_protos_in_virtual_imports
  bazelbuild/bazel@3efaa32

- Comment from: Generated Protos are no longer considered as
  virtual_imports in Bazel 7
  bazelbuild/bazel#21075 (comment)

---

I cherrypicked this commit into #1618. While it fixed the
`//test/proto3` build failure, it does _not_ fix the hanging
scalapb_workers from the ProtoScalaPBRule aspect.

I'll have to investiate further whether than hang is related to Bazel,
rules_proto, com_google_protobuf, or some mixture thereof. Still,
progress!
@simuons simuons reopened this Oct 8, 2024
mbland added a commit to mbland/rules_scala that referenced this issue Oct 8, 2024
Part of bazel-contrib#1482.

Splits the last component off of canonical repo names to produce the
expected repo name.

Without Bzlmod, it returns the original name. With Bzlmod enabled, it
avoids generating output like:

    scala_import(
        name = "_main~scala_deps~io_bazel_rules_scala_scala_compiler",
        jars = ["scala-compiler-2.12.18.jar"],
    )

resulting in errors like:

```
ERROR: .../_main~_repo_rules~io_bazel_rules_scala/scala/BUILD:
no such target '@@_main~scala_deps~io_bazel_rules_scala_scala_compiler//:io_bazel_rules_scala_scala_compiler':
target 'io_bazel_rules_scala_scala_compiler' not declared in package ''
defined by .../_main~scala_deps~io_bazel_rules_scala_scala_compiler/BUILD
and referenced by '@@_main~_repo_rules~io_bazel_rules_scala//scala:default_toolchain_scala_compile_classpath_provider'
```

Also fixes the following error when attaching resources from custom repos to
targets under Bzlmod:

```txt
$ bazel test //test/src/main/scala/scalarules/test/resources:all

1) Scala library depending on resources from external resource-only
  jar::allow to load resources(scalarules.test.resources.ScalaLibResourcesFromExternalDepTest)
  java.lang.NullPointerException
    at scalarules.test.resources.ScalaLibResourcesFromExternalDepTest.get(ScalaLibResourcesFromExternalDepTest.scala:17)
    at scalarules.test.resources.ScalaLibResourcesFromExternalDepTest.$anonfun$new$3(ScalaLibResourcesFromExternalDepTest.scala:11)
    at scalarules.test.resources.ScalaLibResourcesFromExternalDepTest.$anonfun$new$2(ScalaLibResourcesFromExternalDepTest.scala:11)
```

Can be replaced with a future bazel-skylib implementation, if accepted
into that repo.

---

We can't rely on the specific canonical repository name format:

> Repos generated by extensions have canonical names in the form of
> `module_repo_canonical_name+extension_name+repo_name`. For extensions
> hosted in the root module, the `module_repo_canonical_name` part is
> replaced with the string `_main`. Note that the canonical name format is
> not an API you should depend on — it's subject to change at any time.
>
> - https://bazel.build/external/extension#repository_names_and_visibility

The change to no longer encode module versions in canonical repo names in
Bazel 7.1.0 is a recent example of Bazel maintainers altering the format:

- bazelbuild/bazel#21316

And the maintainers recently replaced the `~` delimiter with `+` in the
upcoming Bazel 8 release due to build performance issues on Windows:

- bazelbuild/bazel#22865

This function assumes the only valid `repo_name` characters are letters,
numbers, '_', '-', and '.'. It finds the last character not in this set, and
returns the contents of `name` following this character. This is valid so
long as this condition holds:

- https://github.com/bazelbuild/bazel/blob/7.3.2/src/main/java/com/google/devtools/build/lib/cmdline/RepositoryName.java#L159-L162
@mbland
Copy link
Contributor

mbland commented Oct 11, 2024

A quick update for visibility: I'm very close to having the Bzlmodified rules_scala passing 100% of the tests, down to the last couple of failures:

  • I need to replace the bind() calls from twitter_scrooge with alias() or some such to get test_version.sh to pass.
  • I need to fix the Scala 3.1.2 and Scala 3.3.3 failures for the Scalafmt targets from test/shell/test_cross_build.sh (corresponding to the test3 and library3 test cases in test_scalafmt()).

I also need to get test_lint.sh working again, and update the dt_patches repos for Bzlmod. But the following all pass:

  • test_rules_scala.sh
  • test_reproducibility.sh
  • test_examples.sh
  • test_coverage.sh

Hopefully I can get these fixed up today, and I'll start peeling off the next pull request or two. And thanks to @simuons and @liucijus for reviewing and merging #1619 and #1620 already.

mbland added a commit to mbland/rules_scala that referenced this issue Apr 27, 2025
Separates the latest dependency versions that we test against from the
minimum required versions and bumps `protobuf` to v30.2. Part of bazel-contrib#1482.

Adds `scala/latest_deps.bzl` for `WORKSPACE` and `deps/latest` for
Bzlmod, used by our internal test repos.

Tests used to validate these dependency versions will land in a future
change.

Also fixes a bug in the failure message of `_default_platform()` in
`protoc_toolchains.bzl` by calling `string.join()` on the
`HOST_CONSTRAINTS` list. (Didn't notice this until building on Windows
ARM64, since there's no such binary `protobuf` release yet.)

---

This avoids forcing users to upgrade to the latest versions that
`rules_scala` tests against.

Inspired by a thread in the #bzlmod channel of the Bazel Slack workspace
on 2025-01-01 indicating that rules should require the minumum versions
possible:

- https://bazelbuild.slack.com/archives/C014RARENH0/p1743597941149639
mbland added a commit to mbland/rules_scala that referenced this issue Apr 27, 2025
Separates the latest dependency versions that we test against from the
minimum required versions and bumps `protobuf` to v30.2. Part of bazel-contrib#1482.

Adds `scala/latest_deps.bzl` for `WORKSPACE` and `deps/latest` for
Bzlmod, used by our internal test repos.

Tests used to validate these dependency versions will land in a future
change.

Also:

- Fixes a bug in the failure message of `_default_platform()` in
  `protoc_toolchains.bzl` by calling `string.join()` on the
  `HOST_CONSTRAINTS` list.

- Downloads the `win64` build for Windows ARM64.

---

This avoids forcing users to upgrade to the latest versions that
`rules_scala` tests against.

Inspired by a thread in the #bzlmod channel of the Bazel Slack workspace
on 2025-01-01 indicating that rules should require the minumum versions
possible:

- https://bazelbuild.slack.com/archives/C014RARENH0/p1743597941149639

I didn't notice the `_default_platform()` error until building on
Windows ARM64, since there's not yet a binary `protobuf` release for
that platform. The `win64` workaround fixes the actual error, since
Windows ARM64 can execute x86 and x64 binaries:

- https://learn.microsoft.com/en-us/windows/arm/apps-on-arm-x86-emulation
mbland added a commit to mbland/rules_scala that referenced this issue Apr 27, 2025
Updates `.github/workflows/release.yml` and adds `publish-to-bcr.yml`
for publishing to the Bazel Central Registry. Part of bazel-contrib#1482 broken out
from bazel-contrib#1722.

`release.yml` now uses the `release_ruleset` workflow from
`bazel-contrib/.github`, which does everything `release.yml` did
previously and adds SLSA provenance attestations. `release.yml` then
invokes the new `publish-to-bcr.yml` workflow after publishing a
successful release to GitHub. Based on aspect-build/rules_lint#498 and
aspect-build/rules_lint#501. See `.bcr/README.md`.

---

Extracting this from bazel-contrib#1722 makes that pull request more focused, and
prevents holding it up based on any discussion around these workflow
changes in particular. It's also unclear if the infrastructure will be
in place to support these workflows before we're ready to publish the
first `rules_scala` module. Though these workflows will supersede the
Publish to BCR app, it may take some time to resolve
slsa-framework/slsa-verifier#840.

aspect-build/rules_lint#508, @alexeagle manually triggered a workflow
run based on these workflows, which generated an attestation:

- https://github.com/aspect-build/rules_lint/actions/runs/14095611671
- https://github.com/aspect-build/rules_lint/attestations/5857159

Here are some examples of GitHub's attestation UI in general:

- https://github.com/aspect-build/rules_lint/attestations

And some relevant GitHub docs:

- https://docs.github.com/en/actions/security-for-github-actions/security-guides/using-secrets-in-github-actions#using-secrets-in-a-workflow
- https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/accessing-contextual-information-about-workflow-runs#secrets-context
- https://docs.github.com/en/actions/sharing-automations/reusing-workflows#passing-inputs-and-secrets-to-a-reusable-workflow
- https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions#onworkflow_callsecrets
mbland added a commit to mbland/rules_scala that referenced this issue Apr 27, 2025
Separates the latest dependency versions that we test against from the
minimum required versions and bumps `protobuf` to v30.2. Part of bazel-contrib#1482.

Adds `scala/latest_deps.bzl` for `WORKSPACE` and `deps/latest` for
Bzlmod, used by our internal test repos.

Tests used to validate these dependency versions will land in a future
change.

Also:

- Fixes a bug in the failure message of `_default_platform()` in
  `protoc_toolchains.bzl` by calling `string.join()` on the
  `HOST_CONSTRAINTS` list.

- Downloads the `win64` build for Windows ARM64.

---

This avoids forcing users to upgrade to the latest versions that
`rules_scala` tests against.

Inspired by a thread in the #bzlmod channel of the Bazel Slack workspace
on 2025-01-01 indicating that rules should require the minumum versions
possible:

- https://bazelbuild.slack.com/archives/C014RARENH0/p1743597941149639

I didn't notice the `_default_platform()` error until building on
Windows ARM64, since there's not yet a binary `protobuf` release for
that platform. The `win64` workaround fixes the actual error, since
Windows ARM64 can execute x86 and x64 binaries:

- https://learn.microsoft.com/en-us/windows/arm/apps-on-arm-x86-emulation
mbland added a commit to mbland/rules_scala that referenced this issue Apr 27, 2025
Separates the latest dependency versions that we test against from the
minimum required versions and bumps `protobuf` to v30.2. Part of bazel-contrib#1482.

Adds `scala/latest_deps.bzl` for `WORKSPACE` and `deps/latest` for
Bzlmod, used by our internal test repos.

Tests used to validate these dependency versions will land in a future
change.

Also:

- Fixes a bug in the failure message of `_default_platform()` in
  `protoc_toolchains.bzl` by calling `string.join()` on the
  `HOST_CONSTRAINTS` list.

- Downloads the `win64` build for Windows ARM64.

---

This avoids forcing users to upgrade to the latest versions that
`rules_scala` tests against.

Inspired by a thread in the #bzlmod channel of the Bazel Slack workspace
on 2025-01-01 indicating that rules should require the minumum versions
possible:

- https://bazelbuild.slack.com/archives/C014RARENH0/p1743597941149639

I didn't notice the `_default_platform()` error until building on
Windows ARM64, since there's not yet a binary `protobuf` release for
that platform. The `win64` workaround fixes the actual error, since
Windows ARM64 can execute x86 and x64 binaries:

- https://learn.microsoft.com/en-us/windows/arm/apps-on-arm-x86-emulation
mbland added a commit to mbland/rules_scala that referenced this issue Apr 27, 2025
Updates `.github/workflows/release.yml` and adds `publish-to-bcr.yml`
for publishing to the Bazel Central Registry. Part of bazel-contrib#1482 broken out
from bazel-contrib#1722.

`release.yml` now uses the `release_ruleset` workflow from
`bazel-contrib/.github`, which does everything `release.yml` did
previously and adds SLSA provenance attestations. `release.yml` then
invokes the new `publish-to-bcr.yml` workflow after publishing a
successful release to GitHub. Based on aspect-build/rules_lint#498 and
aspect-build/rules_lint#501. See `.bcr/README.md`.

---

Extracting this from bazel-contrib#1722 makes that pull request more focused, and
prevents holding it up based on any discussion around these workflow
changes in particular. It's also unclear if the infrastructure will be
in place to support these workflows before we're ready to publish the
first `rules_scala` module. Though these workflows will supersede the
Publish to BCR app, it may take some time to resolve
slsa-framework/slsa-verifier#840.

aspect-build/rules_lint#508, @alexeagle manually triggered a workflow
run based on these workflows, which generated an attestation:

- https://github.com/aspect-build/rules_lint/actions/runs/14095611671
- https://github.com/aspect-build/rules_lint/attestations/5857159

Here are some examples of GitHub's attestation UI in general:

- https://github.com/aspect-build/rules_lint/attestations

And some relevant GitHub docs:

- https://docs.github.com/en/actions/security-for-github-actions/security-guides/using-secrets-in-github-actions#using-secrets-in-a-workflow
- https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/accessing-contextual-information-about-workflow-runs#secrets-context
- https://docs.github.com/en/actions/sharing-automations/reusing-workflows#passing-inputs-and-secrets-to-a-reusable-workflow
- https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions#onworkflow_callsecrets
mbland added a commit to mbland/rules_scala that referenced this issue Apr 27, 2025
Separates the latest dependency versions that we test against from the
minimum required versions and bumps `protobuf` to v30.2. Part of bazel-contrib#1482.

Adds `scala/latest_deps.bzl` for `WORKSPACE` and `deps/latest` for
Bzlmod, used by our internal test repos.

Tests used to validate these dependency versions will land in a future
change.

Also:

- Fixes a bug in the failure message of `_default_platform()` in
  `protoc_toolchains.bzl` by calling `string.join()` on the
  `HOST_CONSTRAINTS` list.

- Downloads the `win64` build for Windows ARM64.

---

This avoids forcing users to upgrade to the latest versions that
`rules_scala` tests against.

Inspired by a thread in the #bzlmod channel of the Bazel Slack workspace
on 2025-01-01 indicating that rules should require the minumum versions
possible:

- https://bazelbuild.slack.com/archives/C014RARENH0/p1743597941149639

I didn't notice the `_default_platform()` error until building on
Windows ARM64, since there's not yet a binary `protobuf` release for
that platform. The `win64` workaround fixes the actual error, since
Windows ARM64 can execute x86 and x64 binaries:

- https://learn.microsoft.com/en-us/windows/arm/apps-on-arm-x86-emulation
mbland added a commit to mbland/rules_scala that referenced this issue Apr 27, 2025
Updates `.github/workflows/release.yml` and adds `publish-to-bcr.yml`
for publishing to the Bazel Central Registry. Part of bazel-contrib#1482 broken out
from bazel-contrib#1722.

`release.yml` now uses the `release_ruleset` workflow from
`bazel-contrib/.github`, which does everything `release.yml` did
previously and adds SLSA provenance attestations. `release.yml` then
invokes the new `publish-to-bcr.yml` workflow after publishing a
successful release to GitHub. Based on aspect-build/rules_lint#498 and
aspect-build/rules_lint#501. See `.bcr/README.md`.

---

Extracting this from bazel-contrib#1722 makes that pull request more focused, and
prevents holding it up based on any discussion around these workflow
changes in particular. It's also unclear if the infrastructure will be
in place to support these workflows before we're ready to publish the
first `rules_scala` module. Though these workflows will supersede the
Publish to BCR app, it may take some time to resolve
slsa-framework/slsa-verifier#840.

aspect-build/rules_lint#508, @alexeagle manually triggered a workflow
run based on these workflows, which generated an attestation:

- https://github.com/aspect-build/rules_lint/actions/runs/14095611671
- https://github.com/aspect-build/rules_lint/attestations/5857159

Here are some examples of GitHub's attestation UI in general:

- https://github.com/aspect-build/rules_lint/attestations

And some relevant GitHub docs:

- https://docs.github.com/en/actions/security-for-github-actions/security-guides/using-secrets-in-github-actions#using-secrets-in-a-workflow
- https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/accessing-contextual-information-about-workflow-runs#secrets-context
- https://docs.github.com/en/actions/sharing-automations/reusing-workflows#passing-inputs-and-secrets-to-a-reusable-workflow
- https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions#onworkflow_callsecrets
@simuons simuons reopened this Apr 28, 2025
mbland added a commit to mbland/rules_scala that referenced this issue Apr 28, 2025
Separates the latest dependency versions that we test against from the
minimum required versions and bumps `protobuf` to v30.2. Part of bazel-contrib#1482.

Adds `scala/latest_deps.bzl` for `WORKSPACE` and `deps/latest` for
Bzlmod, used by our internal test repos.

Tests used to validate these dependency versions will land in a future
change.

Also:

- Fixes a bug in the failure message of `_default_platform()` in
  `protoc_toolchains.bzl` by calling `string.join()` on the
  `HOST_CONSTRAINTS` list.

- Downloads the `win64` build for Windows ARM64.

---

This avoids forcing users to upgrade to the latest versions that
`rules_scala` tests against.

Inspired by a thread in the #bzlmod channel of the Bazel Slack workspace
on 2025-01-01 indicating that rules should require the minumum versions
possible:

- https://bazelbuild.slack.com/archives/C014RARENH0/p1743597941149639

I didn't notice the `_default_platform()` error until building on
Windows ARM64, since there's not yet a binary `protobuf` release for
that platform. The `win64` workaround fixes the actual error, since
Windows ARM64 can execute x86 and x64 binaries:

- https://learn.microsoft.com/en-us/windows/arm/apps-on-arm-x86-emulation
mbland added a commit to mbland/rules_scala that referenced this issue Apr 28, 2025
Updates `.github/workflows/release.yml` and adds `publish-to-bcr.yml`
for publishing to the Bazel Central Registry. Part of bazel-contrib#1482 broken out
from bazel-contrib#1722.

`release.yml` now uses the `release_ruleset` workflow from
`bazel-contrib/.github`, which does everything `release.yml` did
previously and adds SLSA provenance attestations. `release.yml` then
invokes the new `publish-to-bcr.yml` workflow after publishing a
successful release to GitHub. Based on aspect-build/rules_lint#498 and
aspect-build/rules_lint#501. See `.bcr/README.md`.

---

Extracting this from bazel-contrib#1722 makes that pull request more focused, and
prevents holding it up based on any discussion around these workflow
changes in particular. It's also unclear if the infrastructure will be
in place to support these workflows before we're ready to publish the
first `rules_scala` module. Though these workflows will supersede the
Publish to BCR app, it may take some time to resolve
slsa-framework/slsa-verifier#840.

aspect-build/rules_lint#508, @alexeagle manually triggered a workflow
run based on these workflows, which generated an attestation:

- https://github.com/aspect-build/rules_lint/actions/runs/14095611671
- https://github.com/aspect-build/rules_lint/attestations/5857159

Here are some examples of GitHub's attestation UI in general:

- https://github.com/aspect-build/rules_lint/attestations

And some relevant GitHub docs:

- https://docs.github.com/en/actions/security-for-github-actions/security-guides/using-secrets-in-github-actions#using-secrets-in-a-workflow
- https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/accessing-contextual-information-about-workflow-runs#secrets-context
- https://docs.github.com/en/actions/sharing-automations/reusing-workflows#passing-inputs-and-secrets-to-a-reusable-workflow
- https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions#onworkflow_callsecrets
mbland added a commit to mbland/rules_scala that referenced this issue Apr 29, 2025
Updates `scala_toolchains()` to accept either boolean or dict arguments
for specific toolchains, and updates `//scala/extensions:deps.bzl` to
generate them from tag classes. Part of bazel-contrib#1482.

Notable qualities:

- Adds toolchain options support to the `scala_toolchains()` parameters
  `scalafmt`, `scala_proto`, and `twitter_scrooge`, and to the
  `scalafmt` tag class.

- Eliminates the `scalafmt_default_config`, `scala_proto_options`, and
  `twitter_scrooge_deps` option parameters from `scala_toolchains()`.

- Provides uniform, strict evaluation and validation of toolchain
  options passed to `scala_toolchains()`.

- Configures enabled toolchains using root module settings or the
  default toolchain settings only.

- Introduces the shared `TOOLCHAIN_DEFAULTS` dict in
  `//scala/private:toolchains_defaults.bzl` to aggregate individual
  `TOOLCHAIN_DEFAULTS` macro parameter dicts.

This change also:

- Replaces the non-dev dependency `scala_deps.scala()` tag instantiation
  in `MODULE.bazel` with `dev_deps.scala()`.

- Renames the `options` parameter of the `scala_deps.scala_proto` tag
  class to `default_gen_opts` to match `setup_scala_proto_toolchain()`.

- Introduces `_stringify_args()` to easily pass all toolchain macro args
  compiled from `scala_toolchains_repo()` attributes through to the
  generated `BUILD` file.

- Extracts `_DEFAULT_TOOLCHAINS_REPO_NAME` and removes the
  `scala_toolchains_repo()` macro.

- Includes docstrings for the new private implementation functions, and
  updates all other docstrings, `README.md`, and other relevant
  documentation accordingly.

---

Inspired by @simuons's suggestion to replace toolchain macros with a
module extension in:

- bazel-contrib#1722 (comment)

Though a full replacement is a ways off, this is a step in that
direction that surfaced several immediate improvements.

First, extensibility and maintainability:

- The new implementation enables adding options support for other
  toolchains in the future while maintaining backward compatibility, for
  both the `WORKSPACE` and Bzlmod APIs. Adding this support will only
  require a minor release, not a major one.

- The `scala_deps` module extension implementation is easier to read,
  since all toolchains now share the `_toolchain_settings` mechanism.

Next, improved consistency of the API and implementation:

- Toolchain options parameters should present all the same parameters as
  the macros to which they correspond, ensured by the
  `TOOLCHAIN_DEFAULTS` mechanism. This is to make it easier for users
  and maintainers to see the direct relationship between these separate
  sets of parameters. (They can also define additional parameters to
  those required by the macro, like `default_config` from the `scalafmt`
  options.)

  This principle drove the renaming of the `scala_deps.scala_proto` tag
  class parameter from `options` to `default_gen_opts`. It also inspired
  updating `scala_toolchains_repo()` to pass toolchain options through
  `_stringify_args()` to generate `BUILD` macro arguments.

- The consolidated `TOOLCHAIN_DEFAULTS` dict reduces duplication between
  the `scala/extensions/deps.bzl` and `scala/toolchains.bzl` files. It
  ensures consistency between tag class `attr` default values for Bzlmod
  users and the `scala_toolchains()` default parameter values for
  `WORKSPACE` users.

  The `TOOLCHAINS_DEFAULTS` dicts corresponding to each toolchain macro
  do duplicate the information in the macro argument lists. However, the
  duplicated values in this case are physically adjacent to one another,
  minimizing the risk of drift.

- Extracting `_DEFAULT_TOOLCHAINS_REPO_NAME` is a step towards enabling
  customized repositories based on the builtin toolchains, while
  specifying different options. This extraction revealed the fact that
  the `scala_toolchains_repo()` macro was no longer necessary, since
  only `scala_toolchains()` ever called it.

Finally, fixes for the following design bugs:

- Previously, `scala_deps.scala_proto(options = [...])` compiled the
  list of `default_gen_opts` from all tag instances in the module graph.
  This might've been convenient, but didn't generalize to other options
  for other toolchains. In particular, it differed from the previous
  `toolchains`, `scalafmt`, and `twitter_scrooge` tag class behavior.

  The new semantics are unambiguous, consistent, and apply to all
  toolchains equally; they do not show a preference for any one
  toolchain over the others. They also maintain the existing `scalafmt`
  and `twitter_scrooge` tag class semantics, but now using a generic
  mechanism, simplifying the implementation.

- Instantating `scala_deps.scala()` was a bug left over from the
  decision in bazel-contrib#1722 _not_ to enable the builtin Scala toolchain by
  default under Bzlmod.

  The previous `scala_deps.toolchains()` tag class had a default `scala
  = True` parameter. The user could set `scala = False` to disable the
  builtin Scala toolchain. After replacing `toolchains()` with
  individual tag classes, the documented behavior was that the user must
  enable the builtin Scala toolchain by instantiating
  `scala_deps.scala()`.

  By instantiating `scala_deps.scala()` in our own `MODULE.bazel` file,
  we ensured that `rules_scala` would always instantiate the builtin Scala
  toolchain. While relatively harmless, it violated the intention of
  allowing the user to avoid instantiating the toolchain altogether.
simuons pushed a commit that referenced this issue Apr 29, 2025
Separates the latest dependency versions that we test against from the
minimum required versions and bumps `protobuf` to v30.2. Part of #1482.

Adds `scala/latest_deps.bzl` for `WORKSPACE` and `deps/latest` for
Bzlmod, used by our internal test repos.

Tests used to validate these dependency versions will land in a future
change.

Also:

- Fixes a bug in the failure message of `_default_platform()` in
  `protoc_toolchains.bzl` by calling `string.join()` on the
  `HOST_CONSTRAINTS` list.

- Downloads the `win64` build for Windows ARM64.

---

This avoids forcing users to upgrade to the latest versions that
`rules_scala` tests against.

Inspired by a thread in the #bzlmod channel of the Bazel Slack workspace
on 2025-01-01 indicating that rules should require the minumum versions
possible:

- https://bazelbuild.slack.com/archives/C014RARENH0/p1743597941149639

I didn't notice the `_default_platform()` error until building on
Windows ARM64, since there's not yet a binary `protobuf` release for
that platform. The `win64` workaround fixes the actual error, since
Windows ARM64 can execute x86 and x64 binaries:

- https://learn.microsoft.com/en-us/windows/arm/apps-on-arm-x86-emulation
mbland added a commit to mbland/rules_scala that referenced this issue Apr 29, 2025
Updates `scala_toolchains()` to accept either boolean or dict arguments
for specific toolchains, and updates `//scala/extensions:deps.bzl` to
generate them from tag classes. Part of bazel-contrib#1482.

Notable qualities:

- Adds toolchain options support to the `scala_toolchains()` parameters
  `scalafmt`, `scala_proto`, and `twitter_scrooge`, and to the
  `scalafmt` tag class.

- Eliminates the `scalafmt_default_config`, `scala_proto_options`, and
  `twitter_scrooge_deps` option parameters from `scala_toolchains()`.

- Provides uniform, strict evaluation and validation of toolchain
  options passed to `scala_toolchains()`.

- Configures enabled toolchains using root module settings or the
  default toolchain settings only.

- Introduces the shared `TOOLCHAIN_DEFAULTS` dict in
  `//scala/private:toolchains_defaults.bzl` to aggregate individual
  `TOOLCHAIN_DEFAULTS` macro parameter dicts.

This change also:

- Replaces the non-dev dependency `scala_deps.scala()` tag instantiation
  in `MODULE.bazel` with `dev_deps.scala()`.

- Renames the `options` parameter of the `scala_deps.scala_proto` tag
  class to `default_gen_opts` to match `setup_scala_proto_toolchain()`.

- Introduces `_stringify_args()` to easily pass all toolchain macro args
  compiled from `scala_toolchains_repo()` attributes through to the
  generated `BUILD` file.

- Extracts `_DEFAULT_TOOLCHAINS_REPO_NAME` and removes the
  `scala_toolchains_repo()` macro.

- Includes docstrings for the new private implementation functions, and
  updates all other docstrings, `README.md`, and other relevant
  documentation accordingly.

---

Inspired by @simuons's suggestion to replace toolchain macros with a
module extension in:

- bazel-contrib#1722 (comment)

Though a full replacement is a ways off, this is a step in that
direction that surfaced several immediate improvements.

First, extensibility and maintainability:

- The new implementation enables adding options support for other
  toolchains in the future while maintaining backward compatibility, for
  both the `WORKSPACE` and Bzlmod APIs. Adding this support will only
  require a minor release, not a major one.

- The `scala_deps` module extension implementation is easier to read,
  since all toolchains now share the `_toolchain_settings` mechanism.

Next, improved consistency of the API and implementation:

- Toolchain options parameters should present all the same parameters as
  the macros to which they correspond, ensured by the
  `TOOLCHAIN_DEFAULTS` mechanism. This is to make it easier for users
  and maintainers to see the direct relationship between these separate
  sets of parameters. (They can also define additional parameters to
  those required by the macro, like `default_config` from the `scalafmt`
  options.)

  This principle drove the renaming of the `scala_deps.scala_proto` tag
  class parameter from `options` to `default_gen_opts`. It also inspired
  updating `scala_toolchains_repo()` to pass toolchain options through
  `_stringify_args()` to generate `BUILD` macro arguments.

- The consolidated `TOOLCHAIN_DEFAULTS` dict reduces duplication between
  the `scala/extensions/deps.bzl` and `scala/toolchains.bzl` files. It
  ensures consistency between tag class `attr` default values for Bzlmod
  users and the `scala_toolchains()` default parameter values for
  `WORKSPACE` users.

  The `TOOLCHAINS_DEFAULTS` dicts corresponding to each toolchain macro
  do duplicate the information in the macro argument lists. However, the
  duplicated values in this case are physically adjacent to one another,
  minimizing the risk of drift.

- Extracting `_DEFAULT_TOOLCHAINS_REPO_NAME` is a step towards enabling
  customized repositories based on the builtin toolchains, while
  specifying different options. This extraction revealed the fact that
  the `scala_toolchains_repo()` macro was no longer necessary, since
  only `scala_toolchains()` ever called it.

Finally, fixes for the following design bugs:

- Previously, `scala_deps.scala_proto(options = [...])` compiled the
  list of `default_gen_opts` from all tag instances in the module graph.
  This might've been convenient, but didn't generalize to other options
  for other toolchains. In particular, it differed from the previous
  `toolchains`, `scalafmt`, and `twitter_scrooge` tag class behavior.

  The new semantics are unambiguous, consistent, and apply to all
  toolchains equally; they do not show a preference for any one
  toolchain over the others. They also maintain the existing `scalafmt`
  and `twitter_scrooge` tag class semantics, but now using a generic
  mechanism, simplifying the implementation.

- Instantating `scala_deps.scala()` was a bug left over from the
  decision in bazel-contrib#1722 _not_ to enable the builtin Scala toolchain by
  default under Bzlmod.

  The previous `scala_deps.toolchains()` tag class had a default `scala
  = True` parameter. The user could set `scala = False` to disable the
  builtin Scala toolchain. After replacing `toolchains()` with
  individual tag classes, the documented behavior was that the user must
  enable the builtin Scala toolchain by instantiating
  `scala_deps.scala()`.

  By instantiating `scala_deps.scala()` in our own `MODULE.bazel` file,
  we ensured that `rules_scala` would always instantiate the builtin Scala
  toolchain. While relatively harmless, it violated the intention of
  allowing the user to avoid instantiating the toolchain altogether.
mbland added a commit to mbland/rules_scala that referenced this issue Apr 29, 2025
Updates `.github/workflows/release.yml` and adds `publish-to-bcr.yml`
for publishing to the Bazel Central Registry. Part of bazel-contrib#1482 broken out
from bazel-contrib#1722.

`release.yml` now uses the `release_ruleset` workflow from
`bazel-contrib/.github`, which does everything `release.yml` did
previously and adds SLSA provenance attestations. `release.yml` then
invokes the new `publish-to-bcr.yml` workflow after publishing a
successful release to GitHub. Based on aspect-build/rules_lint#498 and
aspect-build/rules_lint#501. See `.bcr/README.md`.

---

Extracting this from bazel-contrib#1722 makes that pull request more focused, and
prevents holding it up based on any discussion around these workflow
changes in particular. It's also unclear if the infrastructure will be
in place to support these workflows before we're ready to publish the
first `rules_scala` module. Though these workflows will supersede the
Publish to BCR app, it may take some time to resolve
slsa-framework/slsa-verifier#840.

aspect-build/rules_lint#508, @alexeagle manually triggered a workflow
run based on these workflows, which generated an attestation:

- https://github.com/aspect-build/rules_lint/actions/runs/14095611671
- https://github.com/aspect-build/rules_lint/attestations/5857159

Here are some examples of GitHub's attestation UI in general:

- https://github.com/aspect-build/rules_lint/attestations

And some relevant GitHub docs:

- https://docs.github.com/en/actions/security-for-github-actions/security-guides/using-secrets-in-github-actions#using-secrets-in-a-workflow
- https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/accessing-contextual-information-about-workflow-runs#secrets-context
- https://docs.github.com/en/actions/sharing-automations/reusing-workflows#passing-inputs-and-secrets-to-a-reusable-workflow
- https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions#onworkflow_callsecrets
mbland added a commit to mbland/rules_scala that referenced this issue Apr 29, 2025
Updates `.github/workflows/release.yml` and adds `publish-to-bcr.yml`
for publishing to the Bazel Central Registry. Part of bazel-contrib#1482 (originally
broken out from bazel-contrib#1722).

`release.yml` now uses the `release_ruleset` workflow from
`bazel-contrib/.github`, which does everything `release.yml` did
previously and adds SLSA provenance attestations. `release.yml` then
invokes the new `publish-to-bcr.yml` workflow after publishing a
successful release to GitHub.

Requires that the `BCR_PUBLISH_TOKEN` GitHub secret and the
`registry_fork` specified in `.github/workflows/publish-to-bcr.yml` are
in place.

See `.bcr/README.md` for all the details and references.

---

This will enable automated publishing to https://registry.bazel.build/.
mbland added a commit to mbland/rules_scala that referenced this issue Apr 29, 2025
Updates `scala_toolchains()` to accept either boolean or dict arguments
for specific toolchains, and updates `//scala/extensions:deps.bzl` to
generate them from tag classes. Part of bazel-contrib#1482.

Notable qualities:

- Adds toolchain options support to the `scala_toolchains()` parameters
  `scalafmt`, `scala_proto`, and `twitter_scrooge`, and to the
  `scalafmt` tag class.

- Eliminates the `scalafmt_default_config`, `scala_proto_options`, and
  `twitter_scrooge_deps` option parameters from `scala_toolchains()`.

- Provides uniform, strict evaluation and validation of toolchain
  options passed to `scala_toolchains()`.

- Configures enabled toolchains using root module settings or the
  default toolchain settings only.

- Introduces the shared `TOOLCHAIN_DEFAULTS` dict in
  `//scala/private:toolchains_defaults.bzl` to aggregate individual
  `TOOLCHAIN_DEFAULTS` macro parameter dicts.

This change also:

- Replaces the non-dev dependency `scala_deps.scala()` tag instantiation
  in `MODULE.bazel` with `dev_deps.scala()`.

- Renames the `options` parameter of the `scala_deps.scala_proto` tag
  class to `default_gen_opts` to match `setup_scala_proto_toolchain()`.

- Introduces `_stringify_args()` to easily pass all toolchain macro args
  compiled from `scala_toolchains_repo()` attributes through to the
  generated `BUILD` file.

- Extracts `_DEFAULT_TOOLCHAINS_REPO_NAME` and removes the
  `scala_toolchains_repo()` macro.

- Includes docstrings for the new private implementation functions, and
  updates all other docstrings, `README.md`, and other relevant
  documentation accordingly.

---

Inspired by @simuons's suggestion to replace toolchain macros with a
module extension in:

- bazel-contrib#1722 (comment)

Though a full replacement is a ways off, this is a step in that
direction that surfaced several immediate improvements.

First, extensibility and maintainability:

- The new implementation enables adding options support for other
  toolchains in the future while maintaining backward compatibility, for
  both the `WORKSPACE` and Bzlmod APIs. Adding this support will only
  require a minor release, not a major one.

- The `scala_deps` module extension implementation is easier to read,
  since all toolchains now share the `_toolchain_settings` mechanism.

Next, improved consistency of the API and implementation:

- Toolchain options parameters should present all the same parameters as
  the macros to which they correspond, ensured by the
  `TOOLCHAIN_DEFAULTS` mechanism. This is to make it easier for users
  and maintainers to see the direct relationship between these separate
  sets of parameters. (They can also define additional parameters to
  those required by the macro, like `default_config` from the `scalafmt`
  options.)

  This principle drove the renaming of the `scala_deps.scala_proto` tag
  class parameter from `options` to `default_gen_opts`. It also inspired
  updating `scala_toolchains_repo()` to pass toolchain options through
  `_stringify_args()` to generate `BUILD` macro arguments.

- The consolidated `TOOLCHAIN_DEFAULTS` dict reduces duplication between
  the `scala/extensions/deps.bzl` and `scala/toolchains.bzl` files. It
  ensures consistency between tag class `attr` default values for Bzlmod
  users and the `scala_toolchains()` default parameter values for
  `WORKSPACE` users.

  The `TOOLCHAINS_DEFAULTS` dicts corresponding to each toolchain macro
  do duplicate the information in the macro argument lists. However, the
  duplicated values in this case are physically adjacent to one another,
  minimizing the risk of drift.

- Extracting `_DEFAULT_TOOLCHAINS_REPO_NAME` is a step towards enabling
  customized repositories based on the builtin toolchains, while
  specifying different options. This extraction revealed the fact that
  the `scala_toolchains_repo()` macro was no longer necessary, since
  only `scala_toolchains()` ever called it.

Finally, fixes for the following design bugs:

- Previously, `scala_deps.scala_proto(options = [...])` compiled the
  list of `default_gen_opts` from all tag instances in the module graph.
  This might've been convenient, but didn't generalize to other options
  for other toolchains. In particular, it differed from the previous
  `toolchains`, `scalafmt`, and `twitter_scrooge` tag class behavior.

  The new semantics are unambiguous, consistent, and apply to all
  toolchains equally; they do not show a preference for any one
  toolchain over the others. They also maintain the existing `scalafmt`
  and `twitter_scrooge` tag class semantics, but now using a generic
  mechanism, simplifying the implementation.

- Instantating `scala_deps.scala()` was a bug left over from the
  decision in bazel-contrib#1722 _not_ to enable the builtin Scala toolchain by
  default under Bzlmod.

  The previous `scala_deps.toolchains()` tag class had a default `scala
  = True` parameter. The user could set `scala = False` to disable the
  builtin Scala toolchain. After replacing `toolchains()` with
  individual tag classes, the documented behavior was that the user must
  enable the builtin Scala toolchain by instantiating
  `scala_deps.scala()`.

  By instantiating `scala_deps.scala()` in our own `MODULE.bazel` file,
  we ensured that `rules_scala` would always instantiate the builtin Scala
  toolchain. While relatively harmless, it violated the intention of
  allowing the user to avoid instantiating the toolchain altogether.
mbland added a commit to mbland/rules_scala that referenced this issue Apr 29, 2025
Updates `.github/workflows/release.yml` and adds `publish-to-bcr.yml`
for publishing to the Bazel Central Registry. Part of bazel-contrib#1482 (originally
broken out from bazel-contrib#1722).

`release.yml` now uses the `release_ruleset` workflow from
`bazel-contrib/.github`, which does everything `release.yml` did
previously and adds SLSA provenance attestations. `release.yml` then
invokes the new `publish-to-bcr.yml` workflow after publishing a
successful release to GitHub.

Requires that the `BCR_PUBLISH_TOKEN` GitHub secret and the
`registry_fork` specified in `.github/workflows/publish-to-bcr.yml` are
in place.

See `.bcr/README.md` for all the details and references.

---

This will enable automated publishing to https://registry.bazel.build/.
@mbland
Copy link
Contributor

mbland commented Apr 29, 2025

Weekly update!

Overview

#1722 is in, and MODULE.bazel exists on master. Praise Kier!

No, actually: Praise @simuons and @liucijus! 🙂 Not just for landing #1722, but for following up so quickly on all the refinements I've sent after that.

Now we're down to just three pull requests, all orthogonal to one another, and no pending branches! As noted below:

Once those two land (plus maybe #1729), we're ready to release and publish this thing and close out here.

Merged

Open

Pending branches

None! That's it! No more!

Preview branches

As always, if you want to try everything out before the next release, please only use either my bzlmod or bzlmod-bazel-8 branches. Both contain all the changes from the open pull requests.

Updated scala_toolchains() and scala_deps module extension APIs

I've added what I call "toolchains options support" in #1730. This means that scala_toolchains() accepts either boolean or dict arguments for specific toolchains, and the scala_deps module extension generates them from tag classes. This yields similar changes in both the WORKSPACE and Bzlmod APIs, specifically:

  • Add toolchain options API to WORKSPACE and Bzlmod #1730 adds toolchain options support to the scala_toolchains() parameters scalafmt, scala_proto, and twitter_scrooge, and to the scalafmt tag class.

  • Add toolchain options API to WORKSPACE and Bzlmod #1730 eliminates the scalafmt_default_config, scala_proto_options, and twitter_scrooge_deps option parameters from scala_toolchains().

  • The scala_proto and twitter_scrooge tag class APIs haven't changed, but now they and the scalafmt tag class share a common implementation.

  • All these toolchains options dicts are aligned with the underlying toolchain macro arguments, making the relationship between them clear.

  • Thanks to the shared implementation, it will be easy to add options support to additional toolchains over time. These updates will require only a minor release, not a major one.

For example, under WORKSPACE, enabling scalafmt and setting a custom config changed like this:

# Before
scala_toolchains(
    # Other toolchains settings...
    scalafmt = True,
    scalafmt_default_config = "//path/to/my/custom:scalafmt.conf",
)

# After
scala_toolchains(
    # Other toolchains settings...
    scalafmt = {"default_config": "//path/to/my/custom:scalafmt.conf"},
)

scalafmt = True will still work if you want to use the default options, but it's implied if you supply your own options object.

Under Bzlmod, the scala_proto tag class changed thus to align the interface with setup_scala_proto_toolchains from //scala_proto:toolchains.bzl:

# Before
scala_deps.scala_proto(
    options = ["grpc"],
)

# After
scala_deps.scala_proto(
    default_gen_opts = ["grpc"],
)

scala_deps.scala_proto() will work in this case, since under the hood, {"default_gen_opts": ["grpc"]} is the default.

Please see the description of #1730 for further details on all the good things.

This came about after @simuons asked in #1722 (comment) to replace the boolean flags in scala_deps.toolchains() with individual tag classes. The thought being, each toolchain can potentially define its own set of attributes via its own tag class. (I mentioned all this in last week's update.)

In the same comment, he also asked whether we could replace toolchain macros (invoked by users in BUILD files) entirely with a module extension. Though I noted this won't be trivial to do, and shouldn't hold up the release, I later experimented with the toolchain macro replacement idea. I'm not yet near achieving that goal, but my experimentation yielded the immediate improvements described above and in #1730.

alexeagle pushed a commit that referenced this issue May 1, 2025
* Use the Publish to BCR reusable GitHub workflow

Updates `.github/workflows/release.yml` and adds `publish-to-bcr.yml`
for publishing to the Bazel Central Registry. Part of #1482 (originally
broken out from #1722).

`release.yml` now uses the `release_ruleset` workflow from
`bazel-contrib/.github`, which does everything `release.yml` did
previously and adds SLSA provenance attestations. `release.yml` then
invokes the new `publish-to-bcr.yml` workflow after publishing a
successful release to GitHub.

Requires that the `BCR_PUBLISH_TOKEN` GitHub secret and the
`registry_fork` specified in `.github/workflows/publish-to-bcr.yml` are
in place.

See `.bcr/README.md` for all the details and references.

---

This will enable automated publishing to https://registry.bazel.build/.

* Bump to bazel-contrib/publish-to-bcr v0.1.0

Suggested by @kormide in #1731.

* Bump bazel-contrib/.github release_ruleset v7.2.2

Recommended by @kormide based on my question in #1731.

* Set bazel-contrib registry_fork in publish-to-bcr

@meteorcloudy confirmed the transfer of the repo to the bazel-contrib
org in #1616. Transfering ownership before publishing the release will
streamline publishing to the Bazel Central Registry by avoiding the need
for a personal bazel-central-registry fork.
mbland added a commit to mbland/rules_scala that referenced this issue May 6, 2025
Updates `scala_toolchains()` to accept either boolean or dict arguments
for specific toolchains, and updates `//scala/extensions:deps.bzl` to
generate them from tag classes. Part of bazel-contrib#1482.

Notable qualities:

- Adds toolchain options support to the `scala_toolchains()` parameters
  `scalafmt`, `scala_proto`, and `twitter_scrooge`, and to the
  `scalafmt` tag class.

- Eliminates the `scalafmt_default_config`, `scala_proto_options`, and
  `twitter_scrooge_deps` option parameters from `scala_toolchains()`.

- Provides uniform, strict evaluation and validation of toolchain
  options passed to `scala_toolchains()`.

- Configures enabled toolchains using root module settings or the
  default toolchain settings only.

- Introduces the shared `TOOLCHAIN_DEFAULTS` dict in
  `//scala/private:toolchains_defaults.bzl` to aggregate individual
  `TOOLCHAIN_DEFAULTS` macro parameter dicts.

This change also:

- Replaces the non-dev dependency `scala_deps.scala()` tag instantiation
  in `MODULE.bazel` with `dev_deps.scala()`.

- Renames the `options` parameter of the `scala_deps.scala_proto` tag
  class to `default_gen_opts` to match `setup_scala_proto_toolchain()`.

- Introduces `_stringify_args()` to easily pass all toolchain macro args
  compiled from `scala_toolchains_repo()` attributes through to the
  generated `BUILD` file.

- Extracts `_DEFAULT_TOOLCHAINS_REPO_NAME` and removes the
  `scala_toolchains_repo()` macro.

- Includes docstrings for the new private implementation functions, and
  updates all other docstrings, `README.md`, and other relevant
  documentation accordingly.

---

Inspired by @simuons's suggestion to replace toolchain macros with a
module extension in:

- bazel-contrib#1722 (comment)

Though a full replacement is a ways off, this is a step in that
direction that surfaced several immediate improvements.

First, extensibility and maintainability:

- The new implementation enables adding options support for other
  toolchains in the future while maintaining backward compatibility, for
  both the `WORKSPACE` and Bzlmod APIs. Adding this support will only
  require a minor release, not a major one.

- The `scala_deps` module extension implementation is easier to read,
  since all toolchains now share the `_toolchain_settings` mechanism.

Next, improved consistency of the API and implementation:

- Toolchain options parameters should present all the same parameters as
  the macros to which they correspond, ensured by the
  `TOOLCHAIN_DEFAULTS` mechanism. This is to make it easier for users
  and maintainers to see the direct relationship between these separate
  sets of parameters. (They can also define additional parameters to
  those required by the macro, like `default_config` from the `scalafmt`
  options.)

  This principle drove the renaming of the `scala_deps.scala_proto` tag
  class parameter from `options` to `default_gen_opts`. It also inspired
  updating `scala_toolchains_repo()` to pass toolchain options through
  `_stringify_args()` to generate `BUILD` macro arguments.

- The consolidated `TOOLCHAIN_DEFAULTS` dict reduces duplication between
  the `scala/extensions/deps.bzl` and `scala/toolchains.bzl` files. It
  ensures consistency between tag class `attr` default values for Bzlmod
  users and the `scala_toolchains()` default parameter values for
  `WORKSPACE` users.

  The `TOOLCHAINS_DEFAULTS` dicts corresponding to each toolchain macro
  do duplicate the information in the macro argument lists. However, the
  duplicated values in this case are physically adjacent to one another,
  minimizing the risk of drift.

- Extracting `_DEFAULT_TOOLCHAINS_REPO_NAME` is a step towards enabling
  customized repositories based on the builtin toolchains, while
  specifying different options. This extraction revealed the fact that
  the `scala_toolchains_repo()` macro was no longer necessary, since
  only `scala_toolchains()` ever called it.

Finally, fixes for the following design bugs:

- Previously, `scala_deps.scala_proto(options = [...])` compiled the
  list of `default_gen_opts` from all tag instances in the module graph.
  This might've been convenient, but didn't generalize to other options
  for other toolchains. In particular, it differed from the previous
  `toolchains`, `scalafmt`, and `twitter_scrooge` tag class behavior.

  The new semantics are unambiguous, consistent, and apply to all
  toolchains equally; they do not show a preference for any one
  toolchain over the others. They also maintain the existing `scalafmt`
  and `twitter_scrooge` tag class semantics, but now using a generic
  mechanism, simplifying the implementation.

- Instantating `scala_deps.scala()` was a bug left over from the
  decision in bazel-contrib#1722 _not_ to enable the builtin Scala toolchain by
  default under Bzlmod.

  The previous `scala_deps.toolchains()` tag class had a default `scala
  = True` parameter. The user could set `scala = False` to disable the
  builtin Scala toolchain. After replacing `toolchains()` with
  individual tag classes, the documented behavior was that the user must
  enable the builtin Scala toolchain by instantiating
  `scala_deps.scala()`.

  By instantiating `scala_deps.scala()` in our own `MODULE.bazel` file,
  we ensured that `rules_scala` would always instantiate the builtin Scala
  toolchain. While relatively harmless, it violated the intention of
  allowing the user to avoid instantiating the toolchain altogether.
@mbland
Copy link
Contributor

mbland commented May 6, 2025

Weekly update!

Overview

We're down to one last pull request (for real, this time!): #1730.

With this last API change (described in last week's update), pushing the v7.0.0 tag should publish the rules_scala module to the Bazel Central Registry. This is because #1731 put the necessary Publish to BCR configuration into place. Future dependency version bumps and backward compatible API changes can happen in minor version updates easily after that.

Ideally, #1729 would make it in before publishing v7.0.0 as well, but it's not strictly required. It adds tests to enforce the minimum dependency version guarantees from #1726, but it's not technically blocking v7.0.0. (Same with #1732, a routine dependency version bump.)

Merged

Open

Preview branches

As always, if you want to try everything out before the next release, please only use either my bzlmod or bzlmod-bazel-8 branches. Both contain all the changes from the open pull requests.

Move to the bazel-contrib GitHub org

Thanks to @meteorcloudy, the repo has moved from bazelbuild/rules_scala to bazel-contrib/rules_scala per #1616. The lack of Bzlmod support was the last blocker. Now that #1722 is in, and publishing the first rules_scala module is imminent, moving to bazel-contrib now streamlines the publishing process.

Toolchains blog post

I'm now working in earnest on the next installment in my Bzlmod blog post series, based on this rules_scala experience. I don't know for sure yet when it'll be ready, but I'm having fun retracing all the steps. If I can manage to explain them to myself, hopefully the result will be useful to others, too.

Module extension toolchains experiment

To largely repeat #1730 (comment): I've continued to experiment with generating toolchains from the scala_deps module extension in the bzlmod-toolchains-experiment branch of mbland/rules_scala. I've managed to generate a separate toolchain in @rules_scala_toolchains//scala after updating the scala_deps.scala() tag class.

This confirms that, after #1730 lands, and after the new release, we can expand the tag classes to pass through more parameters. It also confirms that we can generate new toolchains in @rules_scala_toolchains using a module extension.

Such updates can remain backward compatible, requiring only minor version releases. It may even be possible to support an arbitrary number of toolchains and/or separate toolchain repos in a minor version update. I've yet to get around to experimenting with that yet, however.

The goal is to follow through on @simuons's idea of configuring all toolchains via module extensions from #1722 (comment). It's not worth blocking v7.0.0, as existing setup_scala_toolchain macro calls from BUILD files will continue to work. But it might be more idiomatic, following toolchain configuration patterns like those in rules_go and rules_python. (I studied those two rule sets to develop scala_toolchains() and the scala_deps extension in the first place.)

If/when I reach a point where replacing BUILD macros with module extensions is a possibility, I don't think it'll require a major version release. We can publish the new mechanism in a minor release and see how well it works in practice. Then, if we want to make the toolchain setup macros private, that can happen in v8.0.0 or some other future major version release.

simuons pushed a commit that referenced this issue May 7, 2025
* Add toolchain options API to WORKSPACE and Bzlmod

Updates `scala_toolchains()` to accept either boolean or dict arguments
for specific toolchains, and updates `//scala/extensions:deps.bzl` to
generate them from tag classes. Part of #1482.

Notable qualities:

- Adds toolchain options support to the `scala_toolchains()` parameters
  `scalafmt`, `scala_proto`, and `twitter_scrooge`, and to the
  `scalafmt` tag class.

- Eliminates the `scalafmt_default_config`, `scala_proto_options`, and
  `twitter_scrooge_deps` option parameters from `scala_toolchains()`.

- Provides uniform, strict evaluation and validation of toolchain
  options passed to `scala_toolchains()`.

- Configures enabled toolchains using root module settings or the
  default toolchain settings only.

- Introduces the shared `TOOLCHAIN_DEFAULTS` dict in
  `//scala/private:toolchains_defaults.bzl` to aggregate individual
  `TOOLCHAIN_DEFAULTS` macro parameter dicts.

This change also:

- Replaces the non-dev dependency `scala_deps.scala()` tag instantiation
  in `MODULE.bazel` with `dev_deps.scala()`.

- Renames the `options` parameter of the `scala_deps.scala_proto` tag
  class to `default_gen_opts` to match `setup_scala_proto_toolchain()`.

- Introduces `_stringify_args()` to easily pass all toolchain macro args
  compiled from `scala_toolchains_repo()` attributes through to the
  generated `BUILD` file.

- Extracts `_DEFAULT_TOOLCHAINS_REPO_NAME` and removes the
  `scala_toolchains_repo()` macro.

- Includes docstrings for the new private implementation functions, and
  updates all other docstrings, `README.md`, and other relevant
  documentation accordingly.

---

Inspired by @simuons's suggestion to replace toolchain macros with a
module extension in:

- #1722 (comment)

Though a full replacement is a ways off, this is a step in that
direction that surfaced several immediate improvements.

First, extensibility and maintainability:

- The new implementation enables adding options support for other
  toolchains in the future while maintaining backward compatibility, for
  both the `WORKSPACE` and Bzlmod APIs. Adding this support will only
  require a minor release, not a major one.

- The `scala_deps` module extension implementation is easier to read,
  since all toolchains now share the `_toolchain_settings` mechanism.

Next, improved consistency of the API and implementation:

- Toolchain options parameters should present all the same parameters as
  the macros to which they correspond, ensured by the
  `TOOLCHAIN_DEFAULTS` mechanism. This is to make it easier for users
  and maintainers to see the direct relationship between these separate
  sets of parameters. (They can also define additional parameters to
  those required by the macro, like `default_config` from the `scalafmt`
  options.)

  This principle drove the renaming of the `scala_deps.scala_proto` tag
  class parameter from `options` to `default_gen_opts`. It also inspired
  updating `scala_toolchains_repo()` to pass toolchain options through
  `_stringify_args()` to generate `BUILD` macro arguments.

- The consolidated `TOOLCHAIN_DEFAULTS` dict reduces duplication between
  the `scala/extensions/deps.bzl` and `scala/toolchains.bzl` files. It
  ensures consistency between tag class `attr` default values for Bzlmod
  users and the `scala_toolchains()` default parameter values for
  `WORKSPACE` users.

  The `TOOLCHAINS_DEFAULTS` dicts corresponding to each toolchain macro
  do duplicate the information in the macro argument lists. However, the
  duplicated values in this case are physically adjacent to one another,
  minimizing the risk of drift.

- Extracting `_DEFAULT_TOOLCHAINS_REPO_NAME` is a step towards enabling
  customized repositories based on the builtin toolchains, while
  specifying different options. This extraction revealed the fact that
  the `scala_toolchains_repo()` macro was no longer necessary, since
  only `scala_toolchains()` ever called it.

Finally, fixes for the following design bugs:

- Previously, `scala_deps.scala_proto(options = [...])` compiled the
  list of `default_gen_opts` from all tag instances in the module graph.
  This might've been convenient, but didn't generalize to other options
  for other toolchains. In particular, it differed from the previous
  `toolchains`, `scalafmt`, and `twitter_scrooge` tag class behavior.

  The new semantics are unambiguous, consistent, and apply to all
  toolchains equally; they do not show a preference for any one
  toolchain over the others. They also maintain the existing `scalafmt`
  and `twitter_scrooge` tag class semantics, but now using a generic
  mechanism, simplifying the implementation.

- Instantating `scala_deps.scala()` was a bug left over from the
  decision in #1722 _not_ to enable the builtin Scala toolchain by
  default under Bzlmod.

  The previous `scala_deps.toolchains()` tag class had a default `scala
  = True` parameter. The user could set `scala = False` to disable the
  builtin Scala toolchain. After replacing `toolchains()` with
  individual tag classes, the documented behavior was that the user must
  enable the builtin Scala toolchain by instantiating
  `scala_deps.scala()`.

  By instantiating `scala_deps.scala()` in our own `MODULE.bazel` file,
  we ensured that `rules_scala` would always instantiate the builtin Scala
  toolchain. While relatively harmless, it violated the intention of
  allowing the user to avoid instantiating the toolchain altogether.

* Update documentation for toolchain option dicts

Touched up documentation for the `scalafmt` and `scala_proto`
toolchains.

* Replace Scalafmt default_config alias with symlink

This avoids the need for the user to use `exports_files` so
`@rules_scala_toolchains//scalafmt:config` can access the config file.
Essentially restores the API from before #1725, but still fixes the same
bug as #1725.

* Update phase_scalafmt.md, check scalafmt conf path

Updates the Scalafmt documentation to reflect the current API. Adds a
check to `scala_toolchains_repo` to `fail` if the Scalafmt
`default_config` file doesn't exist.

The previous commit doesn't actually restore the exact pre-#1725 API.
It eliminates the `exports_files` requirement, but still requires a
`Label` or a relative path string, not an optional `.scalafmt.conf` in
the root directory.

After experimenting a bit and thinking this through, dropping support
for an optional `.scalafmt.conf` provides the most robust and reliable
interface. Specifically, supporting it requires detecting whether it
actually exists before falling back to the default. Having users
explicitly specify their own config seems a small burden to impose for
a more straightforward and correct implementation.

At the same time, I saw the opportunity to provide the user with
explicit feedback if the specified config file doesn't exist. Hence the
new check and `fail()` message.

Also renamed the generated `.scalafmt.conf` file in
`@rules_scala_toolchains//scalafmt` to `scalafmt.conf`. No need for it
to be a hidden file in that context.

* Update the `scala_deps` module extension docstring

The `scala_deps` docstring now more accurately describes the behavior
implemented by `_toolchain_settings()`.

* Fix `scala_proto` param in test_version/WORKSPACE

Caught this after doing an `--enable_workspace --noenable_bzlmod` build.
@mbland
Copy link
Contributor

mbland commented May 7, 2025

Daily update! 😛

@simuons merged #1729, #1730, and #1732 today, as well as @WojciechMazur's #1733.

So @simuons and @liucijus, I suppose it's up to you to publish v7.0.0 when you like. The only thing is you may consider creating your own Personal Access Token to publish to the BCR, per the dicsussion in #1731.

Then once https://registry.bazel.build/modules/rules_scala goes from HTTP 404 to HTTP 200, we're done here! 😄


In other news, I did just open #1734 with a very small documentation update (on a tip from @gergelyfabian); nothing that should block the release.

I'll continue to experiment with my bzlmod-toolchains-experiment branch for post-v7.0.0 releases.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment