Files
bun-src/.github/workflows/CLAUDE.md
T
2026-08-27 21:09:14 +00:00

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/ and packages/
    • Excludes third-party directories (libuv, napi, deps, vendor, sqlite, etc.)
    • Requires specific clang-format version (no fallbacks)

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-21 package (not the entire LLVM toolchain)
  • Uses --no-install-recommends --no-install-suggests to skip unnecessary packages
  • Quiet installation with -qq and -o=Dpkg::Use-Pty=0
Rustfmt
  • The pinned nightly is set via RUSTUP_TOOLCHAIN in the step env: (kept in sync with channel in rust-toolchain.toml); cargo fmt --all runs against the workspace at the repo root.
  • RUSTUP_TOOLCHAIN makes rustup ignore rust-toolchain.toml entirely, 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:

  1. Bump channel in rust-toolchain.toml (and Dockerfile/bootstrap.sh to match).
  2. Bump RUSTUP_TOOLCHAIN in the Format Code step's env: block in format.yml to the same value.
  3. Bump RUSTUP_TOOLCHAIN in the workflow-level env: block in rust-lints.yml to the same value.
  4. cargo fmt formatting can change between nightlies; run cargo fmt --all locally on the new toolchain and include the resulting diff in the same PR.

To update clang-format version:

  1. Update LLVM_VERSION_MAJOR environment variable at the top of format.yml
  2. Update the version check in scripts/run-clang-format.sh

To add/remove file exclusions:

  1. Edit the exclusion patterns in scripts/run-clang-format.sh (lines 34-39)
  2. Test locally to ensure the right files are being formatted

Performance Optimizations

  1. Parallel execution: All formatters run simultaneously
  2. Minimal installations: Only required packages, no extras
  3. Streaming output: Real-time feedback without buffering
  4. 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 sed for 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, miri and lolhtml pin RUSTUP_TOOLCHAIN at the workflow level (kept in sync with channel in rust-toolchain.toml) so rustup does not install that file's cross-target list; the action installs the toolchain with --profile minimal plus the components the job names (clippy, miri rust-src, none).
  • lolhtml exists because the vendored lol-html is a fork (oven-sh/lol-html, bun branch) whose own test suite is the only thing guarding the fork's invariants. It used to trigger only on scripts/build/deps/lolhtml.ts; it now shares the workflow's wider path filter.
  • mordant runs the mordant dylint pack. It sets RUSTUP_TOOLCHAIN: stable instead: 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_lints through DYLINT_RUSTFLAGS. Two caches cover the slow parts: ~/.cargo/bin/{cargo-dylint,dylint-link} keyed on DYLINT_VERSION, and ~/.dylint_drivers + target/dylint/libraries keyed on DYLINT_VERSION plus the pinned mordant rev read out of Cargo.toml. It is skipped on merge_group.

mordant: pin, baseline, disabled lints

  • The pack is pinned by commit in Cargo.toml under [workspace.metadata.dylint]. A bump can also fail if this workspace stops compiling on mordant's nightly.
  • dylint.toml's [mordant] table points baseline at mordant-baseline.toml (per-(lint, file) counts of the findings that predate the job) and lists the lints this repo has switched off under disabled, 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:mordant is the same dylint invocation and bun run rust:mordant:baseline regenerates the baseline (MORDANT_BASELINE_WRITE=1). Both need cargo install cargo-dylint dylint-link once, and expect build/debug/codegen and vendor/lolhtml to exist, which any normal bun bd leaves 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.