8.6 KiB
GitHub Actions Workflow Maintenance Guide
This document provides guidance for maintaining the GitHub Actions workflows in this repository.
format.yml Workflow
Overview
The format.yml workflow runs code formatters (Prettier, clang-format, and cargo fmt) on pull requests and pushes to main. It's optimized for speed by running all formatters in parallel. It also regenerates the checked-in *.generated.rs string maps (bun run codegen:string-maps) before the formatters start: everything the step leaves modified, formatting or codegen, is what the autofix.ci action at the end of the job pushes back to the PR (failing the run when it had anything to push), so nothing that produces fixes may run after it, and nothing that only verifies should run before it.
Key Components
1. Clang-format Script (scripts/run-clang-format.sh)
- Purpose: Formats C++ source and header files
- What it does:
- Globs C++ files via
bun scripts/glob-sources.ts cxx - Finds all header files in
src/andpackages/ - Excludes third-party directories (libuv, napi, deps, vendor, sqlite, etc.)
- Requires specific clang-format version (no fallbacks)
- Globs C++ files via
Important exclusions:
src/runtime/napi/- Node API headers (third-party)src/jsc/bindings/libuv/- libuv headers (third-party)src/jsc/bindings/sqlite/- SQLite headers (third-party)src/runtime/ffi/ffi-*.h- FFI headers (generated/third-party)src/deps/- Dependencies (third-party)- Files in
vendor/,third_party/,generated/directories
2. Parallel Execution
The workflow runs all three formatters simultaneously:
- Each formatter outputs with a prefix (
[prettier],[clang-format],[rustfmt]) - Output is streamed in real-time without blocking
- Uses GitHub Actions groups (
::group::) for collapsible sections
3. Tool Installation
Clang-format-21
- Installs ONLY
clang-format-21package (not the entire LLVM toolchain) - Uses
--no-install-recommends --no-install-suggeststo skip unnecessary packages - Quiet installation with
-qqand-o=Dpkg::Use-Pty=0
Rustfmt
- The pinned nightly is set via
RUSTUP_TOOLCHAINin the stepenv:(kept in sync withchannelinrust-toolchain.toml);cargo fmt --allruns against the workspace at the repo root. RUSTUP_TOOLCHAINmakes rustup ignorerust-toolchain.tomlentirely, so the workflow installs only the host toolchain +rustfmt(rustup toolchain install --profile minimal --component rustfmt) rather than the file's full cross-target list.
Updating the Workflow
To update the Rust toolchain:
- Bump
channelinrust-toolchain.toml(andDockerfile/bootstrap.shto match). - Bump
RUSTUP_TOOLCHAINin theFormat Codestep'senv:block informat.ymlto the same value. - Bump
RUSTUP_TOOLCHAINin the workflow-levelenv:block inrust-lints.ymlto the same value. cargo fmtformatting can change between nightlies; runcargo fmt --alllocally on the new toolchain and include the resulting diff in the same PR.
To update clang-format version:
- Update
LLVM_VERSION_MAJORenvironment variable at the top of format.yml - Update the version check in
scripts/run-clang-format.sh
To add/remove file exclusions:
- Edit the exclusion patterns in
scripts/run-clang-format.sh(lines 34-39) - Test locally to ensure the right files are being formatted
Performance Optimizations
- Parallel execution: All formatters run simultaneously
- Minimal installations: Only required packages, no extras
- Streaming output: Real-time feedback without buffering
- Early start: Formatting begins immediately after each tool is ready
Troubleshooting
If formatters appear to run sequentially:
- Check if output is being buffered (should use
sedfor line prefixing) - Ensure background processes use
&and proper wait commands
If third-party files are being formatted:
- Review exclusion patterns in
scripts/run-clang-format.sh - Check if new third-party directories were added that need exclusion
If clang-format installation is slow:
- Ensure using minimal package installation flags
- Check if apt cache needs updating
- Consider caching the clang-format binary between runs
Testing Changes Locally
# Test the clang-format script
export LLVM_VERSION_MAJOR=19
./scripts/run-clang-format.sh format
# Test with check mode (no modifications)
./scripts/run-clang-format.sh check
# Test specific file exclusions
./scripts/run-clang-format.sh format 2>&1 | grep -E "(libuv|napi|deps)"
# Should return nothing if exclusions work correctly
Important Notes
- The script defaults to format mode (modifies files)
- Always test locally before pushing workflow changes
- Keep the exclusion list updated as new third-party code is added
rust-lints.yml Workflow
Four independent jobs that each run one cargo command over the Rust workspace. They share .github/actions/rust-lint-setup, a composite action that installs LLVM from apt.llvm.org (configure resolves a clang even though nothing here compiles C++), Bun, optionally a pinned Rust toolchain plus components, runs bun install, then bun scripts/build.ts --configure-only and the ninja targets a job asks for: clone-lolhtml (cargo cannot resolve the workspace until the vendored lol_html path dependency exists) and, for jobs that check bun_runtime/bun_jsc/bun_core, codegen (their include!()d sources under build/debug/codegen).
| Job | Check name | Runs | Blocking |
|---|---|---|---|
clippy |
cargo clippy |
bun run rust:clippy |
yes |
miri |
cargo miri test |
bun run rust:miri (scripts/rust-miri.ts) |
yes |
lolhtml |
lol-html cargo test |
cargo test in vendor/lolhtml |
yes |
mordant |
mordant |
cargo dylint --all --workspace |
advisory (continue-on-error) |
clippy,miriandlolhtmlpinRUSTUP_TOOLCHAINat the workflow level (kept in sync withchannelinrust-toolchain.toml) so rustup does not install that file's cross-target list; the action installs the toolchain with--profile minimalplus the components the job names (clippy,miri rust-src, none).lolhtmlexists because the vendored lol-html is a fork (oven-sh/lol-html,bunbranch) whose own test suite is the only thing guarding the fork's invariants. It used to trigger only onscripts/build/deps/lolhtml.ts; it now shares the workflow's wider path filter.mordantruns the mordant dylint pack. It setsRUSTUP_TOOLCHAIN: stableinstead: mordant is built with, and lints us using, the nightly named in its own rust-toolchain file, which dylint fetches on demand, so the outer cargo only needs to exist. Because that nightly is older than ours, the job passes-A unknown_lintsthroughDYLINT_RUSTFLAGS. Two caches cover the slow parts:~/.cargo/bin/{cargo-dylint,dylint-link}keyed onDYLINT_VERSION, and~/.dylint_drivers+target/dylint/librarieskeyed onDYLINT_VERSIONplus the pinned mordant rev read out ofCargo.toml. It is skipped onmerge_group.
mordant: pin, baseline, disabled lints
- The pack is pinned by commit in
Cargo.tomlunder[workspace.metadata.dylint]. A bump can also fail if this workspace stops compiling on mordant's nightly. dylint.toml's[mordant]table pointsbaselineatmordant-baseline.toml(per-(lint, file) counts of the findings that predate the job) and lists the lints this repo has switched off underdisabled, each with its reason.- In baseline mode mordant prints findings over the baseline as warnings and writes them to
target/mordant/over-baseline.txt(relative to the workspace root). The job deletes that file, runs dylint, and fails if the file is non-empty; absent or empty means clean. Fixing baselined findings needs no baseline update. - Locally,
bun run rust:mordantis the same dylint invocation andbun run rust:mordant:baselineregenerates the baseline (MORDANT_BASELINE_WRITE=1). Both needcargo install cargo-dylint dylint-linkonce, and expectbuild/debug/codegenandvendor/lolhtmlto exist, which any normalbun bdleaves behind.
To bump mordant: change the rev in Cargo.toml, run bun run rust:mordant, fix what the new revision reports or regenerate mordant-baseline.toml with bun run rust:mordant:baseline, and put the triage in the PR description.