diff --git a/.bazelci/presubmit.yml b/.bazelci/presubmit.yml index f6d65f576..30628c175 100644 --- a/.bazelci/presubmit.yml +++ b/.bazelci/presubmit.yml @@ -29,17 +29,15 @@ tasks: # Install xmllint - sudo apt update && sudo apt install --reinstall libxml2-utils -y - "./test_rules_scala.sh" - # Switch `last_rc` to `last_green` once Bzlmod lands. - # https://github.com/bazelbuild/rules_scala/issues/1482 - test_rules_scala_linux_last_rc: - name: "./test_rules_scala (last_rc Bazel)" + test_rules_scala_linux_last_green: + name: "./test_rules_scala (last_green Bazel)" platform: ubuntu2004 - bazel: last_rc + bazel: last_green shell_commands: # Install xmllint - sudo apt update && sudo apt install --reinstall libxml2-utils -y - echo "build --enable_workspace" >> .bazelrc - - "./test_rules_scala.sh || buildkite-agent annotate --style 'warning' \"Optional build with last_rc Bazel version failed, [see here](${BUILDKITE_BUILD_URL}#${BUILDKITE_JOB_ID}) (It is not mandatory but worth checking)\"" + - "./test_rules_scala.sh || buildkite-agent annotate --style 'warning' \"Optional build with last_green Bazel version failed, [see here](${BUILDKITE_BUILD_URL}#${BUILDKITE_JOB_ID}) (It is not mandatory but worth checking)\"" test_rules_scala_macos: name: "./test_rules_scala" platform: macos diff --git a/.bazelignore b/.bazelignore new file mode 100644 index 000000000..324083a11 --- /dev/null +++ b/.bazelignore @@ -0,0 +1,19 @@ +# 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 +dt_patches/compiler_sources +dt_patches/test_dt_patches +dt_patches/test_dt_patches_user_srcjar +examples/crossbuild +examples/overridden_artifacts +examples/scala3 +examples/semanticdb +examples/testing/multi_frameworks_toolchain +examples/testing/scalatest_repositories +examples/testing/specs2_junit_repositories +test/proto_cross_repo_boundary/repo +test_cross_build +third_party/test/example_external_workspace +third_party/test/new_local_repo +third_party/test/proto diff --git a/.bazelrc b/.bazelrc index da79a94c9..77da08d9c 100644 --- a/.bazelrc +++ b/.bazelrc @@ -1,6 +1,5 @@ -# Switch to --noenable_workspace when Bzlmod lands. -# https://github.com/bazelbuild/rules_scala/issues/1482 -common --enable_workspace --noenable_bzlmod +# Remove once Bazel 8 becomes the default supported version. +common --noenable_workspace # Remove once proto toolchainization becomes the default # - https://bazel.build/reference/command-line-reference#flag--incompatible_enable_proto_toolchain_resolution 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..c06870558 --- /dev/null +++ b/MODULE.bazel @@ -0,0 +1,279 @@ +"""Bazel module definition for rules_scala""" + +module( + name = "rules_scala", + version = "7.0.0", + compatibility_level = 7, + bazel_compatibility = [">=7.5.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.16", +] + +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_dep(name = "platforms", version = "0.0.11") +bazel_dep(name = "rules_cc", version = "0.1.1") +bazel_dep(name = "rules_java", version = "8.9.0") +bazel_dep(name = "rules_proto", version = "7.1.0") + +bazel_dep( + name = "protobuf", + version = "29.3", + repo_name = "com_google_protobuf", +) + +# Required for `protoc` toolchainization until resolution of +# protocolbuffers/protobuf#19679. +single_version_override( + module_name = "protobuf", + version = "29.3", + patches = ["//protoc:0001-protobuf-19679-rm-protoc-dep.patch"], + patch_strip = 1, +) + +scala_config = use_extension( + "//scala/extensions:config.bzl", + "scala_config", +) +use_repo(scala_config, "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") + +# This is optional, but still safe to include even when not using +# `--incompatible_enable_proto_toolchain_resolution`. +register_toolchains("//protoc:all") + +# 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, + scalafmt = 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 = "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 = "1.2.0", dev_dependency = True) diff --git a/README.md b/README.md index dbf15995c..b3539b592 100644 --- a/README.md +++ b/README.md @@ -39,6 +39,85 @@ 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 `MODULE.bazel` file. + +```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") + +# This is optional, but still safe to include even when not using +# `--incompatible_enable_proto_toolchain_resolution`. +# See the "Using a precompiled protocol compiler" section below. +register_toolchains("@rules_scala//protoc:all") + +# 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.16") + +# 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 + +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 `WORKSPACE` configuration + +`rules_scala` 7.x enables existing users to migrate to Bzlmod. `WORKSPACE` +continues to work for Bazel [6.5.0 (for now)](#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 + Add the following configuration snippet to your `WORKSPACE` file and update the release `` and its `` as specified on the [rules_scala releases page][releases]. This snippet is designed to ensure that users pick up the @@ -324,7 +403,7 @@ maximum available at the time of writing. | Bazel/Dependency | `rules_scala` 7.x | | :-: | :-: | -| Bazel versions using Bzlmod
(Coming soon! See bazelbuild/rules_scala#1482.) | 7.5.0, 8.x | +| Bazel versions using Bzlmod | 7.5.0, 8.x | | Bazel versions using `WORKSPACE` | 6.5.0, 7.5.0, 8.x
(see the [notes on 6.5.0 compatibility](#6.5.0)) | | `protobuf` | v29.3 | | `abseil-cpp` | 20250127.0 | @@ -559,7 +638,7 @@ 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 @@ -657,12 +736,11 @@ supporting Bazel + MSVC builds per: Enable [protocol compiler toolchainization](#protoc) to fix broken Windows builds by avoiding `@com_google_protobuf//:protoc` recompilation. -### 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 snippet for the `scala_toolchains()` snippet above would be: ```py bazel_dep(name = "rules_scala", version = "7.0.0") @@ -685,7 +763,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 @@ -694,8 +772,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/docs/cross-compilation.md b/docs/cross-compilation.md index 1fbcbef75..144fcb541 100644 --- a/docs/cross-compilation.md +++ b/docs/cross-compilation.md @@ -22,7 +22,7 @@ scala_config = use_extension( ) scala_config.settings( - scala_version = "2.13.15", + scala_version = "2.13.16", # No need to include `scala_version` in `scala_versions`. scala_versions = [ "2.11.12", @@ -45,7 +45,7 @@ scala_config( scala_versions = [ "2.11.12", "2.12.20", - "2.13.15", + "2.13.16", "3.1.3", "3.2.2", "3.3.5", diff --git a/dt_patches/compiler_sources/MODULE.bazel b/dt_patches/compiler_sources/MODULE.bazel new file mode 100644 index 000000000..0ef3ed047 --- /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, "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 ac88e6591..6aec4a5f6 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..83a5731e1 --- /dev/null +++ b/dt_patches/test_dt_patches/MODULE.bazel @@ -0,0 +1,73 @@ +"""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 = "../..", +) + +scala_config = use_extension( + "@rules_scala//scala/extensions:config.bzl", + "scala_config", +) +scala_config.settings( + enable_compiler_dependency_tracking = True, +) +use_repo(scala_config, "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( + "@rules_scala//protoc:all", + "//:dt_scala_toolchain", +) + +# Required for `protoc` toolchainization until resolution of +# protocolbuffers/protobuf#19679. +bazel_dep( + name = "protobuf", + version = "29.3", + repo_name = "com_google_protobuf", +) + +single_version_override( + module_name = "protobuf", + version = "29.3", + patches = ["//:protobuf.patch"], + patch_strip = 1, +) 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/protobuf.patch b/dt_patches/test_dt_patches/protobuf.patch new file mode 100644 index 000000000..86d7d1b82 --- /dev/null +++ b/dt_patches/test_dt_patches/protobuf.patch @@ -0,0 +1,91 @@ +diff --git a/protobuf.bzl b/protobuf.bzl +index 283c85850..ad91faba6 100644 +--- a/protobuf.bzl ++++ b/protobuf.bzl +@@ -1,7 +1,9 @@ + load("@bazel_skylib//lib:versions.bzl", "versions") + load("@rules_cc//cc:defs.bzl", "objc_library") + load("@rules_python//python:defs.bzl", "py_library") ++load("//bazel/common:proto_common.bzl", "proto_common") + load("//bazel/common:proto_info.bzl", "ProtoInfo") ++load("//bazel/private:toolchain_helpers.bzl", "toolchains") + + def _GetPath(ctx, path): + if ctx.label.workspace_root: +@@ -71,6 +73,26 @@ def _CsharpOuts(srcs): + for src in srcs + ] + ++_PROTOC_ATTRS = toolchains.if_legacy_toolchain({ ++ "_proto_compiler": attr.label( ++ cfg = "exec", ++ executable = True, ++ allow_files = True, ++ default = configuration_field("proto", "proto_compiler"), ++ ), ++}) ++_PROTOC_FRAGMENTS = ["proto"] ++_PROTOC_TOOLCHAINS = toolchains.use_toolchain(toolchains.PROTO_TOOLCHAIN) ++ ++def _protoc_files_to_run(ctx): ++ if proto_common.INCOMPATIBLE_ENABLE_PROTO_TOOLCHAIN_RESOLUTION: ++ toolchain = ctx.toolchains[toolchains.PROTO_TOOLCHAIN] ++ if not toolchain: ++ fail("Protocol compiler toolchain could not be resolved.") ++ return toolchain.proto.proto_compiler ++ else: ++ return ctx.attr._proto_compiler[DefaultInfo].files_to_run ++ + ProtoGenInfo = provider( + fields = ["srcs", "import_flags", "deps"], + ) +@@ -310,7 +332,7 @@ def _internal_gen_well_known_protos_java_impl(ctx): + args.add_all([src.path[offset:] for src in dep.direct_sources]) + + ctx.actions.run( +- executable = ctx.executable._protoc, ++ executable = _protoc_files_to_run(ctx), + inputs = descriptors, + outputs = [srcjar], + arguments = [args], +@@ -334,12 +356,9 @@ internal_gen_well_known_protos_java = rule( + "javalite": attr.bool( + default = False, + ), +- "_protoc": attr.label( +- executable = True, +- cfg = "exec", +- default = "//:protoc", +- ), +- }, ++ } | _PROTOC_ATTRS, ++ fragments = _PROTOC_FRAGMENTS, ++ toolchains = _PROTOC_TOOLCHAINS, + ) + + def _internal_gen_kt_protos(ctx): +@@ -373,7 +392,7 @@ def _internal_gen_kt_protos(ctx): + args.add_all([src.path[offset:] for src in dep.direct_sources]) + + ctx.actions.run( +- executable = ctx.executable._protoc, ++ executable = _protoc_files_to_run(ctx), + inputs = descriptors, + outputs = [srcjar], + arguments = [args], +@@ -397,12 +416,9 @@ internal_gen_kt_protos = rule( + "lite": attr.bool( + default = False, + ), +- "_protoc": attr.label( +- executable = True, +- cfg = "exec", +- default = "//:protoc", +- ), +- }, ++ } | _PROTOC_ATTRS, ++ fragments = _PROTOC_FRAGMENTS, ++ toolchains = _PROTOC_TOOLCHAINS, + ) + + def internal_objc_proto_library( 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..b37a83fa2 --- /dev/null +++ b/dt_patches/test_dt_patches_user_srcjar/MODULE.bazel @@ -0,0 +1,189 @@ +"""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 = "../..", +) + +scala_config = use_extension( + "@rules_scala//scala/extensions:config.bzl", + "scala_config", +) +scala_config.settings( + enable_compiler_dependency_tracking = True, +) +use_repo(scala_config, "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/scala-compiler/2.13.16/scala-compiler-2.13.16-sources.jar?foo", + version = "2.13.16", +) +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( + "@rules_scala//protoc:all", + "//:dt_scala_toolchain", +) + +# Required for `protoc` toolchainization until resolution of +# protocolbuffers/protobuf#19679. +bazel_dep( + name = "protobuf", + version = "29.3", + repo_name = "com_google_protobuf", +) + +single_version_override( + module_name = "protobuf", + version = "29.3", + patches = ["//:protobuf.patch"], + patch_strip = 1, +) 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/dt_patches/test_dt_patches_user_srcjar/protobuf.patch b/dt_patches/test_dt_patches_user_srcjar/protobuf.patch new file mode 100644 index 000000000..86d7d1b82 --- /dev/null +++ b/dt_patches/test_dt_patches_user_srcjar/protobuf.patch @@ -0,0 +1,91 @@ +diff --git a/protobuf.bzl b/protobuf.bzl +index 283c85850..ad91faba6 100644 +--- a/protobuf.bzl ++++ b/protobuf.bzl +@@ -1,7 +1,9 @@ + load("@bazel_skylib//lib:versions.bzl", "versions") + load("@rules_cc//cc:defs.bzl", "objc_library") + load("@rules_python//python:defs.bzl", "py_library") ++load("//bazel/common:proto_common.bzl", "proto_common") + load("//bazel/common:proto_info.bzl", "ProtoInfo") ++load("//bazel/private:toolchain_helpers.bzl", "toolchains") + + def _GetPath(ctx, path): + if ctx.label.workspace_root: +@@ -71,6 +73,26 @@ def _CsharpOuts(srcs): + for src in srcs + ] + ++_PROTOC_ATTRS = toolchains.if_legacy_toolchain({ ++ "_proto_compiler": attr.label( ++ cfg = "exec", ++ executable = True, ++ allow_files = True, ++ default = configuration_field("proto", "proto_compiler"), ++ ), ++}) ++_PROTOC_FRAGMENTS = ["proto"] ++_PROTOC_TOOLCHAINS = toolchains.use_toolchain(toolchains.PROTO_TOOLCHAIN) ++ ++def _protoc_files_to_run(ctx): ++ if proto_common.INCOMPATIBLE_ENABLE_PROTO_TOOLCHAIN_RESOLUTION: ++ toolchain = ctx.toolchains[toolchains.PROTO_TOOLCHAIN] ++ if not toolchain: ++ fail("Protocol compiler toolchain could not be resolved.") ++ return toolchain.proto.proto_compiler ++ else: ++ return ctx.attr._proto_compiler[DefaultInfo].files_to_run ++ + ProtoGenInfo = provider( + fields = ["srcs", "import_flags", "deps"], + ) +@@ -310,7 +332,7 @@ def _internal_gen_well_known_protos_java_impl(ctx): + args.add_all([src.path[offset:] for src in dep.direct_sources]) + + ctx.actions.run( +- executable = ctx.executable._protoc, ++ executable = _protoc_files_to_run(ctx), + inputs = descriptors, + outputs = [srcjar], + arguments = [args], +@@ -334,12 +356,9 @@ internal_gen_well_known_protos_java = rule( + "javalite": attr.bool( + default = False, + ), +- "_protoc": attr.label( +- executable = True, +- cfg = "exec", +- default = "//:protoc", +- ), +- }, ++ } | _PROTOC_ATTRS, ++ fragments = _PROTOC_FRAGMENTS, ++ toolchains = _PROTOC_TOOLCHAINS, + ) + + def _internal_gen_kt_protos(ctx): +@@ -373,7 +392,7 @@ def _internal_gen_kt_protos(ctx): + args.add_all([src.path[offset:] for src in dep.direct_sources]) + + ctx.actions.run( +- executable = ctx.executable._protoc, ++ executable = _protoc_files_to_run(ctx), + inputs = descriptors, + outputs = [srcjar], + arguments = [args], +@@ -397,12 +416,9 @@ internal_gen_kt_protos = rule( + "lite": attr.bool( + default = False, + ), +- "_protoc": attr.label( +- executable = True, +- cfg = "exec", +- default = "//:protoc", +- ), +- }, ++ } | _PROTOC_ATTRS, ++ fragments = _PROTOC_FRAGMENTS, ++ toolchains = _PROTOC_TOOLCHAINS, + ) + + def internal_objc_proto_library( diff --git a/examples/crossbuild/BUILD b/examples/crossbuild/BUILD 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..a201f556d --- /dev/null +++ b/examples/crossbuild/MODULE.bazel @@ -0,0 +1,53 @@ +"""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 = "../..", +) + +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.16", + "3.3.5", + ], +) +use_repo(scala_config, "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, +) + +# This is optional, but still safe to include even when not using +# `--incompatible_enable_proto_toolchain_resolution`. +register_toolchains("@rules_scala//protoc:all") + +# Required for `protoc` toolchainization until resolution of +# protocolbuffers/protobuf#19679. +bazel_dep( + name = "protobuf", + version = "29.3", + repo_name = "com_google_protobuf", +) + +single_version_override( + module_name = "protobuf", + version = "29.3", + patches = ["//:protobuf.patch"], + patch_strip = 1, +) diff --git a/examples/crossbuild/WORKSPACE.bzlmod b/examples/crossbuild/WORKSPACE.bzlmod new file mode 100644 index 000000000..e69de29bb diff --git a/examples/crossbuild/protobuf.patch b/examples/crossbuild/protobuf.patch new file mode 100644 index 000000000..86d7d1b82 --- /dev/null +++ b/examples/crossbuild/protobuf.patch @@ -0,0 +1,91 @@ +diff --git a/protobuf.bzl b/protobuf.bzl +index 283c85850..ad91faba6 100644 +--- a/protobuf.bzl ++++ b/protobuf.bzl +@@ -1,7 +1,9 @@ + load("@bazel_skylib//lib:versions.bzl", "versions") + load("@rules_cc//cc:defs.bzl", "objc_library") + load("@rules_python//python:defs.bzl", "py_library") ++load("//bazel/common:proto_common.bzl", "proto_common") + load("//bazel/common:proto_info.bzl", "ProtoInfo") ++load("//bazel/private:toolchain_helpers.bzl", "toolchains") + + def _GetPath(ctx, path): + if ctx.label.workspace_root: +@@ -71,6 +73,26 @@ def _CsharpOuts(srcs): + for src in srcs + ] + ++_PROTOC_ATTRS = toolchains.if_legacy_toolchain({ ++ "_proto_compiler": attr.label( ++ cfg = "exec", ++ executable = True, ++ allow_files = True, ++ default = configuration_field("proto", "proto_compiler"), ++ ), ++}) ++_PROTOC_FRAGMENTS = ["proto"] ++_PROTOC_TOOLCHAINS = toolchains.use_toolchain(toolchains.PROTO_TOOLCHAIN) ++ ++def _protoc_files_to_run(ctx): ++ if proto_common.INCOMPATIBLE_ENABLE_PROTO_TOOLCHAIN_RESOLUTION: ++ toolchain = ctx.toolchains[toolchains.PROTO_TOOLCHAIN] ++ if not toolchain: ++ fail("Protocol compiler toolchain could not be resolved.") ++ return toolchain.proto.proto_compiler ++ else: ++ return ctx.attr._proto_compiler[DefaultInfo].files_to_run ++ + ProtoGenInfo = provider( + fields = ["srcs", "import_flags", "deps"], + ) +@@ -310,7 +332,7 @@ def _internal_gen_well_known_protos_java_impl(ctx): + args.add_all([src.path[offset:] for src in dep.direct_sources]) + + ctx.actions.run( +- executable = ctx.executable._protoc, ++ executable = _protoc_files_to_run(ctx), + inputs = descriptors, + outputs = [srcjar], + arguments = [args], +@@ -334,12 +356,9 @@ internal_gen_well_known_protos_java = rule( + "javalite": attr.bool( + default = False, + ), +- "_protoc": attr.label( +- executable = True, +- cfg = "exec", +- default = "//:protoc", +- ), +- }, ++ } | _PROTOC_ATTRS, ++ fragments = _PROTOC_FRAGMENTS, ++ toolchains = _PROTOC_TOOLCHAINS, + ) + + def _internal_gen_kt_protos(ctx): +@@ -373,7 +392,7 @@ def _internal_gen_kt_protos(ctx): + args.add_all([src.path[offset:] for src in dep.direct_sources]) + + ctx.actions.run( +- executable = ctx.executable._protoc, ++ executable = _protoc_files_to_run(ctx), + inputs = descriptors, + outputs = [srcjar], + arguments = [args], +@@ -397,12 +416,9 @@ internal_gen_kt_protos = rule( + "lite": attr.bool( + default = False, + ), +- "_protoc": attr.label( +- executable = True, +- cfg = "exec", +- default = "//:protoc", +- ), +- }, ++ } | _PROTOC_ATTRS, ++ fragments = _PROTOC_FRAGMENTS, ++ toolchains = _PROTOC_TOOLCHAINS, + ) + + def internal_objc_proto_library( diff --git a/examples/overridden_artifacts/MODULE.bazel b/examples/overridden_artifacts/MODULE.bazel new file mode 100644 index 000000000..0cc9234e5 --- /dev/null +++ b/examples/overridden_artifacts/MODULE.bazel @@ -0,0 +1,80 @@ +"""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 = "../..", +) + +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, +) + +# This is optional, but still safe to include even when not using +# `--incompatible_enable_proto_toolchain_resolution`. +register_toolchains("@rules_scala//protoc:all") + +# Required for `protoc` toolchainization until resolution of +# protocolbuffers/protobuf#19679. +bazel_dep( + name = "protobuf", + version = "29.3", + repo_name = "com_google_protobuf", +) + +single_version_override( + module_name = "protobuf", + version = "29.3", + patches = ["//:protobuf.patch"], + patch_strip = 1, +) 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/overridden_artifacts/protobuf.patch b/examples/overridden_artifacts/protobuf.patch new file mode 100644 index 000000000..86d7d1b82 --- /dev/null +++ b/examples/overridden_artifacts/protobuf.patch @@ -0,0 +1,91 @@ +diff --git a/protobuf.bzl b/protobuf.bzl +index 283c85850..ad91faba6 100644 +--- a/protobuf.bzl ++++ b/protobuf.bzl +@@ -1,7 +1,9 @@ + load("@bazel_skylib//lib:versions.bzl", "versions") + load("@rules_cc//cc:defs.bzl", "objc_library") + load("@rules_python//python:defs.bzl", "py_library") ++load("//bazel/common:proto_common.bzl", "proto_common") + load("//bazel/common:proto_info.bzl", "ProtoInfo") ++load("//bazel/private:toolchain_helpers.bzl", "toolchains") + + def _GetPath(ctx, path): + if ctx.label.workspace_root: +@@ -71,6 +73,26 @@ def _CsharpOuts(srcs): + for src in srcs + ] + ++_PROTOC_ATTRS = toolchains.if_legacy_toolchain({ ++ "_proto_compiler": attr.label( ++ cfg = "exec", ++ executable = True, ++ allow_files = True, ++ default = configuration_field("proto", "proto_compiler"), ++ ), ++}) ++_PROTOC_FRAGMENTS = ["proto"] ++_PROTOC_TOOLCHAINS = toolchains.use_toolchain(toolchains.PROTO_TOOLCHAIN) ++ ++def _protoc_files_to_run(ctx): ++ if proto_common.INCOMPATIBLE_ENABLE_PROTO_TOOLCHAIN_RESOLUTION: ++ toolchain = ctx.toolchains[toolchains.PROTO_TOOLCHAIN] ++ if not toolchain: ++ fail("Protocol compiler toolchain could not be resolved.") ++ return toolchain.proto.proto_compiler ++ else: ++ return ctx.attr._proto_compiler[DefaultInfo].files_to_run ++ + ProtoGenInfo = provider( + fields = ["srcs", "import_flags", "deps"], + ) +@@ -310,7 +332,7 @@ def _internal_gen_well_known_protos_java_impl(ctx): + args.add_all([src.path[offset:] for src in dep.direct_sources]) + + ctx.actions.run( +- executable = ctx.executable._protoc, ++ executable = _protoc_files_to_run(ctx), + inputs = descriptors, + outputs = [srcjar], + arguments = [args], +@@ -334,12 +356,9 @@ internal_gen_well_known_protos_java = rule( + "javalite": attr.bool( + default = False, + ), +- "_protoc": attr.label( +- executable = True, +- cfg = "exec", +- default = "//:protoc", +- ), +- }, ++ } | _PROTOC_ATTRS, ++ fragments = _PROTOC_FRAGMENTS, ++ toolchains = _PROTOC_TOOLCHAINS, + ) + + def _internal_gen_kt_protos(ctx): +@@ -373,7 +392,7 @@ def _internal_gen_kt_protos(ctx): + args.add_all([src.path[offset:] for src in dep.direct_sources]) + + ctx.actions.run( +- executable = ctx.executable._protoc, ++ executable = _protoc_files_to_run(ctx), + inputs = descriptors, + outputs = [srcjar], + arguments = [args], +@@ -397,12 +416,9 @@ internal_gen_kt_protos = rule( + "lite": attr.bool( + default = False, + ), +- "_protoc": attr.label( +- executable = True, +- cfg = "exec", +- default = "//:protoc", +- ), +- }, ++ } | _PROTOC_ATTRS, ++ fragments = _PROTOC_FRAGMENTS, ++ toolchains = _PROTOC_TOOLCHAINS, + ) + + def internal_objc_proto_library( diff --git a/examples/scala3/MODULE.bazel b/examples/scala3/MODULE.bazel new file mode 100644 index 000000000..bc4ae8b98 --- /dev/null +++ b/examples/scala3/MODULE.bazel @@ -0,0 +1,36 @@ +"""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 = "../..", +) + +scala_deps = use_extension( + "@rules_scala//scala/extensions:deps.bzl", + "scala_deps", +) +scala_deps.settings( + fetch_sources = True, +) + +# This is optional, but still safe to include even when not using +# `--incompatible_enable_proto_toolchain_resolution`. +register_toolchains("@rules_scala//protoc:all") + +# Required for `protoc` toolchainization until resolution of +# protocolbuffers/protobuf#19679. +bazel_dep( + name = "protobuf", + version = "29.3", + repo_name = "com_google_protobuf", +) + +single_version_override( + module_name = "protobuf", + version = "29.3", + patches = ["//:protobuf.patch"], + patch_strip = 1, +) diff --git a/examples/scala3/WORKSPACE.bzlmod b/examples/scala3/WORKSPACE.bzlmod new file mode 100644 index 000000000..e69de29bb diff --git a/examples/scala3/protobuf.patch b/examples/scala3/protobuf.patch new file mode 100644 index 000000000..86d7d1b82 --- /dev/null +++ b/examples/scala3/protobuf.patch @@ -0,0 +1,91 @@ +diff --git a/protobuf.bzl b/protobuf.bzl +index 283c85850..ad91faba6 100644 +--- a/protobuf.bzl ++++ b/protobuf.bzl +@@ -1,7 +1,9 @@ + load("@bazel_skylib//lib:versions.bzl", "versions") + load("@rules_cc//cc:defs.bzl", "objc_library") + load("@rules_python//python:defs.bzl", "py_library") ++load("//bazel/common:proto_common.bzl", "proto_common") + load("//bazel/common:proto_info.bzl", "ProtoInfo") ++load("//bazel/private:toolchain_helpers.bzl", "toolchains") + + def _GetPath(ctx, path): + if ctx.label.workspace_root: +@@ -71,6 +73,26 @@ def _CsharpOuts(srcs): + for src in srcs + ] + ++_PROTOC_ATTRS = toolchains.if_legacy_toolchain({ ++ "_proto_compiler": attr.label( ++ cfg = "exec", ++ executable = True, ++ allow_files = True, ++ default = configuration_field("proto", "proto_compiler"), ++ ), ++}) ++_PROTOC_FRAGMENTS = ["proto"] ++_PROTOC_TOOLCHAINS = toolchains.use_toolchain(toolchains.PROTO_TOOLCHAIN) ++ ++def _protoc_files_to_run(ctx): ++ if proto_common.INCOMPATIBLE_ENABLE_PROTO_TOOLCHAIN_RESOLUTION: ++ toolchain = ctx.toolchains[toolchains.PROTO_TOOLCHAIN] ++ if not toolchain: ++ fail("Protocol compiler toolchain could not be resolved.") ++ return toolchain.proto.proto_compiler ++ else: ++ return ctx.attr._proto_compiler[DefaultInfo].files_to_run ++ + ProtoGenInfo = provider( + fields = ["srcs", "import_flags", "deps"], + ) +@@ -310,7 +332,7 @@ def _internal_gen_well_known_protos_java_impl(ctx): + args.add_all([src.path[offset:] for src in dep.direct_sources]) + + ctx.actions.run( +- executable = ctx.executable._protoc, ++ executable = _protoc_files_to_run(ctx), + inputs = descriptors, + outputs = [srcjar], + arguments = [args], +@@ -334,12 +356,9 @@ internal_gen_well_known_protos_java = rule( + "javalite": attr.bool( + default = False, + ), +- "_protoc": attr.label( +- executable = True, +- cfg = "exec", +- default = "//:protoc", +- ), +- }, ++ } | _PROTOC_ATTRS, ++ fragments = _PROTOC_FRAGMENTS, ++ toolchains = _PROTOC_TOOLCHAINS, + ) + + def _internal_gen_kt_protos(ctx): +@@ -373,7 +392,7 @@ def _internal_gen_kt_protos(ctx): + args.add_all([src.path[offset:] for src in dep.direct_sources]) + + ctx.actions.run( +- executable = ctx.executable._protoc, ++ executable = _protoc_files_to_run(ctx), + inputs = descriptors, + outputs = [srcjar], + arguments = [args], +@@ -397,12 +416,9 @@ internal_gen_kt_protos = rule( + "lite": attr.bool( + default = False, + ), +- "_protoc": attr.label( +- executable = True, +- cfg = "exec", +- default = "//:protoc", +- ), +- }, ++ } | _PROTOC_ATTRS, ++ fragments = _PROTOC_FRAGMENTS, ++ toolchains = _PROTOC_TOOLCHAINS, + ) + + def internal_objc_proto_library( diff --git a/examples/semanticdb/MODULE.bazel b/examples/semanticdb/MODULE.bazel new file mode 100644 index 000000000..82e089bb6 --- /dev/null +++ b/examples/semanticdb/MODULE.bazel @@ -0,0 +1,46 @@ +"""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 = "../..", +) + +scala_config = use_extension( + "@rules_scala//scala/extensions:config.bzl", + "scala_config", +) +scala_config.settings( + scala_version = "2.13.16", +) + +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( + "@rules_scala//protoc:all", + "//:semanticdb_toolchain", +) + +# Required for `protoc` toolchainization until resolution of +# protocolbuffers/protobuf#19679. +bazel_dep( + name = "protobuf", + version = "29.3", + repo_name = "com_google_protobuf", +) + +single_version_override( + module_name = "protobuf", + version = "29.3", + patches = ["//:protobuf.patch"], + patch_strip = 1, +) diff --git a/examples/semanticdb/WORKSPACE.bzlmod b/examples/semanticdb/WORKSPACE.bzlmod new file mode 100644 index 000000000..e69de29bb diff --git a/examples/semanticdb/protobuf.patch b/examples/semanticdb/protobuf.patch new file mode 100644 index 000000000..86d7d1b82 --- /dev/null +++ b/examples/semanticdb/protobuf.patch @@ -0,0 +1,91 @@ +diff --git a/protobuf.bzl b/protobuf.bzl +index 283c85850..ad91faba6 100644 +--- a/protobuf.bzl ++++ b/protobuf.bzl +@@ -1,7 +1,9 @@ + load("@bazel_skylib//lib:versions.bzl", "versions") + load("@rules_cc//cc:defs.bzl", "objc_library") + load("@rules_python//python:defs.bzl", "py_library") ++load("//bazel/common:proto_common.bzl", "proto_common") + load("//bazel/common:proto_info.bzl", "ProtoInfo") ++load("//bazel/private:toolchain_helpers.bzl", "toolchains") + + def _GetPath(ctx, path): + if ctx.label.workspace_root: +@@ -71,6 +73,26 @@ def _CsharpOuts(srcs): + for src in srcs + ] + ++_PROTOC_ATTRS = toolchains.if_legacy_toolchain({ ++ "_proto_compiler": attr.label( ++ cfg = "exec", ++ executable = True, ++ allow_files = True, ++ default = configuration_field("proto", "proto_compiler"), ++ ), ++}) ++_PROTOC_FRAGMENTS = ["proto"] ++_PROTOC_TOOLCHAINS = toolchains.use_toolchain(toolchains.PROTO_TOOLCHAIN) ++ ++def _protoc_files_to_run(ctx): ++ if proto_common.INCOMPATIBLE_ENABLE_PROTO_TOOLCHAIN_RESOLUTION: ++ toolchain = ctx.toolchains[toolchains.PROTO_TOOLCHAIN] ++ if not toolchain: ++ fail("Protocol compiler toolchain could not be resolved.") ++ return toolchain.proto.proto_compiler ++ else: ++ return ctx.attr._proto_compiler[DefaultInfo].files_to_run ++ + ProtoGenInfo = provider( + fields = ["srcs", "import_flags", "deps"], + ) +@@ -310,7 +332,7 @@ def _internal_gen_well_known_protos_java_impl(ctx): + args.add_all([src.path[offset:] for src in dep.direct_sources]) + + ctx.actions.run( +- executable = ctx.executable._protoc, ++ executable = _protoc_files_to_run(ctx), + inputs = descriptors, + outputs = [srcjar], + arguments = [args], +@@ -334,12 +356,9 @@ internal_gen_well_known_protos_java = rule( + "javalite": attr.bool( + default = False, + ), +- "_protoc": attr.label( +- executable = True, +- cfg = "exec", +- default = "//:protoc", +- ), +- }, ++ } | _PROTOC_ATTRS, ++ fragments = _PROTOC_FRAGMENTS, ++ toolchains = _PROTOC_TOOLCHAINS, + ) + + def _internal_gen_kt_protos(ctx): +@@ -373,7 +392,7 @@ def _internal_gen_kt_protos(ctx): + args.add_all([src.path[offset:] for src in dep.direct_sources]) + + ctx.actions.run( +- executable = ctx.executable._protoc, ++ executable = _protoc_files_to_run(ctx), + inputs = descriptors, + outputs = [srcjar], + arguments = [args], +@@ -397,12 +416,9 @@ internal_gen_kt_protos = rule( + "lite": attr.bool( + default = False, + ), +- "_protoc": attr.label( +- executable = True, +- cfg = "exec", +- default = "//:protoc", +- ), +- }, ++ } | _PROTOC_ATTRS, ++ fragments = _PROTOC_FRAGMENTS, ++ toolchains = _PROTOC_TOOLCHAINS, + ) + + def internal_objc_proto_library( diff --git a/examples/testing/multi_frameworks_toolchain/MODULE.bazel b/examples/testing/multi_frameworks_toolchain/MODULE.bazel new file mode 100644 index 000000000..7d6184517 --- /dev/null +++ b/examples/testing/multi_frameworks_toolchain/MODULE.bazel @@ -0,0 +1,88 @@ +"""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 = "../../..", +) + +scala_config = use_extension( + "@rules_scala//scala/extensions:config.bzl", + "scala_config", +) +scala_config.settings( + scala_version = SCALA_VERSION, +) +use_repo(scala_config, "rules_scala_config") + +scala_deps = use_extension( + "@rules_scala//scala/extensions:deps.bzl", + "scala_deps", +) +scala_deps.settings( + fetch_sources = True, +) + +scala_deps.toolchains( + junit = True, + 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( + "@rules_scala//protoc:all", + "//:testing_toolchain", +) + +# Required for `protoc` toolchainization until resolution of +# protocolbuffers/protobuf#19679. +bazel_dep( + name = "protobuf", + version = "29.3", + repo_name = "com_google_protobuf", +) + +single_version_override( + module_name = "protobuf", + version = "29.3", + patches = ["//:protobuf.patch"], + patch_strip = 1, +) 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/multi_frameworks_toolchain/protobuf.patch b/examples/testing/multi_frameworks_toolchain/protobuf.patch new file mode 100644 index 000000000..86d7d1b82 --- /dev/null +++ b/examples/testing/multi_frameworks_toolchain/protobuf.patch @@ -0,0 +1,91 @@ +diff --git a/protobuf.bzl b/protobuf.bzl +index 283c85850..ad91faba6 100644 +--- a/protobuf.bzl ++++ b/protobuf.bzl +@@ -1,7 +1,9 @@ + load("@bazel_skylib//lib:versions.bzl", "versions") + load("@rules_cc//cc:defs.bzl", "objc_library") + load("@rules_python//python:defs.bzl", "py_library") ++load("//bazel/common:proto_common.bzl", "proto_common") + load("//bazel/common:proto_info.bzl", "ProtoInfo") ++load("//bazel/private:toolchain_helpers.bzl", "toolchains") + + def _GetPath(ctx, path): + if ctx.label.workspace_root: +@@ -71,6 +73,26 @@ def _CsharpOuts(srcs): + for src in srcs + ] + ++_PROTOC_ATTRS = toolchains.if_legacy_toolchain({ ++ "_proto_compiler": attr.label( ++ cfg = "exec", ++ executable = True, ++ allow_files = True, ++ default = configuration_field("proto", "proto_compiler"), ++ ), ++}) ++_PROTOC_FRAGMENTS = ["proto"] ++_PROTOC_TOOLCHAINS = toolchains.use_toolchain(toolchains.PROTO_TOOLCHAIN) ++ ++def _protoc_files_to_run(ctx): ++ if proto_common.INCOMPATIBLE_ENABLE_PROTO_TOOLCHAIN_RESOLUTION: ++ toolchain = ctx.toolchains[toolchains.PROTO_TOOLCHAIN] ++ if not toolchain: ++ fail("Protocol compiler toolchain could not be resolved.") ++ return toolchain.proto.proto_compiler ++ else: ++ return ctx.attr._proto_compiler[DefaultInfo].files_to_run ++ + ProtoGenInfo = provider( + fields = ["srcs", "import_flags", "deps"], + ) +@@ -310,7 +332,7 @@ def _internal_gen_well_known_protos_java_impl(ctx): + args.add_all([src.path[offset:] for src in dep.direct_sources]) + + ctx.actions.run( +- executable = ctx.executable._protoc, ++ executable = _protoc_files_to_run(ctx), + inputs = descriptors, + outputs = [srcjar], + arguments = [args], +@@ -334,12 +356,9 @@ internal_gen_well_known_protos_java = rule( + "javalite": attr.bool( + default = False, + ), +- "_protoc": attr.label( +- executable = True, +- cfg = "exec", +- default = "//:protoc", +- ), +- }, ++ } | _PROTOC_ATTRS, ++ fragments = _PROTOC_FRAGMENTS, ++ toolchains = _PROTOC_TOOLCHAINS, + ) + + def _internal_gen_kt_protos(ctx): +@@ -373,7 +392,7 @@ def _internal_gen_kt_protos(ctx): + args.add_all([src.path[offset:] for src in dep.direct_sources]) + + ctx.actions.run( +- executable = ctx.executable._protoc, ++ executable = _protoc_files_to_run(ctx), + inputs = descriptors, + outputs = [srcjar], + arguments = [args], +@@ -397,12 +416,9 @@ internal_gen_kt_protos = rule( + "lite": attr.bool( + default = False, + ), +- "_protoc": attr.label( +- executable = True, +- cfg = "exec", +- default = "//:protoc", +- ), +- }, ++ } | _PROTOC_ATTRS, ++ fragments = _PROTOC_FRAGMENTS, ++ toolchains = _PROTOC_TOOLCHAINS, + ) + + def internal_objc_proto_library( diff --git a/examples/testing/scalatest_repositories/MODULE.bazel b/examples/testing/scalatest_repositories/MODULE.bazel new file mode 100644 index 000000000..09d1e0ece --- /dev/null +++ b/examples/testing/scalatest_repositories/MODULE.bazel @@ -0,0 +1,39 @@ +"""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 = "../../..", +) + +scala_deps = use_extension( + "@rules_scala//scala/extensions:deps.bzl", + "scala_deps", +) +scala_deps.settings( + fetch_sources = True, +) +scala_deps.toolchains( + scalatest = True, +) + +# This is optional, but still safe to include even when not using +# `--incompatible_enable_proto_toolchain_resolution`. +register_toolchains("@rules_scala//protoc:all") + +# Required for `protoc` toolchainization until resolution of +# protocolbuffers/protobuf#19679. +bazel_dep( + name = "protobuf", + version = "29.3", + repo_name = "com_google_protobuf", +) + +single_version_override( + module_name = "protobuf", + version = "29.3", + patches = ["//:protobuf.patch"], + patch_strip = 1, +) 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/scalatest_repositories/protobuf.patch b/examples/testing/scalatest_repositories/protobuf.patch new file mode 100644 index 000000000..86d7d1b82 --- /dev/null +++ b/examples/testing/scalatest_repositories/protobuf.patch @@ -0,0 +1,91 @@ +diff --git a/protobuf.bzl b/protobuf.bzl +index 283c85850..ad91faba6 100644 +--- a/protobuf.bzl ++++ b/protobuf.bzl +@@ -1,7 +1,9 @@ + load("@bazel_skylib//lib:versions.bzl", "versions") + load("@rules_cc//cc:defs.bzl", "objc_library") + load("@rules_python//python:defs.bzl", "py_library") ++load("//bazel/common:proto_common.bzl", "proto_common") + load("//bazel/common:proto_info.bzl", "ProtoInfo") ++load("//bazel/private:toolchain_helpers.bzl", "toolchains") + + def _GetPath(ctx, path): + if ctx.label.workspace_root: +@@ -71,6 +73,26 @@ def _CsharpOuts(srcs): + for src in srcs + ] + ++_PROTOC_ATTRS = toolchains.if_legacy_toolchain({ ++ "_proto_compiler": attr.label( ++ cfg = "exec", ++ executable = True, ++ allow_files = True, ++ default = configuration_field("proto", "proto_compiler"), ++ ), ++}) ++_PROTOC_FRAGMENTS = ["proto"] ++_PROTOC_TOOLCHAINS = toolchains.use_toolchain(toolchains.PROTO_TOOLCHAIN) ++ ++def _protoc_files_to_run(ctx): ++ if proto_common.INCOMPATIBLE_ENABLE_PROTO_TOOLCHAIN_RESOLUTION: ++ toolchain = ctx.toolchains[toolchains.PROTO_TOOLCHAIN] ++ if not toolchain: ++ fail("Protocol compiler toolchain could not be resolved.") ++ return toolchain.proto.proto_compiler ++ else: ++ return ctx.attr._proto_compiler[DefaultInfo].files_to_run ++ + ProtoGenInfo = provider( + fields = ["srcs", "import_flags", "deps"], + ) +@@ -310,7 +332,7 @@ def _internal_gen_well_known_protos_java_impl(ctx): + args.add_all([src.path[offset:] for src in dep.direct_sources]) + + ctx.actions.run( +- executable = ctx.executable._protoc, ++ executable = _protoc_files_to_run(ctx), + inputs = descriptors, + outputs = [srcjar], + arguments = [args], +@@ -334,12 +356,9 @@ internal_gen_well_known_protos_java = rule( + "javalite": attr.bool( + default = False, + ), +- "_protoc": attr.label( +- executable = True, +- cfg = "exec", +- default = "//:protoc", +- ), +- }, ++ } | _PROTOC_ATTRS, ++ fragments = _PROTOC_FRAGMENTS, ++ toolchains = _PROTOC_TOOLCHAINS, + ) + + def _internal_gen_kt_protos(ctx): +@@ -373,7 +392,7 @@ def _internal_gen_kt_protos(ctx): + args.add_all([src.path[offset:] for src in dep.direct_sources]) + + ctx.actions.run( +- executable = ctx.executable._protoc, ++ executable = _protoc_files_to_run(ctx), + inputs = descriptors, + outputs = [srcjar], + arguments = [args], +@@ -397,12 +416,9 @@ internal_gen_kt_protos = rule( + "lite": attr.bool( + default = False, + ), +- "_protoc": attr.label( +- executable = True, +- cfg = "exec", +- default = "//:protoc", +- ), +- }, ++ } | _PROTOC_ATTRS, ++ fragments = _PROTOC_FRAGMENTS, ++ toolchains = _PROTOC_TOOLCHAINS, + ) + + def internal_objc_proto_library( diff --git a/examples/testing/specs2_junit_repositories/MODULE.bazel b/examples/testing/specs2_junit_repositories/MODULE.bazel new file mode 100644 index 000000000..5c2a799ba --- /dev/null +++ b/examples/testing/specs2_junit_repositories/MODULE.bazel @@ -0,0 +1,39 @@ +"""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 = "../../..", +) + +scala_deps = use_extension( + "@rules_scala//scala/extensions:deps.bzl", + "scala_deps", +) +scala_deps.settings( + fetch_sources = True, +) +scala_deps.toolchains( + specs2 = True, +) + +# This is optional, but still safe to include even when not using +# `--incompatible_enable_proto_toolchain_resolution`. +register_toolchains("@rules_scala//protoc:all") + +# Required for `protoc` toolchainization until resolution of +# protocolbuffers/protobuf#19679. +bazel_dep( + name = "protobuf", + version = "29.3", + repo_name = "com_google_protobuf", +) + +single_version_override( + module_name = "protobuf", + version = "29.3", + patches = ["//:protobuf.patch"], + patch_strip = 1, +) 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/examples/testing/specs2_junit_repositories/protobuf.patch b/examples/testing/specs2_junit_repositories/protobuf.patch new file mode 100644 index 000000000..86d7d1b82 --- /dev/null +++ b/examples/testing/specs2_junit_repositories/protobuf.patch @@ -0,0 +1,91 @@ +diff --git a/protobuf.bzl b/protobuf.bzl +index 283c85850..ad91faba6 100644 +--- a/protobuf.bzl ++++ b/protobuf.bzl +@@ -1,7 +1,9 @@ + load("@bazel_skylib//lib:versions.bzl", "versions") + load("@rules_cc//cc:defs.bzl", "objc_library") + load("@rules_python//python:defs.bzl", "py_library") ++load("//bazel/common:proto_common.bzl", "proto_common") + load("//bazel/common:proto_info.bzl", "ProtoInfo") ++load("//bazel/private:toolchain_helpers.bzl", "toolchains") + + def _GetPath(ctx, path): + if ctx.label.workspace_root: +@@ -71,6 +73,26 @@ def _CsharpOuts(srcs): + for src in srcs + ] + ++_PROTOC_ATTRS = toolchains.if_legacy_toolchain({ ++ "_proto_compiler": attr.label( ++ cfg = "exec", ++ executable = True, ++ allow_files = True, ++ default = configuration_field("proto", "proto_compiler"), ++ ), ++}) ++_PROTOC_FRAGMENTS = ["proto"] ++_PROTOC_TOOLCHAINS = toolchains.use_toolchain(toolchains.PROTO_TOOLCHAIN) ++ ++def _protoc_files_to_run(ctx): ++ if proto_common.INCOMPATIBLE_ENABLE_PROTO_TOOLCHAIN_RESOLUTION: ++ toolchain = ctx.toolchains[toolchains.PROTO_TOOLCHAIN] ++ if not toolchain: ++ fail("Protocol compiler toolchain could not be resolved.") ++ return toolchain.proto.proto_compiler ++ else: ++ return ctx.attr._proto_compiler[DefaultInfo].files_to_run ++ + ProtoGenInfo = provider( + fields = ["srcs", "import_flags", "deps"], + ) +@@ -310,7 +332,7 @@ def _internal_gen_well_known_protos_java_impl(ctx): + args.add_all([src.path[offset:] for src in dep.direct_sources]) + + ctx.actions.run( +- executable = ctx.executable._protoc, ++ executable = _protoc_files_to_run(ctx), + inputs = descriptors, + outputs = [srcjar], + arguments = [args], +@@ -334,12 +356,9 @@ internal_gen_well_known_protos_java = rule( + "javalite": attr.bool( + default = False, + ), +- "_protoc": attr.label( +- executable = True, +- cfg = "exec", +- default = "//:protoc", +- ), +- }, ++ } | _PROTOC_ATTRS, ++ fragments = _PROTOC_FRAGMENTS, ++ toolchains = _PROTOC_TOOLCHAINS, + ) + + def _internal_gen_kt_protos(ctx): +@@ -373,7 +392,7 @@ def _internal_gen_kt_protos(ctx): + args.add_all([src.path[offset:] for src in dep.direct_sources]) + + ctx.actions.run( +- executable = ctx.executable._protoc, ++ executable = _protoc_files_to_run(ctx), + inputs = descriptors, + outputs = [srcjar], + arguments = [args], +@@ -397,12 +416,9 @@ internal_gen_kt_protos = rule( + "lite": attr.bool( + default = False, + ), +- "_protoc": attr.label( +- executable = True, +- cfg = "exec", +- default = "//:protoc", +- ), +- }, ++ } | _PROTOC_ATTRS, ++ fragments = _PROTOC_FRAGMENTS, ++ toolchains = _PROTOC_TOOLCHAINS, + ) + + def internal_objc_proto_library( 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..7592267da --- /dev/null +++ b/scala/extensions/deps.bzl @@ -0,0 +1,267 @@ +"""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, + "protoc_platforms": [], +} + +_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" + ), + ), + "protoc_platforms": attr.string_list( + default = _settings_defaults["protoc_platforms"], + doc = ( + "Operating system and architecture identifiers for " + + "precompiled protocol compiler releases. If unspecified, will " + + "use the identifier matching the `HOST_CONSTRAINTS` from " + + "`@platforms//host:constraints.bzl`. Only takes effect when " + + "`--incompatible_enable_proto_toolchain_resolution` is `True`." + ), + ), +} + +_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, + "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", + ), + "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, + ), + # `None` breaks the `attr.string_dict` in `scala_toolchains_repo`. + 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/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..92ec10e2f --- /dev/null +++ b/scala/private/macros/test/MODULE.bzlmod_test @@ -0,0 +1,18 @@ +"""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}" +) + +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..99c553886 --- /dev/null +++ b/scala/private/macros/test/MODULE.bzlmod_test_root_module @@ -0,0 +1,19 @@ +"""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}" +) 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/test/proto_cross_repo_boundary/repo/MODULE.bazel b/test/proto_cross_repo_boundary/repo/MODULE.bazel new file mode 100644 index 000000000..20f4e4b26 --- /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 = "7.1.0") 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..6e090b15f --- /dev/null +++ b/test/shell/test_bzlmod_macros.sh @@ -0,0 +1,225 @@ +#!/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 + +if [[ "$(bazel --version)" =~ ^bazel\ 6\. ]]; then + exit +fi + +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_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/BUILD b/test_cross_build/BUILD new file mode 100644 index 000000000..e69de29bb diff --git a/test_cross_build/MODULE.bazel b/test_cross_build/MODULE.bazel new file mode 100644 index 000000000..8502ff6c7 --- /dev/null +++ b/test_cross_build/MODULE.bazel @@ -0,0 +1,57 @@ +"""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 = "..", +) + +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.16", + "3.1.3", + "3.2.2", + "3.3.5", + ], +) +use_repo(scala_config, "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, +) + +# This is optional, but still safe to include even when not using +# `--incompatible_enable_proto_toolchain_resolution`. +register_toolchains("@rules_scala//protoc:all") + +# Required for `protoc` toolchainization until resolution of +# protocolbuffers/protobuf#19679. +bazel_dep( + name = "protobuf", + version = "29.3", + repo_name = "com_google_protobuf", +) + +single_version_override( + module_name = "protobuf", + version = "29.3", + patches = ["//:protobuf.patch"], + patch_strip = 1, +) 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_cross_build/protobuf.patch b/test_cross_build/protobuf.patch new file mode 100644 index 000000000..86d7d1b82 --- /dev/null +++ b/test_cross_build/protobuf.patch @@ -0,0 +1,91 @@ +diff --git a/protobuf.bzl b/protobuf.bzl +index 283c85850..ad91faba6 100644 +--- a/protobuf.bzl ++++ b/protobuf.bzl +@@ -1,7 +1,9 @@ + load("@bazel_skylib//lib:versions.bzl", "versions") + load("@rules_cc//cc:defs.bzl", "objc_library") + load("@rules_python//python:defs.bzl", "py_library") ++load("//bazel/common:proto_common.bzl", "proto_common") + load("//bazel/common:proto_info.bzl", "ProtoInfo") ++load("//bazel/private:toolchain_helpers.bzl", "toolchains") + + def _GetPath(ctx, path): + if ctx.label.workspace_root: +@@ -71,6 +73,26 @@ def _CsharpOuts(srcs): + for src in srcs + ] + ++_PROTOC_ATTRS = toolchains.if_legacy_toolchain({ ++ "_proto_compiler": attr.label( ++ cfg = "exec", ++ executable = True, ++ allow_files = True, ++ default = configuration_field("proto", "proto_compiler"), ++ ), ++}) ++_PROTOC_FRAGMENTS = ["proto"] ++_PROTOC_TOOLCHAINS = toolchains.use_toolchain(toolchains.PROTO_TOOLCHAIN) ++ ++def _protoc_files_to_run(ctx): ++ if proto_common.INCOMPATIBLE_ENABLE_PROTO_TOOLCHAIN_RESOLUTION: ++ toolchain = ctx.toolchains[toolchains.PROTO_TOOLCHAIN] ++ if not toolchain: ++ fail("Protocol compiler toolchain could not be resolved.") ++ return toolchain.proto.proto_compiler ++ else: ++ return ctx.attr._proto_compiler[DefaultInfo].files_to_run ++ + ProtoGenInfo = provider( + fields = ["srcs", "import_flags", "deps"], + ) +@@ -310,7 +332,7 @@ def _internal_gen_well_known_protos_java_impl(ctx): + args.add_all([src.path[offset:] for src in dep.direct_sources]) + + ctx.actions.run( +- executable = ctx.executable._protoc, ++ executable = _protoc_files_to_run(ctx), + inputs = descriptors, + outputs = [srcjar], + arguments = [args], +@@ -334,12 +356,9 @@ internal_gen_well_known_protos_java = rule( + "javalite": attr.bool( + default = False, + ), +- "_protoc": attr.label( +- executable = True, +- cfg = "exec", +- default = "//:protoc", +- ), +- }, ++ } | _PROTOC_ATTRS, ++ fragments = _PROTOC_FRAGMENTS, ++ toolchains = _PROTOC_TOOLCHAINS, + ) + + def _internal_gen_kt_protos(ctx): +@@ -373,7 +392,7 @@ def _internal_gen_kt_protos(ctx): + args.add_all([src.path[offset:] for src in dep.direct_sources]) + + ctx.actions.run( +- executable = ctx.executable._protoc, ++ executable = _protoc_files_to_run(ctx), + inputs = descriptors, + outputs = [srcjar], + arguments = [args], +@@ -397,12 +416,9 @@ internal_gen_kt_protos = rule( + "lite": attr.bool( + default = False, + ), +- "_protoc": attr.label( +- executable = True, +- cfg = "exec", +- default = "//:protoc", +- ), +- }, ++ } | _PROTOC_ATTRS, ++ fragments = _PROTOC_FRAGMENTS, ++ toolchains = _PROTOC_TOOLCHAINS, + ) + + def internal_objc_proto_library( 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 2ca1ee6e6..aa3b0482d 100755 --- a/test_version.sh +++ b/test_version.sh @@ -42,15 +42,22 @@ 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/ + cp ../protoc/0001-protobuf-19679-rm-protoc-dep.patch \ + $NEW_TEST_DIR/protobuf.patch cd $NEW_TEST_DIR diff --git a/test_version/MODULE.bazel.template b/test_version/MODULE.bazel.template new file mode 100644 index 000000000..fad408428 --- /dev/null +++ b/test_version/MODULE.bazel.template @@ -0,0 +1,74 @@ +"""Bazel module template for //:test_version.sh tests""" + +module(name = "rules_scala_test_version") + +bazel_dep(name = "rules_java", version = "8.9.0") +bazel_dep(name = "rules_proto", version = "7.1.0") +bazel_dep(name = "rules_cc", version = "0.1.1") + +bazel_dep( + name = "protobuf", + version = "29.3", + repo_name = "com_google_protobuf", +) + +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, "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//protoc:all", + "@rules_scala//scala:unused_dependency_checker_error_toolchain", + "@twitter_scrooge_test_toolchain//...:all", +) + +# Required for `protoc` toolchainization until resolution of +# protocolbuffers/protobuf#19679. +single_version_override( + module_name = "protobuf", + version = "29.3", + patches = ["//:protobuf.patch"], + patch_strip = 1, +) diff --git a/test_version/protobuf.patch b/test_version/protobuf.patch new file mode 100644 index 000000000..86d7d1b82 --- /dev/null +++ b/test_version/protobuf.patch @@ -0,0 +1,91 @@ +diff --git a/protobuf.bzl b/protobuf.bzl +index 283c85850..ad91faba6 100644 +--- a/protobuf.bzl ++++ b/protobuf.bzl +@@ -1,7 +1,9 @@ + load("@bazel_skylib//lib:versions.bzl", "versions") + load("@rules_cc//cc:defs.bzl", "objc_library") + load("@rules_python//python:defs.bzl", "py_library") ++load("//bazel/common:proto_common.bzl", "proto_common") + load("//bazel/common:proto_info.bzl", "ProtoInfo") ++load("//bazel/private:toolchain_helpers.bzl", "toolchains") + + def _GetPath(ctx, path): + if ctx.label.workspace_root: +@@ -71,6 +73,26 @@ def _CsharpOuts(srcs): + for src in srcs + ] + ++_PROTOC_ATTRS = toolchains.if_legacy_toolchain({ ++ "_proto_compiler": attr.label( ++ cfg = "exec", ++ executable = True, ++ allow_files = True, ++ default = configuration_field("proto", "proto_compiler"), ++ ), ++}) ++_PROTOC_FRAGMENTS = ["proto"] ++_PROTOC_TOOLCHAINS = toolchains.use_toolchain(toolchains.PROTO_TOOLCHAIN) ++ ++def _protoc_files_to_run(ctx): ++ if proto_common.INCOMPATIBLE_ENABLE_PROTO_TOOLCHAIN_RESOLUTION: ++ toolchain = ctx.toolchains[toolchains.PROTO_TOOLCHAIN] ++ if not toolchain: ++ fail("Protocol compiler toolchain could not be resolved.") ++ return toolchain.proto.proto_compiler ++ else: ++ return ctx.attr._proto_compiler[DefaultInfo].files_to_run ++ + ProtoGenInfo = provider( + fields = ["srcs", "import_flags", "deps"], + ) +@@ -310,7 +332,7 @@ def _internal_gen_well_known_protos_java_impl(ctx): + args.add_all([src.path[offset:] for src in dep.direct_sources]) + + ctx.actions.run( +- executable = ctx.executable._protoc, ++ executable = _protoc_files_to_run(ctx), + inputs = descriptors, + outputs = [srcjar], + arguments = [args], +@@ -334,12 +356,9 @@ internal_gen_well_known_protos_java = rule( + "javalite": attr.bool( + default = False, + ), +- "_protoc": attr.label( +- executable = True, +- cfg = "exec", +- default = "//:protoc", +- ), +- }, ++ } | _PROTOC_ATTRS, ++ fragments = _PROTOC_FRAGMENTS, ++ toolchains = _PROTOC_TOOLCHAINS, + ) + + def _internal_gen_kt_protos(ctx): +@@ -373,7 +392,7 @@ def _internal_gen_kt_protos(ctx): + args.add_all([src.path[offset:] for src in dep.direct_sources]) + + ctx.actions.run( +- executable = ctx.executable._protoc, ++ executable = _protoc_files_to_run(ctx), + inputs = descriptors, + outputs = [srcjar], + arguments = [args], +@@ -397,12 +416,9 @@ internal_gen_kt_protos = rule( + "lite": attr.bool( + default = False, + ), +- "_protoc": attr.label( +- executable = True, +- cfg = "exec", +- default = "//:protoc", +- ), +- }, ++ } | _PROTOC_ATTRS, ++ fragments = _PROTOC_FRAGMENTS, ++ toolchains = _PROTOC_TOOLCHAINS, + ) + + def internal_objc_proto_library( diff --git a/test_version/version_specific_tests_dir/scrooge_repositories.bzl b/test_version/version_specific_tests_dir/scrooge_repositories.bzl index b6a1ba08b..9f7ba5440 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/BUILD b/third_party/test/example_external_workspace/BUILD new file mode 100644 index 000000000..e69de29bb 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..3c76583b2 --- /dev/null +++ b/third_party/test/example_external_workspace/MODULE.bazel @@ -0,0 +1,36 @@ +"""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, +) + +# This is optional, but still safe to include even when not using +# `--incompatible_enable_proto_toolchain_resolution`. +register_toolchains("@rules_scala//protoc:all") + +# Required for `protoc` toolchainization until resolution of +# protocolbuffers/protobuf#19679. +bazel_dep( + name = "protobuf", + version = "29.3", + repo_name = "com_google_protobuf", +) + +single_version_override( + module_name = "protobuf", + version = "29.3", + patches = ["//:protobuf.patch"], + patch_strip = 1, +) 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/example_external_workspace/protobuf.patch b/third_party/test/example_external_workspace/protobuf.patch new file mode 100644 index 000000000..86d7d1b82 --- /dev/null +++ b/third_party/test/example_external_workspace/protobuf.patch @@ -0,0 +1,91 @@ +diff --git a/protobuf.bzl b/protobuf.bzl +index 283c85850..ad91faba6 100644 +--- a/protobuf.bzl ++++ b/protobuf.bzl +@@ -1,7 +1,9 @@ + load("@bazel_skylib//lib:versions.bzl", "versions") + load("@rules_cc//cc:defs.bzl", "objc_library") + load("@rules_python//python:defs.bzl", "py_library") ++load("//bazel/common:proto_common.bzl", "proto_common") + load("//bazel/common:proto_info.bzl", "ProtoInfo") ++load("//bazel/private:toolchain_helpers.bzl", "toolchains") + + def _GetPath(ctx, path): + if ctx.label.workspace_root: +@@ -71,6 +73,26 @@ def _CsharpOuts(srcs): + for src in srcs + ] + ++_PROTOC_ATTRS = toolchains.if_legacy_toolchain({ ++ "_proto_compiler": attr.label( ++ cfg = "exec", ++ executable = True, ++ allow_files = True, ++ default = configuration_field("proto", "proto_compiler"), ++ ), ++}) ++_PROTOC_FRAGMENTS = ["proto"] ++_PROTOC_TOOLCHAINS = toolchains.use_toolchain(toolchains.PROTO_TOOLCHAIN) ++ ++def _protoc_files_to_run(ctx): ++ if proto_common.INCOMPATIBLE_ENABLE_PROTO_TOOLCHAIN_RESOLUTION: ++ toolchain = ctx.toolchains[toolchains.PROTO_TOOLCHAIN] ++ if not toolchain: ++ fail("Protocol compiler toolchain could not be resolved.") ++ return toolchain.proto.proto_compiler ++ else: ++ return ctx.attr._proto_compiler[DefaultInfo].files_to_run ++ + ProtoGenInfo = provider( + fields = ["srcs", "import_flags", "deps"], + ) +@@ -310,7 +332,7 @@ def _internal_gen_well_known_protos_java_impl(ctx): + args.add_all([src.path[offset:] for src in dep.direct_sources]) + + ctx.actions.run( +- executable = ctx.executable._protoc, ++ executable = _protoc_files_to_run(ctx), + inputs = descriptors, + outputs = [srcjar], + arguments = [args], +@@ -334,12 +356,9 @@ internal_gen_well_known_protos_java = rule( + "javalite": attr.bool( + default = False, + ), +- "_protoc": attr.label( +- executable = True, +- cfg = "exec", +- default = "//:protoc", +- ), +- }, ++ } | _PROTOC_ATTRS, ++ fragments = _PROTOC_FRAGMENTS, ++ toolchains = _PROTOC_TOOLCHAINS, + ) + + def _internal_gen_kt_protos(ctx): +@@ -373,7 +392,7 @@ def _internal_gen_kt_protos(ctx): + args.add_all([src.path[offset:] for src in dep.direct_sources]) + + ctx.actions.run( +- executable = ctx.executable._protoc, ++ executable = _protoc_files_to_run(ctx), + inputs = descriptors, + outputs = [srcjar], + arguments = [args], +@@ -397,12 +416,9 @@ internal_gen_kt_protos = rule( + "lite": attr.bool( + default = False, + ), +- "_protoc": attr.label( +- executable = True, +- cfg = "exec", +- default = "//:protoc", +- ), +- }, ++ } | _PROTOC_ATTRS, ++ fragments = _PROTOC_FRAGMENTS, ++ toolchains = _PROTOC_TOOLCHAINS, + ) + + def internal_objc_proto_library( 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..9204cf40f --- /dev/null +++ b/third_party/test/proto/MODULE.bazel @@ -0,0 +1,37 @@ +"""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, +) + +register_toolchains( + "@rules_scala//protoc:all", + "@rules_scala//scala:unused_dependency_checker_error_toolchain", +) + +# Required for `protoc` toolchainization until resolution of +# protocolbuffers/protobuf#19679. +bazel_dep( + name = "protobuf", + version = "29.3", + repo_name = "com_google_protobuf", +) + +single_version_override( + module_name = "protobuf", + version = "29.3", + patches = ["//:protobuf.patch"], + patch_strip = 1, +) 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/third_party/test/proto/protobuf.patch b/third_party/test/proto/protobuf.patch new file mode 100644 index 000000000..86d7d1b82 --- /dev/null +++ b/third_party/test/proto/protobuf.patch @@ -0,0 +1,91 @@ +diff --git a/protobuf.bzl b/protobuf.bzl +index 283c85850..ad91faba6 100644 +--- a/protobuf.bzl ++++ b/protobuf.bzl +@@ -1,7 +1,9 @@ + load("@bazel_skylib//lib:versions.bzl", "versions") + load("@rules_cc//cc:defs.bzl", "objc_library") + load("@rules_python//python:defs.bzl", "py_library") ++load("//bazel/common:proto_common.bzl", "proto_common") + load("//bazel/common:proto_info.bzl", "ProtoInfo") ++load("//bazel/private:toolchain_helpers.bzl", "toolchains") + + def _GetPath(ctx, path): + if ctx.label.workspace_root: +@@ -71,6 +73,26 @@ def _CsharpOuts(srcs): + for src in srcs + ] + ++_PROTOC_ATTRS = toolchains.if_legacy_toolchain({ ++ "_proto_compiler": attr.label( ++ cfg = "exec", ++ executable = True, ++ allow_files = True, ++ default = configuration_field("proto", "proto_compiler"), ++ ), ++}) ++_PROTOC_FRAGMENTS = ["proto"] ++_PROTOC_TOOLCHAINS = toolchains.use_toolchain(toolchains.PROTO_TOOLCHAIN) ++ ++def _protoc_files_to_run(ctx): ++ if proto_common.INCOMPATIBLE_ENABLE_PROTO_TOOLCHAIN_RESOLUTION: ++ toolchain = ctx.toolchains[toolchains.PROTO_TOOLCHAIN] ++ if not toolchain: ++ fail("Protocol compiler toolchain could not be resolved.") ++ return toolchain.proto.proto_compiler ++ else: ++ return ctx.attr._proto_compiler[DefaultInfo].files_to_run ++ + ProtoGenInfo = provider( + fields = ["srcs", "import_flags", "deps"], + ) +@@ -310,7 +332,7 @@ def _internal_gen_well_known_protos_java_impl(ctx): + args.add_all([src.path[offset:] for src in dep.direct_sources]) + + ctx.actions.run( +- executable = ctx.executable._protoc, ++ executable = _protoc_files_to_run(ctx), + inputs = descriptors, + outputs = [srcjar], + arguments = [args], +@@ -334,12 +356,9 @@ internal_gen_well_known_protos_java = rule( + "javalite": attr.bool( + default = False, + ), +- "_protoc": attr.label( +- executable = True, +- cfg = "exec", +- default = "//:protoc", +- ), +- }, ++ } | _PROTOC_ATTRS, ++ fragments = _PROTOC_FRAGMENTS, ++ toolchains = _PROTOC_TOOLCHAINS, + ) + + def _internal_gen_kt_protos(ctx): +@@ -373,7 +392,7 @@ def _internal_gen_kt_protos(ctx): + args.add_all([src.path[offset:] for src in dep.direct_sources]) + + ctx.actions.run( +- executable = ctx.executable._protoc, ++ executable = _protoc_files_to_run(ctx), + inputs = descriptors, + outputs = [srcjar], + arguments = [args], +@@ -397,12 +416,9 @@ internal_gen_kt_protos = rule( + "lite": attr.bool( + default = False, + ), +- "_protoc": attr.label( +- executable = True, +- cfg = "exec", +- default = "//:protoc", +- ), +- }, ++ } | _PROTOC_ATTRS, ++ fragments = _PROTOC_FRAGMENTS, ++ toolchains = _PROTOC_TOOLCHAINS, + ) + + def internal_objc_proto_library( diff --git a/tools/bazel.rc.buildkite b/tools/bazel.rc.buildkite index 479197f37..1132fa088 100644 --- a/tools/bazel.rc.buildkite +++ b/tools/bazel.rc.buildkite @@ -1,6 +1,5 @@ -# Switch to --noenable_workspace when Bzlmod lands. -# https://github.com/bazelbuild/rules_scala/issues/1482 -common --enable_workspace --noenable_bzlmod +# Remove once Bazel 8 becomes the default supported version. +common --noenable_workspace # Remove once proto toolchainization becomes the default # - https://bazel.build/reference/command-line-reference#flag--incompatible_enable_proto_toolchain_resolution