Skip to content

Commit

Permalink
Update docs for version 7.0.0, remove old APIs
Browse files Browse the repository at this point in the history
Describes the new `scala_toolchains()` API, breaking changes, Bazel
compatibility matrix, and breaking of the `io_bazel_rules_scala` repo
name dependency. Part of bazelbuild#1482, bazelbuild#1647, bazelbuild#1652, and bazelbuild#1699, it also removes
obsolete `WORKSPACE` APIs in favor of `scala_toolchains()`, et. al.

Much of the README text regarding `WORKSPACE` configuration, Bazel
compatibility, and breaking changes comes from:

- bazelbuild#1482 (comment)

The "Breaking changes in `rules_scala` 7.x" section of `README.md`
describes the removed `WORKSPACE` macros, and provides guidance for
adopting the `scala_toolchains()` API. Also includes information about
the upcoming Bzlmod implementation (bazelbuild#1482) and the Bazel 8 compatibility
changes for `rules_scala` 8.x (bazelbuild#1652).

Contains a light editing pass over almost every Markdown file to resolve
`markdownlint` warnings when editing in VSCode. Also added
`.markdownlint.json` to silence rule `MD033/no-inline-html`, since
several docs contain `<br/>` and/or `<table>` elements.

- https://github.com/DavidAnson/vscode-markdownlint?tab=readme-ov-file#markdownlintconfig

Performed other opportunistic grammar edits and added new information,
including:

- `docs/coverage.md`: Describes how to determine the default JaCoCo
  version used by `rules_java`

- `scripts/README.md`: Updates `create_repository.py` docs extensively,
  and adds a section for `sync_bazelversion.sh`

---

Since the next major release is imminent, ensuring the documentation
accurately reflects all the changes since v6.6.0 has become an urgent
priority.

Rather than leave the old `WORKSPACE` APIs in place, which could lead to
surprising failures, this change removes all of them. This also changes
some code that still depended on some of these obsolete macros,
including `scala_toolchains()`. Since all the toolchainization changes
led to the entire project already using `scala_toolchains()` and
`scala_register_toolchains()` exclusively, this proved a low risk
refactoring.

With some Bzlmod and Bazel 8 information already in place, very little
will need to change when these implementations land. The commits that
contain those implementations will also include their relevant
documentation updates.
  • Loading branch information
mbland committed Feb 18, 2025
1 parent 62a3117 commit a92bc76
Show file tree
Hide file tree
Showing 44 changed files with 1,222 additions and 921 deletions.
5 changes: 5 additions & 0 deletions .markdownlint.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"default": true,
"MD013": false,
"MD033": false
}
632 changes: 502 additions & 130 deletions README.md

Large diffs are not rendered by default.

94 changes: 73 additions & 21 deletions docs/coverage.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
## Coverage support
# Coverage support

### Running tests with coverage
## Running tests with coverage

rules_scala supports coverage:

```
```txt
bazel coverage //...
```

It will produce several .dat files with results for your targets.

You can also add more options to receive a combined coverage report:

```
```txt
bazel coverage \
--combined_report=lcov \
--coverage_report_generator="@bazel_tools//tools/test/CoverageOutputGenerator/java/com/google/devtools/coverageoutputgenerator:Main" \
Expand All @@ -21,18 +21,18 @@ bazel coverage \

This should produce a single `bazel-out/_coverage/_coverage_report.dat` from all coverage files that are generated.

### Processing coverage reports
## Processing coverage reports

You can install `lcov` package (that supports the format Bazel uses for coverage reports) to have access to additional tools:
You can install the [`lcov`](https://github.com/linux-test-project/lcov) package (that supports the format Bazel uses for coverage reports) to have access to additional tools:

```
```txt
# Use your system package manager. E.g. on Ubuntu:
sudo apt install lcov
```

Having `lcov` package installed you can extract information from your coverage reports:

```
```txt
# For a summary:
lcov --summary your-coverage-report.dat
# For details:
Expand All @@ -55,26 +55,78 @@ echo "coverage report at file://${destdir}/index.html"

```

### Support for testing frameworks
## Support for testing frameworks

Coverage support has been only tested with [ScalaTest](http://www.scalatest.org/).

### Working around missing lambda coverage with Scala 2.12+
## JaCoCo

The current Jacoco version in Bazel (0.8.3) has missing coverage for lambdas
(including for comprehensions; see issue https://github.com/bazelbuild/rules_scala/issues/1056). Also, the support for
filtering out code generated by the Scala compiler is quite reduced in Jacoco.
`rules_scala` uses the [JaCoCo](https://www.jacoco.org/jacoco/) library imported
by the underlying [`rules_java`](https://github.com/bazelbuild/rules_java)
module to generate code coverage. `rules_java`, in turn, imports JaCoCo via the
[`java_tools`](https://github.com/bazelbuild/java_tools) repository, built from
the [tools/jdk/BUILD.java_tools](
https://github.com/bazelbuild/bazel/blob/master/tools/jdk/BUILD.java_tools) file
and [third_party/java/jacoco](
https://github.com/bazelbuild/bazel/blob/master/third_party/java/jacoco/BUILD)
package in the Bazel source. `java_tools` and `rules_java` are released more
frequently than Bazel itself, decoupling them from the Bazel release cycle.

This can be worked around by building a fixed version of Jacoco yourselves (including backported fixes from 0.8.5) and reconfiguring your
build to use that one instead of the default `jacocorunner`.
To check the version of JaCoCo used by a specific version of `rules_java`:

You can build jacocorunner with a script in `scripts/build_jacocorunner/build_jacocorunner.sh` (see comments there for more explanation and options).
- Open [`java/repositories.bzl` in the `rules_java` source](
https://github.com/bazelbuild/rules_java/blob/master/java/repositories.bzl).

- Select a specific version of `rules_java` using the **Switch branches/tabs**
dropdown menu.

- Alternatively, replace `master` with the `rules_java` version in the
`java/repositories.bzl` URL.

- Make note of the version of `java_tools` specified in the `JAVA_TOOLS_CONFIG`
dictionary. For example, [`rules_java` 8.9.0 uses `java_tools` v.13.16](
https://github.com/bazelbuild/rules_java/blob/8.9.0/java/repositories.bzl#L49).

- Download the `java_tools` archive using the archive URL:

```txt
curl -LO https://mirror.bazel.build/bazel_java_tools/releases/java/v13.16/java_tools-v13.16.zip
```
- Unzip the archive, then inspect the top level `BUILD` file:
An older version of this script (for Bazel 4) can be found in `scripts/build_jacocorunner/build_jacocorunner_bazel_4.0.sh`.
```sh
$ grep 'jacoco\.core-' BUILD
jars = ["java_tools/third_party/java/jacoco/org.jacoco.core-0.8.11.jar"],
srcjar = "java_tools/third_party/java/jacoco/org.jacoco.core-0.8.11-sources.jar",
srcs = ["java_tools/third_party/java/jacoco/org.jacoco.core-0.8.11.jar"],
```
| `rules_java` version | `java_tools` version | JaCoCo version |
| :-: | :-: | :-: |
| [8.9.0](https://github.com/bazelbuild/rules_java/blob/8.9.0/java/repositories.bzl#L49) | v13.16 | [0.8.11][JaCoCo version] |
| [7.12.4](https://github.com/bazelbuild/rules_java/blob/7.12.4/java/repositories.bzl#L49) | v13.9 | [0.8.11][JaCoCo version] |
For information on updating the [JaCoCo version][] used by `rules_java`,
`java_tools`, and Bazel, see [Bazel's &quot;Upgrading Jacoco version&quot;
README](
https://github.com/bazelbuild/bazel/blob/master/third_party/java/jacoco/README.md).
[JaCoCo version]: https://www.jacoco.org/jacoco/trunk/doc/changes.html
## Working around missing JaCoCo features
The version of JaCoCo that ships with `rules_java` may lack support for newer
Scala features. To work around this, build an updated version of JaCoCo and
configure the project to use this new artifact instead of the default
`jacocorunner`.
You can build jacocorunner with a script in `scripts/build_jacocorunner/build_jacocorunner.sh` (see comments there for more explanation and options).
Then, you can use the `jacocorunner` property of `scala_toolchain` to provide the jacocorunner you have built:
```
```py
# Example contents of coverage_local_jacocorunner/BUILD
scala_toolchain(
name = "local_jacocorunner_toolchain_impl",
Expand All @@ -85,7 +137,7 @@ scala_toolchain(
toolchain(
name = "local_jacocorunner_scala_toolchain",
toolchain = "local_jacocorunner_toolchain_impl",
toolchain_type = "@io_bazel_rules_scala//scala:toolchain_type",
toolchain_type = "@rules_scala//scala:toolchain_type",
visibility = ["//visibility:public"],
)
Expand All @@ -100,15 +152,15 @@ keeping binaries in your repository).

Finally, provide the `scala_toolchain` in your `.bazelrc` or as an option to `bazel coverage`:

```
```txt
coverage --extra_toolchains="//coverage_local_jacocorunner:local_jacocorunner_scala_toolchain"
```

You could also register the toolchain in your `WORKSPACE`.

You can verify that the locally built `jacocorunner` works with `manual_test/coverage_local_jacocorunner/test.sh`.

#### Notes
## Notes

Please ensure these scripts use Java 8.

Expand Down
96 changes: 63 additions & 33 deletions docs/cross-compilation.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,24 @@ Read *Quick start* for an information on how to use cross compilation.
The remaining sections contain more detailed information, useful especially for toolchain & rule developers.

## Quick start

`scala_config` repository rule accepts two parameters related to Scala version:
* `scala_version` – a single, default version;
* `scala_versions` – a list of versions to make available for use.

- `scala_version` – a single, default version;
- `scala_versions` – a list of versions to make available for use.

The first one, `scala_version`, will be used as a default, but it can be overridden for specific targets for any version from the `scala_versions`.

Multiple rules, such as:

- [scala_library](/scala/private/rules/scala_library.bzl)
- [scala_binary](/scala/private/rules/scala_binary.bzl)
- [scala_repl](/scala/private/rules/scala_repl.bzl)
- [scala_test](/scala/private/rules/scala_test.bzl)

support such override via the `scala_version` attribute, e.g.:
```starlark

```py
scala_library(
name = ...
...
Expand All @@ -32,16 +36,19 @@ For this library and all its dependencies 2.12.18 compiler will be used, unless

`scala_config` creates the repository `@io_bazel_rules_scala_config`.
File created there, `config.bzl`, consists of many variables. In particular:
* `SCALA_VERSION` – representing the default Scala version, e.g. `"3.3.1"`;
* `SCALA_VERSIONS` – representing all configured Scala versions, e.g. `["2.12.18", "3.3.1"]`.

- `SCALA_VERSION` – representing the default Scala version, e.g. `"3.3.1"`;
- `SCALA_VERSIONS` – representing all configured Scala versions, e.g. `["2.12.18", "3.3.1"]`.

## Build settings

Configured `SCALA_VERSIONS` correspond to allowed values of [build setting](https://bazel.build/extending/config#user-defined-build-setting).

### `scala_version`

`@io_bazel_rules_scala_config` in its root package defines the following build setting:
```starlark

```py
string_setting(
name = "scala_version",
build_setting_default = "3.3.1",
Expand All @@ -50,45 +57,56 @@ string_setting(
)
...
```

This build setting can be subject of change by [transitions](https://bazel.build/extending/config#user-defined-transitions) (within allowed `values`).

### Config settings

Then for each Scala version we have a [config setting](https://bazel.build/extending/config#build-settings-and-select):
```starlark

```py
config_setting(
name = "scala_version_3_3_1",
flag_values = {":scala_version": "3.3.1"},
)
...
```

The `name` of `config_setting` corresponds to `"scala_version" + version_suffix(scala_version)`.
One may use this config setting in `select()` e.g. to provide dependencies relevant to a currently used Scala version.


## Version-dependent behavior

Don't rely on `SCALA_VERSION` as it represents the default Scala version, not necessarily the one that is currently requested.

If you need to customize the behavior for specific Scala version, there are two scenarios.

### From toolchain
If you have an access to the Scala toolchain (`@io_bazel_rules_scala//scala:toolchain_type`), there is `scala_version` field provided in there:
```starlark

`@rules_scala//scala:toolchain_type` provides the `scala_version` field:

```py
def _rule_impl(ctx):
...
ctx.toolchains["@io_bazel_rules_scala//scala:toolchain_type"].scala_version
ctx.toolchains["@rules_scala//scala:toolchain_type"].scala_version
...
```

### From config setting

In BUILD files, you need to use the config settings with `select()`.
Majority of use cases is covered by the `select_for_scala_version` utility macro.
If more flexibility is needed, you can always write the select manually.

#### With select macro

See example usage of the `select_for_scala_version`:

```starlark
load("@io_bazel_rules_scala//:scala_cross_version_select.bzl", "select_for_scala_version")
```py
load(
"@rules_scala//:scala_cross_version_select.bzl",
"select_for_scala_version",
)

scala_library(
...
Expand All @@ -113,43 +131,49 @@ scala_library(
See complete documentation in the [scala_cross_version_select.bzl](/scala/scala_cross_version_select.bzl) file

#### Manually

An example usage of `select()` to provide custom dependency for specific Scala version:
```starlark

```py
deps = select({
"@io_bazel_rules_scala_config//:scala_version_3_3_1": [...],
...
})
```

For more complex logic, you can extract it to a `.bzl` file:
```starlark

```py
def srcs(scala_version):
if scala_version.startswith("2"):
...
...
```

and then in the `BUILD` file:
```starlark
load("@io_bazel_rules_scala//:scala_cross_version.bzl", "version_suffix")
load("@io_bazel_rules_scala_config//:config.bzl", "SCALA_VERSIONS")

```py
load("....bzl", "srcs")
load("@io_bazel_rules_scala_config//:config.bzl", "SCALA_VERSIONS")
load("@rules_scala//:scala_cross_version.bzl", "version_suffix")

scala_library(
...
srcs = select({
"@io_bazel_rules_scala_config//:scala_version" + version_suffix(v): srcs(v)
for v in SCALA_VERSIONS
}),
}),
...
)
```


## Requesting specific version

To use other than default version of Scala, you need to change the current `@io_bazel_rules_scala_config//:scala_version` build setting.

Simple transition, setting the Scala version to one found in `scala_version` attribute:
```starlark

```py
def _scala_version_transition_impl(settings, attr):
if attr.scala_version:
return {"@io_bazel_rules_scala_config//:scala_version": attr.scala_version}
Expand All @@ -164,8 +188,13 @@ scala_version_transition = transition(
```

To use it in a rule, use the `scala_version_transition` as `cfg` and use `toolchain_transition_attr` in `attrs`:
```starlark
load("@io_bazel_rules_scala//scala:scala_cross_version.bzl", "scala_version_transition", "toolchain_transition_attr")

```py
load(
"@rules_scala//scala:scala_cross_version.bzl",
"scala_version_transition",
"toolchain_transition_attr",
)

_scala_library_attrs.update(toolchain_transition_attr)

Expand All @@ -183,13 +212,13 @@ def make_scala_library(*extras):
)
```


## Toolchains

Standard [toolchain resolution](https://bazel.build/extending/toolchains#toolchain-resolution) procedure determines which toolchain to use for Scala targets.

Toolchain should declare its compatibility with Scala version by using `target_settings` attribute of the `toolchain` rule:

```starlark
```py
toolchain(
...
target_settings = ["@io_bazel_rules_scala_config//:scala_version_3_3_1"],
Expand All @@ -198,16 +227,17 @@ toolchain(
```

### Cross-build support tiers

`rules_scala` consists of many toolchains implementing various toolchain types.
Their support level for cross-build setup varies.

We can distinguish following tiers:

* No `target_settings` set – not migrated, will work on the default `SCALA_VERSION`; undefined behavior on other versions.
* (all toolchains not mentioned elsewhere)
* `target_settings` set to the `SCALA_VERSION` – not fully migrated; will work only on the default `SCALA_VERSION` and will fail the toolchain resolution on other versions.
* (no development in progress)
* Multiple toolchain instances with `target_settings` corresponding to each of `SCALA_VERSIONS` – fully migrated; will work in cross-build setup.
* [the main Scala toolchain](/scala/BUILD)
* [Scalafmt](/scala/scalafmt/BUILD)
* [Scalatest](/testing/testing.bzl)
- No `target_settings` set – not migrated, will work on the default `SCALA_VERSION`; undefined behavior on other versions.
- (all toolchains not mentioned elsewhere)
- `target_settings` set to the `SCALA_VERSION` – not fully migrated; will work only on the default `SCALA_VERSION` and will fail the toolchain resolution on other versions.
- (no development in progress)
- Multiple toolchain instances with `target_settings` corresponding to each of `SCALA_VERSIONS` – fully migrated; will work in cross-build setup.
- [the main Scala toolchain](/scala/BUILD)
- [Scalafmt](/scala/scalafmt/BUILD)
- [Scalatest](/testing/testing.bzl)
Loading

0 comments on commit a92bc76

Please sign in to comment.