bazelbuild/bazel

The polyglot build-system case study where alint stops and `buildifier` begins — and where `.bazelversion` (tracked AND gitignored) was the canonical motivating example for the v0.9.17 `respect_gitignore` per-rule fix.

Narrative
Replaces the structural subset of your custom orchestration layer
Rules
81
Last revalidated
Engineering reference
README on GitHub · .alint.yml

Why this case study matters

bazelbuild/bazel is the canonical “build system that builds itself” repository: 322 BUILD files, 100 *.bzl Starlark macro / rule files, a 482-line MODULE.bazel, plus Java + C++ + Python + shell + .bat source trees, all driven by Bazel itself. There is no pom.xml, no build.gradle, no Cargo.toml, no go.mod, no package.json at the repo root despite the multi-language content. The actual build-and-test CI runs OUT of GitHub on Buildkite via 309 lines of .bazelci/presubmit.yml covering 25+ platform tasks.

Roughly 46% of that structural surface maps to declarative alint rules. ~16% shells out via command: rules (mostly buildifier --lint for the Starlark AST layer plus shellcheck). And ~38% is deliberately out of alint’s scope — the entire Starlark-AST surface where buildifier already does excellent work.

That out-of-scope fraction is the highest of any case study to date, and it is the launch-honesty anchor: bazel is the repo where the boundary between “structural shape” and “language semantics” is at its most visible.

Headline catch

.bazelversion was the canonical motivating example for v0.9.17’s respect_gitignore: false per-rule knob. The file IS tracked in git, but ALSO listed in bazel’s own .gitignore (line 34) — contributors override it locally to use a different installed Bazel version, and the gitignore stops those local edits from drifting back into commits.

Pre-v0.9.17, alint’s walker respected .gitignore for discovery, so a file_exists rule against .bazelversion would silently miss the file even though git ls-files confirmed it tracked. bazel was the first repo in the launch-evidence corpus to expose the pattern.

v0.9.17 closed it: per-rule respect_gitignore: false overrides the workspace default for one rule. Verified working against /tmp/bazel/.bazelversion during the 2026-05-07 revalidation pass — rule passes with the override, rule fails (“expected a file matching [.bazelversion] at the repo root”) without it.

- id: bazel-version-pinned
kind: file_exists
paths: .bazelversion
respect_gitignore: false # ← new in v0.9.17
root_only: true
level: error

bazel is now the documented canonical example in the project’s pitfall catalogue. The fix is general (any repo that ships local-override patterns hits the same shape), but bazel was the demand source.

Where alint earns its keep here

alint owns the filesystem-shape layer that crosses every language in this tree:

The Starlark AST tier — cc_library deps integrity, glob([...]) vs filesystem, target visibility, load() ordering, deprecated rule-attribute usage — stays on buildifier and bazel query. alint orchestrates buildifier via a command: rule so the Starlark AST findings appear in the same alint check invocation, but doesn’t pretend to parse Starlark.

The pattern is consistent: alint shells out to ruff / black / pyink for Python AST work, gofmt / go vet for Go AST work, clang-format / clang-tidy for C++, clippy for Rust, and buildifier / buildozer for Starlark. The cross-language file-structure layer is alint’s; the per-language AST/semantic layer stays with the existing per-language tools.

A new contributor staring at bazel’s structural-validation surface today reads:

That is ~1,000+ lines of structural-validation surface, half of which is enforced only by code-review etiquette. The 81-rule alint config in this case study is one file, declarative, with each rule’s scope, severity, and rationale visible in 5-10 lines.

Future story angles

The factual engineering writeup (tooling inventory, mapping table, gap catalogue, validation status footer) lives in the public alint repo at github.com/asamarts/alint/tree/main/examples/bazelbuild-bazel/README.md.