From 2857e1e548156895e54d27b123e614504d7606bf Mon Sep 17 00:00:00 2001 From: Mike Bland Date: Tue, 8 Apr 2025 13:33:18 -0400 Subject: [PATCH 1/4] Add test_dependency_versions, update test_runner Adds `test_dependency_versions.sh` to validate the minimum Bazel and dependency versions required by `rules_scala`, with and without the precompiled protocol compiler toolchain. Extracts setup, run, and teardown helpers from `test/shell/test_bzlmod_helpers.sh` into `test_runner.sh` for reuse by `test_dependency_versions.sh`. Also: - Adds test files supporting `test_dependency_versions.sh` in `deps/test`. - Adds a mechanism to skip tests by prefixing their name with `_` to `run_test_local` and `run_test_ci`. - Adds the `RULES_SCALA_TEST_REGEX` environment variable to `test_runner.sh`. - Adds documentation for `RULES_SCALA_TEST_{ONLY,REGEX,VERBOSE}` to the header comment of `test_runner.sh`. - Adds `./test_dependency_versions` jobs to `.bazelci/presubmit.yml`. --- Continuation of the previous change to ensure we don't force users to upgrade their dependencies beyond the minimum versions supported by `rules_scala`. Only builds using Bzlmod, as `WORKSPACE` is considered legacy. Inspired by a thread in the #bzlmod channel of the Bazel Slack workspace on 2025-01-01 indicating that rules should require the minumum versions possible: - https://bazelbuild.slack.com/archives/C014RARENH0/p1743597941149639 --- .bazelci/presubmit.yml | 21 +++- README.md | 3 +- deps/test/BUILD.bazel.test | 129 +++++++++++++++++++ deps/test/HelloLib.scala | 22 ++++ deps/test/MODULE.bazel.template | 71 +++++++++++ deps/test/ScalaBinary.scala | 21 ++++ deps/test/defs.bzl | 46 +++++++ test/shell/test_bzlmod_macros.sh | 35 +----- test/shell/test_runner.sh | 121 +++++++++++++++++- test_all.sh | 1 + test_dependency_versions.sh | 210 +++++++++++++++++++++++++++++++ test_lint.sh | 2 - 12 files changed, 643 insertions(+), 39 deletions(-) create mode 100644 deps/test/BUILD.bazel.test create mode 100644 deps/test/HelloLib.scala create mode 100644 deps/test/MODULE.bazel.template create mode 100644 deps/test/ScalaBinary.scala create mode 100644 deps/test/defs.bzl create mode 100755 test_dependency_versions.sh diff --git a/.bazelci/presubmit.yml b/.bazelci/presubmit.yml index beb514ab8..181fbac22 100644 --- a/.bazelci/presubmit.yml +++ b/.bazelci/presubmit.yml @@ -45,7 +45,7 @@ tasks: test_rules_scala_win: name: "./test_rules_scala" platform: windows - environment: + environment: MSYS2_ARG_CONV_EXCL: "*" batch_commands: - "set PATH=/usr/bin;%PATH%" #Make sure bash uses msys commands over windows commands. (i.e. find). @@ -74,7 +74,7 @@ tasks: shell_commands: - "./test_reproducibility.sh" versions_linux: - name: "./test_version.sh" + name: "./test_version.sh" platform: ubuntu2004 shell_commands: - "./test_version.sh" @@ -84,7 +84,7 @@ tasks: shell_commands: - "./test_version.sh" thirdparty_version_linux: - name: "./test_thirdparty_version.sh" + name: "./test_thirdparty_version.sh" platform: ubuntu2204_java17 shell_commands: - "./test_thirdparty_version.sh" @@ -117,3 +117,18 @@ tasks: - echo "build --tool_java_language_version=21" >> .bazelrc - echo "build --tool_java_runtime_version=21" >> .bazelrc - "./test_rules_scala.sh" + dependency_versions_linux: + name: "./test_dependency_versions" + platform: ubuntu2004 + shell_commands: + - "./test_dependency_versions.sh" + dependency_versions_macos: + name: "./test_dependency_versions" + platform: macos + shell_commands: + - "./test_dependency_versions.sh" + dependency_versions_windows: + name: "./test_dependency_versions" + platform: windows + shell_commands: + - "./test_dependency_versions.sh" diff --git a/README.md b/README.md index 8526c1d43..90c9a4520 100644 --- a/README.md +++ b/README.md @@ -349,7 +349,8 @@ by default](#protoc-msvc) section below for details. #### Minimum dependency versions These are the minimum dependency versions required to enable the precompiled -protocol compiler toolchain. +protocol compiler toolchain. These are validated by +[`test_dependency_versions.sh`](./test/shell/test_dependency_versions.sh). Note that `rules_java` can be as low as 8.3.0, compared to `rules_java` 8.5.0 specified in [Compatible Bazel versions](#compatible-bazel-versions). diff --git a/deps/test/BUILD.bazel.test b/deps/test/BUILD.bazel.test new file mode 100644 index 000000000..f4e4dc5cd --- /dev/null +++ b/deps/test/BUILD.bazel.test @@ -0,0 +1,129 @@ +"""Test targets to ensure dependency version compatibility. + +Copied and adapted targets from the main repo as noted. +""" +load( + ":defs.bzl", + "default_outputs_test", + "scalafmt_scala_test", + "scrooge_transitive_outputs_test", +) +load("@rules_proto//proto:defs.bzl", "proto_library") +load("@rules_scala//jmh:jmh.bzl", "scala_benchmark_jmh") +load("@rules_scala//scala/scalafmt:phase_scalafmt_ext.bzl", "ext_scalafmt") +load("@rules_scala//scala:advanced_usage/scala.bzl", "make_scala_test") +load( + "@rules_scala//scala:scala.bzl", + "scala_binary", + "scala_doc", + "scala_junit_test", + "scala_library", + "scala_specs2_junit_test", + "scala_test", +) +load("@rules_scala//scala_proto:scala_proto.bzl", "scala_proto_library") +load("@rules_scala//thrift:thrift.bzl", "thrift_library") +load( + "@rules_scala//twitter_scrooge:twitter_scrooge.bzl", + "scrooge_java_library", + "scrooge_scala_library", +) + +# From: `test/BUILD` +scala_binary( + name = "ScalaBinary", + srcs = ["ScalaBinary.scala"], + main_class = "scalarules.test.ScalaBinary", + deps = [ + ":HelloLib", + ], +) + +scala_library( + name = "HelloLib", + srcs = ["HelloLib.scala"], +) + +scala_doc( + name = "ScalaDoc", + deps = [":HelloLib"], +) + +# From: `examples/testing/multi_frameworks_toolchain/example/BUILD` +scala_test( + name = "scalatest_example", + srcs = ["ScalaTestExampleTest.scala"], +) + +scala_specs2_junit_test( + name = "specs2_example", + srcs = ["Specs2ExampleTest.scala"], + suffixes = ["Test"], +) + +# Manufactured based on `docs/phase_scalafmt.md` and `test/scalafmt/BUILD`. +scalafmt_scala_test( + name = "ScalafmtTest", + srcs = ["ScalaTestExampleTest.scala"], + format = True, +) + +# From: `test/proto/BUILD` +proto_library( + name = "standalone_proto", + srcs = ["standalone.proto"], +) + +scala_proto_library( + name = "standalone_scala_proto", + deps = [":standalone_proto"], +) + +default_outputs_test( + name = "standalone_scala_proto_outs_test", + expected_outs = [ + "standalone_proto_scalapb-src.jar", + "standalone_proto_scalapb.jar", + ], + target_under_test = ":standalone_scala_proto", +) + +# From: `test/jmh/BUILD` +scala_benchmark_jmh( + name = "test_benchmark", + srcs = ["TestBenchmark.scala"], + data = ["data.txt"], + deps = ["@rules_scala//test/jmh:add_numbers"], +) + +# From: `test/src/main/scala/scalarules/test/twitter_scrooge/BUILD` + +thrift_library( + name = "thrift3", + srcs = ["Thrift3.thrift"], + visibility = ["//visibility:public"], +) + +scrooge_scala_library( + name = "scrooge3", + visibility = ["//visibility:public"], + deps = [":thrift3"], +) + +scrooge_java_library( + name = "scrooge3_java", + visibility = ["//visibility:public"], + deps = [":thrift3"], +) + +scrooge_transitive_outputs_test( + name = "scrooge_test_scala", + dep = ":scrooge3", + expected_jars = ["thrift3_scrooge_scala.jar"], +) + +scrooge_transitive_outputs_test( + name = "scrooge_test_java", + dep = ":scrooge3_java", + expected_jars = ["thrift3_scrooge_java.jar"], +) diff --git a/deps/test/HelloLib.scala b/deps/test/HelloLib.scala new file mode 100644 index 000000000..612c9e851 --- /dev/null +++ b/deps/test/HelloLib.scala @@ -0,0 +1,22 @@ +// Copyright 2016 The Bazel Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package scalarules.test + +object HelloLib { + def printMessage(arg: String) { + println(arg) + } +} + diff --git a/deps/test/MODULE.bazel.template b/deps/test/MODULE.bazel.template new file mode 100644 index 000000000..2b5f8a466 --- /dev/null +++ b/deps/test/MODULE.bazel.template @@ -0,0 +1,71 @@ +"""Bazel module template for test/shell/test_deps_versions.sh tests.""" + +module( + name = "rules_scala_deps_versions_test", + bazel_compatibility = [">=${bazelversion}"], +) + +bazel_dep(name = "rules_scala") +local_path_override( + module_name = "rules_scala", + path = "../..", +) + +bazel_dep(name = "bazel_skylib") +single_version_override( + module_name = "bazel_skylib", + version = "${skylib_version}", +) + +bazel_dep(name = "platforms") +single_version_override( + module_name = "platforms", + version = "${platforms_version}", +) + +bazel_dep(name = "rules_java") +single_version_override( + module_name = "rules_java", + version = "${rules_java_version}", +) + +bazel_dep(name = "rules_proto") +single_version_override( + module_name = "rules_proto", + version = "${rules_proto_version}", +) + +# Requires the patch for `protoc` toolchainization until resolution of +# protocolbuffers/protobuf#19679. +bazel_dep(name = "protobuf") +single_version_override( + module_name = "protobuf", + patch_strip = 1, + patches = ["//:protobuf.patch"], + version = "${protobuf_version}", +) + +scala_protoc = use_extension( + "@rules_scala//scala/extensions:protoc.bzl", + "scala_protoc", + dev_dependency = True, +) +use_repo(scala_protoc, "rules_scala_protoc_toolchains") + +register_toolchains( + "@rules_scala_protoc_toolchains//...:all", + dev_dependency = True, +) + +scala_deps = use_extension( + "@rules_scala//scala/extensions:deps.bzl", + "scala_deps", +) +scala_deps.scala() +scala_deps.jmh() +scala_deps.junit() +scala_deps.scala_proto() +scala_deps.scalafmt() +scala_deps.scalatest() +scala_deps.specs2() +scala_deps.twitter_scrooge() diff --git a/deps/test/ScalaBinary.scala b/deps/test/ScalaBinary.scala new file mode 100644 index 000000000..1cf084ee9 --- /dev/null +++ b/deps/test/ScalaBinary.scala @@ -0,0 +1,21 @@ +// Copyright 2016 The Bazel Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package scalarules.test + +object ScalaBinary { + def main(args: Array[String]) { + HelloLib.printMessage("Hello"); + } +} diff --git a/deps/test/defs.bzl b/deps/test/defs.bzl new file mode 100644 index 000000000..3a971d538 --- /dev/null +++ b/deps/test/defs.bzl @@ -0,0 +1,46 @@ +load("@bazel_skylib//lib:unittest.bzl", "analysistest", "asserts", "unittest") +load("@bazel_skylib//lib:collections.bzl", "collections") +load("@rules_scala//scala:advanced_usage/scala.bzl", "make_scala_test") +load("@rules_scala//scala/scalafmt:phase_scalafmt_ext.bzl", "ext_scalafmt") + +# From //test/scalafmt:phase_scalafmt_test.bzl +scalafmt_scala_test = make_scala_test(ext_scalafmt) + +# From //test/proto:default_outputs_test.bzl +def _default_outputs_test(ctx): + env = analysistest.begin(ctx) + + target_under_test = analysistest.target_under_test(env) + actual_outs = [f.basename for f in target_under_test[DefaultInfo].files.to_list()] + + asserts.equals(env, sorted(ctx.attr.expected_outs), sorted(actual_outs)) + + return analysistest.end(env) + +default_outputs_test = analysistest.make( + _default_outputs_test, + attrs = { + "expected_outs": attr.string_list(), + }, +) + +# From +# //test/src/main/scala/scalarules/test/twitter_scrooge:twitter_scrooge_test.bzl +def _scrooge_transitive_outputs(ctx): + env = unittest.begin(ctx) + + asserts.equals( + env, + sorted(ctx.attr.expected_jars), + sorted(collections.uniq([out.class_jar.basename for out in ctx.attr.dep[JavaInfo].outputs.jars])), + ) + + return unittest.end(env) + +scrooge_transitive_outputs_test = unittest.make( + _scrooge_transitive_outputs, + attrs = { + "dep": attr.label(), + "expected_jars": attr.string_list(), + }, +) diff --git a/test/shell/test_bzlmod_macros.sh b/test/shell/test_bzlmod_macros.sh index 1a1aa8a04..055948d00 100755 --- a/test/shell/test_bzlmod_macros.sh +++ b/test/shell/test_bzlmod_macros.sh @@ -9,7 +9,6 @@ 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 @@ -23,14 +22,11 @@ setup_suite() { fi original_dir="$PWD" - test_tmpdir="${dir}/tmp/${BASH_SOURCE[0]##*/}" - test_tmpdir="${test_tmpdir%.*}" - test_srcs_dir="${dir}/scala/private/macros/test" - - mkdir -p "$test_tmpdir" - cd "$test_tmpdir" + setup_test_tmpdir_for_file "$original_dir" "$test_source" + test_tmpdir="$PWD" - rules_scala_dir="../.." + rules_scala_dir="$(relative_path_to_parent "$original_dir" "$test_tmpdir")" + test_srcs_dir="${dir}/scala/private/macros/test" test_tmpdir_base="${test_tmpdir##*/}" test_module_bazel_regex="[^ ]+${test_tmpdir_base}/MODULE.bazel" @@ -44,10 +40,7 @@ setup_suite() { } teardown_suite() { - # Make sure bazel isn't still running for this workspace. - bazel clean --expunge_async 2>/dev/null - cd "$original_dir" - rm -rf "$test_tmpdir" + teardown_test_tmpdir "$original_dir" "$test_tmpdir" } setup_test_module() { @@ -223,22 +216,6 @@ test_bzlmod_repeated_tag_values_fails_on_duplicate_key() { "${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. - setup_suite - -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" - +run_tests "$test_source" "$(get_test_runner "${1:-local}")" teardown_suite diff --git a/test/shell/test_runner.sh b/test/shell/test_runner.sh index 8f65db104..e43c17171 100644 --- a/test/shell/test_runner.sh +++ b/test/shell/test_runner.sh @@ -1,15 +1,62 @@ #!/usr/bin/env bash # # Test runner functions for rules_scala integration tests. +# +# Supports the following env vars: +# +# - `RULES_SCALA_TEST_ONLY`: Run a specific test by name. Emits full Bazel +# output, without having to search for it and recreate its command line. +# +# - `RULES_SCALA_TEST_REGEX`: Run only tests matching the regular expression. +# Does not show full Bazel output by default. +# +# - `RULES_SCALA_TEST_VERBOSE`: Set to a nonempty string to see verbose output +# for all tests. +# +# Skips test cases whose name begins with `_` unless those tests match +# `RULES_SCALA_TEST_ONLY` or `RULES_SCALA_TEST_REGEX`. NC='\033[0m' GREEN='\033[0;32m' RED='\033[0;31m' YELLOW='\033[0;33m' +RULES_SCALA_TEST_ONLY="${RULES_SCALA_TEST_ONLY:-}" +RULES_SCALA_TEST_VERBOSE="${RULES_SCALA_TEST_VERBOSE:-}" +RULES_SCALA_TEST_REGEX="${RULES_SCALA_TEST_REGEX:-}" + +_skip_test() { + local test_name="$1" + + # This allows us to run a single test case with full Bazel output without + # having to search for it and recreate its command line. + if [[ -n "$RULES_SCALA_TEST_ONLY" && + "$test_name" != "$RULES_SCALA_TEST_ONLY" ]]; then + return + + # Same as above, but for multiple tests, and without full output by default. + elif [[ -n "$RULES_SCALA_TEST_REGEX" && + ! "$test_name" =~ $RULES_SCALA_TEST_REGEX ]]; then + return + + # Only skips a test if it wasn't specifically identified by name or regex. + elif [[ -z "${RULES_SCALA_TEST_ONLY}${RULES_SCALA_TEST_REGEX}" && + "${test_name:0:1}" == '_' ]]; then + echo -e "${YELLOW}skipping test ${test_name}${NC}" + return + fi + + return 1 +} + run_test_ci() { # spawns the test to new process local TEST_ARG=$@ + + if _skip_test "$TEST_ARG"; then + return + fi + local log_file=output_$$.log echo "running test $TEST_ARG" eval $TEST_ARG &>$log_file & @@ -65,10 +112,7 @@ run_test_local() { local TEST_ARG=$@ local RES='' - # This allows us to run a single test case with full Bazel output without - # having to search for it and recreate its command line. - if [[ -n "$RULES_SCALA_TEST_ONLY" && - "$TEST_ARG" != "$RULES_SCALA_TEST_ONLY" ]]; then + if _skip_test "$TEST_ARG"; then return fi @@ -104,3 +148,72 @@ get_test_runner() { fi echo "run_test_${test_env}" } + +# Creates a temporary directory for the test file and changes into it. +# +# `$PWD` will be this new test directory upon returning. +# +# Args: +# root_dir: the root directory of the repository +# test_file_name: the name of the test file +setup_test_tmpdir_for_file() { + local root_dir="$1" + local test_file_name="${2##*/}" + local test_tmpdir="${root_dir}/tmp/${test_file_name%.*}" + + mkdir -p "$test_tmpdir" + cd "$test_tmpdir" +} + +# Cleans the Bazel workspace, removes the test dir, and restores `$PWD`. +# +# Args: +# original_dir: `$PWD` at the start of `setup_test_tmpdir_for_file()` +# test_tmpdir: `$PWD` at the end of `setup_test_tmpdir_for_file()` +teardown_test_tmpdir() { + local original_dir="$1" + local test_tmpdir="$2" + + bazel clean --expunge_async 2>/dev/null + cd "$original_dir" + rm -rf "$test_tmpdir" +} + +# Prints the relative path from `child_dir` to `parent_dir`. +# +# Useful for generating symlink paths on Windows in particular, such as +# generated by `local_path_override` since absolute paths may require special +# handling. +# +# Args: +# parent_dir: parent dir for which to derive the relative path +# child_dir: child dir from which to derive the relative path +relative_path_to_parent() { + local parent_dir="$1" + local child_dir="$2" + local relative_path="${child_dir#$parent_dir}" + + if [[ "$relative_path" != "$2" ]]; then + relative_path="${relative_path#/}" + relative_path="$(printf '%s' "$relative_path" | sed 's#[^/][^/]*#..#g')" + fi + printf '%s' "$relative_path" +} + +# Runs test cases extracted from a file whose name matches `test_*() {`. +# +# To skip a test, add a `_` prefix to its function name. +# +# Args: +# test_source: path to the source file containing test functions +# runner: the result from `get_test_runner()` +run_tests() { + local test_source="$1" + local runner="$2" + + while IFS= read -r line; do + if [[ "$line" =~ ^_?(test_[A-Za-z0-9_]+)\(\)\ ?\{$ ]]; then + "$runner" "${BASH_REMATCH[1]}" + fi + done <"$test_source" +} diff --git a/test_all.sh b/test_all.sh index 9864421cc..8b3bcfe26 100755 --- a/test_all.sh +++ b/test_all.sh @@ -6,6 +6,7 @@ dir=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) "${dir}"/test_lint.sh "${dir}"/test_rules_scala.sh "${dir}"/test_version.sh +"${dir}"/test_dependency_versions.sh "${dir}"/test_cross_build.sh "${dir}"/test_reproducibility.sh #"${dir}"/test_intellij_aspect.sh diff --git a/test_dependency_versions.sh b/test_dependency_versions.sh new file mode 100755 index 000000000..5a4fbe9e2 --- /dev/null +++ b/test_dependency_versions.sh @@ -0,0 +1,210 @@ +#!/usr/bin/env bash +# +# Verifies combinations of supported dependency versions. +# +# Starts by testing the oldest dependency versions, then increments some of them +# to more recent versions. These versions should match the guidance in these +# `README.md` sections: +# +# - Compatible Bazel versions +# - Using a precompiled protocol compiler > Minimum dependency versions +# +# Does not test the latest dependency versions, as all other tests in the suite +# already do this. Only builds with Bzlmod, as `WORKSPACE` builds are now +# considered legacy. + +set -e + +dir="$( cd "${BASH_SOURCE[0]%/*}" && echo "${PWD}" )" +test_source="${dir}/${BASH_SOURCE[0]##*/}" +# shellcheck source=./test_runner.sh +. "${dir}"/test/shell/test_runner.sh +. "${dir}"/test/shell/test_helper.sh + +setup_suite() { + original_dir="$PWD" + setup_test_tmpdir_for_file "$dir" "$test_source" + test_tmpdir="$PWD" + + if is_windows && [[ -z "$RULES_SCALA_TEST_REGEX" ]]; then + # Windows now requires a precompiled protoc. + windows_regex="test_precompiled_protoc" + fi +} + +teardown_suite() { + teardown_test_tmpdir "$original_dir" "$test_tmpdir" +} + +# Explicitly disable this, since this test sets the Bazel version. +export USE_BAZEL_VERSION="" + +do_build_and_test() { + # These are the minimum versions as described in `README.md` and as set in the + # top level `MODULE.bazel` file. Update both if/when the first test test + # fails. If another test fails, update the `README.md` informaton. + local bazelversion="7.1.0" + local skylib_version="1.6.0" + local platforms_version="0.0.9" + local protobuf_version="28.2" + local rules_java_version="7.6.0" + local rules_proto_version="6.0.0" + local protoc_toolchain="" + local legacy_api="" + local bazel_major="" + local bazel_minor="" + local current + local arg + + while [[ "$#" -ne 0 ]]; do + current="$1" + shift + arg="${current#*=}" + + case "$current" in + --bazelversion=*) + bazelversion="$arg" + ;; + --skylib=*) + skylib_version="$arg" + ;; + --platforms=*) + platforms_version="$arg" + ;; + --protobuf=*) + protobuf_version="$arg" + ;; + --rules_java=*) + rules_java_version="$arg" + ;; + --rules_proto=*) + rules_proto_version="$arg" + ;; + --protoc_toolchain) + protoc_toolchain="true" + ;; + --legacy_api) + legacy_api="true" + ;; + esac + done + + echo "$bazelversion" >.bazelversion + cp "${dir}/deps/test/BUILD.bazel.test" BUILD + + # Set up .bazelrc + printf '%s\n' \ + 'common --noenable_workspace --enable_bzlmod' \ + 'common --enable_platform_specific_config' \ + 'common:windows --worker_quit_after_build --enable_runfiles' >.bazelrc + + if [[ "$bazelversion" =~ ^([0-9]+)\.([0-9]+)\.[0-9]+.* ]]; then + bazel_major="${BASH_REMATCH[1]}" + bazel_minor="${BASH_REMATCH[2]}" + else + echo "can't parse --bazelversion: $bazelversion" >&2 + exit 1 + fi + + if [[ "$protoc_toolchain" == "true" ]]; then + echo 'common --incompatible_enable_proto_toolchain_resolution' >>.bazelrc + elif [[ "$bazel_major" == "7" ]]; then + printf '%s\n' \ + 'common:linux --cxxopt=-std=c++17' \ + 'common:linux --host_cxxopt=-std=c++17' \ + 'common:macos --cxxopt=-std=c++17' \ + 'common:macos --host_cxxopt=-std=c++17' \ + 'common:windows --cxxopt=/std=c++17' \ + 'common:windows --host_cxxopt=/std=c++17' >>.bazelrc + fi + + if [[ "$legacy_api" == "true" ]]; then + echo 'common --experimental_google_legacy_api' >>.bazelrc + fi + + if [[ "$bazel_major" == "7" && "$bazel_minor" -ge 3 ]]; then + echo 'common --incompatible_use_plus_in_repo_names' >>.bazelrc + fi + + # Set up the `protobuf` precompiled protocol compiler toolchain patch. + if [[ "${protobuf_version:0:3}" =~ ^(29|30)\. ]]; then + cp "${dir}/protoc/0001-protobuf-19679-rm-protoc-dep.patch" ./protobuf.patch + else + touch ./protobuf.patch + fi + + # Render the MODULE.bazel file + sed -e "s%\${bazelversion}%${bazelversion}%" \ + -e "s%\${skylib_version}%${skylib_version}%" \ + -e "s%\${platforms_version}%${platforms_version}%" \ + -e "s%\${protobuf_version}%${protobuf_version}%" \ + -e "s%\${rules_java_version}%${rules_java_version}%" \ + -e "s%\${rules_proto_version}%${rules_proto_version}%" \ + "${dir}/deps/test/MODULE.bazel.template" >MODULE.bazel + + # Copy files needed by the test targets + local test_files=( + "${dir}"/deps/test/*.{scala,bzl} + "${dir}"/examples/testing/multi_frameworks_toolchain/example/*.scala + "${dir}"/test/jmh/{TestBenchmark.scala,data.txt} + "${dir}"/test/proto/standalone.proto + "${dir}"/test/src/main/scala/scalarules/test/twitter_scrooge/thrift/thrift2/thrift3/Thrift3.thrift + ) + cp "${test_files[@]}" . + + set -e + bazel build //... + bazel test //... + bazel run //:ScalafmtTest.format-test +} + +test_minimum_supported_versions() { + do_build_and_test +} + +test_bazel_7_with_rules_java_8() { + do_build_and_test --rules_java=8.4.0 +} + +test_bazel_8() { + do_build_and_test \ + --bazelversion=8.0.0 \ + --skylib=1.7.0 \ + --protobuf=29.0 \ + --rules_java=8.5.0 \ + --rules_proto=7.0.0 +} + +test_precompiled_protoc_rules_java_7() { + do_build_and_test \ + --protoc_toolchain \ + --skylib=1.7.0 \ + --protobuf=29.0 \ + --rules_java=7.10.0 \ + --rules_proto=7.0.0 \ + --legacy_api +} + +test_precompiled_protoc_rules_java_8_3_0() { + do_build_and_test \ + --protoc_toolchain \ + --bazelversion=7.3.2 \ + --skylib=1.7.0 \ + --protobuf=29.0 \ + --rules_java=8.3.0 \ + --rules_proto=7.0.0 +} + +test_precompiled_protoc_rules_java_8_3_2() { + do_build_and_test \ + --protoc_toolchain \ + --skylib=1.7.0 \ + --protobuf=29.0 \ + --rules_java=8.3.2 \ + --rules_proto=7.0.0 +} + +setup_suite +RULES_SCALA_TEST_REGEX="${RULES_SCALA_TEST_REGEX:-$windows_regex}" \ + run_tests "$test_source" "$(get_test_runner "${1:-local}")" +teardown_suite diff --git a/test_lint.sh b/test_lint.sh index 14b95e3be..9a0eff4e3 100755 --- a/test_lint.sh +++ b/test_lint.sh @@ -7,6 +7,4 @@ dir="$( cd "${dir:-.}" && pwd )" bazel run //tools:lint_check -RULES_SCALA_TEST_ONLY="${RULES_SCALA_TEST_ONLY:-}" -RULES_SCALA_TEST_VERBOSE="${RULES_SCALA_TEST_VERBOSE:-}" . "${dir}/test/shell/test_bzlmod_tidy.sh" From 57561f94343b7a2098beff5b2c4d1caa5b3aa218 Mon Sep 17 00:00:00 2001 From: Mike Bland Date: Tue, 29 Apr 2025 08:16:59 -0400 Subject: [PATCH 2/4] Fix test_dependency_versions.sh on macOS, Windows Copied the setup for the Windows `test_rules_scala` job to the Windows `test_dependency_versions` job. Replaced `cp "${test_files[@]}" .` with copying the list of files directly instead of keeping them in an array. The Linux job passed. The Windows job didn't run the script at all. The macOS build broke in a way I've not seen while developing locally: ```txt cp: (/Users/buildkite/builds/bk-macos-intel-m3q2/bazel/rules-scala-scala/deps/test/*.bzl /Users/buildkite/builds/bk-macos-intel-m3q2/bazel/rules-scala-scala/examples/testing/multi_frameworks_toolchain/example/*.scala /Users/buildkite/builds/bk-macos-intel-m3q2/bazel/rules-scala-scala/test/jmh/data.txt /Users/buildkite/builds/bk-macos-intel-m3q2/bazel/rules-scala-scala/test/proto/standalone.proto /Users/buildkite/builds/bk-macos-intel-m3q2/bazel/rules-scala-scala/test/src/main/scala/scalarules/test/twitter_scrooge/thrift/thrift2/thrift3/Thrift3.thrift): No such file or directory ``` --- .bazelci/presubmit.yml | 9 +++++++-- test_dependency_versions.sh | 15 +++++++-------- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/.bazelci/presubmit.yml b/.bazelci/presubmit.yml index 181fbac22..4e7f1690e 100644 --- a/.bazelci/presubmit.yml +++ b/.bazelci/presubmit.yml @@ -130,5 +130,10 @@ tasks: dependency_versions_windows: name: "./test_dependency_versions" platform: windows - shell_commands: - - "./test_dependency_versions.sh" + environment: + MSYS2_ARG_CONV_EXCL: "*" + batch_commands: + - "set PATH=/usr/bin;%PATH%" #Make sure bash uses msys commands over windows commands. (i.e. find). + - "bash -lc \"pacman --noconfirm --needed -S libxml2\"" #tests require xmllint + - "bash test_dependency_versions.sh" + diff --git a/test_dependency_versions.sh b/test_dependency_versions.sh index 5a4fbe9e2..4e3f81dd7 100755 --- a/test_dependency_versions.sh +++ b/test_dependency_versions.sh @@ -143,14 +143,13 @@ do_build_and_test() { "${dir}/deps/test/MODULE.bazel.template" >MODULE.bazel # Copy files needed by the test targets - local test_files=( - "${dir}"/deps/test/*.{scala,bzl} - "${dir}"/examples/testing/multi_frameworks_toolchain/example/*.scala - "${dir}"/test/jmh/{TestBenchmark.scala,data.txt} - "${dir}"/test/proto/standalone.proto - "${dir}"/test/src/main/scala/scalarules/test/twitter_scrooge/thrift/thrift2/thrift3/Thrift3.thrift - ) - cp "${test_files[@]}" . + cp \ + "${dir}"/deps/test/*.{scala,bzl} \ + "${dir}"/examples/testing/multi_frameworks_toolchain/example/*.scala \ + "${dir}"/test/jmh/{TestBenchmark.scala,data.txt} \ + "${dir}"/test/proto/standalone.proto \ + "${dir}"/test/src/main/scala/scalarules/test/twitter_scrooge/thrift/thrift2/thrift3/Thrift3.thrift \ + . set -e bazel build //... From 450a680960f240ec6cb8493fec0f9c3f25a1fe56 Mon Sep 17 00:00:00 2001 From: Mike Bland Date: Tue, 29 Apr 2025 08:36:02 -0400 Subject: [PATCH 3/4] Fix ./test_dependency_versions.sh path on Windows The script expects a directory path at the beginning of `${BASH_SOURCE[0]}`, else the following error occurs: ```txt test_dependency_versions.sh: line 18: cd: test_dependency_versions.sh: Not a directory ``` This is because `${BASH_SOURCE[0]%/*}` will return the original `${BASH_SOURCE[0]}` without a leading path. This failure in the Linux `test_dependency_versions` job looks like a fluke, since the previous run succeeded, as did other current runs: ``` WARNING: Download from https://github.com/bazelbuild/bazel-skylib/releases/download/1.6.0/bazel-skylib-1.6.0.tar.gz failed: class java.io.IOException GET returned 618 jwt:jwt-not-provided `` --- .bazelci/presubmit.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.bazelci/presubmit.yml b/.bazelci/presubmit.yml index 4e7f1690e..cab98ad02 100644 --- a/.bazelci/presubmit.yml +++ b/.bazelci/presubmit.yml @@ -135,5 +135,4 @@ tasks: batch_commands: - "set PATH=/usr/bin;%PATH%" #Make sure bash uses msys commands over windows commands. (i.e. find). - "bash -lc \"pacman --noconfirm --needed -S libxml2\"" #tests require xmllint - - "bash test_dependency_versions.sh" - + - "bash ./test_dependency_versions.sh" # script removes ./ from BASH_SOURCE From 56903c0c8b0c35ec87b3f041cc60367ae41aba76 Mon Sep 17 00:00:00 2001 From: Mike Bland Date: Tue, 29 Apr 2025 09:04:07 -0400 Subject: [PATCH 4/4] Disable //:ScalafmtTest.format-test on Windows Works around the following `test_dependency_version.sh` failure: ```txt FATAL: ExecuteProgram(C:\tools\msys64\home\b\_bazel_b\...\ScalafmtTest.format-test) failed: ERROR: src/main/native/windows/process.cc(202): CreateProcessW("C:\tools\msys64\home\b\_bazel_b\...\ScalafmtTest.format-test"): %1 is not a valid Win32 application. (error: 193) Test "test_precompiled_protoc_rules_java_7" failed (49 sec) ``` --- test_dependency_versions.sh | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/test_dependency_versions.sh b/test_dependency_versions.sh index 4e3f81dd7..b19e0e045 100755 --- a/test_dependency_versions.sh +++ b/test_dependency_versions.sh @@ -154,7 +154,15 @@ do_build_and_test() { set -e bazel build //... bazel test //... - bazel run //:ScalafmtTest.format-test + + # Windows fails with: + # FATAL: ExecuteProgram(C:\...\ScalafmtTest.format-test) failed: + # ERROR: src/main/native/windows/process.cc(202): + # CreateProcessW("C:\...\ScalafmtTest.format-test"): + # %1 is not a valid Win32 application. + if ! is_windows; then + bazel run //:ScalafmtTest.format-test + fi } test_minimum_supported_versions() {