Skip to content

Upgrade to Bazel 8.7.0 - #144

Merged
aviator-app[bot] merged 11 commits into
mainfrom
rjh.bazel-8
Sep 2, 2026
Merged

aviator-app[bot] merged 11 commits into
mainfrom
rjh.bazel-8

Conversation

@rjhuijsman

@rjhuijsman rjhuijsman commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

Bazel 6.5.0 has been out of support for a long time, so we get no upstream fixes and the gap to whatever we eventually migrate to keeps growing. This PR moves the repo to Bazel 8.7.0, the newest stable Bazel that can still build a WORKSPACE repository — Bazel 9 removed all WORKSPACE logic, so anything newer would force a Bzlmod migration, which we deliberately keep as a separate step.

Each commit is one logical change with its own rationale to support Bazel 8; the last two are the Bazel 8 version flip itself and the removal of a flag that the flip makes redundant. Companion PRs: 3rdparty/stout#90 and reboot-dev/pyprotoc-plugin#48, whose commits this PR's submodule bump picks up.

@aviator-app

aviator-app Bot commented Aug 31, 2026

Copy link
Copy Markdown

Current Aviator status

Aviator will automatically update this comment as the status of the PR changes.
Comment /aviator refresh to force Aviator to re-examine your PR (or learn about other /aviator commands).

This PR was merged using Aviator (commit 0e5410e).


See the real-time status of this PR on the Aviator webapp.
Use the Aviator Chrome Extension to see the status of your PR within GitHub.

@rjhuijsman
rjhuijsman marked this pull request as ready for review September 1, 2026 14:03
@rjhuijsman
rjhuijsman requested review from onelxj and a balanced review from Copilot and removed request for Copilot September 1, 2026 14:03
@rjhuijsman rjhuijsman self-assigned this Sep 1, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Upgrades the build system to Bazel 8.7.0 while retaining WORKSPACE mode and addressing dependency and compatibility requirements.

Changes:

  • Updates Bazel, rules_python, Protobuf, and bazel_features.
  • Adds gRPC patches for generated protos and macOS linking.
  • Adjusts Python toolchains, runfiles handling, and build configuration.

Reviewed changes

Copilot reviewed 15 out of 26 changed files in this pull request and generated no comments.

Show a summary per file
File Description
.bazeliskrc Selects Bazel 8.7.0.
.bazelrc Preserves WORKSPACE mode and disables Python precompilation.
bazel/repos.bzl Updates dependencies and applies gRPC patches.
bazel/pypi_repos.bzl Uses the host Python interpreter target.
bazel/grpc_03_generated_protos_staging.patch Handles generated proto staging.
bazel/grpc_04_macos_dynamic_lookup.patch Fixes macOS Cython extension linking.
reboot/requirements.in Pins Protobuf 5.29.3.
reboot/requirements_lock.txt Regenerates the Protobuf lock entry.
tests/requirements.in Aligns the test Protobuf pin.
tests/requirements_lock.txt Regenerates the test lock entry.
reboot/routing/filters/BUILD.bazel Removes the relocated SHA-1 filegroup.
reboot/cli/commands/init/test.sh Resolves expected output beside the test executable.
reboot/cli/commands/init/nodejs_test.sh Updates Node.js test data lookup.
reboot/examples/reboot-swag-store/uv.lock Updates locked Protobuf artifacts.
reboot/examples/monorepo/uv.lock Updates locked Protobuf artifacts.
reboot/examples/kcdc-2025/uv.lock Updates locked Protobuf artifacts.
reboot/examples/chick-potle/uv.lock Updates locked Protobuf artifacts.
reboot/examples/chat-room/uv.lock Updates locked Protobuf artifacts.
reboot/examples/boutique/uv.lock Updates locked Protobuf artifacts.
reboot/examples/bank/uv.lock Updates locked Protobuf artifacts.
reboot/examples/bank-pydantic/uv.lock Updates locked Protobuf artifacts.
reboot/examples/ai-chat-counter/uv.lock Updates locked Protobuf artifacts.
reboot/examples/ai-chat-counter-dashboard/uv.lock Updates locked Protobuf artifacts.
reboot/examples/agent-wiki/uv.lock Updates locked Protobuf artifacts.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@github-actions

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Code review

No issues found. Checked for bugs and CLAUDE.md compliance.

@github-actions

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Code review

No issues found. Checked for bugs and CLAUDE.md compliance.

@github-actions

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Code review

No issues found. Checked for bugs and CLAUDE.md compliance.

@rjhuijsman
rjhuijsman force-pushed the rjh.bazel-8 branch 2 times, most recently from 95cfdc5 to 3b4ac5e Compare September 1, 2026 17:05
@github-actions

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Code review

No issues found. Checked for bugs and CLAUDE.md compliance.

rjhuijsman and others added 7 commits September 2, 2026 11:59
Prepares this repository for Bazel 8, in which
`--incompatible_disallow_empty_glob` defaults to true. Before this
change the `filegroup` globbed `sha1/src/**/*` from a package with no `sha1`
directory - the `sha1` submodule lives at `reboot/server/sha1`, and
`reboot/server/BUILD.bazel` already has the `sha1_lua` target that
actually matches it and is actually depended on. On Bazel 8 the empty
glob turns into `package contains errors: reboot/routing/filters`.

Nothing referenced `//reboot/routing/filters:sha1_lua`, so it is
deleted rather than repointed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QwqjZJ1LqSJp3cM9aJYFWi
Prepares this repository for Bazel 8, whose built-in WORKSPACE suffix
runs `rules_java` 8.12.0's `rules_java_dependencies()`. Loading that
`rules_java` needs `bazel_features` to expose
`rules._has_launcher_maker_toolchain`, which arrived in 1.30.0.

Before this change nothing declared `bazel_features` before
`grpc_deps()` did, at 1.14.0, and Bazel 8 failed the invocation with
`'struct' value has no field or method
'_has_launcher_maker_toolchain'` before it could load a single
package.

Declaring it in `repos()`, which runs before `deps()`, makes
`grpc_deps()`'s own declaration a no-op. Upgrading gRPC instead would
be a much larger change: its Python wheels have to stay aligned with
the `grpcio` version we pin in `reboot/requirements.in`.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QwqjZJ1LqSJp3cM9aJYFWi
Prepares this repository for Bazel 8, which removed the native
`PyInfo` and `PyRuntimeInfo` globals and instead autoloads them from
`@rules_python`. Before this change, `rules_python` 0.27.0 still
re-exported those globals, so every Bazel 8 invocation died while
computing the main repo mapping with `name 'PyInfo' is not defined`.

1.0.0 rather than a 0.4x release: 0.40.0's `py_repositories()`
declares `rules_cc` 0.0.13 and `protobuf` 27.0 with plain
`http_archive` calls, which override whatever we declared earlier -
`maybe()` cannot defend against that. `rules_cc` 0.0.13's
`cc/defs.bzl` then takes `cc_proto_library` from that `@protobuf`
27.0, where it is only a stub reading `native.cc_proto_library`, a
symbol Bazel 8 no longer has, so loading any package that uses
`@rules_cc//cc:defs.bzl` failed. 1.0.0 switched both declarations to
`maybe()` and to versions that work on Bazel 8.

Two follow-on changes come with the upgrade:

- 1.0.0 dropped the `interpreter` symbol from the toolchain repo's
  `defs.bzl`, so `pip_parse` now names the `_host` repository's
  interpreter directly.
- 1.0.0 can precompile `.py` sources to `.pyc` at build time. Several
  of our `.py` files appear in the `srcs` of more than one target,
  which is fine on its own but gives each of those targets its own
  action writing the same `__pycache__/<name>.cpython-310.pyc`, and
  Bazel rejects that as conflicting actions. Precompiling only moves
  work the interpreter already does on first import, so `.bazelrc`
  turns it off rather than us restructuring the targets.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QwqjZJ1LqSJp3cM9aJYFWi
Prepares this repository for Bazel 8, which no longer has a native
`proto_library`; it autoloads the rule from Protobuf's own Starlark
implementation in `bazel/proto_library.bzl` instead. Protobuf 27.1
only has a stub there that reads `native.proto_library`, so on Bazel 8
loading any package with a `proto_library` failed with `no native
function or rule 'proto_library'`. 29.x is the first release with a
real implementation.

29.3 specifically: it is what `stout` already pins, it is what
`rules_java` 8.12.0 expects, and gRPC 1.71.0 - the version we pin -
builds against Protobuf 29.

