Let's not depend on a nightly pre-release, especially not just for a
linting option. We can enable the linter option once it lands in the
stable release.
Problem: A new upstream nightly Rust release made all CI lint code
checks fail in the Set Up Environment step
Cause: CI runs “rustup toolchain install nightly --component rustfmt”.
The runner container ships nightly with rustfmt and clippy preinstalled.
But “rustup toolchain install” treats an existing channel as an upgrade
target, and tries to refresh it whenever a newer nightly is available.
The refresh removes the old clippy component first, renaming
/opt/rustup/toolchains/.../share/doc/clippy into /opt/rustup/tmp/, and
those two directories live on different overlayfs mounts in the
container — so the rename fails with EXDEV.
Fix: Replace “rustup toolchain install nightly --component rustfmt” with
“rustup component add rustfmt --toolchain nightly”. That adds the
component to the existing toolchain without checking for or applying a
channel update — so the cross-mount-rename path is never reached.
Because the container already provisions rustfmt + clippy at build time,
the new command is effectively a no-op on healthy containers, and fails
loudly only if a future container loses the nightly toolchain.
The Linux CI workflows were still pinned to ladybird-ci:2026.05.4, even
though the CI image had since been rebuilt as 2026.05.25 after the Rust
toolchain switched to nightly.
This left CI running in an older container where cargo was not installed
for the nightly toolchain selected by the checked-out tree, causing Rust
crate builds to fail during the fuzzer host-tools build.
Update the workflow image references to the current published CI image.
By default, `rustfmt` persists the import granularity. In practice, most
Rust code has import granularity "Module" due to LSP's actions.
"Item" gets rid of import groupings and achieves cleaner diffs and
better conflict resolution. Better greppability is a positive side
effect.
Note: it's an unstable rustfmt feature. `cargo +nightly fmt` must be
used instead of `cargo fmt`.
Keep GCC compiler warning coverage on pull requests without running the
GCC sanitizer configuration that has been timing out in CI. Leave the
Clang sanitizer jobs in place for sanitizer coverage.
We were forgetting to pass CMake options in the Fuzzers build.
These CMake options contain -DENABLE_CI_BASELINE_CPU=ON, which sets
a baseline architecture to properly allow ccache sharing between
different runners. Without it, it defaults to the native architecture,
which is then cached and can be used on a runner that doesn't have the
same instruction set.
This is targetted at fixing the "Illegal instruction" crash we've been
seeing with the bindings generator.
CTest may run tests from build subdirectories. That means sanitizer logs
can be written below Build instead of the workspace root.
Search Build recursively when printing sanitizer output, and include
matching logs in the LibWeb test artifact.
Keep sanitizer log_path values relative so they work on Windows.
Absolute paths with drive letters contain colons there. That conflicts
with the ASAN_OPTIONS separator.
This means running the build inside a Docker container based on a (more)
stable build image.
* The setup action is now largely simplified for Linux.
* We hardcode llvm@21 for macOS since it allows us to get rid of
specifying llvm_version as an input variable. Since we no longer
support switching the LLVM version on Linux via that variable, this
seems like the best course of action.
We use a trick to optionally introduce a container image: `fromJSON()`
allows `null` as a return value, which causes the job to execute on the
runner directly. We need this for macOS and Windows jobs.
The goal is to have a stable, reproducible build environment for Linux
amd64 and arm64 that we can simply pull in for CI build jobs. We've seen
that apt repositories can be temporarily unreachable or build dependency
versions are silently updated causing builds to fail. A nice benefit of
this is that we can skip most of the environment setup, which takes a
couple of minutes each run.
The idea is that scripts directly under Meta are meant to be run by
people. Scripts that are only imported or run by other scripts are
moved to a subdirectory.
Note that the IPC lint step can be removed from the CI workflow because
we no longer need a build in order to perform the lint, and IPC linting
is now covered by lint-ci.sh.
The vcpkg cache should rarely change - only when new dependencies are
added or a version changes. Both of these events involve modifying the
vcpkg.json file. So instead of uploading duplicated vcpkg caches in each
workflow, let's only upload changed caches.
It doesn't make a whole lot of sense leaving out this variable. We use
the toolchain to construct the main cache key for our ccache and vcpkg
caches, and the JS+WASM artifacts build defaulted to 'GNU' for their
toolchain which got really confusing.
These were originally introduced to make it possible to discern between
GitHub's and Blacksmith's caches. This is no longer necessary since
Blacksmith resolved some issues _and_ switched to transparently
proxying GitHub cache actions to their own caches.
This allows us to get rid of the annoying Build/.../Lagom directory
and helps to deduplicate a bunch of logic while also drastically
simplifying everything.
This is largely based of off the work done by Andrew Kaster in #5918.
Having this toggle makes much more sense, especially if there will be
more UIs in the future.
Co-authored-by: Andrew Kaster <andrew@ladybird.org>