Skip to content

Release/1.2.0 - #1

Merged
marvin-hansen merged 22 commits into
mainfrom
release/1.2.0
Aug 13, 2026
Merged

Release/1.2.0#1
marvin-hansen merged 22 commits into
mainfrom
release/1.2.0

Conversation

@marvin-hansen

Copy link
Copy Markdown
Collaborator

Merging preparation for version 1.2.0

Let a build use a hermetic toolchain instead of probing the host for an Elixir
install.
Same GNU-tar assumption fixed in rules_erlang: --transform does not exist in the
bsdtar macOS ships, so every Elixir target failed on macOS before compiling.
elixir_app hard-failed on any package without a LICENSE file. Separately,
elixir_bytecode could not declare compile-time file inputs, so packages reading
a file at compile time, or declaring @external_resource, failed in the sandbox.
Three problems in one file. Dependencies were staged without their include/
directories, so a test using Record.extract(from_lib: ...) died before running a
case. srcs/data were flattened by stripping the package prefix, breaking any
test resolving a repo-relative path off __DIR__. And everything was copied into
TEST_UNDECLARED_OUTPUTS_DIR and run there -- Bazel treats that as artifacts the
test produced, so each target stat'd, mime-typed and uploaded a few thousand of
its own inputs per run, and emitted ~2,150 "command not found" lines on an
executor carrying no file(1). Nothing was ever collected from there on purpose.
Also a semantic correction: the old key matched the HOST, while the flag decides
whether the generated runner is a batch file or a shell script -- a property of
the platform the test EXECUTES on, which for a test rule is the target platform.
The rules could compile an Elixir app but not produce a .ez archive, and
mix archive.install is the only way to give Mix something it needs before it can
resolve a project. Adapted from rabbitmq-server's
bazel/elixir/mix_archive_build.bzl (MPL-2.0), the same lineage as this ruleset.
Every consumer needs this and cannot discover it: Mix aborts with "Could not
find an SCM for dependency" on any dependency entry in a mix.exs unless Hex is
installed as an archive -- including a build that supplies all deps from Bazel
and passes --no-deps-check. Hex has no dependencies of its own, so it bootstraps
with an empty dep graph.
The README documented neither installation nor the rules the ruleset provides.
It now covers bzlmod setup, the toolchain extension, every public rule, and the
Hex archive extension.

The Broadcom copyright notice moves verbatim to COPYRIGHT.md, along with the
fork point and the mix_archive_build attribution. The README keeps a License
section that points at it.
First release from bazelverse/rules_elixir, continuing from v1.1.0. Requires
rules_erlang 3.18.0. No breaking changes to the rules.
rules_erlang 3.18.0 declares bazel_compatibility >=8.0.0, and this ruleset
requires it, so Bazel 7 was already unreachable. Declared explicitly rather than
left to fail somewhere further in. .bazelversion pins 9.2.0, the latest stable.

bazel_skylib moves 1.7.1 -> 1.9.2. platforms 1.1.0 is new: ex_unit_test selects
on @platforms//os:windows, and the dependency belongs to the module that writes
the select rather than to everyone who calls the macro.

rules_erlang 3.18.0 comes from bazelverse via git_override. Ownership of its
registry entry is still being transferred from rabbitmq, so the bazel_dep cannot
resolve on its own yet. Overrides only take effect in the root module, so this
one covers this repository's build alone and consumers still need their own.
…umer

The select key is a Label rather than the bare string "@platforms//os:windows".
A select key written as a string resolves against the repo mapping of the
package that instantiates the macro, so the string form obliged every consumer
to declare bazel_dep(name = "platforms") and failed with "No repository visible
as '@platforms'" if they did not.

The question never arose while the key was @bazel_tools//src/conditions:host_windows,
because bazel_tools is an implicit dependency of every module. Migrating to the
platforms constraint introduced the requirement silently: a consumer that
happened to declare platforms for its own reasons would never have noticed.
The runner asserted on the summary line, matching "0 failure" and "[0-9] test".
Elixir 1.20 replaced "N tests, M failures" with "Result: N passed", so on it
every passing suite failed its own assertion.

Failure detection now rests on elixir's exit code, which the set -eo pipefail at
the top of the runner already carried through the tee, and which does not change
between releases. The greps were never needed for that.

One assertion on the summary remains, because there is exactly one condition an
exit code cannot express: a suite that executed no tests exits 0. Without the
guard, a target whose srcs stopped matching any test would pass forever. Both
spellings are matched while the supported window spans Elixir 1.19 and 1.20.
sh_test stopped being a native rule in Bazel 8, so BUILD.bazel loads it from
@rules_shell and the module declares that dependency. The load without the
bazel_dep fails only when the module is built, which a repository-root
bazel test never does.

broken_test asserts that a failure in the elixir invocation itself, rather than
in a test case, still fails the target. It passed "-e ExUnit.configure(seed: 0)"
and relied on that raising because ExUnit had not started yet; Elixir 1.20
accepts it, so the target stopped being broken and the assertion stopped
asserting anything. It now raises outright, which breaks on every version.

Verified that failing_test, broken_test and empty_test all still fail. empty_test
in particular passes on exit code alone and is caught only by the no-tests guard.
Bazel 8 removed the autoconfigured local_config_platform repository, so the
platforms inherit from @platforms//host:host instead. They also register
themselves as execution platforms: Bazel 9 resolves a test toolchain against the
target platform, and a platform that is not also an execution platform fails
analysis with "No matching toolchains found".

internal-elixir built OTP 26.2.5 and Elixir 1.16.1. It is the only from-source
coverage in the repository and it sat two OTP majors behind the supported
window, so it now builds OTP 29.0.5 and Elixir 1.20.3. Both checksums are of the
exact archives the extensions fetch. The config names, platform names and
constraint values move with them.

Dropped the BuildBuddy endpoints, which point at an account this project does
not own; that belongs in a user.bazelrc.
Every .bazelrc carried a registry entry for
rabbitmq/bazel-central-registry@erlang-packages, a private fork this project
cannot write to. It served rules_erlang 3.15.x and nothing reads it now.

The checked-in MODULE.bazel.lock files still pinned rules_erlang 3.15.x through
that registry. They are untracked and ignored, matching rules_erlang.

GitHub CI covers the latest two Elixir minors against the latest two OTP majors:
1.20 on OTP 29 and 1.19 on OTP 28. Elixir supports a moving window of OTP
majors, so the matrix tests pairs rather than crossing the two lists, which
would generate combinations Elixir does not support.

The registry presubmit carries the Bazel matrix at 8.x and 9.x, and installs
Elixir, which it never did: it built @rules_elixir//... with only Erlang on the
machine and nothing for the external Elixir toolchain to resolve. Its structure
comes from upstream's rabbitmq#7, merged in through
28bafd6 -- the tasks: schema and the kerl activate. The versions are ours.

Publishing moves to bazel-contrib/publish-to-bcr, and the registry metadata to
this repository and its maintainer.

Fixed the source template's archive name. It asked for rules_elixir-{TAG}.tar.gz
while the release workflow uploads rules_elixir-{VERSION}.tar.gz. Those are equal
only when the tag carries no prefix, and this repository tags with a leading v,
so the published URL would have been rules_elixir-v1.2.0.tar.gz and 404ed.
The README claimed Bazel 7 or newer, which was wrong in the other direction: 7 is
not supported at all.

Neither module is on the registry yet, so the install section gives both
overrides, in tag and commit form, and says why a consumer declares an override
for rules_erlang despite depending on it only through this ruleset. Also notes
the asymmetry in strip_prefix, since the two repositories tag differently.

The internal_elixir_from_github_release example pinned 1.17.3, outside the
supported window; it is 1.20.3 with a real checksum.

Drops the "Maintenance Status" section that came in with the upstream merge. It
reads as this project declaring itself unmaintained, and points at a fork URL
that is not where this lives.
First release from bazelverse/rules_elixir, continuing from v1.1.0. Requires
rules_erlang 3.18.0 and Bazel 8 or newer. No breaking changes to the rules.
The no-tests guard added alongside the Elixir 1.20 summary fix was stricter than
1.1.0 and failed any target that runs no tests, including ones that run none
deliberately. Filtering by tag and excluding everything is a normal way to shard
a suite: serviceradar has five such targets, one of which excludes all 11 of its
tests because none carry the tag that shard selects.

Running nothing is only a defect when nothing was meant to run, so the guard now
requires that nothing ran AND nothing was excluded. Both summary formats report
the exclusion count, so both are read:

  Elixir 1.20   "Result: 0 tests"       vs "Result: 0 tests, 2 excluded"
  earlier       "0 tests, 0 failures"   vs "0 tests, 0 failures (11 excluded)"

//:empty_test still fails, which is the case that motivated the guard. Verified
against serviceradar: the five targets pass and its suite is back to 142 of 142.

Signed-off-by: Marvin Hansen <marvin.hansen@gmail.com>
git_override is the more common form and the one this project's own consumers
use. Dropping the archive form also drops the integrity-hash instructions and
the strip_prefix footnote about the two repositories tagging differently, none
of which a reader needs to get started.

Pin the commit a tag points at rather than the tag, since a SHA cannot be moved.

Signed-off-by: Marvin Hansen <marvin.hansen@gmail.com>
Signed-off-by: Marvin Hansen <marvin.hansen@gmail.com>
@marvin-hansen marvin-hansen self-assigned this Aug 13, 2026
@marvin-hansen
marvin-hansen merged commit b21df99 into main Aug 13, 2026
9 checks passed
@marvin-hansen
marvin-hansen deleted the release/1.2.0 branch August 13, 2026 07:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant