diff --git a/.bazelignore b/.bazelignore
new file mode 100644
index 000000000..76a97d775
--- /dev/null
+++ b/.bazelignore
@@ -0,0 +1,6 @@
+# Remove once the following is fixed:
+# - bazelbuild/bazel: Loading top-level targets in local_path_override modules
+# in child directory breaks the build #22208
+# https://github.com/bazelbuild/bazel/issues/22208
+third_party/test/example_external_workspace
+third_party/test/proto
diff --git a/.bazelrc b/.bazelrc
index 498871943..b366ea644 100644
--- a/.bazelrc
+++ b/.bazelrc
@@ -1,9 +1,8 @@
+# Remove once Bazel 7.5.0 becomes the default supported version.
+common --enable_bzlmod
+
build --enable_platform_specific_config
#Windows needs --worker_quit_after_build due to workers not being shut down when the compiler tools need to be rebuilt (resulting in 'file in use' errors). See Bazel Issue#10498.
build:windows --worker_quit_after_build --enable_runfiles
-
-# Remove upon completing Bzlmod compatibility work.
-# - https://github.com/bazelbuild/rules_scala/issues/1482
-build --noenable_bzlmod
diff --git a/.bcr/config.yml b/.bcr/config.yml
new file mode 100644
index 000000000..e69de29bb
diff --git a/.bcr/metadata.template.json b/.bcr/metadata.template.json
new file mode 100644
index 000000000..717a2d23f
--- /dev/null
+++ b/.bcr/metadata.template.json
@@ -0,0 +1,20 @@
+{
+ "homepage": "https://github.com/bazelbuild/rules_scala",
+ "maintainers": [
+ {
+ "name": "Simonas Pinevičius",
+ "email": "simonas.pinevicius@gmail.com",
+ "github": "simuons"
+ },
+ {
+ "name": "Vaidas Pilkauskas",
+ "email": "vaidas.pilkauskas@gmail.com",
+ "github": "liucijus"
+ }
+ ],
+ "repository": [
+ "github:bazelbuild/rules_scala"
+ ],
+ "versions": [],
+ "yanked_versions": {}
+}
diff --git a/.bcr/presubmit.yml b/.bcr/presubmit.yml
new file mode 100644
index 000000000..0ef780fc0
--- /dev/null
+++ b/.bcr/presubmit.yml
@@ -0,0 +1,14 @@
+# We recommend included a bcr test workspace that exercises your ruleset with bzlmod.
+# For an example, see https://github.com/aspect-build/bazel-lib/tree/main/e2e/bzlmod.
+bcr_test_module:
+ module_path: "examples/crossbuild"
+ matrix:
+ platform: ["debian10", "macos", "ubuntu2004", "windows"]
+ bazel: [6.x, 7.x]
+ tasks:
+ run_tests:
+ name: "Run test module"
+ platform: ${{ platform }}
+ bazel: ${{ bazel }}
+ test_targets:
+ - "//..."
diff --git a/.bcr/source.template.json b/.bcr/source.template.json
new file mode 100644
index 000000000..20374716f
--- /dev/null
+++ b/.bcr/source.template.json
@@ -0,0 +1,5 @@
+{
+ "integrity": "",
+ "strip_prefix": "{REPO}-{VERSION}",
+ "url": "https://github.com/{OWNER}/{REPO}/releases/download/{TAG}/{REPO}-{TAG}.tar.gz"
+}
diff --git a/.gitignore b/.gitignore
index fdf79752d..ce630e21d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -16,3 +16,9 @@ test/semanticdb/tempsrc
# From scripts/create_repository.py
repository-artifacts.json
+
+# Until it settles down
+**/MODULE.bazel.lock
+
+# Used by some tests, but can also be used for local experimentation.
+tmp/
diff --git a/MODULE.bazel b/MODULE.bazel
new file mode 100644
index 000000000..129244659
--- /dev/null
+++ b/MODULE.bazel
@@ -0,0 +1,290 @@
+"""Bazel module definition for rules_scala"""
+
+module(
+ name = "rules_scala",
+ version = "7.0.0",
+ compatibility_level = 7,
+ bazel_compatibility = [">=6.5.0", "<8.0.0"],
+)
+
+SCALA_VERSION = "2.12.20"
+
+# These versions match those required by some tests, including
+# test_thirdparty_version.sh.
+SCALA_2_VERSIONS = [
+ "2.11.12",
+ "2.12.20",
+ "2.13.15",
+]
+
+SCALA_3_VERSIONS = [
+ "3.1.3",
+ "3.3.5",
+ "3.5.2",
+ "3.6.3",
+]
+
+SCALA_VERSIONS = SCALA_2_VERSIONS + SCALA_3_VERSIONS
+
+bazel_dep(name = "bazel_skylib", version = "1.7.1")
+
+# Bazel 6 breaks with any higher version of `rules_cc`, because:
+# - 0.0.10 requires Bazel 7 to define `CcSharedLibraryHintInfo`
+# - 0.0.13 and up don't support `protobuf` v21.7, requiring at least v27.0
+# - 0.1.0 should work, but requires `stardoc` 0.7.0, which requires Bazel 7
+# (though it's a `dev_dependency`, it still gets pulled in during module
+# resolution, breaking the build)
+bazel_dep(name = "rules_cc", version = "0.0.9")
+single_version_override(
+ module_name = "rules_cc",
+ version = "0.0.9",
+)
+
+bazel_dep(name = "rules_java", version = "7.12.4")
+bazel_dep(name = "rules_proto", version = "6.0.2")
+
+# For now, users are revlocked to protobuf-21.7 or protobuf-25.5 (which doesn't
+# build under Bazel 6).
+bazel_dep(
+ name = "protobuf",
+ version = "21.7",
+ repo_name = "com_google_protobuf",
+)
+single_version_override(
+ module_name = "protobuf",
+ version = "21.7",
+)
+
+scala_config = use_extension(
+ "//scala/extensions:config.bzl",
+ "scala_config",
+)
+use_repo(scala_config, "io_bazel_rules_scala_config")
+
+dev_config = use_extension(
+ "//scala/extensions:config.bzl",
+ "scala_config",
+ dev_dependency = True,
+)
+dev_config.settings(
+ enable_compiler_dependency_tracking = True,
+ scala_version = SCALA_VERSION,
+ scala_versions = SCALA_VERSIONS,
+)
+
+scala_deps = use_extension("//scala/extensions:deps.bzl", "scala_deps")
+
+# Register some of our testing toolchains first when building our repo.
+register_toolchains(
+ "//scala:unused_dependency_checker_error_toolchain",
+ "//test/proto:scalapb_toolchain",
+ "//test/toolchains:java21_toolchain_definition",
+ dev_dependency = True,
+)
+
+use_repo(
+ scala_deps,
+ "rules_scala_toolchains",
+ "scala_compiler_sources",
+)
+
+register_toolchains("@rules_scala_toolchains//...:all")
+
+# Dev dependencies
+
+dev_deps = use_extension(
+ "//scala/extensions:deps.bzl",
+ "scala_deps",
+ dev_dependency = True,
+)
+dev_deps.toolchains(
+ jmh = True,
+ scala_proto = True,
+ #scala_proto_enable_all_options = True,
+ scalafmt = True,
+ testing = True,
+ #scalatest = True,
+ #junit = True,
+ #specs2 = True,
+ twitter_scrooge = True,
+)
+
+use_repo(
+ dev_deps,
+ "scala_proto_rules_scalapb_compilerplugin",
+ "scala_proto_rules_scalapb_protoc_bridge",
+ "scalafmt_default",
+)
+
+# Default versions of version specific repos needed by some of our tests. Tests
+# that set `--repo_env=SCALA_VERSION=...` break without using the default here,
+# because version specific repos for other versions won't be available.
+use_repo(
+ dev_deps,
+ "io_bazel_rules_scala_guava",
+ "io_bazel_rules_scala_junit_junit",
+ "io_bazel_rules_scala_scala_compiler",
+ "io_bazel_rules_scala_scala_library",
+)
+
+[
+ [
+ use_repo(dev_deps, dep + "_" + scala_version.replace(".", "_"))
+ for dep in [
+ "io_bazel_rules_scala_junit_junit",
+ "io_bazel_rules_scala_scala_compiler",
+ "io_bazel_rules_scala_scala_library",
+ ] + (
+ # We can remove this condition once we drop support for Scala 2.11.
+ ["scala_proto_rules_scalapb_protoc_gen"]
+ if not scala_version.startswith("2.11.") else []
+ )
+ ]
+ for scala_version in SCALA_VERSIONS
+]
+
+[
+ [
+ use_repo(dev_deps, dep + "_" + scala_version.replace(".", "_"))
+ for dep in [
+ "io_bazel_rules_scala_scala_reflect",
+ ]
+ ]
+ for scala_version in SCALA_2_VERSIONS
+]
+
+[
+ [
+ use_repo(dev_deps, dep + "_" + scala_version.replace(".", "_"))
+ for dep in [
+ "io_bazel_rules_scala_scala_compiler_2",
+ "io_bazel_rules_scala_scala_library_2",
+ "io_bazel_rules_scala_scala_reflect_2",
+ ]
+ ]
+ for scala_version in SCALA_3_VERSIONS
+]
+
+internal_dev_deps = use_extension(
+ "//scala/private/extensions:dev_deps.bzl",
+ "dev_deps",
+ dev_dependency = True,
+)
+
+# See //scala/private:extensions/dev_deps.bzl for notes on some of these repos.
+use_repo(
+ internal_dev_deps,
+ "com_github_bazelbuild_buildtools",
+ "com_github_jnr_jffi_native",
+ "com_google_guava_guava_21_0",
+ "com_google_guava_guava_21_0_with_file",
+ "com_twitter__scalding_date",
+ "org_apache_commons_commons_lang_3_5",
+ "org_apache_commons_commons_lang_3_5_without_file",
+ "org_springframework_spring_core",
+ "org_springframework_spring_tx",
+ "org_typelevel__cats_core",
+ "org_typelevel_kind_projector",
+)
+
+java_toolchains = use_extension(
+ "@rules_java//java:extensions.bzl",
+ "toolchains",
+ dev_dependency = True,
+)
+
+use_repo(
+ java_toolchains,
+ # //test/toolchains:java21_toolchain
+ "remotejdk21_linux",
+ "remotejdk21_macos",
+ "remotejdk21_win",
+ # //test/jmh:test_jmh_jdk8
+ "remote_jdk8_linux",
+ "remote_jdk8_macos",
+ "remote_jdk8_windows",
+)
+
+[
+ (
+ bazel_dep(name = name, dev_dependency = True),
+ local_path_override(module_name = name, path = path)
+ )
+ for name, path in [
+ (
+ "proto_cross_repo_boundary",
+ "test/proto_cross_repo_boundary/repo",
+ ),
+ (
+ "test_new_local_repo",
+ "third_party/test/new_local_repo",
+ ),
+ (
+ "example_external_workspace",
+ "third_party/test/example_external_workspace",
+ ),
+ ]
+]
+
+bazel_dep(
+ name = "platforms",
+ version = "0.0.11",
+ dev_dependency = True,
+)
+bazel_dep(
+ name = "bazel_ci_rules",
+ version = "1.0.0",
+ dev_dependency = True,
+ repo_name = "bazelci_rules",
+)
+bazel_dep(
+ name = "rules_go",
+ version = "0.53.0",
+ dev_dependency = True,
+ repo_name = "io_bazel_rules_go", # for com_github_bazelbuild_buildtools
+)
+bazel_dep(name = "gazelle", version = "0.42.0", dev_dependency = True)
+
+go_sdk = use_extension(
+ "@io_bazel_rules_go//go:extensions.bzl",
+ "go_sdk",
+ dev_dependency = True,
+)
+go_sdk.download(version = "1.24.0")
+
+go_deps = use_extension(
+ "@gazelle//:extensions.bzl",
+ "go_deps",
+ dev_dependency = True,
+)
+
+# The go_deps.module calls are inspired by the following to get the
+# com_github_bazelbuild_buildtools repo to work:
+#
+# - https://github.com/bazelbuild/bazel-central-registry/blob/main/modules/gazelle/0.39.1/MODULE.bazel#L31-L57
+#
+# To get the latest version and hashes for each per:
+#
+# - https://go.dev/ref/mod#go-list-m
+# - https://go.dev/ref/mod#checksum-database
+#
+# go list -m golang.org/x/tools@latest
+# curl https://sum.golang.org/lookup/golang.org/x/tools@v0.29.0
+go_deps.module(
+ path = "golang.org/x/tools",
+ sum = "h1:BgcpHewrV5AUp2G9MebG4XPFI1E2W41zU1SaqVA9vJY=",
+ version = "v0.30.0",
+)
+
+go_deps.module(
+ path = "github.com/golang/protobuf",
+ sum = "h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=",
+ version = "v1.5.4",
+)
+use_repo(
+ go_deps,
+ "com_github_golang_protobuf",
+ "org_golang_x_tools",
+)
+
+bazel_dep(name = "rules_python", version = "0.38.0", dev_dependency = True)
diff --git a/README.md b/README.md
index b1aed2e88..cfff267a8 100644
--- a/README.md
+++ b/README.md
@@ -39,16 +39,122 @@ Bazel version.
[Install Bazel]: https://docs.bazel.build/versions/master/install.html
[Bazelisk]: https://docs.bazel.build/versions/master/install.html
-Add the following configuration snippet to your `WORKSPACE` file and update
-versions with their sha256s if needed. This snippet is designed to ensure that
-users pick up the correct order of dependencies for `rules_scala`. If you want
-to override any of the following dependency versions, make sure to `load()` them
-before calling `rules_scala_dependencies()`.
-
As of version 7.0.0, __`rules_scala` no longer requires the
`io_bazel_rules_scala` repository name__ unless your `BUILD` files or those of
your dependencies require it (bazelbuild/rules_scala#1696).
+```py
+# MODULE.bazel
+
+# You can add `repo_name = "io_bazel_rules_scala"` if you still need it.
+bazel_dep(name = "rules_scala", version = "7.0.0")
+
+# Selects the Scala version and other configuration parameters.
+#
+# 2.12 is the default version. Use other versions by passing them explicitly, as
+# illustrated below.
+#
+# See the documentation of `_settings_attrs` in `scala/extensions/config.bzl`
+# for other available parameters.
+#
+# You may define your own custom toolchain using Maven artifact dependencies
+# configured by your `WORKSPACE` file, imported using external loader like
+# https://github.com/bazelbuild/rules_jvm_external.
+scala_config = use_extension(
+ "@rules_scala//scala/extensions:config.bzl",
+ "scala_config",
+)
+
+scala_config.settings(scala_version = "2.13.15")
+
+# See the `scala/extensions/deps.bzl` docstring for a high level description of
+# the tag classes exported by this module extension.
+scala_deps = use_extension(
+ "@rules_scala//scala/extensions:deps.bzl",
+ "scala_deps",
+)
+
+# Defines a default toolchain repo for the configured Scala version that
+# loads Maven deps like the Scala compiler and standard libs. On production
+# projects, you may consider defining a custom toolchain to use your project's
+# required dependencies instead.
+#
+# Optional builtin rules_scala toolchains may be configured by setting the
+# appropriate parameter to `True`. See the documentation of `_toolchains_attrs`
+# from `scala/extensions/deps.bzl` for details.
+scala_deps.toolchains(
+ scalatest = True,
+)
+```
+
+### Resolving `protobuf` conflicts
+
+For rules_scala 7.x, `scala_proto` and `scalafmt` users are revlocked between
+protobuf-v21.7 and protobuf-v25.5 ([which requires compiler flags to build under
+Bazel 6](#6.5.0)). rules_scala 8.0.0 will drop Bazel 6.5.0 Bzlmod support and
+support protobuf-v28.2 and later. See [Compatible Bazel
+versions](#compatible-bazel-versions) below for details regarding these
+`protobuf` related restrictions.
+
+If a newer `protobuf` version in the module graph breaks your build, use
+[`single_version_override`][] or [`multiple_version_override`][] to fix it:
+
+[`single_version_override`]: https://bazel.build/external/module#single-version_override
+[`multiple_version_override`]: https://bazel.build/external/module#multiple-version_override
+
+```py
+bazel_dep(
+ name = "protobuf",
+ version = "25.5",
+ repo_name = "com_google_protobuf",
+)
+single_version_override(
+ module_name = "protobuf",
+ version = "25.5",
+)
+```
+
+### Legacy Bazel 6.5.0 support
+
+One primary objective of `rules_scala` 7.x is to enable existing users to
+migrate to Bazel 7. [__`rules_scala` 8.0.0 will drop support for Bazel 6.5.0
+Bzlmod builds__](#6.5.0).
+
+If you're still on Bazel 6.5.0 for now, you will need to add the following
+stanza to your `MODULE.bazel` file:
+
+```py
+# Bazel 6 breaks with any higher version of `rules_cc`, because:
+#
+# - 0.0.10 requires Bazel 7 to define `CcSharedLibraryHintInfo`
+#
+# - 0.0.13 and up don't support `protobuf` v21.7, requiring at least v27.0
+#
+# - 0.1.0 should work, but requires `stardoc` 0.7.0, which requires Bazel 7
+# (though it's a `dev_dependency`, it still gets pulled in during module
+# resolution, breaking the build)
+bazel_dep(name = "rules_cc", version = "0.0.9")
+single_version_override(
+ module_name = "rules_cc",
+ version = "0.0.9",
+)
+```
+
+### Legacy `WORKSPACE` configuration
+
+Another primary objective of `rules_scala` 7.x is to enable existing users to
+migrate to Bzlmod. `WORKSPACE` will continue to work in `rules_scala` 8.0.0, for
+Bazel 6.5.0, 7.5.0, and 8, but [__`WORKSPACE` is going away in Bazel
+9__][bazel-9].
+
+[bazel-9]: https://bazel.build/external/migration
+
+If you continue to use `WORKSPACE`, add the following stanza to your `WORKSPACE`
+file and update versions with their sha256s if needed. This stanza is designed
+to ensure that users pick up the correct order of dependencies for
+`rules_scala`. If you want to override any of the following dependency versions,
+make sure to `load()` them before calling `rules_scala_dependencies()`.
+
Note that __`rules_scala` 7 introduces a new `scala_toolchains()` API that is
very different from `rules_scala` 6__. For details on what's changed, see the
[New `scala_toolchains()` API for `WORKSPACE`](#new-toolchains-api) section
@@ -247,7 +353,7 @@ maximum available at the time of writing.
| Bazel/Dependency | `rules_scala` 7.x | `rules_scala` 8.x
(Coming soon! See bazelbuild/rules_scala#1482 and bazelbuild/rules_scala#1652.) |
| :-: | :-: | :-: |
-| Bazel versions using Bzlmod
(Coming soon! See bazelbuild/rules_scala#1482.) | 6.5.0, 7.5.0 | 7.5.0, 8.x |
+| Bazel versions using Bzlmod | 6.5.0, 7.5.0 | 7.5.0, 8.x |
| Bazel versions using `WORKSPACE` | 6.5.0, 7.5.0 | 6.5.0, 7.5.0, 8.x
(see the [notes on 6.5.0 compatibility](#6.5.0)) |
| `protobuf` | v21.7
(can support up to v25.5) | v29.3 |
| `abseil-cpp` | 20220623.1 | 20250127.0 |
@@ -478,18 +584,17 @@ same exact call will also work in `MODULE.bazel`.
#### Copy `register_toolchains()` calls from `WORKSPACE` to `MODULE.bazel`
-The `MODULE.bazel` file from `rules_scala` will automatically call
+The `MODULE.bazel` file from `rules_scala` automatically calls
`register_toolchains()` for toolchains configured via its `scala_deps` module
extension. However, you must register explicitly in your `MODULE.bazel` file any
toolchains that you want to take precedence over the toolchains configured by
`scala_deps`.
-### Bzlmod configuration (coming soon!)
+### Bzlmod configuration
-The upcoming Bzlmod implementation will funnel through the `scala_toolchains()`
-macro as well, ensuring maximum compatibility with `WORKSPACE` configurations.
-The equivalent Bzlmod configuration for the `scala_toolchains()` configuration
-above would be:
+The Bzlmod implementation funnels through the `scala_toolchains()` macro as
+well, ensuring maximum compatibility with `WORKSPACE` configurations. The
+equivalent Bzlmod stanza for the `scala_toolchains()` stanza above would be:
```py
bazel_dep(name = "rules_scala", version = "7.0.0")
@@ -512,7 +617,7 @@ scala_deps.toolchains(
)
```
-The module extensions will call `scala_config()` and `scala_toolchains()`
+The module extensions call `scala_config()` and `scala_toolchains()`
respectively. The `MODULE.bazel` file for `rules_scala` declares its own
dependencies via `bazel_dep()`, allowing Bazel to resolve versions according to
the main repository/root module configuration. It also calls
@@ -521,8 +626,7 @@ register a specific toolchain to resolve first).
[reg_tool]: https://bazel.build/rules/lib/globals/module#register_toolchains
-The `MODULE.bazel` files in this repository will also provide many examples
-(when they land per bazelbuild/rules_scala#1482).
+The `MODULE.bazel` files in this repository provide many examples.
### Embedded resource paths no longer begin with `external/`
diff --git a/WORKSPACE.bzlmod b/WORKSPACE.bzlmod
new file mode 100644
index 000000000..e69de29bb
diff --git a/dt_patches/compiler_sources/MODULE.bazel b/dt_patches/compiler_sources/MODULE.bazel
new file mode 100644
index 000000000..c730e803b
--- /dev/null
+++ b/dt_patches/compiler_sources/MODULE.bazel
@@ -0,0 +1,15 @@
+"""Bazel module ./test/shell/test_examples.sh tests"""
+
+module(name = "compiler_sources")
+
+bazel_dep(name = "rules_scala")
+local_path_override(
+ module_name = "rules_scala",
+ path = "../..",
+)
+
+scala_config = use_extension(
+ "@rules_scala//scala/extensions:config.bzl",
+ "scala_config",
+)
+use_repo(scala_config, "io_bazel_rules_scala_config")
diff --git a/dt_patches/compiler_sources/WORKSPACE.bzlmod b/dt_patches/compiler_sources/WORKSPACE.bzlmod
new file mode 100644
index 000000000..e69de29bb
diff --git a/dt_patches/compiler_sources/extensions.bzl b/dt_patches/compiler_sources/extensions.bzl
index 0cf38b169..7bd7ade0d 100644
--- a/dt_patches/compiler_sources/extensions.bzl
+++ b/dt_patches/compiler_sources/extensions.bzl
@@ -61,3 +61,10 @@ def import_compiler_source_repos():
licenses = ["notice"],
server_urls = default_maven_server_urls(),
)
+
+def _compiler_source_repos_impl(_ctx):
+ import_compiler_source_repos()
+
+compiler_source_repos = module_extension(
+ implementation = _compiler_source_repos_impl,
+)
diff --git a/dt_patches/test_dt_patches/BUILD b/dt_patches/test_dt_patches/BUILD
index a3726aea1..4110341ba 100644
--- a/dt_patches/test_dt_patches/BUILD
+++ b/dt_patches/test_dt_patches/BUILD
@@ -17,7 +17,9 @@ SCALA_LIBS = ["@scala_library"] + select_for_scala_version(
setup_scala_toolchain(
name = "dt_scala_toolchain",
+ parser_combinators_deps = [],
scala_compile_classpath = ["@scala_compiler"] + SCALA_LIBS,
scala_library_classpath = SCALA_LIBS,
scala_macro_classpath = SCALA_LIBS,
+ scala_xml_deps = [],
)
diff --git a/dt_patches/test_dt_patches/MODULE.bazel b/dt_patches/test_dt_patches/MODULE.bazel
new file mode 100644
index 000000000..40b98a4d3
--- /dev/null
+++ b/dt_patches/test_dt_patches/MODULE.bazel
@@ -0,0 +1,61 @@
+"""Bazel module ./test/shell/test_examples.sh tests"""
+
+module(name = "scala3_example")
+
+bazel_dep(name = "rules_scala")
+local_path_override(
+ module_name = "rules_scala",
+ path = "../..",
+)
+
+bazel_dep(name = "rules_cc", version = "0.0.9")
+single_version_override(
+ module_name = "rules_cc",
+ version = "0.0.9",
+)
+
+scala_config = use_extension(
+ "@rules_scala//scala/extensions:config.bzl",
+ "scala_config",
+)
+scala_config.settings(
+ enable_compiler_dependency_tracking = True,
+)
+use_repo(scala_config, "io_bazel_rules_scala_config")
+
+bazel_dep(name = "compiler_sources")
+local_path_override(
+ module_name = "compiler_sources",
+ path = "../compiler_sources",
+)
+
+source_repos = use_extension(
+ "@compiler_sources//:extensions.bzl",
+ "compiler_source_repos",
+)
+use_repo(
+ source_repos,
+ # Configured for the current Scala version
+ "scala_compiler",
+ "scala_library",
+ # Scala 2 specific
+ "scala_reflect",
+ # Scala 3 specific
+ "scala3_interfaces",
+ "tasty_core",
+ # Hardcoded versions
+ "sbt_compiler_interface",
+ "scala2_library",
+ "scala_asm",
+)
+
+scala_deps = use_extension(
+ "@rules_scala//scala/extensions:deps.bzl",
+ "scala_deps",
+)
+scala_deps.settings(
+ fetch_sources = True,
+ validate_scala_version = False,
+)
+
+register_toolchains("//:dt_scala_toolchain")
diff --git a/dt_patches/test_dt_patches/WORKSPACE.bzlmod b/dt_patches/test_dt_patches/WORKSPACE.bzlmod
new file mode 100644
index 000000000..e69de29bb
diff --git a/dt_patches/test_dt_patches_user_srcjar/BUILD b/dt_patches/test_dt_patches_user_srcjar/BUILD
index a5844ba9b..f3345ba4d 100644
--- a/dt_patches/test_dt_patches_user_srcjar/BUILD
+++ b/dt_patches/test_dt_patches_user_srcjar/BUILD
@@ -20,7 +20,9 @@ SCALA_LIBS = ["@scala_library"] + select_for_scala_version(
setup_scala_toolchain(
name = "dt_scala_toolchain",
+ parser_combinators_deps = [],
scala_compile_classpath = ["@scala_compiler"] + SCALA_LIBS,
scala_library_classpath = SCALA_LIBS,
scala_macro_classpath = SCALA_LIBS,
+ scala_xml_deps = [],
)
diff --git a/dt_patches/test_dt_patches_user_srcjar/MODULE.bazel b/dt_patches/test_dt_patches_user_srcjar/MODULE.bazel
new file mode 100644
index 000000000..b8a21d8e8
--- /dev/null
+++ b/dt_patches/test_dt_patches_user_srcjar/MODULE.bazel
@@ -0,0 +1,173 @@
+"""Bazel module ./test/shell/test_examples.sh tests"""
+
+module(name = "scala3_example")
+
+bazel_dep(name = "rules_scala")
+local_path_override(
+ module_name = "rules_scala",
+ path = "../..",
+)
+
+bazel_dep(name = "rules_cc", version = "0.0.9")
+single_version_override(
+ module_name = "rules_cc",
+ version = "0.0.9",
+)
+
+scala_config = use_extension(
+ "@rules_scala//scala/extensions:config.bzl",
+ "scala_config",
+)
+scala_config.settings(
+ enable_compiler_dependency_tracking = True,
+)
+use_repo(scala_config, "io_bazel_rules_scala_config")
+
+bazel_dep(name = "compiler_sources")
+local_path_override(
+ module_name = "compiler_sources",
+ path = "../compiler_sources",
+)
+
+source_repos = use_extension(
+ "@compiler_sources//:extensions.bzl",
+ "compiler_source_repos",
+)
+use_repo(
+ source_repos,
+ # Configured for the current Scala version
+ "scala_compiler",
+ "scala_library",
+ # Scala 2 specific
+ "scala_reflect",
+ # Scala 3 specific
+ "scala3_interfaces",
+ "tasty_core",
+ # Hardcoded versions
+ "sbt_compiler_interface",
+ "scala2_library",
+ "scala_asm",
+)
+
+srcjar_repos = use_extension(
+ "//:extensions.bzl",
+ "compiler_user_srcjar_repos",
+)
+use_repo(
+ srcjar_repos,
+ "scala3_compiler_srcjar",
+ "scala_compiler_srcjar",
+)
+
+scala_deps = use_extension(
+ "@rules_scala//scala/extensions:deps.bzl",
+ "scala_deps",
+)
+scala_deps.settings(
+ fetch_sources = True,
+ validate_scala_version = False,
+)
+
+# The `scala_deps.compiler_srcjar()` tag prevents some of the kinds of errors
+# represented in the corresponding `WORKSPACE` file, so we have to force
+# different ones. In particular, we can't use unspecified data types or kwargs,
+# or Bazel itself will error out.
+
+# Invalid
+scala_deps.compiler_srcjar(
+ url = "foo",
+ urls = ["bar"],
+ version = "2.12.11",
+)
+
+# Invalid
+scala_deps.compiler_srcjar(
+ label = "baz",
+ url = "foo",
+ version = "2.12.12",
+)
+
+# Invalid
+scala_deps.compiler_srcjar(
+ label = "baz",
+ urls = ["bar"],
+ version = "2.12.13",
+)
+scala_deps.compiler_srcjar(
+ integrity = "sha384-yKJTudaHM2dA+VM//elLxhEfOmyCYRHzbLlQcf5jlrR+G5FEW+fBW/b794mQLMOX",
+ urls = ["https://repo1.maven.org/maven2/org/scala-lang/scala-compiler/2.12.14/scala-compiler-2.12.14-sources.jar"],
+ version = "2.12.14",
+)
+scala_deps.compiler_srcjar(
+ sha256 = "65f783f1fbef7de661224f607ac07ca03c5d19acfdb7f2234ff8def1e79b5cd8",
+ url = "https://repo1.maven.org/maven2/org/scala-lang/scala-compiler/2.12.15/scala-compiler-2.12.15-sources.jar",
+ version = "2.12.15",
+)
+scala_deps.compiler_srcjar(
+ label = "@scala_compiler_srcjar//jar:downloaded.jar",
+ version = "2.12.16",
+)
+scala_deps.compiler_srcjar(
+ url = "https://repo1.maven.org/maven2/org/scala-lang/scala-compiler/2.12.17/scala-compiler-2.12.17-sources.jar?foo",
+ version = "2.12.17",
+)
+scala_deps.compiler_srcjar(
+ url = "https://repo1.maven.org/maven2/org/scala-lang/scala-compiler/2.12.18/scala-compiler-2.12.18-sources.jar?foo",
+ version = "2.12.18",
+)
+scala_deps.compiler_srcjar(
+ url = "https://repo1.maven.org/maven2/org/scala-lang/scala-compiler/2.12.19/scala-compiler-2.12.19-sources.jar?foo",
+ version = "2.12.19",
+)
+scala_deps.compiler_srcjar(
+ url = "https://repo1.maven.org/maven2/org/scala-lang/scala-compiler/2.12.20/scala-compiler-2.12.20-sources.jar?foo",
+ version = "2.12.20",
+)
+scala_deps.compiler_srcjar(
+ url = "https://repo1.maven.org/maven2/org/scala-lang/scala-compiler/2.13.11/scala-compiler-2.13.11-sources.jar?foo",
+ version = "2.13.11",
+)
+scala_deps.compiler_srcjar(
+ url = "https://repo1.maven.org/maven2/org/scala-lang/scala-compiler/2.13.12/scala-compiler-2.13.12-sources.jar?foo",
+ version = "2.13.12",
+)
+scala_deps.compiler_srcjar(
+ url = "https://repo1.maven.org/maven2/org/scala-lang/scala-compiler/2.13.14/scala-compiler-2.13.14-sources.jar?foo",
+ version = "2.13.14",
+)
+scala_deps.compiler_srcjar(
+ url = "https://repo1.maven.org/maven2/org/scala-lang/scala-compiler/2.13.15/scala-compiler-2.13.15-sources.jar?foo",
+ version = "2.13.15",
+)
+scala_deps.compiler_srcjar(
+ url = "https://repo1.maven.org/maven2/org/scala-lang/scala3-compiler_3/3.1.3/scala3-compiler_3-3.1.3-sources.jar",
+ integrity = "sha384-4J2ihR1QSdP5cvL3y2OUfw4uUX/hsQqcPlJV+IrQdsM/soiIAYfoEeIEt6vl3xBk",
+ version = "3.1.3",
+)
+scala_deps.compiler_srcjar(
+ url = "https://repo1.maven.org/maven2/org/scala-lang/scala3-compiler_3/3.2.2/scala3-compiler_3-3.2.2-sources.jar",
+ sha256 = "669d580fc4a8d3c2e2d13d5735ae9be05d567613fe44482de5bcc5e2e2ee89ea",
+ version = "3.2.2",
+)
+scala_deps.compiler_srcjar(
+ url = "https://repo1.maven.org/maven2/org/scala-lang/scala3-compiler_3/3.3.5/scala3-compiler_3-3.3.5-sources.jar",
+ version = "3.3.5",
+)
+scala_deps.compiler_srcjar(
+ label = "@scala3_compiler_srcjar//jar:downloaded.jar",
+ version = "3.4.3",
+)
+scala_deps.compiler_srcjar(
+ url = "https://repo1.maven.org/maven2/org/scala-lang/scala3-compiler_3/3.5.2/scala3-compiler_3-3.5.2-sources.jar",
+ version = "3.5.2",
+)
+scala_deps.compiler_srcjar(
+ url = "https://repo1.maven.org/maven2/org/scala-lang/scala3-compiler_3/3.6.2/scala3-compiler_3-3.6.2-sources.jar",
+ version = "3.6.2",
+)
+scala_deps.compiler_srcjar(
+ url = "https://repo1.maven.org/maven2/org/scala-lang/scala3-compiler_3/3.6.3/scala3-compiler_3-3.6.3-sources.jar",
+ version = "3.6.3",
+)
+
+register_toolchains("//:dt_scala_toolchain")
diff --git a/dt_patches/test_dt_patches_user_srcjar/WORKSPACE.bzlmod b/dt_patches/test_dt_patches_user_srcjar/WORKSPACE.bzlmod
new file mode 100644
index 000000000..e69de29bb
diff --git a/examples/crossbuild/MODULE.bazel b/examples/crossbuild/MODULE.bazel
new file mode 100644
index 000000000..a3c2ba7a8
--- /dev/null
+++ b/examples/crossbuild/MODULE.bazel
@@ -0,0 +1,40 @@
+"""Bazel module ./test/shell/test_examples.sh tests"""
+
+module(name = "cross_build")
+
+bazel_dep(name = "rules_scala")
+local_path_override(
+ module_name = "rules_scala",
+ path = "../..",
+)
+
+bazel_dep(name = "rules_cc", version = "0.0.9")
+single_version_override(
+ module_name = "rules_cc",
+ version = "0.0.9",
+)
+
+scala_config = use_extension(
+ "@rules_scala//scala/extensions:config.bzl",
+ "scala_config",
+)
+scala_config.settings(
+ scala_version = "3.3.5",
+ scala_versions = [
+ "2.11.12",
+ "2.13.15",
+ "3.3.5",
+ ],
+)
+use_repo(scala_config, "io_bazel_rules_scala_config")
+
+scala_deps = use_extension(
+ "@rules_scala//scala/extensions:deps.bzl",
+ "scala_deps",
+)
+scala_deps.settings(
+ fetch_sources = True,
+)
+scala_deps.toolchains(
+ scalatest = True,
+)
diff --git a/examples/crossbuild/WORKSPACE.bzlmod b/examples/crossbuild/WORKSPACE.bzlmod
new file mode 100644
index 000000000..e69de29bb
diff --git a/examples/overridden_artifacts/.bazelrc b/examples/overridden_artifacts/.bazelrc
new file mode 100644
index 000000000..005efba2f
--- /dev/null
+++ b/examples/overridden_artifacts/.bazelrc
@@ -0,0 +1 @@
+import ../../.bazelrc
diff --git a/examples/overridden_artifacts/.bazelversion b/examples/overridden_artifacts/.bazelversion
new file mode 100644
index 000000000..f22d756da
--- /dev/null
+++ b/examples/overridden_artifacts/.bazelversion
@@ -0,0 +1 @@
+6.5.0
diff --git a/examples/overridden_artifacts/BUILD b/examples/overridden_artifacts/BUILD
new file mode 100644
index 000000000..10bac303d
--- /dev/null
+++ b/examples/overridden_artifacts/BUILD
@@ -0,0 +1,12 @@
+load("@rules_scala//scala:scala.bzl", "scala_library", "scala_test")
+
+scala_library(
+ name = "hello",
+ srcs = ["Hello.scala"],
+)
+
+scala_test(
+ name = "hello-test",
+ srcs = ["HelloTest.scala"],
+ deps = [":hello"],
+)
diff --git a/examples/overridden_artifacts/Hello.scala b/examples/overridden_artifacts/Hello.scala
new file mode 100644
index 000000000..d65a1270a
--- /dev/null
+++ b/examples/overridden_artifacts/Hello.scala
@@ -0,0 +1,4 @@
+package overriddenartifactstest
+
+class Hello(version: String):
+ def greetings(): String = "Hello, World! This is Scala " + version + "."
diff --git a/examples/overridden_artifacts/HelloTest.scala b/examples/overridden_artifacts/HelloTest.scala
new file mode 100644
index 000000000..262b1c28d
--- /dev/null
+++ b/examples/overridden_artifacts/HelloTest.scala
@@ -0,0 +1,12 @@
+package overriddenartifactstest
+
+import org.scalatest.funsuite.AnyFunSuite
+
+class HelloTest extends AnyFunSuite:
+ test("greetings includes the correct Scala version number") {
+ val hello = new Hello(util.Properties.versionNumberString)
+
+ // Apparently Scala 3 code will still return a Scala 2 version number:
+ // - https://users.scala-lang.org/t/what-scala-library-version-is-used-by-which-scala-3-version/9999
+ assert(hello.greetings().endsWith("2.13.14."))
+ }
diff --git a/examples/overridden_artifacts/MODULE.bazel b/examples/overridden_artifacts/MODULE.bazel
new file mode 100644
index 000000000..c0f934e62
--- /dev/null
+++ b/examples/overridden_artifacts/MODULE.bazel
@@ -0,0 +1,67 @@
+"""Bazel module ./test/shell/test_examples.sh tests"""
+
+module(name = "overridden_artifacts")
+
+bazel_dep(name = "rules_scala")
+local_path_override(
+ module_name = "rules_scala",
+ path = "../..",
+)
+
+bazel_dep(name = "rules_cc", version = "0.0.9")
+single_version_override(
+ module_name = "rules_cc",
+ version = "0.0.9",
+)
+
+scala_config = use_extension(
+ "@rules_scala//scala/extensions:config.bzl",
+ "scala_config",
+)
+scala_config.settings(
+ scala_version = "3.3.5",
+)
+
+scala_deps = use_extension(
+ "@rules_scala//scala/extensions:deps.bzl",
+ "scala_deps",
+)
+
+scala_deps.settings(
+ fetch_sources = False,
+)
+
+# Deliberately set for Scala 3.3 and 2.13 versions less than the most
+# recently supported. See the `scala_version` setting at the top of
+# `third_party/repositories/scala_{2_13,3_3}.bzl`.
+scala_deps.overridden_artifact(
+ name = "io_bazel_rules_scala_scala_library",
+ artifact = "org.scala-lang:scala3-library_3:3.3.4",
+ sha256 = "d95184acfcd814da2e051378e4962c653f4b468f4086452ab427af030482bd3c",
+)
+scala_deps.overridden_artifact(
+ name = "io_bazel_rules_scala_scala_compiler",
+ artifact = "org.scala-lang:scala3-compiler_3:3.3.4",
+ sha256 = "2cca65fdb92e2cc393786cae61b4f7bcb9032ad4be61f9cebae1dca72997e52f",
+ # These are _not_ strictly required in this case, but we want to test that
+ # nothing breaks when they're specified.
+ deps = [
+ "@io_bazel_rules_scala_scala_asm",
+ "@io_bazel_rules_scala_scala_interfaces",
+ "@io_bazel_rules_scala_scala_library",
+ "@io_bazel_rules_scala_scala_tasty_core",
+ "@org_jline_jline_reader",
+ "@org_jline_jline_terminal",
+ "@org_jline_jline_terminal_jni",
+ "@org_scala_sbt_compiler_interface",
+ ],
+)
+scala_deps.overridden_artifact(
+ name = "io_bazel_rules_scala_scala_library_2",
+ artifact = "org.scala-lang:scala-library:2.13.14",
+ sha256 = "43e0ca1583df1966eaf02f0fbddcfb3784b995dd06bfc907209347758ce4b7e3",
+)
+
+scala_deps.toolchains(
+ scalatest = True,
+)
diff --git a/examples/overridden_artifacts/WORKSPACE b/examples/overridden_artifacts/WORKSPACE
new file mode 100644
index 000000000..05aa04810
--- /dev/null
+++ b/examples/overridden_artifacts/WORKSPACE
@@ -0,0 +1,94 @@
+workspace(name = "overridden_artifacts")
+
+load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
+
+local_repository(
+ name = "rules_scala",
+ path = "../..",
+)
+
+load("@rules_scala//scala:deps.bzl", "rules_scala_dependencies")
+
+rules_scala_dependencies()
+
+load("@rules_java//java:repositories.bzl", "rules_java_dependencies", "rules_java_toolchains")
+
+rules_java_dependencies()
+
+load("@bazel_skylib//:workspace.bzl", "bazel_skylib_workspace")
+
+bazel_skylib_workspace()
+
+http_archive(
+ name = "rules_python",
+ sha256 = "ca2671529884e3ecb5b79d6a5608c7373a82078c3553b1fa53206e6b9dddab34",
+ strip_prefix = "rules_python-0.38.0",
+ url = "https://github.com/bazelbuild/rules_python/releases/download/0.38.0/rules_python-0.38.0.tar.gz",
+)
+
+load("@rules_python//python:repositories.bzl", "py_repositories")
+
+py_repositories()
+
+load("@com_google_protobuf//:protobuf_deps.bzl", "protobuf_deps")
+
+protobuf_deps()
+
+rules_java_toolchains()
+
+load("@rules_proto//proto:repositories.bzl", "rules_proto_dependencies")
+
+rules_proto_dependencies()
+
+load("@rules_proto//proto:setup.bzl", "rules_proto_setup")
+
+rules_proto_setup()
+
+load("@rules_proto//proto:toolchains.bzl", "rules_proto_toolchains")
+
+rules_proto_toolchains()
+
+load("@rules_scala//:scala_config.bzl", "scala_config")
+
+scala_config(scala_version = "3.3.5")
+
+load(
+ "@rules_scala//scala:toolchains.bzl",
+ "scala_register_toolchains",
+ "scala_toolchains",
+)
+
+scala_toolchains(
+ # Deliberately set for Scala 3.3 and 2.13 versions less than the most
+ # recently supported. See the `scala_version` setting at the top of
+ # `third_party/repositories/scala_{2_13,3_3}.bzl`.
+ overridden_artifacts = {
+ "io_bazel_rules_scala_scala_library": {
+ "artifact": "org.scala-lang:scala3-library_3:3.3.4",
+ "sha256": "d95184acfcd814da2e051378e4962c653f4b468f4086452ab427af030482bd3c",
+ },
+ "io_bazel_rules_scala_scala_compiler": {
+ "artifact": "org.scala-lang:scala3-compiler_3:3.3.4",
+ "sha256": "2cca65fdb92e2cc393786cae61b4f7bcb9032ad4be61f9cebae1dca72997e52f",
+ # These are _not_ strictly required in this case, but we want to
+ # test that nothing breaks when they're specified.
+ "deps": [
+ "@io_bazel_rules_scala_scala_asm",
+ "@io_bazel_rules_scala_scala_interfaces",
+ "@io_bazel_rules_scala_scala_library",
+ "@io_bazel_rules_scala_scala_tasty_core",
+ "@org_jline_jline_reader",
+ "@org_jline_jline_terminal",
+ "@org_jline_jline_terminal_jni",
+ "@org_scala_sbt_compiler_interface",
+ ],
+ },
+ "io_bazel_rules_scala_scala_library_2": {
+ "artifact": "org.scala-lang:scala-library:2.13.14",
+ "sha256": "43e0ca1583df1966eaf02f0fbddcfb3784b995dd06bfc907209347758ce4b7e3",
+ },
+ },
+ scalatest = True,
+)
+
+scala_register_toolchains()
diff --git a/examples/overridden_artifacts/WORKSPACE.bzlmod b/examples/overridden_artifacts/WORKSPACE.bzlmod
new file mode 100644
index 000000000..e69de29bb
diff --git a/examples/scala3/MODULE.bazel b/examples/scala3/MODULE.bazel
new file mode 100644
index 000000000..07561dbc6
--- /dev/null
+++ b/examples/scala3/MODULE.bazel
@@ -0,0 +1,23 @@
+"""Bazel module ./test/shell/test_examples.sh tests"""
+
+module(name = "scala3_example")
+
+bazel_dep(name = "rules_scala")
+local_path_override(
+ module_name = "rules_scala",
+ path = "../..",
+)
+
+bazel_dep(name = "rules_cc", version = "0.0.9")
+single_version_override(
+ module_name = "rules_cc",
+ version = "0.0.9",
+)
+
+scala_deps = use_extension(
+ "@rules_scala//scala/extensions:deps.bzl",
+ "scala_deps",
+)
+scala_deps.settings(
+ fetch_sources = True,
+)
diff --git a/examples/scala3/WORKSPACE.bzlmod b/examples/scala3/WORKSPACE.bzlmod
new file mode 100644
index 000000000..e69de29bb
diff --git a/examples/semanticdb/MODULE.bazel b/examples/semanticdb/MODULE.bazel
new file mode 100644
index 000000000..45b36a66f
--- /dev/null
+++ b/examples/semanticdb/MODULE.bazel
@@ -0,0 +1,36 @@
+"""Bazel module ./test/shell/test_examples.sh tests"""
+
+module(name = "semanticdb_example")
+
+bazel_dep(name = "rules_scala")
+local_path_override(
+ module_name = "rules_scala",
+ path = "../..",
+)
+
+bazel_dep(name = "rules_cc", version = "0.0.9")
+single_version_override(
+ module_name = "rules_cc",
+ version = "0.0.9",
+)
+
+scala_config = use_extension(
+ "@rules_scala//scala/extensions:config.bzl",
+ "scala_config",
+)
+scala_config.settings(
+ scala_version = "2.13.15",
+)
+
+scala_deps = use_extension(
+ "@rules_scala//scala/extensions:deps.bzl",
+ "scala_deps",
+)
+scala_deps.settings(
+ fetch_sources = True,
+)
+
+#Register and use the custom toolchain that has semanticdb enabled
+register_toolchains(
+ "//:semanticdb_toolchain",
+)
diff --git a/examples/semanticdb/WORKSPACE.bzlmod b/examples/semanticdb/WORKSPACE.bzlmod
new file mode 100644
index 000000000..e69de29bb
diff --git a/examples/testing/multi_frameworks_toolchain/MODULE.bazel b/examples/testing/multi_frameworks_toolchain/MODULE.bazel
new file mode 100644
index 000000000..b27757431
--- /dev/null
+++ b/examples/testing/multi_frameworks_toolchain/MODULE.bazel
@@ -0,0 +1,76 @@
+"""Bazel module ./test/shell/test_examples.sh tests"""
+
+module(name = "multi_frameworks_toolchain")
+
+SCALA_VERSION = "2.12.20"
+
+VERSION_SUFFIX = "_" + SCALA_VERSION.replace(".", "_")
+
+bazel_dep(name = "rules_scala")
+local_path_override(
+ module_name = "rules_scala",
+ path = "../../..",
+)
+
+bazel_dep(name = "rules_cc", version = "0.0.9")
+single_version_override(
+ module_name = "rules_cc",
+ version = "0.0.9",
+)
+
+scala_config = use_extension(
+ "@rules_scala//scala/extensions:config.bzl",
+ "scala_config",
+)
+scala_config.settings(
+ scala_version = SCALA_VERSION,
+)
+use_repo(scala_config, "io_bazel_rules_scala_config")
+
+scala_deps = use_extension(
+ "@rules_scala//scala/extensions:deps.bzl",
+ "scala_deps",
+)
+scala_deps.settings(
+ fetch_sources = True,
+)
+
+# Setting `testing = True` would set scalatest, junit, and specs2 to `True`.
+scala_deps.toolchains(
+ scalatest = True,
+ specs2 = True,
+)
+
+# Under normal circumstances, the above `scala_deps.toolchains()` registration
+# would be all you need. rules_scala will set up and register the toolchains
+# automatically.
+#
+# However, we need to import the repos used by the
+# `setup_scala_testing_toolchain()` example in the `BUILD` file. These repos
+# are versioned by Scala version, so we have to append the `VERSION_SUFFIX`.
+[
+ use_repo(scala_deps, "io_bazel_rules_scala_" + dep + VERSION_SUFFIX)
+ for dep in [
+ "junit_junit",
+ "org_hamcrest_hamcrest_core",
+ "scalactic",
+ "scalatest",
+ "scalatest_compatible",
+ "scalatest_core",
+ "scalatest_featurespec",
+ "scalatest_flatspec",
+ "scalatest_freespec",
+ "scalatest_funspec",
+ "scalatest_funsuite",
+ "scalatest_matchers_core",
+ "scalatest_mustmatchers",
+ "scalatest_shouldmatchers",
+ "org_specs2_specs2_common",
+ "org_specs2_specs2_core",
+ "org_specs2_specs2_fp",
+ "org_specs2_specs2_matcher",
+ "org_specs2_specs2_junit",
+ ]
+]
+
+register_toolchains("//:testing_toolchain")
diff --git a/examples/testing/multi_frameworks_toolchain/WORKSPACE.bzlmod b/examples/testing/multi_frameworks_toolchain/WORKSPACE.bzlmod
new file mode 100644
index 000000000..e69de29bb
diff --git a/examples/testing/scalatest_repositories/MODULE.bazel b/examples/testing/scalatest_repositories/MODULE.bazel
new file mode 100644
index 000000000..3c8a39595
--- /dev/null
+++ b/examples/testing/scalatest_repositories/MODULE.bazel
@@ -0,0 +1,26 @@
+"""Bazel module ./test/shell/test_examples.sh tests"""
+
+module(name = "scalatest_repositories")
+
+bazel_dep(name = "rules_scala")
+local_path_override(
+ module_name = "rules_scala",
+ path = "../../..",
+)
+
+bazel_dep(name = "rules_cc", version = "0.0.9")
+single_version_override(
+ module_name = "rules_cc",
+ version = "0.0.9",
+)
+
+scala_deps = use_extension(
+ "@rules_scala//scala/extensions:deps.bzl",
+ "scala_deps",
+)
+scala_deps.settings(
+ fetch_sources = True,
+)
+scala_deps.toolchains(
+ scalatest = True,
+)
diff --git a/examples/testing/scalatest_repositories/WORKSPACE.bzlmod b/examples/testing/scalatest_repositories/WORKSPACE.bzlmod
new file mode 100644
index 000000000..e69de29bb
diff --git a/examples/testing/specs2_junit_repositories/MODULE.bazel b/examples/testing/specs2_junit_repositories/MODULE.bazel
new file mode 100644
index 000000000..f5ac371fd
--- /dev/null
+++ b/examples/testing/specs2_junit_repositories/MODULE.bazel
@@ -0,0 +1,26 @@
+"""Bazel module ./test/shell/test_examples.sh tests"""
+
+module(name = "specs2_junit_repositories")
+
+bazel_dep(name = "rules_scala")
+local_path_override(
+ module_name = "rules_scala",
+ path = "../../..",
+)
+
+bazel_dep(name = "rules_cc", version = "0.0.9")
+single_version_override(
+ module_name = "rules_cc",
+ version = "0.0.9",
+)
+
+scala_deps = use_extension(
+ "@rules_scala//scala/extensions:deps.bzl",
+ "scala_deps",
+)
+scala_deps.settings(
+ fetch_sources = True,
+)
+scala_deps.toolchains(
+ specs2 = True,
+)
diff --git a/examples/testing/specs2_junit_repositories/WORKSPACE.bzlmod b/examples/testing/specs2_junit_repositories/WORKSPACE.bzlmod
new file mode 100644
index 000000000..e69de29bb
diff --git a/scala/extensions/BUILD b/scala/extensions/BUILD
new file mode 100644
index 000000000..e69de29bb
diff --git a/scala/extensions/config.bzl b/scala/extensions/config.bzl
new file mode 100644
index 000000000..81e5bbcd6
--- /dev/null
+++ b/scala/extensions/config.bzl
@@ -0,0 +1,81 @@
+"""Configures core `rules_scala` parameters and exports @io_bazel_rules_scala.
+
+Provides the `scala_config` module extension with the `settings` tag class.
+See the `_settings_attrs` dict for documentation.
+"""
+
+load(
+ "//scala/private:macros/bzlmod.bzl",
+ "root_module_tags",
+ "single_tag_values",
+)
+load(
+ "//:scala_config.bzl",
+ "DEFAULT_SCALA_VERSION",
+ _scala_config = "scala_config",
+)
+
+_settings_defaults = {
+ "scala_version": DEFAULT_SCALA_VERSION,
+ "scala_versions": [],
+ "enable_compiler_dependency_tracking": False,
+}
+
+_settings_attrs = {
+ "scala_version": attr.string(
+ default = _settings_defaults["scala_version"],
+ doc = (
+ "Scala version used by the default toolchain. " +
+ "Overridden by the `SCALA_VERSION` environment variable."
+ ),
+ ),
+ "scala_versions": attr.string_list(
+ default = _settings_defaults["scala_versions"],
+ doc = (
+ "Other Scala versions used in cross build targets " +
+ "(specified by the `scala_version` attribute of `scala_*` rules)"
+ ),
+ ),
+ "enable_compiler_dependency_tracking": attr.bool(
+ default = _settings_defaults["enable_compiler_dependency_tracking"],
+ doc = (
+ "Enables `scala_toolchain` dependency tracking features. " +
+ "Overridden by the `ENABLE_COMPILER_DEPENDENCY_TRACKING` " +
+ "environment variable."
+ ),
+ ),
+}
+
+_tag_classes = {
+ "settings": tag_class(
+ attrs = _settings_attrs,
+ doc = "Core `rules_scala` parameters",
+ ),
+}
+
+def _scala_config_impl(module_ctx):
+ tags = root_module_tags(module_ctx, _tag_classes.keys())
+ settings = single_tag_values(module_ctx, tags.settings, _settings_defaults)
+
+ menv = module_ctx.os.environ
+ version = menv.get("SCALA_VERSION", settings["scala_version"])
+ versions = {version: None} | {v: None for v in settings["scala_versions"]}
+
+ _scala_config(
+ scala_version = version,
+ scala_versions = versions.keys(),
+ enable_compiler_dependency_tracking = menv.get(
+ "ENABLE_COMPILER_DEPENDENCY_TRACKING",
+ settings["enable_compiler_dependency_tracking"],
+ ),
+ )
+
+scala_config = module_extension(
+ implementation = _scala_config_impl,
+ tag_classes = _tag_classes,
+ environ = ["SCALA_VERSION", "ENABLE_COMPILER_DEPENDENCY_TRACKING"],
+ doc = (
+ "Configures core `rules_scala` parameters and exports them via the " +
+ "@io_bazel_rules_scala repository"
+ ),
+)
diff --git a/scala/extensions/deps.bzl b/scala/extensions/deps.bzl
new file mode 100644
index 000000000..1e12a8861
--- /dev/null
+++ b/scala/extensions/deps.bzl
@@ -0,0 +1,265 @@
+"""Configures builtin toolchains.
+
+Provides the `scala_deps` module extension with the following tag classes:
+
+- `settings`
+- `scalafmt`
+- `overridden_artifact`
+- `compiler_srcjar`
+- `toolchains`
+- `twitter_scrooge`
+
+For documentation, see the `_tag_classes` dict, and the `__attrs` dict
+corresponding to each `` listed above.
+
+See the `scala/private/macros/bzlmod.bzl` docstring for a description of
+the defaults, attrs, and tag class dictionaries pattern employed here.
+"""
+
+load(
+ "//scala/private:macros/bzlmod.bzl",
+ "repeated_tag_values",
+ "root_module_tags",
+ "single_tag_values",
+)
+load("//scala:scala_cross_version.bzl", "default_maven_server_urls")
+load("//scala:toolchains.bzl", "scala_toolchains")
+
+_settings_defaults = {
+ "maven_servers": default_maven_server_urls(),
+ "fetch_sources": True,
+ "validate_scala_version": True,
+}
+
+_settings_attrs = {
+ "maven_servers": attr.string_list(
+ default = _settings_defaults["maven_servers"],
+ doc = "Maven servers used to fetch dependency jar files",
+ ),
+ "fetch_sources": attr.bool(
+ default = _settings_defaults["fetch_sources"],
+ doc = "Download dependency source jars",
+ ),
+ "validate_scala_version": attr.bool(
+ default = _settings_defaults["validate_scala_version"],
+ doc = (
+ "Check if the configured Scala version matches " +
+ "the default version supported by rules_scala"
+ ),
+ ),
+}
+
+_scalafmt_defaults = {
+ "default_config_path": ".scalafmt.conf",
+}
+
+_scalafmt_attrs = {
+ "default_config_path": attr.string(
+ default = _scalafmt_defaults["default_config_path"],
+ doc = (
+ "The relative path to the default Scalafmt config file " +
+ "within the repository"
+ ),
+ ),
+}
+
+_overridden_artifact_attrs = {
+ "name": attr.string(
+ doc = (
+ "Repository name of artifact to override from " +
+ "`third_party/repositories/scala_*.bzl`"
+ ),
+ mandatory = True,
+ ),
+ "artifact": attr.string(
+ doc = "Maven coordinates of the overriding artifact",
+ mandatory = True,
+ ),
+ "sha256": attr.string(
+ doc = "SHA256 checksum of the `artifact`",
+ mandatory = True,
+ ),
+ "deps": attr.string_list(
+ doc = (
+ "Repository names of artifact dependencies (with leading `@`), " +
+ "if required"
+ ),
+ ),
+}
+
+_compiler_srcjar_attrs = {
+ "version": attr.string(mandatory = True),
+ "url": attr.string(),
+ "urls": attr.string_list(),
+ "label": attr.label(),
+ "sha256": attr.string(),
+ "integrity": attr.string(),
+}
+
+_toolchains_defaults = {
+ "scalatest": False,
+ "junit": False,
+ "specs2": False,
+ "testing": False,
+ "scalafmt": False,
+ "scala_proto": False,
+ "scala_proto_enable_all_options": False,
+ "twitter_scrooge": False,
+ "jmh": False,
+}
+
+_toolchains_attrs = {
+ "scalatest": attr.bool(
+ default = _toolchains_defaults["scalatest"],
+ doc = "Register the Scalatest toolchain",
+ ),
+ "junit": attr.bool(
+ default = _toolchains_defaults["junit"],
+ doc = "Register the JUnit toolchain",
+ ),
+ "specs2": attr.bool(
+ default = _toolchains_defaults["specs2"],
+ doc = "Register the Specs2 JUnit toolchain",
+ ),
+ "testing": attr.bool(
+ default = _toolchains_defaults["testing"],
+ doc = (
+ "Register the Scalatest, JUnit, and Specs2 JUnit toolchains " +
+ "(in place of individual settings)"
+ ),
+ ),
+ "scalafmt": attr.bool(
+ default = _toolchains_defaults["scalafmt"],
+ doc = (
+ "Register the Scalafmt toolchain; configured by the " +
+ "`scalafmt` tag"
+ ),
+ ),
+ "scala_proto": attr.bool(
+ default = _toolchains_defaults["scala_proto"],
+ doc = "Register the scala_proto toolchain",
+ ),
+ "scala_proto_enable_all_options": attr.bool(
+ default = _toolchains_defaults["scala_proto_enable_all_options"],
+ doc = (
+ "Register the scala_proto toolchain with all options enabled; " +
+ "`scala_proto` must also be `True` for this to take effect"
+ ),
+ ),
+ "twitter_scrooge": attr.bool(
+ default = _toolchains_defaults["twitter_scrooge"],
+ doc = (
+ "Use the twitter_scrooge toolchain; configured by the " +
+ "`twitter_scrooge` tag"
+ ),
+ ),
+ "jmh": attr.bool(
+ default = _toolchains_defaults["jmh"],
+ doc = "Use the jmh toolchain",
+ ),
+}
+
+def _toolchains(mctx):
+ result = dict(_toolchains_defaults)
+
+ for mod in mctx.modules:
+ toolchains_tags = mod.tags.toolchains
+ values = single_tag_values(mctx, toolchains_tags, _toolchains_defaults)
+
+ # Don't overwrite `True` values from one tag with `False` from another.
+ result.update({k: v for k, v in values.items() if v})
+
+ return result
+
+_twitter_scrooge_defaults = {
+ "libthrift": None,
+ "scrooge_core": None,
+ "scrooge_generator": None,
+ "util_core": None,
+ "util_logging": None,
+}
+
+_twitter_scrooge_attrs = {
+ k: attr.label(default = v)
+ for k, v in _twitter_scrooge_defaults.items()
+}
+
+_tag_classes = {
+ "settings": tag_class(
+ attrs = _settings_attrs,
+ doc = "Settings affecting the configuration of all toolchains",
+ ),
+ "scalafmt": tag_class(
+ attrs = _scalafmt_attrs,
+ doc = "Options for the Scalafmt toolchain",
+ ),
+ "overridden_artifact": tag_class(
+ attrs = _overridden_artifact_attrs,
+ doc = """
+Artifacts overriding the defaults for the configured Scala version.
+
+Can be specified multiple times, but each `name` must be unique. The default
+artifacts are defined by the `third_party/repositories/scala_*.bzl` file
+matching the Scala version.
+""",
+ ),
+ "compiler_srcjar": tag_class(
+ attrs = _compiler_srcjar_attrs,
+ doc = """
+Metadata for locating compiler source jars. Can be specified multiple times,
+but each `version` must be unique. Each instance must contain:
+
+ - `version`
+ - exactly one of `label`, `url`, or `urls`
+ - `integrity` or `sha256` are optional, but highly recommended
+""",
+ ),
+ "toolchains": tag_class(
+ attrs = _toolchains_attrs,
+ doc = (
+ "Selects which builtin toolchains to use; the toolchain for the " +
+ "configured Scala version is always enabled"
+ ),
+ ),
+ "twitter_scrooge": tag_class(
+ attrs = _twitter_scrooge_attrs,
+ doc = (
+ "Targets that override default `twitter_scrooge` toolchain " +
+ "dependency providers"
+ ),
+ ),
+}
+
+def _scala_deps_impl(module_ctx):
+ tags = root_module_tags(module_ctx, _tag_classes.keys())
+ scalafmt = single_tag_values(module_ctx, tags.scalafmt, _scalafmt_defaults)
+ scrooge_deps = single_tag_values(
+ module_ctx,
+ tags.twitter_scrooge,
+ _twitter_scrooge_defaults,
+ )
+
+ scala_toolchains(
+ overridden_artifacts = repeated_tag_values(
+ tags.overridden_artifact,
+ _overridden_artifact_attrs,
+ ),
+ scala_compiler_srcjars = repeated_tag_values(
+ tags.compiler_srcjar,
+ _compiler_srcjar_attrs,
+ ),
+ # attr.string_keyed_label_dict isn't available in Bazel 6, and `None`
+ # breaks attr.string_dict. We can switch after enabling Bazel 8 in #1652.
+ twitter_scrooge_deps = {k: v for k, v in scrooge_deps.items() if v},
+ **(
+ single_tag_values(module_ctx, tags.settings, _settings_defaults) |
+ {"scalafmt_%s" % k: v for k, v in scalafmt.items()} |
+ _toolchains(module_ctx)
+ )
+ )
+
+scala_deps = module_extension(
+ implementation = _scala_deps_impl,
+ tag_classes = _tag_classes,
+ doc = "Configures builtin toolchains",
+)
diff --git a/scala/private/extensions/dev_deps.bzl b/scala/private/extensions/dev_deps.bzl
index 29c4fd52c..db15fcdd2 100644
--- a/scala/private/extensions/dev_deps.bzl
+++ b/scala/private/extensions/dev_deps.bzl
@@ -1,5 +1,10 @@
"""Repositories for testing rules_scala itself"""
+load(
+ "//scala/private:macros/bzlmod.bzl",
+ "root_module_tags",
+ "single_tag_values",
+)
load("//scala:scala_cross_version.bzl", "default_maven_server_urls")
load("//scala:scala_maven_import_external.bzl", "java_import_external")
load("//third_party/repositories:repositories.bzl", "repositories")
@@ -7,10 +12,28 @@ load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
_BUILD_TOOLS_RELEASE = "5.1.0"
+_settings_defaults = {
+ "maven_servers": default_maven_server_urls(),
+ "fetch_sources": False,
+}
+
+_settings_attrs = {
+ "maven_servers": attr.string_list(
+ default = _settings_defaults["maven_servers"],
+ ),
+ "fetch_sources": attr.bool(
+ default = _settings_defaults["fetch_sources"],
+ ),
+}
+
+_tag_classes = {
+ "settings": tag_class(attrs = _settings_attrs),
+}
+
def dev_deps_repositories(
name = "unused_dev_deps_name",
- maven_servers = default_maven_server_urls(),
- fetch_sources = False):
+ maven_servers = _settings_defaults["maven_servers"],
+ fetch_sources = _settings_defaults["fetch_sources"]):
"""Instantiates internal only repos for development and testing
Args:
@@ -67,3 +90,15 @@ def dev_deps_repositories(
],
maven_servers = maven_servers,
)
+
+def _dev_deps_impl(module_ctx):
+ """Instantiate internal only repos for development and testing"""
+ tags = root_module_tags(module_ctx, _tag_classes.keys())
+ settings = single_tag_values(module_ctx, tags.settings, _settings_defaults)
+ dev_deps_repositories(**settings)
+
+dev_deps = module_extension(
+ implementation = _dev_deps_impl,
+ tag_classes = _tag_classes,
+ doc = "Configures repositories used only for internal testing",
+)
diff --git a/scala/private/macros/bzlmod.bzl b/scala/private/macros/bzlmod.bzl
new file mode 100644
index 000000000..332a3294c
--- /dev/null
+++ b/scala/private/macros/bzlmod.bzl
@@ -0,0 +1,211 @@
+"""Utilities for working with Bazel modules
+
+These utilities facilitate the pattern of defining defaults, attrs, and tag
+class dictionaries, as employed by:
+
+- //scala/extensions:config.bzl
+- //scala/extensions:deps.bzl
+- //scala/private/extensions:dev_deps.bzl
+- //scala/private:macros/test/bzlmod_test_ext.bzl
+
+This pattern overcomes the restriction that tag class attrs are not iterable,
+which would otherwise yield lots of initialization logic with duplicated default
+values.
+
+These functions facilitate writing module extensions that need to implement
+three common cases:
+
+- `root_module_tags`: for abiding the root module configuration only, returning
+ an empty struct if the root module doesn't specify any tags
+
+- `single_tag_values`: for enforcing that a tag appears at most once per module
+ as a regular and/or dev dependency, returning default values if unspecified
+
+- `repeated_tag_values`: for collecting unique tag instance values into a dict
+ of dicts, keyed by a particular tag `attr`
+
+For example:
+
+```py
+_string_tag_defaults = {
+ "first": "foo",
+ "second": "bar",
+ "third": "baz",
+}
+
+# A dict comprehension works if all attrs are of the same type.
+_string_tag_attrs = {
+ k: attr.string(default = v)
+ for k, v in _string_tag_defaults.items()
+}
+
+_mixed_tag_defaults = {
+ "fourth": "quux",
+ "fifth": ["xyzzy"],
+ "sixth": {"plugh": "frobozz"},
+}
+
+_mixed_tag_attrs = {
+ "fourth": attr.string(default = _mixed_tag_defaults["fourth"]),
+ "fifth": attr.string_list(default = _mixed_tag_defaults["fifth"]),
+ "sixth": attr.string_dict(default = _mixed_tag_defaults["sixth"]),
+}
+
+_repeated_tag_attrs = {
+ "key": attr.string(mandatory = True),
+ "required_value": attr.string(mandatory = True),
+ "optional_value": attr.string(),
+}
+
+_tag_classes = {
+ "string_tag": tag_class(attrs = _string_tag_attrs),
+ "mixed_tag": tag_class(attrs = _mixed_tag_attrs),
+ "repeated_tag": tag_class(attrs = _repeated_tag_attrs),
+}
+
+def _example_ext_impl(module_ctx):
+ root_tags = root_module_tags(module_ctx, _tag_classes.keys())
+ string_values_dict = single_tag_values(
+ module_ctx,
+ root_tags.string_tag,
+ _string_tag_defaults,
+ )
+ mixed_values_dict = single_tag_values(
+ module_ctx,
+ root_tags.mixed_tag,
+ _mixed_tag_defaults,
+ )
+ repeated_values_dict = repeated_tag_values(
+ root_tags.repeated_tag,
+ _repeated_tag_attrs,
+ )
+
+ some_macro_or_repo_rule_that_uses_these_tag_values(
+ name = "example_repo",
+ repeated = repeated_values_dict,
+ **(string_values_dict | mixed_values_dict),
+ )
+
+example_ext = module_extension(
+ implementation = _example_ext_impl,
+ tag_classes = _tag_classes,
+)
+```py
+"""
+
+def root_module_tags(module_ctx, tag_class_names):
+ """Returns the bazel_module_tags from the root bazel_module or a fake.
+
+ Returns a fake struct constructed from `tag_class_names` if `module_ctx`
+ doesn't contain the root module (i.e., the root module doesn't use the
+ module extension). This is useful for configuring default values in that
+ case, without having to add special case module extension logic.
+
+ Args:
+ module_ctx: the module extension context
+ tag_class_names: tag classes used to create a struct if no root module
+ detected
+
+ Returns:
+ The bazel_module_tags from the root bazel_module object if
+ `module_ctx.modules` contains the root module,
+ or a struct mapping the specified tag class fields to the empty list
+ otherwise
+ """
+ for module in module_ctx.modules:
+ if module.is_root:
+ return module.tags
+ return struct(**{name: [] for name in tag_class_names})
+
+_single_tag_err = (
+ "expected one regular tag instance and/or one dev_dependency instance, " +
+ "got %s:"
+)
+
+def single_tag_values(module_ctx, tags, tag_defaults):
+ """Returns a dictionary of tag attr names to explicit or default values.
+
+ Use for tags that should appear at most once in a module as a regular tag
+ and at most once as a `dev_dependency` tag.
+
+ Nondefault values from a `dev_dependency` instance will override the regular
+ instance's values.
+
+ Args:
+ module_ctx: the module extension context
+ tags: a list of tag class values from a `bazel_module_tags` object
+ tag_defaults: a dictionary of tag attr names to default values
+
+ Returns:
+ `tag_defaults` if `tags` is empty, or a new dict created from the
+ elements of `tags`
+
+ Raises:
+ If `tags` contains more than one two tag instances, if both are
+ `dev_dependency` or regular instances, or if the regular instance
+ doesn't come first
+ """
+ if len(tags) == 0:
+ return tag_defaults
+ if len(tags) > 2:
+ fail(_single_tag_err % len(tags), *tags)
+
+ result = {k: getattr(tags[0], k) for k in tag_defaults}
+
+ if len(tags) == 2:
+ first_is_dev = module_ctx.is_dev_dependency(tags[0])
+ second_is_dev = module_ctx.is_dev_dependency(tags[1])
+
+ if first_is_dev == second_is_dev:
+ tag_type = "dev_dependency" if first_is_dev else "regular"
+ fail(_single_tag_err % ("two %s instances" % (tag_type)), *tags)
+
+ elif first_is_dev:
+ msg = "the dev_dependency instance before the regular instance"
+ fail(_single_tag_err % msg, *tags)
+
+ dev_dep_values = {k: getattr(tags[1], k) for k in tag_defaults}
+ result.update({
+ k: v
+ for k, v in dev_dep_values.items()
+ if v != tag_defaults[k]
+ })
+
+ return result
+
+def repeated_tag_values(tags, attr_dict):
+ """Compiles repeated tag instances into a dict of dicts.
+
+ The first key from `attr_dict` identifies the tag field used as the dict
+ key. Fails if more than one tag instance has the same key value, regardless
+ of `dev_dependency` status.
+
+ Args:
+ tags: a list of tag class values from a `bazel_module_tags` object
+ attr_dict: a dict from `attr` name to `attr` instance
+
+ Returns:
+ a dict of dicts representing unique `tag_name` instance values, using
+ the first key from `attr_dict` as the key value
+
+ Raises:
+ if more than one tag instance contains the same key value (i.e., the
+ same value for the first `attr` in `attr_dict`)
+ """
+ attr_names = attr_dict.keys()
+ key_name = attr_names[0]
+ instances = {}
+ result = {}
+
+ for instance in tags:
+ values = {field: getattr(instance, field) for field in attr_names}
+ key = values.pop(key_name)
+
+ if key in instances:
+ msg = "multiple tags with same %s:" % key_name
+ fail(msg, instances[key], instance)
+
+ instances[key] = instance
+ result[key] = {k: v for k, v in values.items()}
+
+ return result
diff --git a/scala/private/macros/scala_repositories.bzl b/scala/private/macros/scala_repositories.bzl
index d6ca48393..974a8dda8 100644
--- a/scala/private/macros/scala_repositories.bzl
+++ b/scala/private/macros/scala_repositories.bzl
@@ -56,7 +56,7 @@ def _validate_scalac_srcjar(srcjar):
oneof = ["url", "urls", "label"]
count = 0
for key in oneof:
- if key in srcjar:
+ if srcjar.get(key):
count += 1
return count == 1
@@ -94,7 +94,7 @@ def dt_patched_compiler_setup(scala_version, scala_compiler_srcjar = None):
("scala_compiler_srcjar invalid, must be a dict with exactly one of \"label\", \"url\"" +
" or \"urls\" keys, got: ") + repr(srcjar),
)
- if "label" in srcjar:
+ if srcjar.get("label"):
dt_patched_compiler(
name = "scala_compiler_source" + version_suffix(scala_version),
build_file_content = build_file_content,
diff --git a/scala/private/macros/test/BUILD.bzlmod_test b/scala/private/macros/test/BUILD.bzlmod_test
new file mode 100644
index 000000000..3a2611b8d
--- /dev/null
+++ b/scala/private/macros/test/BUILD.bzlmod_test
@@ -0,0 +1,27 @@
+"""Used by test/shell/test_bzlmod_helpers.sh to test bzlmod.bzl."""
+
+load(
+ "@test_tag_values//:results.bzl",
+ "FIRST",
+ "SECOND",
+ "THIRD",
+ "REPEATED",
+)
+
+sh_binary(
+ name = "print-single-test-tag-values",
+ srcs = [":print-tag-values"],
+ args = ["%s %s %s" % (FIRST, SECOND, THIRD)],
+)
+
+sh_binary(
+ name = "print-repeated-test-tag-values",
+ srcs = [":print-tag-values"],
+ args = ["'%s'" % str(REPEATED)],
+)
+
+genrule(
+ name = "print-tag-values",
+ outs = ["print-tag-values.sh"],
+ cmd = "echo 'echo \"$$*\"' >$@",
+)
diff --git a/scala/private/macros/test/MODULE.bzlmod_test b/scala/private/macros/test/MODULE.bzlmod_test
new file mode 100644
index 000000000..ad87195f4
--- /dev/null
+++ b/scala/private/macros/test/MODULE.bzlmod_test
@@ -0,0 +1,25 @@
+"""Used by test/shell/test_bzlmod_helpers.sh to test bzlmod.bzl."""
+
+module(name = "test_module", version = "0.0.0")
+
+bazel_dep(name = "rules_scala")
+local_path_override(
+ module_name = "rules_scala",
+ path = "${rules_scala_dir}"
+)
+
+# Remove as part of implementing Bazel 8 compatibility in #1652.
+bazel_dep(name = "rules_cc", version = "0.0.9")
+single_version_override(
+ module_name = "rules_cc",
+ version = "0.0.9",
+)
+
+test_ext = use_extension("//:bzlmod_test_ext.bzl", "test_ext")
+use_repo(test_ext, "test_tag_values")
+
+dev_test_ext = use_extension(
+ "//:bzlmod_test_ext.bzl",
+ "test_ext",
+ dev_dependency = True,
+)
diff --git a/scala/private/macros/test/MODULE.bzlmod_test_root_module b/scala/private/macros/test/MODULE.bzlmod_test_root_module
new file mode 100644
index 000000000..9a588c3a8
--- /dev/null
+++ b/scala/private/macros/test/MODULE.bzlmod_test_root_module
@@ -0,0 +1,26 @@
+"""Used by test/shell/test_bzlmod_helpers.sh to test bzlmod.bzl.
+
+Used by `test_bzlmod_creates_fake_root_module_tags_when_unused_by_root_module`
+to test `root_module_tags` when the extension isn't imported by the root module.
+"""
+
+module(name = "test_root_module", version = "0.0.0")
+
+bazel_dep(name = "rules_scala")
+local_path_override(
+ module_name = "rules_scala",
+ path = "${rules_scala_dir}"
+)
+
+bazel_dep(name = "test_module")
+local_path_override(
+ module_name = "test_module",
+ path = "${test_module_dir}"
+)
+
+# Remove as part of implementing Bazel 8 compatibility in #1652.
+bazel_dep(name = "rules_cc", version = "0.0.9")
+single_version_override(
+ module_name = "rules_cc",
+ version = "0.0.9",
+)
diff --git a/scala/private/macros/test/bzlmod_test_ext.bzl b/scala/private/macros/test/bzlmod_test_ext.bzl
new file mode 100644
index 000000000..b2864e9b2
--- /dev/null
+++ b/scala/private/macros/test/bzlmod_test_ext.bzl
@@ -0,0 +1,91 @@
+"""Used by test/shell/test_bzlmod_helpers.sh to test bzlmod.bzl.
+
+Defines a module extension with two tag classes:
+
+- `single_test_tag`: Contains three `attr.string` fields with nonempty default
+ values. Should have at most one regular instance and one `dev_dependency`
+ instance. Used to test `single_tag_values`.
+
+- `repeated_test_tag`: Contains a mandatory `key` attr, one `required` attr, and
+ one `optional` attr. Used to test `repeated_tag_values`.
+
+Generates `@test_tag_values//:results.bzl` from `_test_tag_results_bzl_template`.
+`BUILD.bzlmod_test` imports the following symbols from this generated file:
+
+- For `single_test_tag`: the `FIRST`, `SECOND`, and `THIRD` string constants
+- For `repeated_test_tag`: the `REPEATED` dict of dicts
+"""
+
+load(
+ "@rules_scala//scala/private:macros/bzlmod.bzl",
+ "repeated_tag_values",
+ "root_module_tags",
+ "single_tag_values",
+)
+
+visibility("private")
+
+_single_test_tag_defaults = {
+ "first": "foo",
+ "second": "bar",
+ "third": "baz",
+}
+
+_single_test_tag_attrs = {
+ k: attr.string(default = v)
+ for k, v in _single_test_tag_defaults.items()
+}
+
+_repeated_test_tag_attrs = {
+ "unique_key": attr.string(mandatory = True),
+ "required": attr.string(mandatory = True),
+ "optional": attr.string(),
+}
+
+_tag_classes = {
+ "single_test_tag": tag_class(attrs = _single_test_tag_attrs),
+ "repeated_test_tag": tag_class(attrs = _repeated_test_tag_attrs),
+}
+
+_test_tag_results_bzl_template = """
+FIRST = "{first}"
+SECOND = "{second}"
+THIRD = "{third}"
+REPEATED = {repeated}
+"""
+
+def _test_tag_results_repo_impl(rctx):
+ rctx.file("BUILD")
+ rctx.file(
+ "results.bzl",
+ _test_tag_results_bzl_template.format(**rctx.attr.test_tag_values),
+ )
+
+_test_tag_results_repo = repository_rule(
+ implementation = _test_tag_results_repo_impl,
+ attrs = {
+ "test_tag_values": attr.string_dict(mandatory = True),
+ },
+)
+
+def _test_ext_impl(mctx):
+ root_tags = root_module_tags(mctx, _tag_classes.keys())
+ single_values = single_tag_values(
+ mctx,
+ root_tags.single_test_tag,
+ _single_test_tag_defaults,
+ )
+ repeated_values = repeated_tag_values(
+ root_tags.repeated_test_tag,
+ _repeated_test_tag_attrs,
+ )
+
+ _test_tag_results_repo(
+ name = "test_tag_values",
+ test_tag_values = single_values | {"repeated": str(repeated_values)},
+ )
+
+test_ext = module_extension(
+ implementation = _test_ext_impl,
+ tag_classes = _tag_classes,
+)
diff --git a/scala/toolchains.bzl b/scala/toolchains.bzl
index 637bce98e..867ef75df 100644
--- a/scala/toolchains.bzl
+++ b/scala/toolchains.bzl
@@ -60,17 +60,20 @@ def scala_toolchains(
Args:
maven_servers: Maven servers used to fetch dependency jar files
- overridden_artifacts: specific dependency jar files to use instead of
- those from `maven_servers`, in the format:
+ overridden_artifacts: artifacts overriding the defaults for the
+ configured Scala version, in the format:
```starlark
"repo_name": {
"artifact": "",
"sha256": "",
"deps": [
- "repository_names_of_dependencies",
+ "repository_labels_of_dependencies",
],
}
```
+ The default artifacts are defined by the
+ `third_party/repositories/scala_*.bzl` file matching the Scala
+ version.
fetch_sources: whether to download dependency source jars
validate_scala_version: whether to check if the configured Scala version
matches the default version supported by rules_scala
diff --git a/scala/toolchains_repo.bzl b/scala/toolchains_repo.bzl
index ff237e36c..35a919ed7 100644
--- a/scala/toolchains_repo.bzl
+++ b/scala/toolchains_repo.bzl
@@ -102,7 +102,8 @@ _scala_toolchains_repo = repository_rule(
"scala_proto_enable_all_options": attr.bool(),
"jmh": attr.bool(),
"twitter_scrooge": attr.bool(),
- # attr.string_keyed_label_dict isn't available in Bazel 6
+ # attr.string_keyed_label_dict isn't available in Bazel 6.
+ # We can switch to it after enabling Bazel 8 in #1652.
"twitter_scrooge_deps": attr.string_dict(),
},
)
diff --git a/scala_config.bzl b/scala_config.bzl
index 70cf132c3..7fe4fd615 100644
--- a/scala_config.bzl
+++ b/scala_config.bzl
@@ -1,8 +1,7 @@
load("//scala:scala_cross_version.bzl", "extract_major_version", "extract_minor_version", "version_suffix")
-def _default_scala_version():
- """return the scala version for use in maven coordinates"""
- return "2.12.20"
+"""Default Scala version for use in Maven coordinates"""
+DEFAULT_SCALA_VERSION = "2.12.20"
def _validate_supported_scala_version(scala_major_version, scala_minor_version):
if scala_major_version == "2.11" and int(scala_minor_version) != 12:
@@ -86,7 +85,7 @@ _config_repository = repository_rule(
)
def scala_config(
- scala_version = _default_scala_version(),
+ scala_version = DEFAULT_SCALA_VERSION,
scala_versions = [],
enable_compiler_dependency_tracking = False):
_config_repository(
diff --git a/test/proto_cross_repo_boundary/repo/MODULE.bazel b/test/proto_cross_repo_boundary/repo/MODULE.bazel
new file mode 100644
index 000000000..780bcb364
--- /dev/null
+++ b/test/proto_cross_repo_boundary/repo/MODULE.bazel
@@ -0,0 +1,3 @@
+module(name = "proto_cross_repo_boundary")
+
+bazel_dep(name = "rules_proto", version = "6.0.2")
diff --git a/test/proto_cross_repo_boundary/repo/WORKSPACE.bzlmod b/test/proto_cross_repo_boundary/repo/WORKSPACE.bzlmod
new file mode 100644
index 000000000..e69de29bb
diff --git a/test/shell/test_bzlmod_macros.sh b/test/shell/test_bzlmod_macros.sh
new file mode 100755
index 000000000..3a50c9bb1
--- /dev/null
+++ b/test/shell/test_bzlmod_macros.sh
@@ -0,0 +1,221 @@
+#!/usr/bin/env bash
+#
+# Tests for //scala/private:macros/bzlmod.bzl
+
+set -e
+
+dir="$( cd "${BASH_SOURCE[0]%/*}" && echo "${PWD%/test/shell}" )"
+test_source="${dir}/test/shell/${BASH_SOURCE[0]#*test/shell/}"
+# shellcheck source=./test_runner.sh
+. "${dir}"/test/shell/test_runner.sh
+. "${dir}"/test/shell/test_helper.sh
+runner=$(get_test_runner "${1:-local}")
+export USE_BAZEL_VERSION=${USE_BAZEL_VERSION:-$(cat $dir/.bazelversion)}
+
+# Setup and teardown
+
+test_tmpdir="${dir}/tmp/${BASH_SOURCE[0]##*/}"
+test_tmpdir="${test_tmpdir%.*}"
+mkdir -p "$test_tmpdir"
+original_dir="$PWD"
+cd "$test_tmpdir"
+
+teardown_suite() {
+ # Make sure bazel isn't still running for this workspace.
+ bazel shutdown
+ cd "$original_dir"
+ rm -rf "$test_tmpdir"
+}
+trap 'teardown_suite' EXIT
+
+test_srcs_dir="${dir}/scala/private/macros/test"
+
+setup_test_module() {
+ # Bazel 6, at least, seems to want external repos to have a `WORKSPACE`.
+ # Perhaps remove it once we implement Bazel 8 support in #1652.
+ touch WORKSPACE WORKSPACE.bzlmod
+
+ cp "${dir}"/.bazel{rc,version} "${test_srcs_dir}"/bzlmod_test_ext.bzl .
+ cp "${test_srcs_dir}/BUILD.bzlmod_test" 'BUILD'
+ sed -e "s%\${rules_scala_dir}%${dir}%" \
+ "${test_srcs_dir}/MODULE.bzlmod_test" > 'MODULE.bazel'
+
+ printf '%s\n' "$@" >>'MODULE.bazel'
+}
+
+# Test utilities
+
+bazel_run_args=('run' '--enable_bzlmod')
+print_single_test_tag_values_target='//:print-single-test-tag-values'
+print_repeated_test_tag_values_target='//:print-repeated-test-tag-values'
+
+print_single_test_tag_values() {
+ bazel "${bazel_run_args[@]}" "$print_single_test_tag_values_target" 2>&1
+}
+
+print_single_test_tag_values_should_fail_with_message() {
+ local expected=(
+ "expected one regular tag instance and/or one dev_dependency instance,"
+ "${1}: 'single_test_tag' tag at ${test_tmpdir}/MODULE.bazel:"
+ )
+
+ action_should_fail_with_message "${expected[*]}" \
+ "${bazel_run_args[@]}" "$print_single_test_tag_values_target"
+}
+
+print_repeated_test_tag_values() {
+ bazel "${bazel_run_args[@]}" "$print_repeated_test_tag_values_target" 2>&1
+}
+
+# Test cases
+
+test_bzlmod_single_tag_values_returns_defaults_when_no_root_tag() {
+ setup_test_module
+
+ assert_matches 'foo bar baz$' "$(print_single_test_tag_values)"
+}
+
+test_bzlmod_creates_fake_root_module_tags_when_unused_by_root_module() {
+ # This setup is a bit more involved because this is the only test that sets
+ # up the test module as a non-root module.
+ local test_module_dir="${test_tmpdir}_test_module"
+
+ mkdir -p "$test_module_dir"
+ cd "$test_module_dir"
+ setup_test_module
+ cd "$test_tmpdir"
+ sed -e "s%\${rules_scala_dir}%${dir}%" \
+ -e "s%\${test_module_dir}%${test_module_dir}%" \
+ "${test_srcs_dir}/MODULE.bzlmod_test_root_module" > 'MODULE.bazel'
+
+ local target='@test_module//:print-single-test-tag-values'
+ local tag_values="$(bazel run --enable_bzlmod "$target")"
+
+ rm -rf "$test_module_dir"
+ assert_matches 'foo bar baz$' "$tag_values"
+}
+
+test_bzlmod_single_tag_values_returns_regular_root_tag_values() {
+ setup_test_module \
+ 'test_ext.single_test_tag(first = "quux", third = "plugh")'
+
+ assert_matches 'quux bar plugh$' "$(print_single_test_tag_values)"
+}
+
+test_bzlmod_single_tag_values_returns_dev_root_tag_values() {
+ setup_test_module \
+ 'dev_test_ext.single_test_tag(first = "quux", third = "plugh")'
+
+ assert_matches 'quux bar plugh$' "$(print_single_test_tag_values)"
+}
+
+test_bzlmod_single_tag_values_combines_regular_and_dev_dep_tags() {
+ setup_test_module \
+ 'test_ext.single_test_tag(first = "quux", third = "plugh")' \
+ 'dev_test_ext.single_test_tag(second = "xyzzy", third = "frobozz")'
+
+ # Dev values matching the default won't overwrite regular tag values.
+ assert_matches 'quux xyzzy frobozz$' "$(print_single_test_tag_values)"
+}
+
+test_bzlmod_single_tag_values_fails_if_more_than_two_tags() {
+ setup_test_module \
+ 'test_ext.single_test_tag()' \
+ 'dev_test_ext.single_test_tag()' \
+ 'dev_test_ext.single_test_tag(second = "not", third = "happening")'
+
+ print_single_test_tag_values_should_fail_with_message "got 3"
+}
+
+test_bzlmod_single_tag_values_fails_if_dev_tag_before_regular() {
+ setup_test_module \
+ 'dev_test_ext.single_test_tag()' \
+ 'test_ext.single_test_tag(first = "should be, but isn''t")'
+
+ print_single_test_tag_values_should_fail_with_message \
+ "got the dev_dependency instance before the regular instance"
+}
+
+test_bzlmod_single_tag_values_fails_if_two_regular_tags() {
+ setup_test_module \
+ 'test_ext.single_test_tag(first = "of two")' \
+ 'test_ext.single_test_tag(second = "of two")'
+
+ print_single_test_tag_values_should_fail_with_message \
+ "got two regular instances"
+}
+
+test_bzlmod_single_tag_values_fails_if_two_dev_tags() {
+ setup_test_module \
+ 'dev_test_ext.single_test_tag(first = "of two")' \
+ 'dev_test_ext.single_test_tag(second = "of two")'
+
+ print_single_test_tag_values_should_fail_with_message \
+ "got two dev_dependency instances"
+}
+
+test_bzlmod_repeated_tag_values_for_zero_instances() {
+ setup_test_module
+
+ assert_matches '{}$' "$(print_repeated_test_tag_values)"
+}
+
+test_bzlmod_repeated_tag_values_for_one_instance() {
+ setup_test_module \
+ 'test_ext.repeated_test_tag(unique_key = "foo", required = "bar")'
+
+ assert_matches '{"foo": {"required": "bar", "optional": ""}}$' \
+ "$(print_repeated_test_tag_values)"
+}
+
+test_bzlmod_repeated_tag_values_for_multiple_instances() {
+ setup_test_module \
+ 'test_ext.repeated_test_tag(unique_key = "foo", required = "bar")' \
+ 'test_ext.repeated_test_tag(' \
+ ' unique_key = "baz",' \
+ ' required = "quux",' \
+ ' optional = "xyzzy",' \
+ ')' \
+ 'dev_test_ext.repeated_test_tag(' \
+ ' unique_key = "plugh",' \
+ ' required = "frobozz",' \
+ ')'
+
+ local expected=(
+ '{"foo": {"required": "bar", "optional": ""},'
+ '"baz": {"required": "quux", "optional": "xyzzy"},'
+ '"plugh": {"required": "frobozz", "optional": ""}}$'
+ )
+
+ assert_matches "${expected[*]}" "$(print_repeated_test_tag_values)"
+}
+
+test_bzlmod_repeated_tag_values_fails_on_duplicate_key() {
+ setup_test_module \
+ 'test_ext.repeated_test_tag(unique_key = "foo", required = "bar")' \
+ 'dev_test_ext.repeated_test_tag(unique_key = "foo", required = "baz")'
+
+ local expected=(
+ "multiple tags with same unique_key:"
+ "'repeated_test_tag' tag at ${test_tmpdir}/MODULE.bazel:"
+ )
+
+ action_should_fail_with_message "${expected[*]}" \
+ "${bazel_run_args[@]}" "$print_repeated_test_tag_values_target"
+}
+
+# Run tests
+# To skip a test, add a `_` prefix to its function name.
+# To run a specific test, set the `RULES_SCALA_TEST_ONLY` env var to its name.
+
+while IFS= read -r line; do
+ if [[ "$line" =~ ^_?(test_[A-Za-z0-9_]+)\(\)\ ?{$ ]]; then
+ test_name="${BASH_REMATCH[1]}"
+
+ if [[ "${line:0:1}" == '_' ]]; then
+ echo -e "${YELLOW}skipping ${test_name}${NC}"
+ else
+ "$runner" "$test_name"
+ fi
+ fi
+done <"$test_source"
diff --git a/test/shell/test_examples.sh b/test/shell/test_examples.sh
index 4889f709c..cfe2d7dc5 100755
--- a/test/shell/test_examples.sh
+++ b/test/shell/test_examples.sh
@@ -67,6 +67,11 @@ function cross_build_example() {
test_example examples/crossbuild "bazel build //..."
}
+function overridden_artifacts_example() {
+ test_example examples/overridden_artifacts \
+ "bazel test --test_output=errors //..."
+}
+
$runner scalatest_repositories_example
$runner specs2_junit_repositories_example
$runner multi_framework_toolchain_example
@@ -77,4 +82,5 @@ $runner scala3_3_example
$runner scala3_4_example
$runner scala3_5_example
$runner scala3_6_example
-$runner cross_build_example
\ No newline at end of file
+$runner cross_build_example
+$runner overridden_artifacts_example
diff --git a/test/shell/test_helper.sh b/test/shell/test_helper.sh
index 11262d33c..47a71b5dc 100755
--- a/test/shell/test_helper.sh
+++ b/test/shell/test_helper.sh
@@ -142,3 +142,21 @@ jar_contains_files() {
fi
done
}
+
+_print_error_msg() {
+ printf '%b' "$RED"
+ printf '%b\n' "$@"
+ printf '%b' "$NC"
+}
+
+assert_matches() {
+ local expected="$1"
+ local actual="$2"
+
+ if [[ ! "$actual" =~ $expected ]]; then
+ _print_error_msg "Value did not match regular expression" \
+ "Expected: \"$expected\"" \
+ "Actual: \"$actual\""
+ return 1
+ fi
+}
diff --git a/test/shell/test_runner.sh b/test/shell/test_runner.sh
index db3a7aa68..8f65db104 100644
--- a/test/shell/test_runner.sh
+++ b/test/shell/test_runner.sh
@@ -5,6 +5,7 @@
NC='\033[0m'
GREEN='\033[0;32m'
RED='\033[0;31m'
+YELLOW='\033[0;33m'
run_test_ci() {
# spawns the test to new process
diff --git a/test_cross_build/MODULE.bazel b/test_cross_build/MODULE.bazel
new file mode 100644
index 000000000..68746f870
--- /dev/null
+++ b/test_cross_build/MODULE.bazel
@@ -0,0 +1,44 @@
+"""Bazel module ./test/shell/test_examples.sh tests"""
+
+module(name = "cross_build")
+
+bazel_dep(name = "rules_scala")
+local_path_override(
+ module_name = "rules_scala",
+ path = "..",
+)
+
+bazel_dep(name = "rules_cc", version = "0.0.9")
+single_version_override(
+ module_name = "rules_cc",
+ version = "0.0.9",
+)
+
+scala_config = use_extension(
+ "@rules_scala//scala/extensions:config.bzl",
+ "scala_config",
+)
+scala_config.settings(
+ scala_version = "3.1.3",
+ scala_versions = [
+ "2.11.12",
+ "2.12.20",
+ "2.13.15",
+ "3.1.3",
+ "3.2.2",
+ "3.3.5",
+ ],
+)
+use_repo(scala_config, "io_bazel_rules_scala_config")
+
+scala_deps = use_extension(
+ "@rules_scala//scala/extensions:deps.bzl",
+ "scala_deps",
+)
+scala_deps.settings(
+ fetch_sources = True,
+)
+scala_deps.toolchains(
+ scalafmt = True,
+ scalatest = True,
+)
diff --git a/test_cross_build/WORKSPACE.bzlmod b/test_cross_build/WORKSPACE.bzlmod
new file mode 100644
index 000000000..e69de29bb
diff --git a/test_rules_scala.sh b/test_rules_scala.sh
index 554da4735..317ef91a6 100755
--- a/test_rules_scala.sh
+++ b/test_rules_scala.sh
@@ -12,6 +12,7 @@ test_dir=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )/test/shell
. "${test_dir}"/test_runner.sh
runner=$(get_test_runner "${1:-local}")
+"${test_dir}"/test_bzlmod_macros.sh
$runner bazel build test/...
#$runner bazel build "test/... --all_incompatible_changes"
$runner bazel test test/...
diff --git a/test_version.sh b/test_version.sh
index f88fd3e43..6afbb5c5b 100755
--- a/test_version.sh
+++ b/test_version.sh
@@ -43,14 +43,19 @@ run_in_test_repo() {
cp -r $test_target $NEW_TEST_DIR
local scrooge_ws=""
+ local scrooge_mod=""
if [[ -n "$TWITTER_SCROOGE_VERSION" ]]; then
local version_param="version = \"$TWITTER_SCROOGE_VERSION\""
scrooge_ws="$version_param"
+ scrooge_mod="scrooge_repos.settings($version_param)"
fi
sed -e "s%\${twitter_scrooge_repositories}%${scrooge_ws}\n%" \
WORKSPACE.template >> $NEW_TEST_DIR/WORKSPACE
+ sed -e "s%\${twitter_scrooge_repositories}%${scrooge_mod}\n%" \
+ MODULE.bazel.template >> $NEW_TEST_DIR/MODULE.bazel
+ touch $NEW_TEST_DIR/WORKSPACE.bzlmod
cp ../.bazel{rc,version} $NEW_TEST_DIR/
cd $NEW_TEST_DIR
diff --git a/test_version/MODULE.bazel.template b/test_version/MODULE.bazel.template
new file mode 100644
index 000000000..907d01ec5
--- /dev/null
+++ b/test_version/MODULE.bazel.template
@@ -0,0 +1,72 @@
+"""Bazel module template for //:test_version.sh tests"""
+
+module(name = "rules_scala_test_version")
+
+bazel_dep(name = "rules_java", version = "7.12.4")
+bazel_dep(name = "rules_proto", version = "6.0.2")
+bazel_dep(name = "rules_cc", version = "0.0.9")
+single_version_override(
+ module_name = "rules_cc",
+ version = "0.0.9",
+)
+
+bazel_dep(
+ name = "protobuf",
+ version = "21.7",
+ repo_name = "com_google_protobuf",
+)
+single_version_override(
+ module_name = "protobuf",
+ version = "21.7",
+)
+
+bazel_dep(name = "rules_scala")
+local_path_override(
+ module_name = "rules_scala",
+ path = "../.."
+)
+
+scala_config = use_extension(
+ "@rules_scala//scala/extensions:config.bzl",
+ "scala_config",
+)
+
+scala_config.settings(
+ enable_compiler_dependency_tracking = True,
+)
+
+use_repo(scala_config, "io_bazel_rules_scala_config")
+
+scala_deps = use_extension(
+ "@rules_scala//scala/extensions:deps.bzl",
+ "scala_deps",
+)
+
+scala_deps.settings(
+ fetch_sources = True,
+)
+
+scrooge_repos = use_extension(
+ "//:scrooge_repositories.bzl",
+ "scrooge_repositories_ext",
+)
+${twitter_scrooge_repositories}
+use_repo(
+ scrooge_repos,
+ "io_bazel_rules_scala_scrooge_core",
+ "io_bazel_rules_scala_scrooge_generator",
+ "io_bazel_rules_scala_util_core",
+ "io_bazel_rules_scala_util_logging",
+ "twitter_scrooge_test_toolchain",
+)
+
+scala_deps.toolchains(
+ scala_proto = True,
+ scalatest = True,
+ specs2 = True,
+)
+
+register_toolchains(
+ "@rules_scala//scala:unused_dependency_checker_error_toolchain",
+ "@twitter_scrooge_test_toolchain//...:all",
+)
diff --git a/test_version/version_specific_tests_dir/scrooge_repositories.bzl b/test_version/version_specific_tests_dir/scrooge_repositories.bzl
index 17e33aa55..d44c27c6e 100644
--- a/test_version/version_specific_tests_dir/scrooge_repositories.bzl
+++ b/test_version/version_specific_tests_dir/scrooge_repositories.bzl
@@ -112,3 +112,20 @@ def scrooge_repositories(version = None):
twitter_scrooge = True,
twitter_scrooge_deps = toolchain_deps,
)
+
+_settings = tag_class(
+ attrs = {
+ "version": attr.string(mandatory = True),
+ },
+)
+
+def _scrooge_repositories_ext_impl(module_ctx):
+ settings = module_ctx.modules[0].tags.settings
+ scrooge_repositories(settings[0].version if len(settings) != 0 else None)
+
+scrooge_repositories_ext = module_extension(
+ implementation = _scrooge_repositories_ext_impl,
+ tag_classes = {
+ "settings": _settings,
+ },
+)
diff --git a/third_party/test/example_external_workspace/MODULE.bazel b/third_party/test/example_external_workspace/MODULE.bazel
new file mode 100644
index 000000000..a6b0871c0
--- /dev/null
+++ b/third_party/test/example_external_workspace/MODULE.bazel
@@ -0,0 +1,17 @@
+"""Bazel example module for several top level tests"""
+
+module(name = "example_external_workspace")
+
+bazel_dep(name = "rules_scala")
+local_path_override(
+ module_name = "rules_scala",
+ path = "../../..",
+)
+
+scala_deps = use_extension(
+ "@rules_scala//scala/extensions:deps.bzl",
+ "scala_deps",
+)
+scala_deps.toolchains(
+ scalatest = True,
+)
diff --git a/third_party/test/example_external_workspace/WORKSPACE.bzlmod b/third_party/test/example_external_workspace/WORKSPACE.bzlmod
new file mode 100644
index 000000000..e69de29bb
diff --git a/third_party/test/new_local_repo/MODULE.bazel b/third_party/test/new_local_repo/MODULE.bazel
new file mode 100644
index 000000000..796331ee2
--- /dev/null
+++ b/third_party/test/new_local_repo/MODULE.bazel
@@ -0,0 +1 @@
+module(name = "test_new_local_repo")
diff --git a/third_party/test/new_local_repo/WORKSPACE.bzlmod b/third_party/test/new_local_repo/WORKSPACE.bzlmod
new file mode 100644
index 000000000..e69de29bb
diff --git a/third_party/test/proto/MODULE.bazel b/third_party/test/proto/MODULE.bazel
new file mode 100644
index 000000000..d8bd75a1a
--- /dev/null
+++ b/third_party/test/proto/MODULE.bazel
@@ -0,0 +1,17 @@
+"""Bazel module ./test/shell/test_scala_proto_library.sh tests"""
+
+module(name = "proto")
+
+bazel_dep(name = "rules_scala")
+local_path_override(
+ module_name = "rules_scala",
+ path = "../../..",
+)
+
+scala_deps = use_extension(
+ "@rules_scala//scala/extensions:deps.bzl",
+ "scala_deps",
+)
+scala_deps.toolchains(
+ scala_proto = True,
+)
diff --git a/third_party/test/proto/WORKSPACE.bzlmod b/third_party/test/proto/WORKSPACE.bzlmod
new file mode 100644
index 000000000..e69de29bb
diff --git a/tools/bazel.rc.buildkite b/tools/bazel.rc.buildkite
index 5126d6eaf..11137dd31 100644
--- a/tools/bazel.rc.buildkite
+++ b/tools/bazel.rc.buildkite
@@ -1,5 +1,4 @@
-build --strategy=Scalac=worker --strategy=ScroogeRule=worker --worker_max_instances=3
+# Remove once Bazel 7.5.0 becomes the default supported version.
+common --enable_bzlmod
-# Remove upon completing Bzlmod compatibility work.
-# - https://github.com/bazelbuild/rules_scala/issues/1482
-build --noenable_bzlmod
+build --strategy=Scalac=worker --strategy=ScroogeRule=worker --worker_max_instances=3