Generated Python code refuses to load against an older runtime, so the
`protobuf` pin moves from 5.28.3 to 5.29.3 in lockstep; without it
every `protoc` invocation that runs our own Python plugins died with
`Detected incompatible Protobuf Gencode/Runtime versions ... gencode
5.29.3 runtime 5.28.3`. `grpcio-tools` 1.64.3 accepts any `protobuf`
below 6.0, so the `grpcio` pin is unaffected.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QwqjZJ1LqSJp3cM9aJYFWi
Prepares this repository for Bazel 8. Bazel's native `proto_library`
used to place generated `.proto` sources under `_virtual_imports` (see
Bazel's `--incompatible_generated_protos_in_virtual_imports`).
Protobuf's Starlark reimplementation, which Bazel 8 autoloads in place
of the native rule, only creates virtual imports when `import_prefix`
or `strip_import_prefix` is set, so a generated `.proto` now reaches
gRPC's `get_staged_proto_file()` as a plain file under
`bazel-out/.../bin`.

Before this change that made gRPC take its "different package" branch
and strip a source-tree prefix off an output-tree path. Whether the
result was merely wrong or fatal depended on how long the package path
happened to be; for `tests/reboot/pydantic_web/nested_types` it
produced `/pydantic_web/nested_types/servicer_api.proto` and failed
analysis outright.

`declare_out_files()`, immediately below the patched function, already
knows how to handle a generated proto that sits in its own package
directory, so the patch teaches `get_staged_proto_file()` the same
check and leaves such a file alone.

Two alternatives were rejected: giving our generated `proto_library`
targets a `strip_import_prefix` to force virtual imports would change
the import path every consumer of those protos sees, and upgrading
gRPC would drag the `grpcio` Python pin along with it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QwqjZJ1LqSJp3cM9aJYFWi
Picks up the Bazel 8 preparation in both submodules. They are
`local_repository` dependencies, so their `repos()` functions are what
declare `rules_java` and `bazel_skylib` at versions Bazel 8 can use,
and their `pip_parse` calls need the same `interpreter` fix as ours.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QwqjZJ1LqSJp3cM9aJYFWi
Before this change we built with Bazel 6.5.0, which reached end of
support long ago; staying on it means no upstream fixes and a growing
gap to whatever we eventually migrate to.

8.7.0 is the newest stable Bazel that can still build a `WORKSPACE`
repository. Bazel 9 removed all `WORKSPACE` logic, so going further
would force a Bzlmod migration, which we deliberately keep as a
separate step.

Bazel 8 disables `WORKSPACE` by default, so `.bazelrc` now asks for it
explicitly. Our existing `--enable_bzlmod=false` is not enough on its
own: Bazel then refuses to fetch anything at all, with `Both
--enable_bzlmod and --enable_workspace are disabled, but one of them
must be enabled to fetch external dependencies.`

The preceding commits make the dependency versions and BUILD files
Bazel 8 needs.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QwqjZJ1LqSJp3cM9aJYFWi
rjhuijsman and others added 4 commits September 2, 2026 11:59
The flag defaults to true from Bazel 7 on, which the comment on it
already anticipated, so on Bazel 8.7.0 it only restates a default.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QwqjZJ1LqSJp3cM9aJYFWi
Bazel 8's test setup no longer defines an implicit `rlocation` shell
function; a test that calls one now aborts with `rlocation is no
longer implicitly provided by Bazel's test setup`. Before this change
that took out `//tests/reboot/cli/init:init_sh_test_python311` and
`//tests/reboot/cli/init:init_nodejs_sh_test` after their assertions
had already passed.

Both call sites passed an absolute path - `$(dirname "$0")/...` - and
Bazel's `rlocation` echoed absolute paths back unchanged, so the call
was already doing nothing. Dropping it keeps the behaviour identical.
Sourcing `rules_shell`'s `runfiles.bash` instead would mean naming the
files by repository-qualified runfiles path, which is a bigger change
for no gain here.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QwqjZJ1LqSJp3cM9aJYFWi
`cython_library()` builds each Cython extension as a `cc_binary` with
`linkshared = 1` that deliberately leaves every `Py*` symbol
undefined, for the interpreter that loads it to resolve. On MacOS that
only links with `-undefined dynamic_lookup`.

Bazel 6's MacOS crosstool added that flag to every dynamic-library
link action from its `default_link_flags` feature; Bazel 8's does not.
Before this change, `Build public repo for MacOS arm64` failed
linking `cygrpc.so` with several hundred `Undefined symbols for
architecture arm64` errors.

Passing the flag through `--linkopt` in `.bazelrc` would apply it to
every MacOS link, including executables, where it would turn a genuine
missing-symbol error into a crash at run time. Setting it on the one
target that wants it keeps that error checking everywhere else.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QwqjZJ1LqSJp3cM9aJYFWi
Our example projects lock their transitive dependencies against the
*released* `reboot` wheel, but their Docker-based tests run against
the *dev* wheel, which is pre-installed in the locally built
`reboot-base` image. Both agreed on `protobuf` 5.28.3 until the
Protobuf upgrade earlier in this branch moved the dev wheel to 5.29.3.

Before this change, the `pip install` of the `uv export`ed lockfile
inside each example's Docker build then had to satisfy both
`protobuf==5.28.3` (from the lockfile) and `protobuf==5.29.3` (from
the already-installed dev `reboot`), and failed with
`ResolutionImpossible`. That took out `serve_test` on the Linux arm64
runner, which unlike x86_64 does not filter out `requires-docker`
tests.

`uv lock` cannot produce these lockfiles on its own yet: the released
`reboot` 1.4.1 on PyPI still declares `protobuf==5.28.3`, so a plain
re-resolve returns 5.28.3. Each lockfile was therefore re-resolved
with a temporary `[tool.uv] override-dependencies` entry forcing
5.29.3, and only the `protobuf` entry changed. The next release runs
`make lockfiles`, which re-resolves them against the newly published
`reboot` and reaches the same place on its own.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QwqjZJ1LqSJp3cM9aJYFWi
@aviator-app
aviator-app Bot merged commit 0e5410e into main Sep 2, 2026
24 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants