The Problem
Bazel projects benefit from consistent code formatting. While Buildifier handles formatting when run manually through text editors, this approach lacks reliability across teams and automated processes. Code from various sources—scripts, contributors without Buildifier installed—can bypass formatting standards.
Continuous integration typically catches formatting issues, but this feedback arrives late in the development cycle. Wouldn’t it be great to get this feedback when building and testing your code before submitting it to the CI system?
Solution: bzlformat
bzlformat integrates formatting into the normal build workflow by providing Bazel rules that:
- Format Starlark files using Buildifier
- Test that formatted files exist in the workspace
- Copy formatted files to source directories
Implementation Steps
1. Configure Your Workspace
Add to your WORKSPACE file:
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
http_archive(
name = "cgrindel_bazel_starlib",
sha256 = "fc2ee0fce914e3aee1a6af460d4ba1eed9d82e8125294d14e7d3f236d4a10a5d",
strip_prefix = "bazel-starlib-0.3.2",
urls = ["http://github.com/cgrindel/bazel-starlib/archive/v0.3.2.tar.gz"],
)
load("@cgrindel_bazel_starlib//:deps.bzl", "bazel_starlib_dependencies")
bazel_starlib_dependencies()
load("@bazel_skylib//:workspace.bzl", "bazel_skylib_workspace")
bazel_skylib_workspace()
Include Buildifier:
load("@buildifier_prebuilt//:deps.bzl", "buildifier_prebuilt_deps")
buildifier_prebuilt_deps()
load("@buildifier_prebuilt//:defs.bzl", "buildifier_prebuilt_register_toolchains")
buildifier_prebuilt_register_toolchains()
2. Update Root BUILD File
load("@cgrindel_bazel_starlib//bzlformat:defs.bzl",
"bzlformat_missing_pkgs", "bzlformat_pkg")
load("@cgrindel_bazel_starlib//updatesrc:defs.bzl",
"updatesrc_update_all")
bzlformat_pkg(name = "bzlformat")
bzlformat_missing_pkgs(name = "bzlformat_missing_pkgs")
updatesrc_update_all(
name = "update_all",
targets_to_run = [":bzlformat_missing_pkgs_fix"],
)
3. Add bzlformat_pkg to Every Package
Run:
bazel run //:update_all
4. Format and Test
# Format and copy files back
bazel run //:update_all
# Test including formatting checks
bazel test //...
5. Optional CI Integration
bazel run //:bzlformat_missing_pkgs_test
If failures occur, run the fix command and re-test.
How It Works
bzlformat_pkg creates three types of targets per package:
- Format targets - Build-time actions that format Starlark files (
.bzl,BUILD,BUILD.bazel) - Test targets - Diff tests comparing source files with formatted output; fails if differences exist
- Update target - Executable that copies formatted files back to source
bzlformat_missing_pkgs provides three executable targets:
find- Reports packages missing bzlformat declarationstest- Same query but fails if packages found (for CI)fix- Automatically adds missing declarations
Conclusion
By embedding format checks into the development build cycle rather than deferring to CI, developers receive immediate feedback. This approach maintains code consistency while improving the developer experience through earlier problem detection.